├── plot
├── Heap
│ ├── data1.dat
│ ├── data2.dat
│ ├── x.pdf
│ ├── x2.pdf
│ ├── xAdd256.txt
│ ├── xAdd16.txt
│ ├── xAdd4.txt
│ ├── xRem4.txt
│ ├── xRem16.txt
│ ├── xRem256.txt
│ └── script.gp
└── Array
│ ├── data1.dat
│ ├── data2.dat
│ ├── x.pdf
│ ├── x2.pdf
│ ├── x3.pdf
│ ├── xAdd16.txt
│ ├── xAdd4.txt
│ ├── xAdd64.txt
│ ├── xAdd256.txt
│ └── script.gp
├── img
├── obj.png
├── prop.png
├── uml.png
├── prop2.png
├── centric.png
├── hierarchy.png
├── obj_unity.png
├── overview.png
├── uml_swim.png
├── dragontable.png
├── obj_cryengine.png
├── containerresults.png
├── overview.graphml
├── hierarchy.graphml
├── ds_array.svg
├── ds_array_of_pointers.svg
└── ds_stationary_array.svg
├── refs.bib
└── README.md
/plot/Heap/data1.dat:
--------------------------------------------------------------------------------
1 | 8 10.1075
2 | 16 9.13967
3 | 32 8.61036
4 |
--------------------------------------------------------------------------------
/plot/Heap/data2.dat:
--------------------------------------------------------------------------------
1 | 8 8.00463
2 | 16 7.02438
3 | 32 7.89346
4 |
--------------------------------------------------------------------------------
/plot/Array/data1.dat:
--------------------------------------------------------------------------------
1 | 8 10.1075
2 | 16 9.13967
3 | 32 8.61036
4 |
--------------------------------------------------------------------------------
/plot/Array/data2.dat:
--------------------------------------------------------------------------------
1 | 8 8.00463
2 | 16 7.02438
3 | 32 7.89346
4 |
--------------------------------------------------------------------------------
/img/obj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/obj.png
--------------------------------------------------------------------------------
/img/prop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/prop.png
--------------------------------------------------------------------------------
/img/uml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/uml.png
--------------------------------------------------------------------------------
/img/prop2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/prop2.png
--------------------------------------------------------------------------------
/img/centric.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/centric.png
--------------------------------------------------------------------------------
/img/hierarchy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/hierarchy.png
--------------------------------------------------------------------------------
/img/obj_unity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/obj_unity.png
--------------------------------------------------------------------------------
/img/overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/overview.png
--------------------------------------------------------------------------------
/img/uml_swim.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/uml_swim.png
--------------------------------------------------------------------------------
/plot/Array/x.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/plot/Array/x.pdf
--------------------------------------------------------------------------------
/plot/Array/x2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/plot/Array/x2.pdf
--------------------------------------------------------------------------------
/plot/Array/x3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/plot/Array/x3.pdf
--------------------------------------------------------------------------------
/plot/Heap/x.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/plot/Heap/x.pdf
--------------------------------------------------------------------------------
/plot/Heap/x2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/plot/Heap/x2.pdf
--------------------------------------------------------------------------------
/img/dragontable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/dragontable.png
--------------------------------------------------------------------------------
/img/obj_cryengine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/obj_cryengine.png
--------------------------------------------------------------------------------
/img/containerresults.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adelost/entity-component-systems-study/HEAD/img/containerresults.png
--------------------------------------------------------------------------------
/plot/Array/xAdd16.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 1
3 | 10000 2
4 | 15000 1
5 | 20000 1
6 | 25000 1
7 | 30000 1
8 | 35000 2
9 | 40000 1
10 | 45000 1
11 | 50000 1
12 | 55000 1
13 | 60000 2
14 | 65000 1
15 | 70000 2
16 | 75000 2
17 | 80000 2
18 | 85000 3
19 | 90000 2
20 | 95000 2
21 | 100000 2
22 |
--------------------------------------------------------------------------------
/plot/Array/xAdd4.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 0
3 | 10000 0
4 | 15000 1
5 | 20000 1
6 | 25000 2
7 | 30000 2
8 | 35000 2
9 | 40000 0
10 | 45000 1
11 | 50000 1
12 | 55000 1
13 | 60000 1
14 | 65000 1
15 | 70000 1
16 | 75000 1
17 | 80000 1
18 | 85000 1
19 | 90000 1
20 | 95000 1
21 | 100000 1
22 |
--------------------------------------------------------------------------------
/plot/Array/xAdd64.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 1
3 | 10000 1
4 | 15000 1
5 | 20000 3
6 | 25000 3
7 | 30000 3
8 | 35000 5
9 | 40000 5
10 | 45000 5
11 | 50000 5
12 | 55000 5
13 | 60000 5
14 | 65000 6
15 | 70000 11
16 | 75000 10
17 | 80000 11
18 | 85000 11
19 | 90000 9
20 | 95000 10
21 | 100000 10
22 |
--------------------------------------------------------------------------------
/plot/Array/xAdd256.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 3
3 | 10000 6
4 | 15000 4
5 | 20000 11
6 | 25000 10
7 | 30000 20
8 | 35000 27
9 | 40000 21
10 | 45000 19
11 | 50000 18
12 | 55000 19
13 | 60000 21
14 | 65000 21
15 | 70000 58
16 | 75000 46
17 | 80000 40
18 | 85000 45
19 | 90000 45
20 | 95000 42
21 | 100000 36
22 |
--------------------------------------------------------------------------------
/plot/Heap/xAdd256.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 8
3 | 10000 51
4 | 15000 390
5 | 20000 90
6 | 25000 69
7 | 30000 141
8 | 35000 266
9 | 40000 250
10 | 45000 441
11 | 50000 109
12 | 55000 257
13 | 60000 339
14 | 65000 415
15 | 70000 497
16 | 75000 163
17 | 80000 438
18 | 85000 490
19 | 90000 501
20 | 95000 471
21 | 100000 813
22 |
--------------------------------------------------------------------------------
/plot/Heap/xAdd16.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 11
3 | 10000 83
4 | 15000 615
5 | 20000 110
6 | 25000 167
7 | 30000 420
8 | 35000 858
9 | 40000 45
10 | 45000 495
11 | 50000 520
12 | 55000 1280
13 | 60000 419
14 | 65000 881
15 | 70000 1705
16 | 75000 491
17 | 80000 99
18 | 85000 970
19 | 90000 1026
20 | 95000 776
21 | 100000 645
22 |
--------------------------------------------------------------------------------
/plot/Heap/xAdd4.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 13
3 | 10000 60
4 | 15000 454
5 | 20000 629
6 | 25000 1758
7 | 30000 205
8 | 35000 776
9 | 40000 2871
10 | 45000 1351
11 | 50000 1831
12 | 55000 2608
13 | 60000 1292
14 | 65000 1677
15 | 70000 1233
16 | 75000 3134
17 | 80000 1576
18 | 85000 1010
19 | 90000 266
20 | 95000 2106
21 | 100000 276
22 |
--------------------------------------------------------------------------------
/plot/Heap/xRem4.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 110
3 | 10000 437
4 | 15000 1113
5 | 20000 1747
6 | 25000 1895
7 | 30000 2177
8 | 35000 2856
9 | 40000 3058
10 | 45000 3497
11 | 50000 4300
12 | 55000 4678
13 | 60000 5067
14 | 65000 5759
15 | 70000 6500
16 | 75000 7386
17 | 80000 7869
18 | 85000 7953
19 | 90000 8713
20 | 95000 9052
21 | 100000 9010
22 |
--------------------------------------------------------------------------------
/plot/Heap/xRem16.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 150
3 | 10000 591
4 | 15000 1405
5 | 20000 1536
6 | 25000 1844
7 | 30000 2622
8 | 35000 3343
9 | 40000 3570
10 | 45000 3819
11 | 50000 4323
12 | 55000 5088
13 | 60000 5298
14 | 65000 5955
15 | 70000 6164
16 | 75000 7469
17 | 80000 7736
18 | 85000 8384
19 | 90000 8912
20 | 95000 9368
21 | 100000 10169
22 |
--------------------------------------------------------------------------------
/plot/Heap/xRem256.txt:
--------------------------------------------------------------------------------
1 | 0 0
2 | 5000 463
3 | 10000 987
4 | 15000 1411
5 | 20000 1946
6 | 25000 2489
7 | 30000 2972
8 | 35000 3550
9 | 40000 4127
10 | 45000 4626
11 | 50000 5093
12 | 55000 5660
13 | 60000 6124
14 | 65000 6710
15 | 70000 7112
16 | 75000 7750
17 | 80000 8290
18 | 85000 8785
19 | 90000 9345
20 | 95000 9942
21 | 100000 10421
22 |
--------------------------------------------------------------------------------
/plot/Array/script.gp:
--------------------------------------------------------------------------------
1 | set terminal pdfcairo font "Gill Sans,9" linewidth 4 rounded fontscale 0.8
2 |
3 | # Line style for axes
4 | set style line 80 lt rgb "#808080"
5 |
6 | # Line style for grid
7 | set style line 81 lt 0 # dashed
8 | set style line 81 lt rgb "#808080" # grey
9 |
10 | set grid back linestyle 81
11 | set border 3 back linestyle 80
12 | set xtics nomirror
13 | set ytics nomirror
14 |
15 | #set log x
16 | #set mxtics 10 # Makes logscale look good.
17 |
18 | set style line 1 lt rgb "#78ee00" lw 2 pt 1
19 | set style line 2 lt rgb "#51a200" lw 2 pt 1
20 | set style line 3 lt rgb "#408000" lw 2 pt 1
21 | set style line 4 lt rgb "#2c5800" lw 2 pt 1
22 | set style line 5 lt rgb "#cb0000" lw 2 pt 1
23 | set style line 6 lt rgb "#620000" lw 2 pt 1
24 |
25 |
26 | set output 'x.pdf'
27 | set xlabel 'Elements'
28 | set ylabel 'Milliseconds'
29 |
30 | set key top left
31 |
32 | #set xrange [0:30000]
33 | #set yrange [0:5000]
34 |
35 | plot \
36 | "xAdd4.txt" title '4 bytes new' w lp ls 1, \
37 | 'xAdd16.txt' title '16 bytes new' w lp ls 2, \
38 | 'xAdd64.txt' title '64 bytes new' w lp ls 3, \
39 | 'xAdd256.txt' title '256 bytes new' w lp ls 4
40 |
41 |
42 | set terminal x11
43 | set output
--------------------------------------------------------------------------------
/plot/Heap/script.gp:
--------------------------------------------------------------------------------
1 | set terminal pdfcairo font "Gill Sans,9" linewidth 3 rounded fontscale 0.77
2 | #set rmargin 12
3 |
4 | # Line style for axes
5 | set style line 80 lt rgb "#808080"
6 |
7 | # Line style for grid
8 | set style line 81 lt 0 # dashed
9 | set style line 81 lt rgb "#808080" # grey
10 |
11 | set grid back linestyle 81
12 | set border 3 back linestyle 80
13 | set xtics nomirror
14 | set ytics nomirror
15 |
16 | #set log x
17 | #set mxtics 10 # Makes logscale look good.
18 |
19 | set style line 1 lt rgb "#78ee00" lw 2 pt 1
20 | set style line 2 lt rgb "#51a200" lw 2 pt 1
21 | set style line 3 lt rgb "#2c5800" lw 2 pt 1
22 | set style line 4 lt rgb "#ff7d7d" lw 2 pt 2
23 | set style line 5 lt rgb "#cb0000" lw 2 pt 2
24 | set style line 6 lt rgb "#620000" lw 2 pt 2
25 |
26 |
27 | set output 'x.pdf'
28 | set xlabel 'Elements'
29 | set ylabel 'Milliseconds'
30 |
31 | set key top left
32 |
33 | #set xrange [0:30000]
34 | #set yrange [0:5000]
35 |
36 | plot \
37 | "xAdd4.txt" title '4 bytes new' w lp ls 1, \
38 | 'xAdd16.txt' title '16 bytes new' w lp ls 2, \
39 | 'xAdd256.txt' title '256 bytes new' w lp ls 3, \
40 | 'xRem4.txt' title '4 bytes delete' w lp ls 4, \
41 | 'xRem16.txt' title '16 bytes delete' w lp ls 5, \
42 | 'xRem256.txt' title '256 bytes delete' w lp ls 6
43 |
44 |
45 | set terminal x11
46 | set output
--------------------------------------------------------------------------------
/img/overview.graphml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Subsystems
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Game Architecture
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | Object System
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | Component-Based
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | Hierarchy-Based
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | Component-Centric
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | Object-Centric
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------
/refs.bib:
--------------------------------------------------------------------------------
1 | %====================================
2 |
3 | @incollection{gem3ObjectComposition,
4 | author = {Scott Patterson},
5 | title = {An Object-Composition Game Framework},
6 | editor = {Treglia, Dante},
7 | booktitle = {Game programming gems 3},
8 | publisher = {Charles River Media},
9 | year = {2002},
10 | address = {Hingham Mass}
11 | }
12 |
13 | @mastersthesis{plummer2004,
14 | author = {Jeff Plummer},
15 | title = {A fexible and expandable architecture for computer games},
16 | school = {Arizona State University},
17 | type = {Master's thesis},
18 | year = {2004}
19 | }
20 |
21 | @incollection{gem5GenericComponent,
22 | author = {Warrick Buchanan},
23 | title = {A Generic Component Library},
24 | editor = {Pallister, Kim},
25 | booktitle = {Game programming gems 5},
26 | publisher = {Charles River Media},
27 | year = {2005},
28 | address = {Hingham, Mass}
29 | }
30 |
31 |
32 |
33 | @incollection{gem4,
34 | author = { Matthew Harmon},
35 | title = {A System for Managing Game Entities},
36 | editor = {Kirmse, Andrew},
37 | booktitle = {Game programming gems 4},
38 | publisher = {Charles River Media},
39 | year = {2004},
40 | address = {Hingham, Mass}
41 | }
42 |
43 | @incollection{gem5,
44 | author = {Bjarne Rene},
45 | title = {Component Based Object Management},
46 | editor = {Pallister, Kim},
47 | booktitle = {Game programming gems 5},
48 | publisher = {Charles River Media},
49 | year = {2005},
50 | address = {Hingham, Mass}
51 | }
52 |
53 |
54 | @incollection{gem6,
55 | author = {Chris Stoy},
56 | title = {Game Object Component System},
57 | editor = {Dickheiser, Michael},
58 | booktitle = {Game programming gems 6},
59 | publisher = {Charles River Media},
60 | year = {2006},
61 | address = {Boston, Mass}
62 | }
63 |
64 |
65 | @mastersthesis{magnusson2011,
66 | author = {Lars V. Magnusson},
67 | title = {Game Mechanics Engine},
68 | school = {{\O}stfold University College},
69 | type = {Master's thesis},
70 | year = {2011}
71 | }
72 |
73 | %====================================
74 | @inbook{bosh2000,
75 | author = {Jan Bosch},
76 | year = {2000},
77 | title = {Design and use of software architectures: Adopting and evolving a product-line approach},
78 | publisher = {Addison-Wesley},
79 | language = {English},
80 | chapter = {Assessing software architectures},
81 | pages = {79}
82 | }
83 |
84 | @incollection{gem1DDD,
85 | author = {Steve Rabin},
86 | title = {The Magic of Data-Driven Design},
87 | editor = {DeLoura, Mark},
88 | booktitle = {Game programming gems},
89 | publisher = {Charles River Media},
90 | year = {2000},
91 | address = {Boston, Mass}
92 | }
93 |
94 | @incollection{gem2DirectAccessQuadtree,
95 | author = {Matt Pritchard},
96 | title = {Direct Access Quadtree Lookup},
97 | editor = {DeLoura, Mark},
98 | booktitle = {Game programming gems 2},
99 | publisher = {Charles River Media},
100 | year = {2001},
101 | address = {Hingham, Mass}
102 | }
103 |
104 | @incollection{gem2GenericMemberAccess,
105 | author = {Charles Cafrelli},
106 | title = {A Property Class for Generic {C++} Member Access},
107 | editor = {DeLoura, Mark},
108 | booktitle = {Game programming gems 2},
109 | publisher = {Charles River Media},
110 | year = {2001},
111 | address = {Hingham, Mass}
112 | }
113 |
114 | @incollection{gem2EntityFactory,
115 | author = {Fran{\c{c}}ois Dominic Laramee},
116 | title = {A Game Entity Factory},
117 | editor = {DeLoura, Mark},
118 | booktitle = {Game programming gems 2},
119 | publisher = {Charles River Media},
120 | year = {2001},
121 | address = {Hingham, Mass}
122 | }
123 |
124 | @incollection{gem4ObjectManager,
125 | author = {Natalya Tatarchuk},
126 | title = {A Flexible, On-the-Fly Object Manager},
127 | editor = {Kirmse, Andrew},
128 | booktitle = {Game programming gems 4},
129 | publisher = {Charles River Media},
130 | year = {2004},
131 | address = {Hingham, Mass}
132 | }
133 |
134 | @inbook{Eberly2005,
135 | author = {Eberly, David},
136 | title = {3D game engine architecture : engineering real-time applications with Wild Magic},
137 | publisher = {Morgan Kaufman Publishers},
138 | year = {2005},
139 | address = {Amsterdam Boston},
140 | isbn = {978-0122290640},
141 | chapter = {The Object System},
142 | pages = {105-148}
143 | }
144 |
145 | @misc{Kreuzer2014,
146 | author = {Jonathan Kreuzer},
147 | title = {Some Notes on Programming 3D Editing Software},
148 | howpublished = {\url{http://www.3dkingdoms.com/EditorTutorial.htm}},
149 | note = {Accessed: 2014-02-03},
150 | year = {2006}
151 | }
152 |
153 | @inbook{wihlidal2006game,
154 | author = {Wihlidal, Graham},
155 | title = {Game engine toolset development},
156 | publisher = {Thomson Course Technology},
157 | year = {2006},
158 | address = {Boston, MA},
159 | isbn = {978-1592009633},
160 | chapter = {Distributed Componential Architecture Design, Techniques to Improve Performance},
161 | pages = {57-74, 371-431}
162 | }
163 |
164 | @mastersthesis{golodetz2006,
165 | author = {Stuart M. Golodetz},
166 | title = {A 3D Map Editor},
167 | school = {Oxford University Computing Laboratory},
168 | type = {Third Year Undergraduate Project Report},
169 | year = {2006}
170 | }
171 |
172 | @inbook{Gregory2009,
173 | author = {Gregory, Jason},
174 | title = {Game engine architecture},
175 | publisher = {A K Peters},
176 | year = {2009},
177 | address = {Wellesley, Mass},
178 | isbn = {978-1568814131},
179 | chapter = {Engine Support Systems, Runtime Gameplay Foundation Systems},
180 | pages = {197-259, 711-817}
181 | }
182 |
183 | @inbook{harbour2011multi-threaded,
184 | author = {Harbour, Jonathan},
185 | title = {Multi-threaded game engine design},
186 | publisher = {Delmar Cengage Learning distributor},
187 | year = {2011},
188 | address = {Clifton Park, N.Y. Andover},
189 | isbn = {978-1435454170},
190 | chapter = {Entity Management},
191 | pages = {451-508}
192 | }
193 |
194 | @inbook{ggc,
195 | author = {McShaffry,Mike and Graham,David},
196 | year = {2012},
197 | title = {Game Coding Complete; Fourth Edition},
198 | publisher = {Cengage Learning},
199 | chapter = {Class Hierarkies: Kep Them Flat, Inheritance Versus Composition, Game Actors and Component Architecture}
200 | }
201 |
202 |
203 | @incollection{Llopis2011,
204 | author = {Noel Llopis},
205 | title = {High-Performance Programming with Data-Oriented Design},
206 | editor = {Eric Lengyel},
207 | booktitle = {Game Engine Gems 2},
208 | publisher = {A K Peters},
209 | year = {2011},
210 | address = {Wellesley, Mass}
211 | }
212 |
213 | %====================================
214 | @incollection{gem1FBMemAloc,
215 | author = {Steven Ranck},
216 | title = {Frame-Based Memory Allocation},
217 | editor = {DeLoura, Mark},
218 | booktitle = {Game programming gems},
219 | publisher = {Charles River Media},
220 | year = {2000},
221 | address = {Boston, Mass}
222 | }
223 | @incollection{gem2Optimization,
224 | author = {Andew Kirmse},
225 | title = {Optimization for {C++} Games},
226 | editor = {DeLoura, Mark},
227 | booktitle = {Game programming gems 2},
228 | publisher = {Charles River Media},
229 | year = {2001},
230 | address = {Hingham, Mass}
231 | }
232 |
233 | @incollection{gem3CustomStl,
234 | author = {Pete Isensee},
235 | title = {Custom {STL} Allocators},
236 | editor = {Treglia, Dante},
237 | booktitle = {Game programming gems 3},
238 | publisher = {Charles River Media},
239 | year = {2002},
240 | address = {Hingham Mass}
241 | }
242 |
243 | @incollection{gem7HeapAlloc,
244 | author = {Dimitar Lazarov},
245 | title = {High Performance Heap Allocator},
246 | editor = {Jacobs, Scott},
247 | booktitle = {Game programming gems 7},
248 | publisher = {Charles River Media/Course Technology},
249 | year = {2008},
250 | address = {Boston, MA}
251 | }
252 |
253 | @incollection{gem8StackAlloc,
254 | author = {Michael Dailly},
255 | title = {Stack Allocation},
256 | editor = {Lake, Adam},
257 | booktitle = {Game programming Gems 8},
258 | publisher = {Course Technology},
259 | year = {2011},
260 | address = {Boston, Mass}
261 | }
262 |
263 |
264 | @mastersthesis{lennartsson2011,
265 | author = {Joel Lennartsson},
266 | title = {Data Oriented Interactive Water: An Interactive Water Simulation For {PlayStation} 3},
267 | school = {Linköping University},
268 | type = {Master's thesis},
269 | year = {2012}
270 | }
271 |
272 |
273 | %====================================
274 |
275 | @inproceedings{Folmer:2007:CBG:1770657.1770663,
276 | author = {Folmer, Eelke},
277 | title = {Component Based Game Development: A Solution to Escalating Costs and Expanding Deadlines?},
278 | booktitle = {Proceedings of the 10th International Conference on Component-based Software Engineering},
279 | series = {CBSE'07},
280 | year = {2007},
281 | isbn = {978-3-540-73550-2},
282 | location = {Medford, MA, USA},
283 | pages = {66--73},
284 | numpages = {8},
285 | url = {http://dl.acm.org/citation.cfm?id=1770657.1770663},
286 | acmid = {1770663},
287 | publisher = {Springer-Verlag},
288 | address = {Berlin, Heidelberg},
289 | keywords = {COTS, game architectures, games}
290 | }
291 |
292 | @inproceedings{Anderson:2008:CRG:1496984.1497031,
293 | author = {Anderson, Eike Falk and Engel, Steffen and Comninos, Peter and McLoughlin, Leigh},
294 | title = {The Case for Research in Game Engine Architecture},
295 | booktitle = {Proceedings of the 2008 Conference on Future Play: Research, Play, Share},
296 | series = {Future Play '08},
297 | year = {2008},
298 | isbn = {978-1-60558-218-4},
299 | location = {Toronto, Ontario, Canada},
300 | pages = {228--231},
301 | numpages = {4},
302 | url = {http://doi.acm.org/10.1145/1496984.1497031},
303 | doi = {10.1145/1496984.1497031},
304 | acmid = {1497031},
305 | publisher = {ACM},
306 | address = {New York, NY, USA},
307 | keywords = {entertainment systems, game engine, game engine architecture}
308 | }
309 |
310 |
311 |
312 | @article{Knuth1974,
313 | author = {Knuth,Donald},
314 | year = {1974},
315 | title = {Structured Programming with go to Statements},
316 | journal = {ACM Computing Surveys (CSUR)},
317 | volume = {6},
318 | number = {4},
319 | pages = {261-301},
320 | isbn = {0360-0300},
321 | language = {English}
322 | }
323 |
324 | @book{Williams2012,
325 | author = {Anthony Williams},
326 | title = {C++ Concurrency in Action: Practical Multithreading},
327 | publisher = {Manning Publications},
328 | year = {2012},
329 | isbn = {1933988770}
330 | }
331 |
332 | @book{Doherty2003,
333 | author = {Michael Doherty},
334 | title = {A Software Architecture for Games},
335 | publisher = {University of the Pacific Depratment of Computer Science Research and Project Journal},
336 | year = {2003}
337 | }
338 |
339 |
340 | @inproceedings{Church2002,
341 | author = {Doug Church},
342 | title = {Object Systems:
343 | Methods for Attaching Data to Objects and
344 | Connecting Behavior},
345 | booktitle = {Game Developers Conference Proceedings},
346 | year = 2002
347 | }
348 |
349 | @inproceedings{Bilas2002,
350 | author = {Scott Bilas},
351 | title = {A Data-Driven Game Object System},
352 | booktitle = {Game Developers Conference Proceedings},
353 | year = 2002
354 | }
355 |
356 | @inproceedings{Bilas2003,
357 | author = {Scott Bilas},
358 | title = {The Continuous World of Dungeon Siege},
359 | booktitle = {Game Developers Conference Proceedings},
360 | year = 2003
361 | }
362 |
363 | @inproceedings{Chady2009,
364 | author = {Marcin Chady},
365 | title = {Theory and Practice of Game Object Component Architecture},
366 | booktitle = {Game Developers Conference Proceedings},
367 | year = 2009
368 | }
369 |
370 | @inproceedings{Duran2003,
371 | author = {Alex Duran},
372 | title = {Building Object Systems: Features, Tradeoofs, and Pitfalls},
373 | booktitle = {Game Developers Conference Proceedings},
374 | year = 2003
375 | }
376 |
377 | @mastersthesis{Magnusson2011,
378 | author = {Lars V. Magnusson},
379 | title = {Game Mechanics Engine},
380 | school = {Ostfold University College},
381 | type = {Master's thesis},
382 | year = {2011}
383 | }
384 |
385 | @book{Freeman2004,
386 | author = {Eric Freeman},
387 | title = {Head First design patterns},
388 | publisher = {O'Reilly},
389 | year = {2004},
390 | address = {Sebastopol, CA},
391 | isbn = {978-0596007126}
392 | }
393 |
394 |
395 | @book{Freeman2004,
396 | author = {Eric Freeman},
397 | title = {The Direct Cost of Virtual Function Calls in C++},
398 | publisher = {O'Reilly},
399 | year = {2004},
400 | address = {Sebastopol, CA},
401 | isbn = {978-0596007126}
402 | }
403 |
404 |
405 | @inproceedings{Holzle1994,
406 | author = {H\"{o}lzle, Urs and Ungar, David},
407 | title = {Optimizing Dynamically-dispatched Calls with Run-time Type Feedback},
408 | booktitle = {Proceedings of the ACM SIGPLAN 1994 Conference on Programming Language Design and Implementation},
409 | year = {1994},
410 | isbn = {0-89791-662-X},
411 | location = {Orlando, Florida, USA},
412 | pages = {326--336},
413 | publisher = {ACM},
414 | address = {New York, NY, USA}
415 | }
416 |
417 | @inproceedings{Chang2001,
418 | author = {Chang,J. M. and Lee,Woo H. and Srisa-an,Witawas},
419 | year = {2001},
420 | title = {A study of the allocation behavior of C++ programs},
421 | journal = {The Journal of Systems & Software},
422 | volume = {57},
423 | number = {2},
424 | pages = {107-118},
425 | isbn = {0164-1212},
426 | language = {English}
427 | }
428 |
429 | @book{Pedriana2007,
430 | author = {Paul Pedriana},
431 | title = {EASTL -- Electronic Arts Standard Template Library},
432 | year = {2007}
433 | }
434 |
435 | @inbook{Meyers2005,
436 | author = {Scott Meyers},
437 | title = {Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)},
438 | publisher = {Addison-Wesley Professional},
439 | year = {2005},
440 | chapter = {Customizing new and delete},
441 | isbn = {0321334876}
442 | }
443 |
444 | @inbook{Gerber2002,
445 | author = {Richard Gerber},
446 | title = {Software Optimization Cookbook: High-Performance Recipes for the Intel Architecture},
447 | publisher = {Intel Pr},
448 | year = {2002},
449 | chapter = {Memory},
450 | pages = {89-116},
451 | isbn = {0971288712}
452 | }
453 |
454 | @inbook{Moller2008,
455 | author = {Tomas Akenine-Moller and Eric Haines and Naty Hoffman},
456 | title = {Real-Time Rendering, Third Edition},
457 | publisher = {A K Peters/CRC Press},
458 | year = {2008},
459 | isbn = {1568814240},
460 | chapter = {Optimization},
461 | pages = {703-707}
462 | }
463 |
464 | @inbook{Martin2008,
465 | author = {Robert C. Martin},
466 | title = {Clean Code: A Handbook of Agile Software Craftsmanship},
467 | publisher = {Prentice Hall},
468 | year = {2008},
469 | isbn = {0132350882},
470 | chapter = {Classes},
471 | pages = {135-152}
472 | }
473 |
--------------------------------------------------------------------------------
/img/hierarchy.graphml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Animated
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Entity
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | Projectile
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | Collectable
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | Fireball
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | Treasure
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | Weapon
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | Arrow
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 | Knight
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 | Dragon
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | Drawable
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
--------------------------------------------------------------------------------
/img/ds_array.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/img/ds_array_of_pointers.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/img/ds_stationary_array.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Allocation and Access Optimizations in a Component-Centric Entity Component System in C++
2 |
3 | **Mattias E. O. Andersson** - written 2014-05-15, minor update 2021-08-28
4 |
5 |
6 | ## Abstract
7 |
8 | - **Context:** An Entity Component System (ECS) is an architecture pattern most commonly used in games. An entity represents a discernible element within the game world and is made up of a combination of modular components that determines the entity’s overall behavior. ECSs can be further divided into Object-Centric and Component-Centric.
9 |
10 | - **Objectives:** This study investigates optimization strategies in allocating and accessing components in a component-centric ECS and aims to provide a guideline to anyone interested in choosing from or implementing such a system. It also provides an overview of the history and terminology of ECS.
11 |
12 | - **Methods:** A number of sources and articles on ECS are investigated. The object system of each ECS is broken down and into a series of data structures of increasing complexity and representative of the allocation and access pattern of each implementation. These are then compared with regards to allocation speed, access speed and memory consumption, using a basic array data structure as a baseline for comparison.
13 |
14 | - **Results:** A number of data structures useful in an ECS are presented and the result of each data structure with regards to allocation and access are measured. Data structures using custom memory allocation proved to have a substantial improvement on allocation and deallocation performance. Only a moderate impact of access time was measured between the data structures of high-complexity, and data structures of low complexity.
15 |
16 | **Keywords:** Games Architecture, Entity Component Systems, Software Performance
17 |
18 | ## Table of Content
19 |
20 | - [Introduction](#introduction)
21 | - [Topic](#topic)
22 | - [Object Systems](#object-systems)
23 | - [Entity Component Systems](#entity-component-systems)
24 | - [Object-Centric and Component-Centric Architectures](#object-centric-and-component-centric-architectures)
25 | - [Terminology](#terminology)
26 | - [Related Work](#related-work)
27 | - [Access Patterns](#access-patterns)
28 | - [Problem Formulation](#problem-formulation)
29 | - [Aim](#aim)
30 | - [Research Questions](#research-questions)
31 | - [Objectives](#objectives)
32 | - [Background](#background)
33 | - [Entities](#entities)
34 | - [Component-Based Object Systems](#component-based-object-systems)
35 | - [Container Data Structures](#container-data-structures)
36 | - [Memory Allocators](#memory-allocators)
37 | - [Memory Optimizations](#memory-optimizations)
38 | - [Memory Locality](#memory-locality)
39 | - [Instruction Cache](#instruction-cache)
40 | - [Data Hazards](#data-hazards)
41 | - [Data Alignment](#data-alignment)
42 | - [Method](#method)
43 | - [Implementations](#implementations)
44 | - [C++ Standard Library](#c-standard-library)
45 | - [Custom Data Structures](#custom-data-structures)
46 | - [ae::Array](#aearray)
47 | - [ae::StationaryArray](#aestationaryarray)
48 | - [ae::PoolArray](#aepoolarray)
49 | - [ae::PoolPtr](#aepoolptr)
50 | - [ae::IdPoolArray](#aeidpoolarray)
51 | - [ae::PoolList](#aepoollist)
52 | - [Note on Thread Safety](#note-on-thread-safety)
53 | - [Hardware](#hardware)
54 | - [Results](#results)
55 | - [Conclusions](#conclusions)
56 | - [Future Work](#future-work)
57 | - [Bibliography](#bibliography)
58 | - [Internet Links](#internet-links)
59 |
60 |
61 | ## Introduction
62 |
63 | This study will analyse and compare some of the most common optimization strategies used in allocating and accessing components in a component-centric Entity Component System. The section starts by introducing the area and terminology of entity component systems. It also cover the objective of the study and what can be expected in later sections.
64 |
65 | ### Topic
66 |
67 | Game engines, both available publicly or commercially, can vary greatly in details of their implementation. Some are tied to a specific game or game genre, while some strive to be generic, but even so, almost all share a set of recognizable subsystems usually operating within specific domains, such as rendering, audio, physics and AI [\[1\]](#b_1). This requires a mean of communication between the different systems, usually done in what has been referred by many authors as an Object System [\[2\]](#b_2)[\[3\]](#b_3)[\[4\]](#b_4).
68 |
69 | #### Object Systems
70 |
71 | The object system allows different systems to share data between each other in the form of Entities (sometimes referred to as Game Objects) which represent a discernible elements within the game world. An entity usually contains the properties required by one or more systems to operate, e.g. the position of an object, required in both a rendering system to know where to render an object and a physics system to move an object.
72 |
73 | #### Entity Component Systems
74 |
75 | An increasingly popular category of object system is a component based object systems, often referred to as an Entity Component System (ECS). It allows entities to be described as a set of modular components which collectively provide the overall behavior of the object. This offers flexibility as a wide range of entities with varying behavior can be created through combinations of reusable components.
76 |
77 | Barring some variations in terminology, an ECS consists in some form or another of the following elements:
78 |
79 | - **Entity**: General-purpose object, composed by a set of components. An entity by itself has no effect on the game world, it is simply a way to collect components.
80 |
81 | - **Property**: Particular attribute (or property) of an element in the game world, e.g. position, rotation or health. The property could either be an atomic data type, such as a boolean, an integer or a floating point; or a more advanced type, such as an array, a 3D vector or a matrix [\[1\]](#b_1).
82 |
83 | - **Component**: Container used to label a collection of properties and behaviors. The properties are usually stored inside the components themselves, but could also be stored separately and accessed as key-value pairs [\[5\]](#b_5)[\[2\]](#b_2). The behavior could also be provided by systems operating on the specific component or through scripting [\[1\]](#b_1).
84 |
85 | - **System**: A system (or a subsystem) is a separate part of the architecture responsible for a specific domain, e.g. rendering, audio or physics. A system is interested in one or more types of components as they contain the data used by the system to operate.
86 |
87 | #### Object-Centric and Component-Centric Architectures
88 |
89 | An object systems usually ranges from one of two architectures [\[2\]](#b_2)[\[6\]](#b_6)[\[1\]](#b_1) (see [Figure 1.1](#fig_1_1) for a visual comparison):
90 |
91 |
92 |
93 |
94 |
95 | > Figure 1.1: Comparison of an Object-Centric (left) and a Component-Centric (right) object system.
96 |
97 |
98 | - **Object-Centric**: In an object-centric architecture the data and behavior relevant to the entity is encapsulated inside the entity in an object-oriented manner. The game world is generally updated by calling an update method on each entity. The entity may then proceed to either update itself or call and update method on each of its components which thereafter performs its behavior by calculating on its properties, accessing other components or by communicating with subsystems.
99 |
100 | - **Component-Centric**: In a component-centric architecture the entity as a whole is seen and updated through its components. The components are usually stored in a separate data structure and keyed to the unique id of an object. A system interested in a particular type of component may then query the components directly without the indirection of the entity.
101 |
102 | An object-centric architecture tend to be more intuitive than a component-centric design, as the representation of an object is encapsulated within the entity, which matches how an object is usually modelled in the game world. This also makes it easier to operate on the entity as a whole, such as inserting, copying or extracting entities from the game world [\[2\]](#b_2).
103 |
104 | A component-centric architecture on the other hand is easier to optimize. One such optimization is to store components in separate data structures appropriate to the access pattern of each component type . This allows systems to more readily read and update components in batches which usually is far more efficient than updating each entity individually, in large data sets, as this allows better use of system resources, such as the CPU cache. Even object-centric architectures often try to mix in some form of batched updates in systems such as rendering and physics, as these types of systems generally have very stringent performance constrains [\[1\]](#b_1).
105 |
106 | A visual overview of the area of component based object systems, as covered in this section, is seen in [Figure 1.2](#fig_1_2).
107 |
108 |
109 |
110 |
111 |
112 | >
Figure 1.2: Visual overview of component based object systems.
113 |
114 | ### Terminology
115 |
116 | There are some variations in terminology used by various authors to refer to a component based object system.
117 |
118 | The term Entity System or Entity Component System was established fairly recently in 2007[4](#l_4) but has grown to become the most commonly used name to referred to the architecture.
119 |
120 | It should be noted that there are some disagreement if object-centric object system, which is similar in design to the strategy pattern [\[12\]](#b_12), should be called an ECS or not, or if it should only apply to component-centric architectures. In this study we will make no such distinction as each architecture involves entities, components and systems, and instead refer to each ECS as being either object-centric or component-centric.
121 |
122 | Some authors also use the term property-centric architecture instead of component-centric. As noted by Jason Gregory [\[1\]](#b_1) in a property-centric design, each subobject defines a particular attribute of an entity, whereas a component in an object-centric design typically represents linkages to particular subsystems, but that the distinction is so subtle as to be irrelevant in most cases as both designs consists of a logical game object comprised of, and that derives its behavior from, a collection of subobjects.
123 |
124 | ### Related Work
125 |
126 | First known instances of ECS was seen in 2002 [\[3\]](#b_3)[\[6\]](#b_6)[\[1\]](#b_2) and has since been used in a number of publications [\[7\]](#b_7)[\[8\]](#b_8)[\[9\]](#b_9), and by a number of game studios, including but not limited to Gas Powered Games [\[3\]](#b_3), Ion Storm [\[6\]](#b_6), Codemasters[1](#l_1), Neversoft[2](#l_2) and Radical Entertainment [\[5\]](#b_5). In addition to this, the game engine Unity[3](#l_3), which is used by a large number of developers today, can be considered as an ECS. Notably, the Unity game engine has a component-based game object architecture that according to Scott Bilas (now employed by Unity Technologies) was directly derived from his "A Data-Driven Game Object System" lecture from 2002 while employed at Gas Powered Games[8](#l_8).
127 |
128 | As these implementations of ECSs has become well known, future game engines and game architectures are likely to take inspirations from them. Despite this, relatively little research into game engine architectures has been made. There are exceptions however.
129 |
130 | Michael Doherty has proposed a high-level general software architecture for games, designed to maximize reusability in both single player and networked multiplayer [\[2\]](#b_2) inspired by ECSs as outlined by Scott Bilas [\[3\]](#b_3) and Alex Duran [\[10\]](#b_10). He also discusses several design options, and particularly addresses object-centric and component-centric architectures.
131 |
132 | Lars Magnusson presents a component-centric ECS that attempts to completely separate dependencies in the object system from subsystems to create a genre independent game engine he refers to as a Game Mechanics Engine [\[11\]](#b_11). He also presents an extensive overview of various publications in game architecture.
133 |
134 |
135 | ### Access Patterns
136 |
137 | Typically the following scenarios can be found in most games, which can be represented by a specific access or allocation pattern.
138 |
139 | - **Sequential Access:** Entities are accessed sequentially, as part of updating a specific system, such as when a frame is rendered by the render system.
140 |
141 | - **Random Access:** Entities are accessed randomly, as part of of game logic or interaction with other objects, such as collision detection.
142 |
143 | - **Sequential Creation/Removal:** Entities are created and destroyed sequentially when a level loads during the start of the game, or when exiting a level.
144 |
145 | - **Random Creation/Removal:** Entities are created and destroyed randomly as part of game logic.
146 |
147 | In addition to this, different levels of indirection is used to access entities and components.
148 |
149 | - **Direct Sequential Access:** Entities could be laid out directly in memory in the order they are accessed, which would be the extreme case of a component-centric ECS.
150 |
151 | - **Indirect Sequential Access:** Entities could be accessed through pointers which adds additional overhead, but is stored sequentially in blocks that fit inside the CPU cache.
152 |
153 | - **Indirect Random Access:** Entities could be accessed through pointers but be shattered in memory, as is most often the case of an object-oriented ECS.
154 |
155 | ### Problem Formulation
156 |
157 | As evident in section [Introduction](#introduction), there is a multitude of ways to represent and implement ECSs. A component-centric ECS generally stores its components in a separate data structure. This data structure is likely to have a large impact on the creation and allocation of entities, which impacts the performance of the application, and could be seen as a major design decision. Performance optimizations such as these are best implemented early at the design phase as they would require a major overhaul of the design if they were to be implemented at a later stage [\[13\]](#b_13).
158 |
159 | The most commonly used data structures is likely to be some form of linear data structure, such as an array. A very basic implementation proposed by Gregoy [\[1\]](#b_1) is to allocate a static array of each component large enough that each index of the array corresponds to the maximum number of entities supported. This allows each entity to store and fetch components from the array with minimal overhead, as accessing a component is as simple as accessing an index in the array. However, by making our allocation static we cannot increase the amount of entities beyond our maximum limit. We also end up occupying more memory than we actually need as every entity need to allocate space for every component. Some games disallow dynamic spawning of entities, making this simple approach appropriate in some case.
160 |
161 | A dynamic array is more flexible as this allows resizing of elements, but resizing an array has the disadvantage that this would invalidate all iterators, pointers and references related to objects stored inside the array[5](#l_5). Deletion can also be costly as this may require rearranging elements to cover any potential gap caused by the deletion.
162 |
163 | Considering this, different data structures of increasing complexity is likely to be used, depending on the need of the current application.
164 |
165 | Most games are also written in low-level languages such as C++ where allocating and deallocating large number of objects on the heap using the default memory allocator can be very costly [\[14\]](#b_14), leading many game engine employ some form of custom memory allocation [\[1\]](#b_1). Memory allocation will therefore either have to be accounted for internally by the data structure or externally by a custom memory allocator to ensure optimal allocation performance when creating entities.
166 |
167 | ### Aim
168 |
169 |
170 | This study aims to provide a general guideline when choosing between data structures to implement a component-centric ECS. Data structures are evaluated with regards to allocation, deallocation and accessing elements, which would corresponds to entities and components.
171 |
172 | As memory allocation of each element either has to be done internally or externally by each data structure, a custom memory allocator will also have to be considered to some degree.
173 |
174 | Results will be obtained with regards to the programming language C++ as this is commonly the language of choice when writing performance critical sections of a game engine.
175 |
176 | ### Research Questions
177 |
178 | The study will attempt to answer:
179 |
180 | - Which data structures are most commonly used to manage components and entities in a component centric architecture?
181 |
182 | - What is the performance of each data structure with regards to allocation, deallocation and memory usage?
183 |
184 | - Which data structures should be used under different situations?
185 |
186 | ### Objectives
187 |
188 | To conduct an investigation and arrive at a conclusion, the objectives of this study can be summarized as follows:
189 |
190 | 1. Research data structures used to handle components in a ECS.
191 |
192 | 2. Establish a list of data structures of increasing complexity, used and likely to be used to handle components in an ECS.
193 |
194 | 3. Implement or use publicly available implementations of said data structures in C++.
195 |
196 | 4. Compare each data structure through a series of benchmark corresponding to typical usage inside a game engine, with regards to allocation, deallocation and accessing elements.
197 |
198 | 5. Determine the overhead caused by C++’s standard heap allocation to compare against the allocation of each data structures.
199 |
200 | ## Background
201 |
202 | This section covers the background necessary to appreciate the topics covered in this study.
203 |
204 | The section starts by familiarizing the reader with entities and components as used in game development. It then covers the most commonly used data structures. After this a section is dedicated to memory optimization. And lastly a section covering commonly used memory allocation techniques.
205 |
206 | Sections covering topics already known by the reader may be skipped at the readers own discretion.
207 |
208 | ### Entities
209 |
210 | Entities represents an individual elements within the simulation of a game. Typically visible objects within the simulation, such as players, enemies, trees and projectiles are represented as entities, but may also encompass invisible objects such as bounding boxes (used in collision detection), triggers (used to trigger scripted sequences), and even objects with no position inside the game world, such as items hidden in a players inventory [\[3\]](#b_3).
211 |
212 | The amount and nature of entities varies between games. A real-time strategy game (RTS), may feature hundreds, even thousands of active objects, all represented as entities within the simulation. In contrast a first-person shooter game (FPS) may only have a few dozen active objects. However, these objects may themselves be surrounded by a large number of props, decals, triggers, and level geometry, which may themselves also be represented by entities. For example, in the game Dungeon Siege (2002), by Gas Powered Games, some levels contained up to 60,000 entities [\[15\]](#b_15). [Figure 2.1](#fig_2_1) shows an example of various entities distributed in a level seen in Cry Engine 3[6](#l_6) and Unity[7](#l_7).
213 |
214 |
215 |
216 |
217 |
218 |
219 | > Figure 2.1: Screenshots from Cry Engine 3 (left) and Unity (right), showing various game objects distributed in a level.
220 |
221 | Traditionally, object systems within games have relied on inheritance hierarchies to share functionality between entities. However, as hierarchies grow they get harder to design, and redesign [\[8\]](#b_8).
222 |
223 | Consider a class hierarchy as seen in [Figure 2.2](#fig_2_2) which corresponds to a hypothetical fantasy themed game. Problem would arise if a new feature calls for Collectables or Projectiles to be animated as the logic necessary is not part of either class. One solution is to move the needed functionality higher up in the hierarchy and merge Animated with Drawable. However, this requires changing the hierarchy and merging two unrelated classes, which lowers the design quality of cohesion (a measure of how closely related data and methods of a class are to each other) [\[16\]](#b_16), as they try to be all things to all objects. This usually makes the class harder to maintain, modify and understand.
224 |
225 |
226 |
227 |
228 |
229 | > Figure 2.2: Traditional class inheritance tree of entities.
230 |
231 |
232 |
233 | ### Component-Based Object Systems
234 |
235 | An often time better solution when designing object systems is to have a system where exiting functionality can be combined into new objects, and new functionality can be added to existing objects without the need to refactor code and change the inheritance tree.
236 |
237 | An attempt to accomplish this is to view each game object as an aggregation of modules or subobjects (usually referred to as components), which provides the entities with access to unique data or functionality. In order to keep this as flexible as possible, the entities needs to be completely generic, with unique functionality provided by modular components. Depending on the kind of object to create, different combinations of components is added to the entity.
238 |
239 | A simplified component-based design somewhat inspired by our previous example is illustrated in [Figure 2.3](#fig_2_3).
240 |
241 |
242 |
243 |
244 |
245 | > Figure 2.3: Hypothetical relationship table among components (top) and entities (left).
246 |
247 | In comparison to [Figure 2.2](#fig_2_2) attributes related to Knights and Dragons previously (and implicitly) contained within each class, such as Fire Breathing and Ignitable, has been made into generic components which can be attached to any game objects. Components can be both game-play related, such as Health (which keeps track of health, and allows objects to be damaged and destroyed) and Flying (which modifies movement to allow flying), or subsystem related such as Render (which allows access by the render subsystem to the game objects). The name of an entity is purely nominal and one entity could easily be extended or changed into another, e.g. a fire breathing human or an animated tree swaying in the wind.
248 |
249 | Because of its position as the central interface between all other components, the design and implementation of the object system can have a strong impact on all other system components. It also impacts the flexibility at which game designer can make changes to the game.
250 |
251 | ### Container Data Structures
252 |
253 | A wide variety of container type data structures is generally employed by programmers to solve the given task at hand. The details of each container varies greatly, but all have the task of managing one or more elements.
254 |
255 | Some of the most commonly used containers [\[1\]](#b_1) are listed as follows:
256 |
257 | - **Static Array**: A collection of elements stored contiguously in memory and accessible by an index. Its length is usually statically defined at compile time and do not allow new elements to be added or removed.
258 |
259 | - **Dynamic Array**: An array whose length can change dynamically as new elements are added. However, doing so requires allocating and transferring the elements to a new memory block which can be costly and will also invalidate any potential references pointing directly to the old memory location of elements.
260 |
261 | - **Linked List**: A collection of elements not stored continuously in memory but linked to one another via pointers.
262 |
263 | - **Stack**: A container of elements where elements are added or removed on a last-in-first-out basis often referred to as LIFO.
264 |
265 | - **Associative Array**: A collection of key-value pairs. Each stored element have an associated key which can be used to access the stored element.
266 |
267 | ### Memory Allocators
268 |
269 | Most game engines make use of custom allocators to manage memory [\[1\]](#b_1). The principal reason for this is to increase runtime performance, but sometimes also to reduce memory consumption.
270 |
271 | Dynamic memory allocation via malloc() or C++’s global operator new, usually referred to as the a heap allocation, are designed for general-purpose allocations [\[17\]](#b_17). They have to handle allocation of memory blocks of mixed sizes. They have to accommodate allocation patterns ranging from long-lived objects existing during the full duration of the program, to large number of temporarily short-lived objects. It also has to deal with memory fragmentation, where free memory becomes locked up in a large number of non-contiguous blocks which otherwise makes the free memory unusable for most sceneries.
272 |
273 | By making assumption about the applications memory usage, a custom allocator can often outperform the default allocator. Some caveats however is that custom allocators may sometimes ignore details such as portability, alignment consideration and thread safety [\[17\]](#b_17).
274 |
275 | Custom memory allocation in C++ can be handled in a number of ways. The global new operator can be overridden. However, this limits the allocator to use the same allocation strategy on all allocations. Instead the new operator can also be overridden on a per-class basis, which allows the allocator can make assumptions about the size the object, such as in the case of a pool allocator. Finally, in the case of STL-containers, memory allocation is handled using a specific allocator object, which can be specified as a template parameter of the container.
276 |
277 | ### Memory Optimizations
278 |
279 | The CPU cache is important in any memory optimizations as almost all memory used by the application flows through the cache. A cache is a special memory that can be read and written to by the CPU at a much faster rate than the main RAM. When an application accesses a piece of memory it first checks if the data is already in the cache. If the data is in the cache, a “cache hit” occurs, and the data can be loaded into CPU registers without touching the RAM. If the data do not exist, a “cache miss” occurs, and a small piece of memory called a “cache line” is copied to the cache. This can have a large effect on performance, especially on consoles, such as the PS3 fetching memory directly from RAM can have an access time on more than 500 cycles [\[13\]](#b_13). A cache line is generally larger than the requested memory, as the extra memory is expected to be accessed shortly.
280 |
281 | ### Memory Locality
282 |
283 | Since all memory has to move between the RAM and cache eventually, cache misses cannot be avoided. But the data can be rearranged in memory to reduce the number of cache misses. These memory access patterns are generally divided into what is called temporal locality and spatial locality [\[18\]](#b_18)[\[19\]](#b_19).
284 |
285 | - **Spatial Locality**: Memory locations near each other tend to be used together. Because of this, when a cache miss occurs, a full cache line is fetched. This improves performance as one big memory transaction is faster than many small transactions. Maximum spatial locality can be achieved by storing data contiguously in memory, such as arranging our data inside an array, an then accessing it sequentially. This reduces the number of cache misses as it allows a maximum number of neighbouring elements to be loaded into the same cache line.
286 |
287 | - **Temporal Locality**: Some memory tend to be accessed repeatedly. Because of this recently used memory is kept in the cache. To improve temporal locality, small pieces of data should be reused as much as possible in order to keep the data it in the cache.
288 |
289 | ### Instruction Cache
290 |
291 | A CPU caches instructions as well as data. On most CPUs these are separated in what is often referred to as an I-cache (instruction cache) and a D-cache (data cache). As the two caches is often physically separate, a program can run slow, both because of an I-cache miss or because of a D-cache miss.
292 |
293 | Reducing D-cache misses is the same when improving data locality. The data should be organized in continuous blocks that are as small as possible, and then accessed sequentially. When the data is small it is more likely to fit in the cache line, and when the data is accessed sequentially, the CPU never has to reload a cache line from the same region of RAM [\[1\]](#b_1).
294 |
295 | The performance of the I-cache is decided by the memory layout of the code, which is often dictated by the compiler. However, depending on the compiler, I-cache misses can be reduced by keeping high-performance code as small as possible in terms of machine language instructions, avoiding calling functions from within performance-critical sections of code and through judicious use of inline functions.
296 |
297 | ### Data Hazards
298 |
299 | Data hazards are problems with the instruction pipeline of a CPU architecture that leads to reduced performance, or in worse case incorrect computation result. The pipeline generally consists of several stages. In optimal situations each instruction and each stage of the pipeline takes 1 cycle to executes. But in some situations an instruction can not execute until a previous instructions is complete.
300 |
301 | There are three situations data hazards can occur, all involving writing data:
302 |
303 | - **Read After Write (RAW)**: occurs when an instruction refers to the result of an instruction that has not yet exited the pipeline.
304 |
305 | - **Write After Read (WAR)**: occurs when an instruction needs to write to a location that is still being read.
306 |
307 | - **Write After Write (WAW)**: occurs when an instruction needs to write to a location that another instruction is already writing to.
308 |
309 | ### Data Alignment
310 |
311 | Depending on the architecture, different sized classes and structs generally have an alignment requirement which must be respected to allow the CPU to read and write to the memory effectively. E.g. in a 32-bit architecture the data may be aligned if the data is stored in 4 consecutive bytes (4*8=32) and if the first byte lies on a 4 byte boundary. For small structures, e.g. a Booleans, the structure needs to be padded by the compiler to allow optimal performance, but at the cost of extra memory. Alternatively the padding can sometimes be omitted by packing the structure and reducing memory usage, but may lead to slower access.
312 |
313 | ## Method
314 |
315 | The performance of each data structures is measured using 3 different benchmarks, each designed to measures how execution time correlates to the number of elements with regards to operations typically used in a game simulation. The elapsed time is measured using a high precision timer. A brief description of each benchmark is as follows:
316 |
317 | - **Allocation:** The average time to create varying number of elements. The elements to be put inside the array is calculated in advance. Only the time of adding the precalculated is measured.
318 |
319 | - **Deallocation:** The average time to remove varying number of elements.
320 |
321 | - **Iteration speed:** The average time to read a small amount of data from varying number of elements. This data is then used to compute a checksum to make sure that all elements has been read properly. The read data is needed to give accurate readings on performance as most compilers optimizing away unused code and variables.
322 |
323 | ## Implementations
324 |
325 | This section covers the implementations of the custom data structures used in the experiment.
326 |
327 | Each custom data structure has been collected under a library referred to as AberrantUtils and made available available on GitHub. The source source code for each implementation can be viewed at the readers own discretion from the following link:
328 |
329 | ### C++ Standard Library
330 |
331 | Apart from the custom data structures, the following data structures from the C++ Standard Library are used for comparison:
332 |
333 | - **std::vector:** A dynamic array.
334 |
335 | - **std::list:** A linked list.
336 |
337 | - **std::unordered\_map:** An associative array.
338 |
339 | - **std::map:** An associative array which keeps keys sorted alphabetically.
340 |
341 | ### Custom Data Structures
342 |
343 | #### ae::Array
344 |
345 | The Array container is a custom dynamic array implementation to compare against std::vector.
346 |
347 |
348 |
349 |
350 |
351 | > Figure 4.1: An array of elements laid out in memory.
352 |
353 |
354 |
355 |
356 |
357 | > Figure 4.2: An array of pointers (pointing to elements) laid out in memory. Each shifting color represents an individual memory segment.
358 |
359 | #### ae::StationaryArray
360 |
361 | A data structure similar to a dynamic-array, but which does not reallocate the memory address of the stored elements when growing. However, elements are not guaranteed to be stored in adjacent memory locations.
362 |
363 | Elements are allocated in memory segments which doubles in size for each added segment. This makes the data structure cache oblivious as it is designed to work for all types of cache sizes. The likelihood of cache misses is increased in the smaller segments, but as more elements are added to the data structures, this overhead often becomes negligible.
364 |
365 |
366 |
367 |
368 |
369 |
370 | > Figure 4.3: A Stationary Array laid out in memory. Each color represents an individual memory segment.
371 |
372 | **Pros**
373 |
374 | - Fast.
375 |
376 | - No reallocation of objects.
377 |
378 | **Cons**
379 |
380 | - Not as fast as arrays.
381 |
382 | - Memory address of elements cannot be used to calculate index.
383 |
384 | #### ae::PoolArray
385 |
386 | A data structure inspired by a pool allocator, that picks lower indexes first when reusing empty slots (compared to the linked list approach by a pool allocator). As large numbers of allocations and deallocations are likely to be done consecutively inside a game, new elements will end up next to each other in memory, which may improves data locality and reduces memory fragmentation.
387 |
388 |
389 |
390 |
391 |
392 | > Figure 4.4: A Pool Array laid out in memory with no deleted elements (top) and 5 deleted elements (bottom). The top array denotes deleted elements (gaps) and the bottom array contains elements.
393 |
394 | **Usage**
395 |
396 | Allocating a single element with a PoolPtr:
397 |
398 | ``` c++
399 | PoolPtr p = 42;
400 |
401 | assert(*p == 42);
402 |
403 | p.release();
404 | ```
405 |
406 | Allocating multiple elements with a PoolPtr and Array:
407 |
408 | ``` c++
409 | Array> a = {0, 1, 2, 3, 4};
410 |
411 | int total = 0;
412 | for (PoolPtr i : a) {
413 | total += *i;
414 | }
415 |
416 | assert(total == 10);
417 |
418 | for (PoolPtr i : a) {
419 | i.release();
420 | }
421 | ```
422 |
423 | #### ae::PoolPtr
424 |
425 | A PoolPtr is a template based custom allocator wrapper. It can be used to improve performance when allocating almost any object. This requires an object to be instantiated with the PoolPtr and the object can then be accessed from the PoolPtr similarly to an ordinary pointer or a smart pointer. This also requires the allocated object to be released from the PoolPtr before existing the application, similarly to deleting a pointer.
426 |
427 | The PoolPtr works by simply wrapping an index to a StablePoolArray. The object is then allocated using the StablePoolArray as a memory allocator.
428 |
429 | The pool allocator can be used in conjunction with a data structure to behave in the same way as if the data structure contained pointers to elements.
430 |
431 | **Usage**
432 |
433 | Allocating a single element with a PoolPtr:
434 |
435 | ``` c++
436 | PoolPtr p = 42;
437 |
438 | assert(*p == 42);
439 |
440 | p.release();
441 | ```
442 |
443 | Allocating multiple elements with a PoolPtr and Array:
444 |
445 | ``` c++
446 | Array> a = {0, 1, 2, 3, 4};
447 |
448 | int total = 0;
449 | for (PoolPtr i : a) {
450 | total += *i;
451 | }
452 |
453 | assert(total == 10);
454 |
455 | for (PoolPtr i : a) {
456 | i.release();
457 | }
458 | ```
459 |
460 | #### ae::IdPoolArray
461 |
462 | A wrapped PoolArray that associates each element with an id. Suitable for a component-centric architecture where the id corresponds to an entity.
463 |
464 | **Usage**
465 |
466 | Allocating multiple elements to an IdPoolArray.
467 |
468 | ``` c++
469 | IdPoolArray a;
470 |
471 | assert(a[0] == nullptr);
472 |
473 | a.add(0, 0);
474 |
475 | assert(a[0]);
476 | assert(*a[0] == 0);
477 |
478 | a.add(0, 1);
479 | a.add(1, 1);
480 | a.add(2, 2);
481 |
482 | assert(*a[0] == 1);
483 | assert(*a[2] == 2);
484 |
485 | a.count();
486 | ```
487 |
488 | Iterating all elements inside an IdPoolArray:
489 |
490 | ``` c++
491 | a.add(0, 1);
492 | a.add(1, 2);
493 | a.add(2, 3);
494 |
495 | int total = 0;
496 |
497 | for (auto i : a) {
498 | total += *i;
499 | }
500 |
501 | assert(total == 6);
502 | ```
503 |
504 | #### ae::PoolList
505 |
506 | A mix between a linked list and a pool allocator. The pool allocator should make it faster to add and remove elements than in a ordinary linked list.
507 |
508 | Linked lists are optimized for random insertion and deletion since, since memory does not have to be consecutive.
509 |
510 | One suggested use case for a linked list inside an ECS could be to keep track of individual compontents assigned to each entity, or similar statistics that would be hard to keep track of if all components are spread in a Property-Centric manner.
511 |
512 | ### Note on Thread Safety
513 |
514 | Some of the custom data structures make use of static variables when allocating memory. As mentioned in section [Memory Allocators](#memory-allocators), this is generally not thread safe. Multithreading is out of scope of this study, but if needed this can probably be fixed with the C++ keyword `thread_local` that allows each thread to have its own copy of the variable.
515 |
516 | ## Hardware
517 |
518 | The benchmark is measured on the following hardware:
519 |
520 | * **CPU:** Intel Core 2 Q6600 CPU (8M Cache, 2.40 GHz)
521 | * **RAM:** 8 GB
522 | * **Operating System:** Windows 8
523 |
524 | ## Results
525 |
526 |
527 |
528 |
529 |
530 | > Figure 5.1: Heap allocation (new) and deallocation (delete) with varying numbers and sizes of elements.
531 |
532 |
533 |
534 |
535 |
536 | > Figure 5.2: Time in milliseconds to add (add) and retrieve (get) a large number of elements of varying sizes (x bytes) from different containters.
537 |
538 |
539 | ## Conclusions
540 |
541 | Allocating and deleting elements using C++’s standard heap allocator had a large impact on performance with deletion of elements being by far slowest with deleting 100,000 object taking up to 10 seconds. Elements of different sizes had no notable impact on performance, and in the case of allocating, actually worsened performance on average.
542 |
543 | Compared to the standard heap allocator all proposed data structures except `std::list` was vastly superior when adding elements.
544 |
545 | - **std::array** is the standard library implementation of a resizable array, and is used as a baseline that other data structures can be compared against. By comparing it to a static array that does not require any allocation, it can be deduced that about 50 ms is spent writing to the data structure, and 250 ms resizing/allocating memory.
546 |
547 | - **ae::Array** performed slightly better than `std::vector` especially when adding 4 bytes elements. It also performed slighly better when accessing 64 bytes elements. One possible explanation might the that `ae::Array` has a growth factory of 2, whereas the growth factor of `std::vector` varies between implementations but most make use of 1.5. This might result in `ae::Array` having a more optimized [data alignment](#data-alignment) compared to `std::vector`.
548 |
549 | - **ae::PoolArray** performed very similar to `std::vector` when adding. Slightly worse during access, especially at 4 bytes, though in practice the cost might be negligible compared to any calculation that should be made with the data.
550 |
551 | - **std::list** is the standard library implementation of a linked list. Overhead was very high when adding elements. Many times higher than all other data structure. Access time is about 3-6 times higher than `std::vector`. Though in practice this might still be acceptable.
552 |
553 | - **std::PoolList** provide drastically improved performance compared to `std::list` when adding, and slightly improved performance during access.
554 |
555 | - **ae::IdPoolArray** performed 4 times slower than `std::vector` when adding, though depending on the use case this might be negligable. Access time is on pair with ``ae::PoolArray``.
556 |
557 |
558 |
559 | ## Future Work
560 |
561 | * A benchmark comparing randomly accessed attributes to sequential attributes is not included in this study and would be of high interest to investigate further. This could further be compared to a property-centric vs an object-centric ECS.
562 |
563 | * The benchmark was measured only on PC. It would be of interest to repeat the measurement on limited hardware with a slower cache memory than an average PC, such as PS3 or Raspberry Pi.
564 |
565 | * Additional optimizations such as multithreading, SIMD or GPGPU could have a large effect on performance when working with sequential memory.
566 |
567 | * Additional options of the C++ language could be investigated, e.g. modifying data structures with "alloca" which can improve performance by allocating memory on the stack stack frame instead of heap, or features new to C++ 11 such as thread_local.
568 |
569 |
570 | ## Bibliography
571 |
572 | -
[1] J. Gregory, Game engine architecture. Wellesley, Mass: A K Peters, 2009, ch. Engine Support Systems, Runtime Gameplay Foundation Systems, pp. 197–259, 711–817.
573 | -
[2] M. Doherty, A Software Architecture for Games. University of the Pacific Depratment of Computer Science Research and Project Journal, 2003.
574 | -
[3] S. Bilas, “A data-driven game object system,” in Game Developers Confer- ence Proceedings, 2002.
575 | -
[4] D. Eberly, 3D game engine architecture : engineering real-time applications with Wild Magic. Amsterdam Boston: Morgan Kaufman Publishers, 2005, ch. The Object System, pp. 105–148.
576 | -
[5] M. Chady, “Theory and practice of game object component architecture,” in Game Developers Conference Proceedings, 2009.
577 | -
[6] D. Church, “Object systems: Methods for attaching data to objects and connecting behavior,” in Game Developers Conference Proceedings, 2002.
578 | -
[7] M. Harmon, “A system for managing game entities,” in Game programming gems 4, A. Kirmse, Ed. Hingham, Mass: Charles River Media, 2004.
579 | -
[8] B. Rene, “Component based object management,” in Game programming gems 5, K. Pallister, Ed. Hingham, Mass: Charles River Media, 2005.
580 | -
[9] C. Stoy, “Game object component system,” in Game programming gems 6, M. Dickheiser, Ed. Boston, Mass: Charles River Media, 2006.
581 | -
[10] A. Duran, “Building object systems: Features, trade offs, and pitfalls,” in Game Developers Conference Proceedings, 2003.
582 | -
[11] L. V. Magnusson, “Game mechanics engine,” Master’s thesis, Østfold University College, 2011.
583 | -
[12] E. Freeman, Head First design patterns. Sebastopol, CA: O’Reilly, 2004.
584 | -
[13] N. Llopis, “High-performance programming with data-oriented design,” in Game Engine Gems 2, E. Lengyel, Ed. Wellesley, Mass: A K Peters, 2011.
585 | -
[14] J. M. Chang, W. H. Lee, and W. Srisa-an, “A study of the allocation behavior of c++ programs,” vol. 57, no. 2, 2001, pp. 107–118.
586 | -
[15] S. Bilas, “The continuous world of dungeon siege,” in Game Developers Conference Proceedings, 2003.
587 | -
[16] R. Martin, Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall, 2008, pp. 135-152.
588 | -
[17] S. Meyers, Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition). Addison-Wesley Professional, 2005, ch. Customizing new and delete.
589 | -
[18] T. Akenine-Moller, E. Haines, and N. Hoffman, Real-Time Rendering, Third Edition. A K Peters/CRC Press, 2008, ch. Optimization, pp. 703–707.
590 | -
[19] R. Gerber, Software Optimization Cookbook: High-Performance Recipes for the Intel Architecture. Intel Pr, 2002, ch. Memory, pp. 89–116.