A game about forced loneliness, made by TACStudios
1using NUnit.Framework;
2using UnityEngine;
3using Unity.Collections.LowLevel.Unsafe;
4using Unity.PerformanceTesting;
5using Unity.PerformanceTesting.Benchmark;
6using System.Runtime.CompilerServices;
7using System.Threading;
8
9namespace Unity.Collections.PerformanceTests
10{
11 static class QueueUtil
12 {
13 static public void AllocInt(ref NativeQueue<int> container, int capacity, bool addValues)
14 {
15 if (capacity >= 0)
16 {
17 Random.InitState(0);
18 container = new NativeQueue<int>(Allocator.Persistent);
19 if (addValues)
20 {
21 for (int i = 0; i < capacity; i++)
22 container.Enqueue(i);
23 }
24 }
25 else
26 container.Dispose();
27 }
28 static public void AllocInt(ref UnsafeQueue<int> container, int capacity, bool addValues)
29 {
30 if (capacity >= 0)
31 {
32 Random.InitState(0);
33 container = new UnsafeQueue<int>(Allocator.Persistent);
34 if (addValues)
35 {
36 for (int i = 0; i < capacity; i++)
37 container.Enqueue(i);
38 }
39 }
40 else
41 container.Dispose();
42 }
43 static public object AllocBclContainer(int capacity, bool addValues)
44 {
45 if (capacity < 0)
46 return null;
47
48 Random.InitState(0);
49 var bclContainer = new System.Collections.Generic.Queue<int>();
50 if (addValues)
51 {
52 for (int i = 0; i < capacity; i++)
53 bclContainer.Enqueue(i);
54 }
55 return bclContainer;
56 }
57
58 static public void CreateRandomValues(int capacity, ref UnsafeList<int> values)
59 {
60 if (capacity >= 0)
61 {
62 values = new UnsafeList<int>(capacity, Allocator.Persistent);
63 Random.InitState(0);
64 for (int i = 0; i < capacity; i++)
65 {
66 int randKey = Random.Range(0, capacity);
67 values.Add(randKey);
68 }
69 }
70 else
71 values.Dispose();
72 }
73 }
74
75 struct QueueIsEmpty100k : IBenchmarkContainer
76 {
77 const int kIterations = 100_000;
78 NativeQueue<int> nativeContainer;
79 UnsafeQueue<int> unsafeContainer;
80
81 public void AllocNativeContainer(int capacity) => QueueUtil.AllocInt(ref nativeContainer, capacity, true);
82 public void AllocUnsafeContainer(int capacity) => QueueUtil.AllocInt(ref unsafeContainer, capacity, true);
83 public object AllocBclContainer(int capacity) => QueueUtil.AllocBclContainer(capacity, true);
84
85 [MethodImpl(MethodImplOptions.NoOptimization)]
86 public void MeasureNativeContainer()
87 {
88 for (int i = 0; i < kIterations; i++)
89 _ = nativeContainer.IsEmpty();
90 }
91 public void MeasureUnsafeContainer()
92 {
93 for (int i = 0; i < kIterations; i++)
94 _ = unsafeContainer.IsEmpty();
95 }
96 [MethodImpl(MethodImplOptions.NoOptimization)]
97 public void MeasureBclContainer(object container)
98 {
99 var bclContainer = (System.Collections.Generic.Queue<int>)container;
100 for (int i = 0; i < kIterations; i++)
101 _ = bclContainer.Count == 0;
102 }
103 }
104
105 struct QueueCount100k : IBenchmarkContainer
106 {
107 const int kIterations = 100_000;
108 NativeQueue<int> nativeContainer;
109 UnsafeQueue<int> unsafeContainer;
110
111 public void AllocNativeContainer(int capacity) => QueueUtil.AllocInt(ref nativeContainer, capacity, true);
112 public void AllocUnsafeContainer(int capacity) => QueueUtil.AllocInt(ref unsafeContainer, capacity, true);
113 public object AllocBclContainer(int capacity) => QueueUtil.AllocBclContainer(capacity, true);
114
115 [MethodImpl(MethodImplOptions.NoOptimization)]
116 public void MeasureNativeContainer()
117 {
118 for (int i = 0; i < kIterations; i++)
119 _ = nativeContainer.Count;
120 }
121 public void MeasureUnsafeContainer()
122 {
123 for (int i = 0; i < kIterations; i++)
124 _ = unsafeContainer.Count;
125 }
126 [MethodImpl(MethodImplOptions.NoOptimization)]
127 public void MeasureBclContainer(object container)
128 {
129 var bclContainer = (System.Collections.Generic.Queue<int>)container;
130 for (int i = 0; i < kIterations; i++)
131 _ = bclContainer.Count;
132 }
133 }
134
135 struct QueueToNativeArray : IBenchmarkContainer
136 {
137 NativeQueue<int> nativeContainer;
138 UnsafeQueue<int> unsafeContainer;
139
140 public void AllocNativeContainer(int capacity) => QueueUtil.AllocInt(ref nativeContainer, capacity, true);
141 public void AllocUnsafeContainer(int capacity) => QueueUtil.AllocInt(ref unsafeContainer, capacity, true);
142 public object AllocBclContainer(int capacity) => QueueUtil.AllocBclContainer(capacity, true);
143
144 public void MeasureNativeContainer()
145 {
146 var asArray = nativeContainer.ToArray(Allocator.Temp);
147 asArray.Dispose();
148 }
149 public void MeasureUnsafeContainer()
150 {
151 var asArray = unsafeContainer.ToArray(Allocator.Temp);
152 asArray.Dispose();
153 }
154 public void MeasureBclContainer(object container)
155 {
156 var bclContainer = (System.Collections.Generic.Queue<int>)container;
157 int[] asArray = new int[bclContainer.Count];
158 bclContainer.CopyTo(asArray, 0);
159 }
160 }
161
162 struct QueueEnqueueGrow : IBenchmarkContainer
163 {
164 int capacity;
165 int workers;
166 NativeQueue<int> nativeContainer;
167 UnsafeQueue<int> unsafeContainer;
168
169 void IBenchmarkContainer.SetParams(int capacity, params int[] args) => this.capacity = capacity;
170
171 public void AllocNativeContainer(int capacity) => QueueUtil.AllocInt(ref nativeContainer, capacity >= 0 ? 0 : -1, false);
172 public void AllocUnsafeContainer(int capacity) => QueueUtil.AllocInt(ref unsafeContainer, capacity >= 0 ? 0 : -1, false);
173 public object AllocBclContainer(int capacity) => QueueUtil.AllocBclContainer(capacity >= 0 ? 0 : -1, false);
174
175 public void MeasureNativeContainer()
176 {
177 for (int i = 0; i < capacity; i++)
178 nativeContainer.Enqueue(i);
179 }
180 public void MeasureUnsafeContainer()
181 {
182 for (int i = 0; i < capacity; i++)
183 unsafeContainer.Enqueue(i);
184 }
185 public void MeasureBclContainer(object container)
186 {
187 var bclContainer = (System.Collections.Generic.Queue<int>)container;
188 for (int i = 0; i < capacity; i++)
189 bclContainer.Enqueue(i);
190 }
191 }
192
193 struct QueueEnqueue : IBenchmarkContainer
194 {
195 int capacity;
196 int workers;
197 NativeQueue<int> nativeContainer;
198 UnsafeQueue<int> unsafeContainer;
199
200 void IBenchmarkContainer.SetParams(int capacity, params int[] args) => this.capacity = capacity;
201
202 public void AllocNativeContainer(int capacity) => QueueUtil.AllocInt(ref nativeContainer, capacity, false);
203 public void AllocUnsafeContainer(int capacity) => QueueUtil.AllocInt(ref unsafeContainer, capacity, false);
204 public object AllocBclContainer(int capacity) => QueueUtil.AllocBclContainer(capacity, false);
205
206 public void MeasureNativeContainer()
207 {
208 for (int i = 0; i < capacity; i++)
209 nativeContainer.Enqueue(i);
210 }
211 public void MeasureUnsafeContainer()
212 {
213 for (int i = 0; i < capacity; i++)
214 unsafeContainer.Enqueue(i);
215 }
216 public void MeasureBclContainer(object container)
217 {
218 var bclContainer = (System.Collections.Generic.Queue<int>)container;
219 for (int i = 0; i < capacity; i++)
220 bclContainer.Enqueue(i);
221 }
222 }
223
224 struct QueueDequeue : IBenchmarkContainer
225 {
226 int capacity;
227 NativeQueue<int> nativeContainer;
228 UnsafeQueue<int> unsafeContainer;
229
230 void IBenchmarkContainer.SetParams(int capacity, params int[] args) => this.capacity = capacity;
231
232 public void AllocNativeContainer(int capacity) => QueueUtil.AllocInt(ref nativeContainer, capacity, true);
233 public void AllocUnsafeContainer(int capacity) => QueueUtil.AllocInt(ref unsafeContainer, capacity, true);
234 public object AllocBclContainer(int capacity) => QueueUtil.AllocBclContainer(capacity, true);
235
236 public void MeasureNativeContainer()
237 {
238 int keep = 0;
239 for (int i = 0; i < capacity; i++)
240 Volatile.Write(ref keep, nativeContainer.Dequeue());
241 }
242 public void MeasureUnsafeContainer()
243 {
244 int keep = 0;
245 for (int i = 0; i < capacity; i++)
246 Volatile.Write(ref keep, unsafeContainer.Dequeue());
247 }
248 public void MeasureBclContainer(object container)
249 {
250 var bclContainer = (System.Collections.Generic.Queue<int>)container;
251 for (int i = 0; i < capacity; i++)
252 {
253 bclContainer.TryDequeue(out int value);
254 Volatile.Read(ref value);
255 }
256 }
257 }
258
259 struct QueuePeek: IBenchmarkContainer
260 {
261 int capacity;
262 NativeQueue<int> nativeContainer;
263 UnsafeQueue<int> unsafeContainer;
264
265 void IBenchmarkContainer.SetParams(int capacity, params int[] args) => this.capacity = capacity;
266
267 public void AllocNativeContainer(int capacity) => QueueUtil.AllocInt(ref nativeContainer, capacity, true);
268 public void AllocUnsafeContainer(int capacity) => QueueUtil.AllocInt(ref unsafeContainer, capacity, true);
269 public object AllocBclContainer(int capacity) => QueueUtil.AllocBclContainer(capacity, true);
270
271 [MethodImpl(MethodImplOptions.NoOptimization)]
272 public void MeasureNativeContainer()
273 {
274 for (int i = 0; i < capacity; i++)
275 _ = nativeContainer.Peek();
276 }
277 public void MeasureUnsafeContainer()
278 {
279 for (int i = 0; i < capacity; i++)
280 _ = unsafeContainer.Peek();
281 }
282 [MethodImpl(MethodImplOptions.NoOptimization)]
283 public void MeasureBclContainer(object container)
284 {
285 var bclContainer = (System.Collections.Generic.Queue<int>)container;
286 for (int i = 0; i < capacity; i++)
287 {
288 bclContainer.TryPeek(out int value);
289 Volatile.Read(ref value);
290 }
291 }
292 }
293
294 struct QueueForEach : IBenchmarkContainer
295 {
296 NativeQueue<int> nativeContainer;
297 UnsafeQueue<int> unsafeContainer;
298 public int total;
299
300 public void AllocNativeContainer(int capacity) => QueueUtil.AllocInt(ref nativeContainer, capacity, true);
301 public void AllocUnsafeContainer(int capacity) => QueueUtil.AllocInt(ref unsafeContainer, capacity, true);
302 public object AllocBclContainer(int capacity) => QueueUtil.AllocBclContainer(capacity, true);
303
304 public void MeasureNativeContainer()
305 {
306 int value = 0;
307 var ro = nativeContainer.AsReadOnly();
308 foreach (var element in ro)
309 Volatile.Write(ref value, element);
310 }
311 public void MeasureUnsafeContainer()
312 {
313 int value = 0;
314 var ro = unsafeContainer.AsReadOnly();
315 foreach (var element in ro)
316 Volatile.Write(ref value, element);
317 }
318 public void MeasureBclContainer(object container)
319 {
320 int value = 0;
321 var bclContainer = (System.Collections.Generic.Queue<int>)container;
322 foreach (var element in bclContainer)
323 Volatile.Write(ref value, element);
324 }
325 }
326
327
328 [Benchmark(typeof(BenchmarkContainerType))]
329 class Queue
330 {
331#if UNITY_EDITOR
332 [UnityEditor.MenuItem(BenchmarkContainerConfig.kMenuItemIndividual + nameof(Queue))]
333 static void RunIndividual()
334 => BenchmarkContainerConfig.RunBenchmark(typeof(Queue));
335#endif
336
337 [Test, Performance]
338 [Category("Performance")]
339 public unsafe void IsEmpty_x_100k(
340 [Values(0, 100)] int capacity,
341 [Values] BenchmarkContainerType type)
342 {
343 BenchmarkContainerRunner<QueueIsEmpty100k>.Run(capacity, type);
344 }
345
346 [Test, Performance]
347 [Category("Performance")]
348 public unsafe void Count_x_100k(
349 [Values(0, 100)] int capacity,
350 [Values] BenchmarkContainerType type)
351 {
352 BenchmarkContainerRunner<QueueCount100k>.Run(capacity, type);
353 }
354
355 [Test, Performance]
356 [Category("Performance")]
357 public unsafe void ToNativeArray(
358 [Values(10000, 100000, 1000000)] int capacity,
359 [Values] BenchmarkContainerType type)
360 {
361 BenchmarkContainerRunner<QueueToNativeArray>.Run(capacity, type);
362 }
363
364 [Test, Performance]
365 [Category("Performance")]
366 [BenchmarkTestFootnote]
367 public unsafe void EnqueueGrow(
368 [Values(10000, 100000, 1000000)] int insertions,
369 [Values] BenchmarkContainerType type)
370 {
371 BenchmarkContainerRunner<QueueEnqueueGrow>.Run(insertions, type);
372 }
373
374 [Test, Performance]
375 [Category("Performance")]
376 [BenchmarkTestFootnote]
377 public unsafe void Enqueue(
378 [Values(10000, 100000, 1000000)] int insertions,
379 [Values] BenchmarkContainerType type)
380 {
381 BenchmarkContainerRunner<QueueEnqueue>.Run(insertions, type);
382 }
383
384 [Test, Performance]
385 [Category("Performance")]
386 public unsafe void Dequeue(
387 [Values(10000, 100000, 1000000)] int insertions,
388 [Values] BenchmarkContainerType type)
389 {
390 BenchmarkContainerRunner<QueueDequeue>.Run(insertions, type);
391 }
392
393 [Test, Performance]
394 [Category("Performance")]
395 public unsafe void Peek(
396 [Values(10000, 100000, 1000000)] int insertions,
397 [Values] BenchmarkContainerType type)
398 {
399 BenchmarkContainerRunner<QueuePeek>.Run(insertions, type);
400 }
401
402 [Test, Performance]
403 [Category("Performance")]
404 public unsafe void Foreach(
405 [Values(10000, 100000, 1000000)] int insertions,
406 [Values] BenchmarkContainerType type)
407 {
408 BenchmarkContainerRunner<QueueForEach>.Run(insertions, type);
409 }
410 }
411}