Monday, June 28, 2010

Fortune Engine helps Debug Infinite Loop

The fortune engine helped debug an infinite loop with relative ease today. There was a bug in our code that caused the game to come to a halt. The bug was in one of our drawing callbacks that didn't return back to the game engine.

What is great about the design of the game engine is there are (as of today) two threads, a drawing thread and an event loop thread. This bug showed a problem with the design of the engine, you can't run the debug console when the user code in drawing or event thread fails to return control to the game engine loop. I will have to make a fix for this later.

So how did the engine help debug the loop? Well once you can determine that it was with the drawing and not the event loop it cuts out half of the things you need to debug. This was easy to do as the engine now uses a lock to ensure either a drawing or updating state gets to finish before switching threads. So by simply adding two print statements I was able to find it was crashing in the drawing thread as it didn't return the lock.

The next step was to figure out which draw callback was causing problems. This was as simple as adding one print statement.

diff --git a/MAFH2/fortuneengine/GameEngine.py b/MAFH2/fortuneengine/GameEngine.
index 477bd07..610de30 100644
--- a/MAFH2/fortuneengine/GameEngine.py
+++ b/MAFH2/fortuneengine/GameEngine.py
@@ -129,6 +129,7 @@ class GameEngine(object):
             else:
                 self.event_lock.acquire()
                 for fnc in self.__draw_lst:
+                    print "DRAWING", fnc
                     fnc(self.screen)

This one statement brought the scope of the problem down to a single function.


DRAWING <bound method TermBox.draw of <TermBox.TermBox object at 0x99cdfec>>
DRAWING <bound method Dungeon.draw of <Dungeon.Dungeon object at 0x99bf0ec>>
DRAWING <bound method Map.draw of <Map.Map object at 0x99d884c>>
DRAWING <bound method BattleEngine.draw of <BattleEngine.BattleEngine object at 0x99d8f8c>>
DRAWING <bound method BattleMenuHolder.draw of <BattleMenu.BattleMenuHolder object at 0x99d88cc>>
DRAWING <bound method BattleMenu.draw of <BattleMenu.BattleMenu object at 0x99dc4ac>>
DRAWING <bound method MagicMenuHolder.draw of <MagicMenu.MagicMenuHolder object at 0x99dcc6c>>
DRAWING <bound method MagicMenu.draw of <MagicMenu.MagicMenu object at 0x99dcd6c>>
zsh: killed ./MafhActivity.py


This output showed the last function the game engine was able to call in the drawing thread was the draw method of the MagicMenu class. From this point, we knew the function that was causing the issue and from there it was pretty clear to look for any loops.

No comments:

Post a Comment