240 likes | 405 Views
GAME 1024: Advanced Game Programming. Lesson 4: Debugging Is As Easy As 01, 10, 11 By Kain Shin. Quiz. What’s your full name State TWO reasons to make your program data driven What’s one reason to use an INI file over XML? What’s one reason to use an XML file over INI?
E N D
GAME 1024: Advanced Game Programming Lesson 4: Debugging Is As Easy As 01, 10, 11 By Kain Shin
Quiz • What’s your full name • State TWO reasons to make your program data driven • What’s one reason to use an INI file over XML? • What’s one reason to use an XML file over INI? • What is the difference between a function pointer and a functor? • Give an example of a situation where you would want to use either a function pointer or a functor.
Bonus C++ Topic: Templates • Definition: special code (classes/functions) that can operate with generic types • How? The compiler will create the explicit version of your generic template AS NEEDED. • “As Needed” means templates do not exist in the exe unless something in code uses it • Beware: Using a template with 100 different types is like writing 100 different explicit pieces of code for that type as far as exe size is concerned. • Examples of templates already in use are STL and Boost
Template Function Example • Template Function Declaration:template <class T>T GetMin(T a, T b){ return a<b ? a:b;} • Template Function Usage:int minimumInt = GetMin<int>(10, 24); • T is of type “int”, which means the return value (minimumInt) as well as the a and b parameters (10 and 24) must all be of type “int” • Because “a<b” is used in the template, that means that whatever type T is needs to have operator< defined for it. So this code would not compile if I used a custom class in place of T that did not have “operator<“ defined.
Template Class Example • Declaration:template <class T>class cPair{public: cPair(T v1, T v2); bool operator==(const cPair& rhs)const;private: T m_v1; T m_v2;};template <class T>cPair::cPair(T v1, T v2): m_v1(v1), m_v2(v2){}template <class T>bool cPair::operator==(const cPair& rhs)const{ return m_v1==rhs.m_v1 && m_v2==rhs.m_v2;}
Templates Continued • Template Class Usage:cPair<float> myFloatPair; • Unlike a normal C++ class, template classes have restrictions on the class declaration being in a separate file from the class implementation. You can do it, but the method is messy and it’s just not worth it. • You can have as many generic types as you want in a template. For example, you could do something like this….template <class X, class Y, class Z> • You can even specify an explicit type in your template argument. Like this…template <class X, int i, float f> • Remember that you don’t always have to pass in int or float as the explicit type for a template. You can use a complex type such as “cEventID” as long as cEventID has the proper functions defined that are needed by the template • Think of templates as a syntax that tells the compiler to “copy this code, but replace the placeholder template parameters (like T) with my explicit parameters (like int)”
Kill Your Bugs! • Definition: When something doesn’t work as intended (crashes or acts “wrong”) • Debugging is where the “Scientist” in “Computer Science” kicks in. The person debugging is playing the role of a detective. • Debugging Workflow • Identify the Bug • Isolate the Source • Isolate the Cause • Determine the Fix • Execute and Test the Fix • Things to Debug… • Algorithmic Error • Memory Leaks • User Error • Bad Data • Etc.
Level 1: IDE Tools • Call Stack • Breakpoints • Watch Windows • Setting/Stepping the Instruction Pointer • Disassembly • Remote Debugging
Level 2:Tools You Write In Game Code • Special Debug Visualizations (i.e. Physics Hulls or Camera “Bread Crumbs”) • Log Files • Output Messages • Asserts • User Dialog Boxes • Stuff Related to a Memory Manager
Level 3: HARDCORE!!!Using A Server App As A Debugger • Communicates with the main app through TCP or UDP • Visualizes the world in a data-centric manner as opposed to graphics-centric… like Neo inside the Matrix! • Great for debugging apps on one or more separate machines (Like multiplayer deathmatch, MMOs) • Great for visualizing and setting data that would be too messy to tweak in the main app (such as AI states) • Lots of logging…. Potentially able to play back recorded events to simulate a recorded crash
A Note About Fullscreen Debugging • It Sucks, try not to do it unless you have a second monitor • If you have only one monitor, run in windowed mode • It is possible to have bugs that only happen in fullscreen mode. If this is the case AND you can’t get a second monitor, then use techniques that don’t interrupt the program (log files, output messages, remote debugging, stand-alone app running on another machine)
Detecting Memory Leaks • What is a memory leak: It is when a heap allocation is not deallocated when the program exits. The classic case is when a pointer gets orphaned. • A custom memory manager is the best way to detect memory leaks. We will cover this in a later lecture. • Visual Studio’s C Runtime Library Offers Three Functions that access the special debug heap that gets used when you run from the IDE: • _CrtSetDbgFlag( int newFlag ) – Sets the behavior of the debug heap. You typically use “_CRTDBG_LEAK_CHECK_DF” to get a dump of any leaks upon app exit • _CrtCheckMemory() – Runs a check on the debug heap for any orphaned memory • _CrtDumpMemoryLeaks() – Reports any leaks to stdout
_CrtSetDbgFlag Usage Example #if defined(_DEBUG) # define NEW new(_NORMAL_BLOCK,FILE,LINE_) #else # define NEW new #endif #include <crtdbg.h> void main() {int tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);// always perform a leak check just before app exits. tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;CrtSetDbgFlag(tmpDbgFlag);cGame game; bool playGame; do { playGame = game.Update(); } while( playGame ); }
Watch Windows • Lets you see the value of any variable or memory address • Only works if debug information is available, which it should be by default in DEBUG builds. You can do this in RELEASE builds, too, if you set it in your IDE • Only updates when program execution is paused
Using Asserts • Pauses code execution if evaluated to false, but only in debug mode • Usage:#include <assert.h>…assert(false); • Useful Trick:assert(false && “Helpful message here”);
Breakpoints • Definition: Guaranteed to pause program execution when it hits the set condition • Visual Studio: F9 or click on area to the left of the target code • The condition is commonly “when execution hits a specific instruction in code” • The condition can be “when a certain memory address changes” • Can use the watch window while execution is paused
Stepping/Setting the Instruction Pointer • You can make code execute one line at a time • Visual Studio: Debug->Step* Menu or F10/F11 keys • You can set what line of code executes next • Visual Studio: right-click -> “Set Next Statement” • This may be the single most helpful debugging technique at your disposal
Call Stack • Only active when code execution is paused (assert, breakpoint, access violation crash) • Lets you know where current execution is in relation to the codebase • When you have a problem in code and need to communicate with another programmer, show them the call stack at the very least, or else it will be difficult to help you
Log Files • An easy implementation is “fprintf(stderr, …)” as seen in the class project, BUT… • If you want more control, then you will need to wrap your log functionality into a proper log file class that a program can properly append to, wipe, or create a new dated version as needed. • Reasons to wrap log functionality into a class instead of using stderr: • Can use more than one log file for different systems • Probably want log entries to be automatically timestamped • Could be written in XML for “smart analysis” by another application • The class can display logged info as an Output Message while logging • Log files should output to a temp folder so that people don’t accidentally think it is needed for the install
Output Messages • Shows Up in the IDE and/or Custom User Tool within a special output window • Usually displays information that goes to a log file. It is still useful because people can watch this window while the app is running instead of checking the log file every X seconds • With Visual Studio, you can use “OutputDebugString” to get your messages into the IDE’s output window
Remote Debugging • Definition: Attaching your IDE to an external exe on another machine • You would do this if developing on a console (PC to console connection) • Also useful for debugging an exe on another person’s machine (like a non-programmer) • Could be used to debug something that only happens in fullscreen on a system with only one monitor
Putting It All Together • You get an access violation crash… What Do You Do? • View the call stack to see if there is any place in the stack that you should dig into • Drag variables into the watch window to see their values • If that is still not enough, place a breakpoint in a key location to see what you’re getting and try to reproduce the crash • From the breakpoint, use the step functions to step the code one line at a time, checking your watched variables at relevant steps • Place asserts in code to catch bad things as they are happening • View log output, set the instruction pointer, be like the Batman of bugs, etc…
Your Class Project • In Milestone 1: “#define your own versions of “new” and “delete”. Call them NEW and DELETE, respectively. For now, leave them as the default new and delete. You’ll be writing a custom memory allocator eventually.” • Why do I make you define your own “NEW” and “DELETE” in all caps instead of redefining “new” and “delete”? Because you want to use the caps version to get the benefits of whatever memory management code you write without name-colliding with another library’s use of “new” and “delete”, which may have been redefined by them in the same way, but without the upper case. • In Milestone 2: “Logging/Debug Output: Make sure all notable occurences are logged in a log file and outputted in the debug window” • You will need to write a cLogger class that takes strings you send in and spits it out within the IDE’s Output window AND a file specified upon construction of the cLogger object
Final Thoughts… • You get better at debugging as you gain programming experience and a deeper understanding of how the hardware works • There is a lot of material out there that goes deeper into debugging than this lame PowerPoint presentation. • Your debugging methods will vary depending on the hardware you use • Sometimes, a really tough bug becomes an easy bug after a full night’s rest • Bugs will happen: You will never be a good programmer unless your debugging skills are decent, at the very least