Game Programming Debugging & Performance Optimization Nick Prühs
Game ProgrammingDebugging & Performance Optimization
Nick Prühs
Objectives
• To get an overview of techniques for preventing bugs beforehand
• To learn how to track down and properly remove bugs from your code
• To understand possible performance bottlenecks
2 / 49
Why you should alwaysstart debugging immediately• Code entropy says your code will get worse, all the
time, unless you actively invest in preventing that
• Broken windows theory says the worse your code is, the worse it will become
• Tracking down bugs is harder in a larger code base
• Tracking down bugs is harder in a buggy code base
3 / 12
Code Quality Tools
4 / 12
Code Quality Tools
5 / 12
Code Quality Tools
6 / 12
/// <summary>
/// Attaches the passed component to the entity with the specified id.
/// Note that this manager does not check whether the specified id is valid.
/// </summary>
/// <exception cref="ArgumentNullException">
/// Passed component is null.
/// </exception>
/// <exception cref="InvalidOperationException">
/// There is already a component of the same type attached.
/// </exception>
public void AddComponent(int entityId, IEntityComponent component)
{
if (component == null)
{
throw new ArgumentNullException("component");
}
if (this.components.ContainsKey(entityId))
{
throw new InvalidOperationException(
"There is already a component of type " + component.GetType() + " attached to entity with id "
+ entityId + ".");
}
this.components.Add(entityId, component);
this.OnComponentAdded(entityId, component);
}
You need a repro. Period.
How can you be sure you’ve fixed it?
7 / 12
Stack Traces
Object reference not set to an instance of an object
at LifeApplication.Initializer.CreateManagers () [0x00488] in Initializer.cs:481
at LifeApplication.Initializer.OnLoad () [0x00016] in Initializer.cs:235
8 / 12
What’s null here?
// Initialize progress manager.
var progressConfig = newProgressConfig(this.unityLoader.Version.Code);
if (this.config.Progress.Encrypt)
{
progressConfig.SetEncryption(
this.config.Progress.Encryption.EncryptKey,
this.config.Progress.Encryption.EncryptIv);
}
9 / 12
What’s null here?
// Initialize progress manager.
var progressConfig = newProgressConfig(this.unityLoader.Version.Code);
if (this.config.Progress.Encrypt)
{
progressConfig.SetEncryption(
this.config.Progress.Encryption.EncryptKey,
this.config.Progress.Encryption.EncryptIv);
}
10 / 12
What’s null here?
// Initialize progress manager.
var progressConfig = newProgressConfig(this.unityLoader.Version.Code);
if (this.config.Progress.Encrypt)
{
progressConfig.SetEncryption(
this.config.Progress.Encryption.EncryptKey,
this.config.Progress.Encryption.EncryptIv);
}
11 / 12
What’s null here?
// Initialize progress manager.
var progressConfig = newProgressConfig(this.unityLoader.Version.Code);
if (this.config.Progress.Encrypt)
{
progressConfig.SetEncryption(
this.config.Progress.Encryption.EncryptKey,
this.config.Progress.Encryption.EncryptIv);
}
12 / 12
What’s null here?
// Initialize progress manager.
var progressConfig = newProgressConfig(this.unityLoader.Version.Code);
if (this.config.Progress.Encrypt)
{
progressConfig.SetEncryption(
this.config.Progress.Encryption.EncryptKey,
this.config.Progress.Encryption.EncryptIv);
}
13 / 12
What’s null here?
// Initialize progress manager.
var progressConfig = newProgressConfig(this.unityLoader.Version.Code);
if (this.config.Progress.Encrypt)
{
progressConfig.SetEncryption(
this.config.Progress.Encryption.EncryptKey,
this.config.Progress.Encryption.EncryptIv);
}
14 / 12
Divide-and-conquer
15 / 12
Divide-and-conquer
16 / 12
Divide-and-conquer
17 / 12
Divide-and-conquer
18 / 12
Divide-and-conquer
19 / 12
Divide-and-conquer
20 / 12
Conditional Breakpoints
21 / 12
Logging
22 / 12
On-Screen
23 / 12
Crash Dump Analaysis
24 / 43
C:\Program Files\Procdump>procdump.exe -ma -i D:\Temp\Dumps
ProcDump v7.0 - Writes process dump files
Copyright (C) 2009-2014 Mark Russinovich
Sysinternals - www.sysinternals.com
With contributions from Andrew Richards
Set to:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
(REG_SZ) Auto = 1
(REG_SZ) Debugger = "C:\Program Files\Procdump\procdump.exe" -accepteula -ma
-j "D:\Temp\Dumps" %ld %ld %p
Set to:
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug
(REG_SZ) Auto = 1
(REG_SZ) Debugger = "C:\Program Files\Procdump\procdump.exe" -accepteula -ma
-j "D:\Temp\Dumps" %ld %ld %p
ProcDump is now set as the Just-in-time (AeDebug) debugger.
Crash Dump Analaysis
25 / 43
C:\Program Files\Procdump>procdump.exe -u
ProcDump v7.0 - Writes process dump files
Copyright (C) 2009-2014 Mark Russinovich
Sysinternals - www.sysinternals.com
With contributions from Andrew Richards
Reset to:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
(REG_SZ) Auto = <deleted>
(REG_SZ) Debugger = "C:\WINDOWS\system32\vsjitdebugger.exe" -p %ld -e %ld
Reset to:
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug
(REG_SZ) Auto = <deleted>
(REG_SZ) Debugger = "C:\WINDOWS\system32\vsjitdebugger.exe" -p %ld -e %ld
ProcDump is no longer the Just-in-time (AeDebug) debugger.
Crash Dump Analaysis
26 / 43
Deferencing a nullptr that will cause a crash
Crash Dump Analaysis
27 / 43
Minidump File Summary in Visual Studio
Crash Dump Analaysis
28 / 43
Debugging a Minidump in Visual Studio
Pair Programming
29 / 12Source: University of Utah, UIT
And if nothings helps …
30 / 12
And if nothings helps …
31 / 12
TRY AGAIN TOMORROW!
Some are really nasty …
• Remote systems
• Race conditions
• Mobile development, embedded systems, drivers
• “Release Mode only” bugs
32 / 12
Quoting My Tutor
“If the bug is not where you expect it to be,
you better start looking for it where you’re not expecting it to be.”
- Hagen Peters
33 / 12
Why you should neverstart optimizing immediately• Your code base will change over time, a lot, most
likely removing some of the code you’ve spent time on optimizing
• Optimized code tends to be hard to read• … and thus, hard to debug.
34 / 12
Performance Optimization
1. Profile first!
35 / 12
Performance Optimization
1. Profile first!
2. Profile again!
36 / 12
Performance Optimization
1. Profile first!
2. Profile again!
3. Identify the bottlenecks: CPU vs. GPU vs. Memory
37 / 12
Fighting CPU Bottlenecks
Pooling
Trades memory for CPU performance.
Re-uses objects to prevent costly construction and destruction.
Requires proper (cheap) reset of pooled objects.
38 / 12
Fighting CPU Bottlenecks
Caching
Trades memory for CPU performance.
Stores computed values for later use.
Requires proper cache invalidation whenever the input changes.
39 / 12
Fighting CPU Bottlenecks
Bucketing
Trades accuracy for CPU performance.
Distributes computations across multiple frames by dividing operation into multiple input sets.
Can only be applied if player doesn’t notice difference immediately (e.g. updating AI just twice per second).
40 / 12
Memory Bottleneck
41 / 12
Memory Bottleneck
42 / 12
Memory Bottleneck
43 / 12
GPU Bottleneck
44 / 12
Frame Debugger
45 / 12
Frame Debugger
46 / 12
Frame Debugger
47 / 12
Frame Debugger
48 / 12
Frame Debugger
49 / 12
Gotcha!
Always turn off logging before profiling!
Otherwise, disk I/O will lead to false results.
50 / 28
Hint
If no native profiling tools are available (or applicable), you can always fall back to utility classes
such as System.Diagnostics.Stopwatch.
51 / 28
References
• McShaffry. Debugging Your Game … or “That’s not supposed to happen!”. Austin Game Conference, 2003.
52 / 28