data oriented design and c++

201
Data-Oriented Design and C++ Mike Acton Engine Director, Insomniac Games @mike_acton

Upload: mike-acton

Post on 18-Nov-2014

12.133 views

Category:

Technology


5 download

DESCRIPTION

cppcon keynote

TRANSCRIPT

Page 1: Data oriented design and c++

Data-Oriented Design and C++

Mike ActonEngine Director, Insomniac Games

@mike_acton

Page 2: Data oriented design and c++

A bit of background…

Page 3: Data oriented design and c++

What does an “Engine” team do?

Page 4: Data oriented design and c++

Runtime systems

e.g.• Rendering• Animation and gestures• Streaming• Cinematics• VFX• Post-FX• Navigation• Localization• …many, many more!

Page 5: Data oriented design and c++

Development tools

e.g.• Level creation• Lighting• Material editing• VFX creation• Animation/state machine editing• Visual scripting• Scene painting• Cinematics creation• …many, many more!

Page 6: Data oriented design and c++

What’s important to us?

Page 7: Data oriented design and c++

What’s important to us?

• Hard deadlines

Page 8: Data oriented design and c++

What’s important to us?

• Hard deadlines• Soft realtime performance requirements (Soft=33ms)

Page 9: Data oriented design and c++

What’s important to us?

• Hard deadlines• Soft realtime performance requirements (Soft=33ms)• Usability

Page 10: Data oriented design and c++

What’s important to us?

• Hard deadlines• Soft realtime performance requirements (Soft=33ms)• Usability• Performance

Page 11: Data oriented design and c++

What’s important to us?

• Hard deadlines• Soft realtime performance requirements (Soft=33ms)• Usability• Performance• Maintenance

Page 12: Data oriented design and c++

What’s important to us?

• Hard deadlines• Soft realtime performance requirements (Soft=33ms)• Usability• Performance• Maintenance• Debugability

Page 13: Data oriented design and c++

What languages do we use…?

Page 14: Data oriented design and c++

What languages do we use…?

• C• C++• Asm• Perl• Javascript• C#

Page 15: Data oriented design and c++

What languages do we use…?

• C• C++ ~70%• Asm• Perl• Javascript• C#

Page 16: Data oriented design and c++

What languages do we use…?

• C• C++ ~70%• Asm• Perl• Javascript• C#• Pixel shaders, vertex shaders, geometry shaders, compute shaders, …

Page 17: Data oriented design and c++

We don’t make games for Mars but…

Page 18: Data oriented design and c++

How are games like the Mars rovers?

Page 19: Data oriented design and c++

How are games like the Mars rovers?•Exceptions

Page 20: Data oriented design and c++

How are games like the Mars rovers?•Exceptions•Templates

Page 21: Data oriented design and c++

How are games like the Mars rovers?•Exceptions•Templates• Iostream

Page 22: Data oriented design and c++

How are games like the Mars rovers?•Exceptions•Templates• Iostream•Multiple inheritance

Page 23: Data oriented design and c++

How are games like the Mars rovers?•Exceptions•Templates• Iostream•Multiple inheritance•Operator overloading

Page 24: Data oriented design and c++

How are games like the Mars rovers?•Exceptions•Templates• Iostream•Multiple inheritance•Operator overloading•RTTI

Page 25: Data oriented design and c++

How are games like the Mars rovers?•No STL

Page 26: Data oriented design and c++

How are games like the Mars rovers?•No STL•Custom allocators (lots)

Page 27: Data oriented design and c++

How are games like the Mars rovers?•No STL•Custom allocators (lots)•Custom debugging tools

Page 28: Data oriented design and c++

Is data-oriented even a thing…?

Page 29: Data oriented design and c++

Data-Oriented Design Principles

The purpose of all programs, and all parts of those programs, is to transform data from one form to another.

Page 30: Data oriented design and c++

Data-Oriented Design Principles

If you don’t understand the data you don’t understand the problem.

Page 31: Data oriented design and c++

Data-Oriented Design Principles

Conversely, understand the problem by understanding the data.

Page 32: Data oriented design and c++

Data-Oriented Design Principles

Different problems require different solutions.

Page 33: Data oriented design and c++

Data-Oriented Design Principles

If you have different data, you have a different problem.

Page 34: Data oriented design and c++

Data-Oriented Design Principles

If you don’t understand the cost of solving the problem, you don’t understand the problem.

Page 35: Data oriented design and c++

Data-Oriented Design Principles

If you don’t understand the hardware, you can’t reason about the cost of solving the problem.

Page 36: Data oriented design and c++

Data-Oriented Design Principles

Everything is a data problem. Including usability, maintenance, debug-ability, etc. Everything.

Page 37: Data oriented design and c++

Data-Oriented Design Principles

Solving problems you probably don’t have creates more problems you definitely do.

Page 38: Data oriented design and c++

Data-Oriented Design Principles

Latency and throughput are only the same in sequential systems.

Page 39: Data oriented design and c++

Data-Oriented Design Principles

Latency and throughput are only the same in sequential systems.

Page 40: Data oriented design and c++

Data-Oriented Design Principles

Rule of thumb: Where there is one, there are many. Try looking on the time axis.

Page 41: Data oriented design and c++

Data-Oriented Design Principles

Rule of thumb: The more context you have, the better you can make the solution. Don’t throw away data you need.

Page 42: Data oriented design and c++

Data-Oriented Design Principles

Rule of thumb: NUMA extends to I/O and pre-built data all the way back through time to original source creation.

Page 43: Data oriented design and c++

Data-Oriented Design Principles

Software does not run in a magic fairy aether powered by the fevered dreams of CS PhDs.

Page 44: Data oriented design and c++

Is data-oriented even a thing…?

…certainly not new ideas.

…more of a reminder of first principles.

Page 45: Data oriented design and c++

…but it is a response to the culture of C++

Page 46: Data oriented design and c++

…but it is a response to the culture of C++

…and The Three Big Lies it has engendered

Page 47: Data oriented design and c++
Page 48: Data oriented design and c++
Page 49: Data oriented design and c++
Page 50: Data oriented design and c++
Page 51: Data oriented design and c++
Page 52: Data oriented design and c++
Page 53: Data oriented design and c++
Page 54: Data oriented design and c++
Page 55: Data oriented design and c++
Page 56: Data oriented design and c++
Page 57: Data oriented design and c++
Page 58: Data oriented design and c++
Page 59: Data oriented design and c++
Page 60: Data oriented design and c++
Page 61: Data oriented design and c++
Page 62: Data oriented design and c++
Page 63: Data oriented design and c++
Page 64: Data oriented design and c++

i.e. Programmer’s job is NOT to write code; Programmer’s job is to solve (data transformation) problems

Page 65: Data oriented design and c++
Page 66: Data oriented design and c++
Page 67: Data oriented design and c++
Page 68: Data oriented design and c++
Page 69: Data oriented design and c++
Page 70: Data oriented design and c++
Page 71: Data oriented design and c++
Page 72: Data oriented design and c++

A simple example…

Page 73: Data oriented design and c++
Page 74: Data oriented design and c++
Page 75: Data oriented design and c++
Page 76: Data oriented design and c++
Page 77: Data oriented design and c++
Page 78: Data oriented design and c++
Page 79: Data oriented design and c++
Page 80: Data oriented design and c++
Page 81: Data oriented design and c++
Page 82: Data oriented design and c++

Solve for the most common case first,

Not the most generic.

Page 83: Data oriented design and c++

“Can’t the compiler do it?”

Page 84: Data oriented design and c++

A little review…

Page 85: Data oriented design and c++

http://www.agner.org/optimize/instruction_tables.pdf

(AMD Piledriver)

Page 86: Data oriented design and c++

http://www.agner.org/optimize/instruction_tables.pdf

(AMD Piledriver)

Page 87: Data oriented design and c++

http://research.scee.net/files/presentations/gcapaustralia09/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf

Page 88: Data oriented design and c++

http://www.gameenginebook.com/SINFO.pdf

Page 89: Data oriented design and c++

The Battle of North Bridge

L1

L2

RAM

Page 90: Data oriented design and c++

L2 cache misses/frame(Most significant component)

Page 91: Data oriented design and c++

Not even including shared memory modes…

Name GPU-visible Cached GPU Coherent

Heap-cacheable No Yes No

Heap-write-combined No No No

Physical-uncached ? No No

GPU-write-combined Yes No No

GPU-write-combined-read-only Yes No No

GPU-cacheable Yes Yes Yes

GPU-cacheable-noncoherent-RO Yes Yes No

Command-write-combined No No No

Command-cacheable No Yes Yes

Page 92: Data oriented design and c++

http://deplinenoise.wordpress.com/2013/12/28/optimizable-code/

Page 93: Data oriented design and c++
Page 94: Data oriented design and c++

2 x 32bit read; same cache line = ~200

Page 95: Data oriented design and c++

Float mul, add = ~10

Page 96: Data oriented design and c++

Let’s assume callq is replaced. Sqrt = ~30

Page 97: Data oriented design and c++

Mul back to same addr; in L1; = ~3

Page 98: Data oriented design and c++

Read+add from new line= ~200

Page 99: Data oriented design and c++

Time spent waiting for L2 vs. actual work

~10:1

Page 100: Data oriented design and c++

Time spent waiting for L2 vs. actual work

~10:1

This is the compiler’s space.

Page 101: Data oriented design and c++

Time spent waiting for L2 vs. actual work

~10:1

This is the compiler’s space.

Page 102: Data oriented design and c++

Compiler cannot solve the most significant problems.

Page 103: Data oriented design and c++

Today’s subject: The 90% of problem space we need to solve that the compiler

cannot.

(And how we can help it with the 10% that it can.)

Page 104: Data oriented design and c++

Simple, obvious things to look for + Back of the envelope

calculations = Substantial wins

Page 105: Data oriented design and c++

L2 cache misses/frame(Don’t waste them!)

Page 106: Data oriented design and c++

Waste 56 bytes / 64 bytes

Page 107: Data oriented design and c++

Waste 60 bytes / 64 bytes

Page 108: Data oriented design and c++

90% waste!

Page 109: Data oriented design and c++

Alternatively,Only 10% capacity used*

* Not the same as “used well”, but we’ll start here.

Page 110: Data oriented design and c++
Page 111: Data oriented design and c++

12 bytes x count(5) = 72

Page 112: Data oriented design and c++

12 bytes x count(5) = 72

4 bytes x count(5) = 20

Page 113: Data oriented design and c++

12 bytes x count(32) = 384 = 64 x 6

4 bytes x count(32) = 128 = 64 x 2

Page 114: Data oriented design and c++

12 bytes x count(32) = 384 = 64 x 6

4 bytes x count(32) = 128 = 64 x 2

(6/32) = ~5.33 loop/cache line

Page 115: Data oriented design and c++

12 bytes x count(32) = 384 = 64 x 6

4 bytes x count(32) = 128 = 64 x 2

Sqrt + math = ~40 x 5.33 = 213.33 cycles/cache line(6/32) = ~5.33 loop/cache line

Page 116: Data oriented design and c++

12 bytes x count(32) = 384 = 64 x 6

4 bytes x count(32) = 128 = 64 x 2

Sqrt + math = ~40 x 5.33 = 213.33 cycles/cache line(6/32) = ~5.33 loop/cache line

+ streaming prefetch bonus

Page 117: Data oriented design and c++

12 bytes x count(32) = 384 = 64 x 6

4 bytes x count(32) = 128 = 64 x 2

Sqrt + math = ~40 x 5.33 = 213.33 cycles/cache line(6/32) = ~5.33 loop/cache line

+ streaming prefetch bonus

Using cache line to capacity* =10x speedup

* Used. Still not necessarily as efficiently as possible

Page 118: Data oriented design and c++

Sqrt + math = ~40 x 5.33 = 213.33 cycles/cache line(6/32) = ~5.33 loop/cache line

+ streaming prefetch bonus

In addition…1. Code is maintainable

2. Code is debugable3. Can REASON about cost of change

Page 119: Data oriented design and c++

Sqrt + math = ~40 x 5.33 = 213.33 cycles/cache line(6/32) = ~5.33 loop/cache line

+ streaming prefetch bonus

In addition…1. Code is maintainable

2. Code is debugable3. Can REASON about cost of change

Ignoring inconvenient facts is not engineering;It’s dogma.

Page 120: Data oriented design and c++

bools in structs… (3) Extremely low information density

Page 121: Data oriented design and c++

bools in structs… (3) Extremely low information density

How big is your cache line?

Page 122: Data oriented design and c++

bools in structs… (3) Extremely low information density

How big is your cache line?

What’s the most commonly accessed data?

64b?

Page 123: Data oriented design and c++

(2) Bools and last-minute decision makingHow is it used? What does it generate?

Page 124: Data oriented design and c++

MSVC

Page 125: Data oriented design and c++

MSVC

Re-read and re-test…

Increment and loop…

Page 126: Data oriented design and c++

Re-read and re-test…

Increment and loop…

Why?

Super-conservative aliasing rules…?Member value might change?

Page 127: Data oriented design and c++

What about something more aggressive…?

Page 128: Data oriented design and c++

Test once and return…

What about something more aggressive…?

Page 129: Data oriented design and c++

Okay, so what about…

Page 130: Data oriented design and c++

…well at least it inlined it?

Page 131: Data oriented design and c++

MSVC doesn’t fare any better…

Page 132: Data oriented design and c++

Don’t re-read member values or re-call functions whenyou already have the data.

(4) Ghost reads and writes

Page 133: Data oriented design and c++

BAM!

Page 134: Data oriented design and c++

:(

Page 135: Data oriented design and c++

(4) Ghost reads and writes

Don’t re-read member values or re-call functions whenyou already have the data.

Hoist all loop-invariant reads and branches. Even super-obvious ones that should already be in registers.

Page 136: Data oriented design and c++

:)

Page 137: Data oriented design and c++

:)

A bit of unnecessary branching, but more-or-less equivalent.

Page 138: Data oriented design and c++

(4) Ghost reads and writes

Don’t re-read member values or re-call functions whenyou already have the data.

Hoist all loop-invariant reads and branches. Even super-obvious ones that should already be in registers.

Applies to any member fields especially. (Not particular to bools)

Page 139: Data oriented design and c++

(3) Extremely low information density

Page 140: Data oriented design and c++

(3) Extremely low information density

What is the information density for is_spawnover time?

Page 141: Data oriented design and c++

(3) Extremely low information density

What is the information density for is_spawnover time?

The easy way.

Page 142: Data oriented design and c++
Page 143: Data oriented design and c++

Zip the output10,000 frames= 915 bytes= (915*8)/10,000= 0.732 bits/frame

Page 144: Data oriented design and c++

Zip the output10,000 frames= 915 bytes= (915*8)/10,000= 0.732 bits/frame

Alternatively,Calculate Shannon Entropy:

Page 145: Data oriented design and c++

(3) Extremely low information density

What does that tell us?

Page 146: Data oriented design and c++

(3) Extremely low information density

What does that tell us?

Figure (~2 L2 misses each frame ) x 10,000If each cache line = 64b,128b x 10,000 = 1,280,000 bytes

Page 147: Data oriented design and c++

(3) Extremely low information density

What does that tell us?

Figure (~2 L2 misses each frame ) x 10,000If each cache line = 64b,128b x 10,000 = 1,280,000 bytes

If avg information content = 0.732bits/frameX 10,000 = 7320 bits/ 8 = 915 bytes

Page 148: Data oriented design and c++

(3) Extremely low information density

What does that tell us?

Figure (~2 L2 misses each frame ) x 10,000If each cache line = 64b,128b x 10,000 = 1,280,000 bytes

If avg information content = 0.732bits/frameX 10,000 = 7320 bits/ 8 = 915 bytes

Percentage waste (Noise::Signal) =(1,280,000-915)/1,280,000

Page 149: Data oriented design and c++

What’re the alternatives?

Page 150: Data oriented design and c++

(1) Per-frame…

Page 151: Data oriented design and c++

(1) Per-frame…

1 of 512 (8*64) bits used…

(decision table)

Page 152: Data oriented design and c++

(1) Per-frame…

1 of 512 (8*64) bits used…

(decision table)

(a) Make same decision x 512

Page 153: Data oriented design and c++

(1) Per-frame…

1 of 512 (8*64) bits used…

(decision table)

(a) Make same decision x 512

(b) Combine with other reads / xforms

Page 154: Data oriented design and c++

(1) Per-frame…

1 of 512 (8*64) bits used…

(decision table)

(a) Make same decision x 512

(b) Combine with other reads / xforms

Generally simplest. - But things cannot exist in abstract bubble.- Will require context.

Page 155: Data oriented design and c++

(2) Over-frames…

Page 156: Data oriented design and c++

(2) Over-frames…

i.e. Only read when needed

Page 157: Data oriented design and c++

(2) Over-frames…

i.e. Only read when needed

e.g.

Arrays of command buffers for future frames…

Page 158: Data oriented design and c++

Let’s review some code…

Page 159: Data oriented design and c++
Page 160: Data oriented design and c++

http://yosoygames.com.ar/wp/2013/11/on-mike-actons-review-of-ogrenode-cpp/

Page 161: Data oriented design and c++
Page 162: Data oriented design and c++

(1) Can’t re-arrange memory (much)

Limited by ABI

Can’t limit unused reads

Extra padding

Page 163: Data oriented design and c++

(2) Bools and last-minute decision making

Page 164: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

Page 165: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

Complex constructors tend to imply that…- Reads are unmanaged (one at a time…)

Page 166: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

Complex constructors tend to imply that…- Reads are unmanaged (one at a time…)- Unnecessary reads/writes in destructors

Page 167: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

Complex constructors tend to imply that…- Reads are unmanaged (one at a time…)- Unnecessary reads/writes in destructors- Unmanaged icache (i.e. virtuals)

=> unmanaged reads/writes

Page 168: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

Complex constructors tend to imply that…- Reads are unmanaged (one at a time…)- Unnecessary reads/writes in destructors- Unmanaged icache (i.e. virtuals)

=> unmanaged reads/writes- Unnecessarily complex state machines (back to bools)

- E.g. 2^7 states

Page 169: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

Complex constructors tend to imply that…- Reads are unmanaged (one at a time…)- Unnecessary reads/writes in destructors- Unmanaged icache (i.e. virtuals)

=> unmanaged reads/writes- Unnecessarily complex state machines (back to bools)

- E.g. 2^7 states

Rule of thumb:Store each state type separately

Store same states together(No state value needed)

Page 170: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

(6) Undefined or under-defined constraints

Page 171: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

(6) Undefined or under-defined constraints

Imply more (wasted) reads because pretending youdon’t know what it could be.

Page 172: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

(6) Undefined or under-defined constraints

Imply more (wasted) reads because pretending youdon’t know what it could be.

e.g. Strings, generally. Filenames, in particular.

Page 173: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

(6) Undefined or under-defined constraints

Imply more (wasted) reads because pretending youdon’t know what it could be.

e.g. Strings, generally. Filenames, in particular.

Rule of thumb:The best code is code that doesn’t need to exist.

Do it offline. Do it once.e.g. precompiled string hashes

Page 174: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

(6) Undefined or under-defined constraints

(7) Over-solving (computing too much)

Compiler doesn’t have enough context to know how to simplify your problems for you.

Page 175: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

(6) Undefined or under-defined constraints

(7) Over-solving (computing too much)

Compiler doesn’t have enough context to know how to simplify your problems for you.

But you can make simple tools that do…- E.g. Premultiply matrices

Page 176: Data oriented design and c++

Are we done with the constructor?

(5) Over-generalization

(6) Undefined or under-defined constraints

(7) Over-solving (computing too much)

Compiler doesn’t have enough context to know how to simplify your problems for you.

But you can make simple tools that do…- E.g. Premultiply matrices

Work with the (actual) data you have.- E.g. Sparse or affine matrices

Page 177: Data oriented design and c++

How do we approach “fixing” it?

Page 178: Data oriented design and c++
Page 179: Data oriented design and c++

(2) Bools and last-minute decision making

Page 180: Data oriented design and c++

Step 1: organizeSeparate states so you can reason about them

Page 181: Data oriented design and c++

Step 1: organizeSeparate states so you can reason about them

Step 2: triageWhat are the relative values of each casei.e. p(call) * count

Page 182: Data oriented design and c++

Step 1: organizeSeparate states so you can reason about them

Step 2: triageWhat are the relative values of each casei.e. p(call) * count

e.g. in-game vs. in-editor

Page 183: Data oriented design and c++

Step 1: organizeSeparate states so you can reason about them

Step 2: triageWhat are the relative values of each casei.e. p(call) * count

Step 3: reduce waste

Page 184: Data oriented design and c++

~200 cycles x 2 x count

(back of the envelope read cost)

Page 185: Data oriented design and c++

~200 cycles x 2 x count

~2.28 count per 200 cycles= ~88

(back of the envelope read cost)

Page 186: Data oriented design and c++

~200 cycles x 2 x count

~2.28 count per 200 cycles= ~88

(back of the envelope read cost)

t = 2 * cross(q.xyz, v)v' = v + q.w * t + cross(q.xyz, t)

Page 187: Data oriented design and c++

~200 cycles x 2 x count

~2.28 count per 200 cycles= ~88

(back of the envelope read cost)

t = 2 * cross(q.xyz, v)v' = v + q.w * t + cross(q.xyz, t)

(close enough to dig in andmeasure)

Page 188: Data oriented design and c++

Apply the same steps recursively…

Page 189: Data oriented design and c++

Apply the same steps recursively…

Step 1: organizeSeparate states so you can reason about them

Root or not; Calling function with context can distinguish

Page 190: Data oriented design and c++

Apply the same steps recursively…

Step 1: organizeSeparate states so you can reason about them

Root or not; Calling function with context can distinguish

Page 191: Data oriented design and c++

Apply the same steps recursively…

Step 1: organizeSeparate states so you can reason about them

Page 192: Data oriented design and c++

Apply the same steps recursively…

Step 1: organizeSeparate states so you can reason about them

Can’t reason well about the cost from…

Page 193: Data oriented design and c++

Step 1: organizeSeparate states so you can reason about them

Page 194: Data oriented design and c++

Step 1: organizeSeparate states so you can reason about them

Step 2: triageWhat are the relative values of each casei.e. p(call) * count

Step 3: reduce waste

Page 195: Data oriented design and c++

Good News:Most problems are

easy to see.

Page 196: Data oriented design and c++

Good News:Side-effect of solving the 90% well, compiler can solve the

10% better.

Page 197: Data oriented design and c++

Good News:Organized data makes

maintenance, debugging and concurrency much easier

Page 198: Data oriented design and c++

Bad News:Good programming is hard.Bad programming is easy.

Page 199: Data oriented design and c++

http://realtimecollisiondetection.net/blog/?p=81

http://realtimecollisiondetection.net/blog/?p=44

While we’re on the subject…DESIGN PATTERNS:

Page 200: Data oriented design and c++
Page 201: Data oriented design and c++