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;
8using Unity.Mathematics;
9using UnityEditor;
10using Random = Unity.Mathematics.Random;
11
12namespace Unity.Collections.PerformanceTests
13{
14 static class HashMapUtil
15 {
16 internal const uint K_RANDOM_SEED_1 = 2210602657;
17 internal const uint K_RANDOM_SEED_2 = 2210602658;
18 internal const uint K_RANDOM_SEED_3 = 2210602659;
19 static public void AllocInt(ref NativeHashMap<int, int> container, int capacity, bool addValues)
20 {
21 if (capacity >= 0)
22 {
23 Unity.Mathematics.Random random = new Mathematics.Random(K_RANDOM_SEED_1);
24 container = new NativeHashMap<int, int>(capacity, Allocator.Persistent);
25 if (addValues)
26 {
27 int keysAdded = 0;
28
29 while (keysAdded < capacity)
30 {
31 int randKey = random.NextInt();
32 if (container.TryAdd(randKey, keysAdded))
33 {
34 ++keysAdded;
35 }
36 }
37 }
38 }
39 else
40 container.Dispose();
41 }
42 static public void AllocInt(ref UnsafeHashMap<int, int> container, int capacity, bool addValues)
43 {
44 if (capacity >= 0)
45 {
46 Unity.Mathematics.Random random = new Mathematics.Random(K_RANDOM_SEED_1);
47 container = new UnsafeHashMap<int, int>(capacity, Allocator.Persistent);
48 if (addValues)
49 {
50 int keysAdded = 0;
51
52 while (keysAdded < capacity)
53 {
54 int randKey = random.NextInt();
55 if (container.TryAdd(randKey, keysAdded))
56 {
57 ++keysAdded;
58 }
59 }
60 }
61 }
62 else
63 container.Dispose();
64 }
65 static public object AllocBclContainer(int capacity, bool addValues)
66 {
67 if (capacity < 0)
68 return null;
69
70 Unity.Mathematics.Random random = new Mathematics.Random(K_RANDOM_SEED_1);
71 var bclContainer = new System.Collections.Generic.Dictionary<int, int>(capacity);
72 if (addValues)
73 {
74 int keysAdded = 0;
75
76 while (keysAdded < capacity)
77 {
78 int randKey = random.NextInt();
79 if (bclContainer.TryAdd(randKey, keysAdded))
80 {
81 ++keysAdded;
82 }
83 }
84 }
85 return bclContainer;
86 }
87 static public void CreateRandomKeys(int capacity, ref UnsafeList<int> keys)
88 {
89 if (capacity >= 0)
90 {
91 keys = new UnsafeList<int>(capacity, Allocator.Persistent);
92 using (UnsafeHashSet<int> randomFilter = new UnsafeHashSet<int>(capacity, Allocator.Persistent))
93 {
94 Unity.Mathematics.Random random = new Mathematics.Random(K_RANDOM_SEED_2);
95 int keysAdded = 0;
96
97 while (keysAdded < capacity)
98 {
99 int randKey = random.NextInt();
100 if (randomFilter.Add(randKey))
101 {
102 keys.Add(randKey);
103 ++keysAdded;
104 }
105 }
106 }
107
108 }
109 else
110 keys.Dispose();
111 }
112
113 static public void CreateRandomKeys(int capacity, ref UnsafeList<int> keys, ref UnsafeHashMap<int, int> hashMap)
114 {
115 if (capacity >= 0)
116 {
117 keys = new UnsafeList<int>(capacity, Allocator.Persistent);
118 using (UnsafeHashSet<int> randomFilter = new UnsafeHashSet<int>(capacity, Allocator.Persistent))
119 {
120 Unity.Mathematics.Random random = new Mathematics.Random(K_RANDOM_SEED_2);
121 int keysAdded = 0;
122
123 while (keysAdded < capacity)
124 {
125 int randKey = random.NextInt();
126 if (randomFilter.Add(randKey) && !hashMap.ContainsKey(randKey))
127 {
128 keys.Add(randKey);
129 ++keysAdded;
130 }
131 }
132 }
133
134 }
135 else
136 keys.Dispose();
137 }
138
139 static public void CreateRandomKeys(int capacity, ref UnsafeList<int> keys, ref System.Collections.Generic.Dictionary<int, int> hashMap)
140 {
141 if (capacity >= 0)
142 {
143 keys = new UnsafeList<int>(capacity, Allocator.Persistent);
144 using (UnsafeHashSet<int> randomFilter = new UnsafeHashSet<int>(capacity, Allocator.Persistent))
145 {
146 Unity.Mathematics.Random random = new Mathematics.Random(K_RANDOM_SEED_2);
147 int keysAdded = 0;
148
149 while (keysAdded < capacity)
150 {
151 int randKey = random.NextInt();
152 if (randomFilter.Add(randKey) && !hashMap.ContainsKey(randKey))
153 {
154 keys.Add(randKey);
155 ++keysAdded;
156 }
157 }
158 }
159
160 }
161 else
162 keys.Dispose();
163 }
164
165 static public void CreateRandomKeys(int capacity, ref UnsafeList<int> keys, ref NativeHashMap<int, int> hashMap)
166 {
167 if (capacity >= 0)
168 {
169 keys = new UnsafeList<int>(capacity, Allocator.Persistent);
170 using (UnsafeHashSet<int> randomFilter = new UnsafeHashSet<int>(capacity, Allocator.Persistent))
171 {
172 Unity.Mathematics.Random random = new Mathematics.Random(K_RANDOM_SEED_2);
173 int keysAdded = 0;
174
175 while (keysAdded < capacity)
176 {
177 int randKey = random.NextInt();
178 if (randomFilter.Add(randKey) && !hashMap.ContainsKey(randKey))
179 {
180 keys.Add(randKey);
181 ++keysAdded;
182 }
183 }
184 }
185
186 }
187 else
188 keys.Dispose();
189 }
190
191 static public void RandomlyShuffleKeys(int capacity, ref UnsafeList<int> keys)
192 {
193 if (capacity >= 0)
194 {
195 Unity.Mathematics.Random random = new Mathematics.Random(K_RANDOM_SEED_3);
196 for (int i = 0; i < capacity; i++)
197 {
198 int keyAt = keys[i];
199 int randomIndex = random.NextInt(0, capacity - 1);
200 keys[i] = keys[randomIndex];
201 keys[randomIndex] = keyAt;
202 }
203 }
204 }
205 }
206
207 struct HashMapIsEmpty100k : IBenchmarkContainer
208 {
209 const int kIterations = 100_000;
210 NativeHashMap<int, int> nativeContainer;
211 UnsafeHashMap<int, int> unsafeContainer;
212
213 public void AllocNativeContainer(int capacity) => HashMapUtil.AllocInt(ref nativeContainer, capacity, true);
214 public void AllocUnsafeContainer(int capacity) => HashMapUtil.AllocInt(ref unsafeContainer, capacity, true);
215 public object AllocBclContainer(int capacity) => HashMapUtil.AllocBclContainer(capacity, true);
216
217 [MethodImpl(MethodImplOptions.NoOptimization)]
218 public void MeasureNativeContainer()
219 {
220 var reader = nativeContainer.AsReadOnly();
221 for (int i = 0; i < kIterations; i++)
222 _ = reader.IsEmpty;
223 }
224 [MethodImpl(MethodImplOptions.NoOptimization)]
225 public void MeasureUnsafeContainer()
226 {
227 var reader = unsafeContainer.AsReadOnly();
228 for (int i = 0; i < kIterations; i++)
229 _ = reader.IsEmpty;
230 }
231 [MethodImpl(MethodImplOptions.NoOptimization)]
232 public void MeasureBclContainer(object container)
233 {
234 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
235 for (int i = 0; i < kIterations; i++)
236 _ = bclContainer.Count == 0;
237 }
238 }
239
240 struct HashMapCount100k : IBenchmarkContainer
241 {
242 const int kIterations = 100_000;
243 NativeHashMap<int, int> nativeContainer;
244 UnsafeHashMap<int, int> unsafeContainer;
245
246 public void AllocNativeContainer(int capacity) => HashMapUtil.AllocInt(ref nativeContainer, capacity, true);
247 public void AllocUnsafeContainer(int capacity) => HashMapUtil.AllocInt(ref unsafeContainer, capacity, true);
248 public object AllocBclContainer(int capacity) => HashMapUtil.AllocBclContainer(capacity, true);
249
250 [MethodImpl(MethodImplOptions.NoOptimization)]
251 public void MeasureNativeContainer()
252 {
253 var reader = nativeContainer.AsReadOnly();
254 for (int i = 0; i < kIterations; i++)
255 _ = reader.Count;
256 }
257 [MethodImpl(MethodImplOptions.NoOptimization)]
258 public void MeasureUnsafeContainer()
259 {
260 var reader = unsafeContainer.AsReadOnly();
261 for (int i = 0; i < kIterations; i++)
262 _ = reader.Count;
263 }
264 [MethodImpl(MethodImplOptions.NoOptimization)]
265 public void MeasureBclContainer(object container)
266 {
267 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
268 for (int i = 0; i < kIterations; i++)
269 _ = bclContainer.Count;
270 }
271 }
272
273 struct HashMapToNativeArrayKeys : IBenchmarkContainer
274 {
275 NativeHashMap<int, int> nativeContainer;
276 UnsafeHashMap<int, int> unsafeContainer;
277
278 public void AllocNativeContainer(int capacity) => HashMapUtil.AllocInt(ref nativeContainer, capacity, true);
279 public void AllocUnsafeContainer(int capacity) => HashMapUtil.AllocInt(ref unsafeContainer, capacity, true);
280 public object AllocBclContainer(int capacity) => HashMapUtil.AllocBclContainer(capacity, true);
281
282 public void MeasureNativeContainer()
283 {
284 var asArray = nativeContainer.GetKeyArray(Allocator.Temp);
285 asArray.Dispose();
286 }
287 public void MeasureUnsafeContainer()
288 {
289 var asArray = unsafeContainer.GetKeyArray(Allocator.Temp);
290 asArray.Dispose();
291 }
292 public void MeasureBclContainer(object container)
293 {
294 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
295 int[] asArray = new int[bclContainer.Count];
296 bclContainer.Keys.CopyTo(asArray, 0);
297 }
298 }
299
300 struct HashMapToNativeArrayValues : IBenchmarkContainer
301 {
302 NativeHashMap<int, int> nativeContainer;
303 UnsafeHashMap<int, int> unsafeContainer;
304
305 public void AllocNativeContainer(int capacity) => HashMapUtil.AllocInt(ref nativeContainer, capacity, true);
306 public void AllocUnsafeContainer(int capacity) => HashMapUtil.AllocInt(ref unsafeContainer, capacity, true);
307 public object AllocBclContainer(int capacity) => HashMapUtil.AllocBclContainer(capacity, true);
308
309 public void MeasureNativeContainer()
310 {
311 var asArray = nativeContainer.GetValueArray(Allocator.Temp);
312 asArray.Dispose();
313 }
314 public void MeasureUnsafeContainer()
315 {
316 var asArray = unsafeContainer.GetValueArray(Allocator.Temp);
317 asArray.Dispose();
318 }
319 public void MeasureBclContainer(object container)
320 {
321 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
322 int[] asArray = new int[bclContainer.Count];
323 bclContainer.Values.CopyTo(asArray, 0);
324 }
325 }
326
327 struct HashMapInsert : IBenchmarkContainer
328 {
329 int capacity;
330 NativeHashMap<int, int> nativeContainer;
331 UnsafeHashMap<int, int> unsafeContainer;
332 UnsafeList<int> keys;
333
334 void IBenchmarkContainer.SetParams(int capacity, params int[] args) => this.capacity = capacity;
335
336 public void AllocNativeContainer(int capacity)
337 {
338 HashMapUtil.AllocInt(ref nativeContainer, capacity, false);
339 HashMapUtil.CreateRandomKeys(capacity, ref keys, ref nativeContainer);
340 }
341
342 public void AllocUnsafeContainer(int capacity)
343 {
344 HashMapUtil.AllocInt(ref unsafeContainer, capacity, false);
345 HashMapUtil.CreateRandomKeys(capacity, ref keys, ref unsafeContainer);
346 }
347
348 public object AllocBclContainer(int capacity)
349 {
350 object container = HashMapUtil.AllocBclContainer(capacity, false);
351 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
352 HashMapUtil.CreateRandomKeys(capacity, ref keys, ref bclContainer);
353 return container;
354 }
355
356 public void MeasureNativeContainer()
357 {
358 for (int i = 0; i < capacity; i++)
359 nativeContainer.Add(keys[i], i);
360 }
361 public void MeasureUnsafeContainer()
362 {
363 for (int i = 0; i < capacity; i++)
364 unsafeContainer.Add(keys[i], i);
365 }
366 public void MeasureBclContainer(object container)
367 {
368 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
369 for (int i = 0; i < capacity; i++)
370 bclContainer.Add(keys[i], i);
371 }
372 }
373
374 struct HashMapAddGrow : IBenchmarkContainer
375 {
376 int capacity;
377 int toAdd;
378 NativeHashMap<int, int> nativeContainer;
379 UnsafeHashMap<int, int> unsafeContainer;
380 UnsafeList<int> keys;
381
382 void IBenchmarkContainer.SetParams(int capacity, params int[] args)
383 {
384 this.capacity = capacity;
385 toAdd = args[0];
386 }
387
388 public void AllocNativeContainer(int capacity)
389 {
390 HashMapUtil.AllocInt(ref nativeContainer, capacity, true);
391 int toAddCount = capacity < 0 ? -1 : toAdd;
392 HashMapUtil.CreateRandomKeys(toAddCount, ref keys, ref nativeContainer);
393 }
394
395 public void AllocUnsafeContainer(int capacity)
396 {
397 HashMapUtil.AllocInt(ref unsafeContainer, capacity, true);
398 int toAddCount = capacity < 0 ? -1 : toAdd;
399 HashMapUtil.CreateRandomKeys(toAddCount, ref keys, ref unsafeContainer);
400 }
401
402 public object AllocBclContainer(int capacity)
403 {
404 object container = HashMapUtil.AllocBclContainer(capacity, true);
405 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
406 int toAddCount = capacity < 0 ? -1 : toAdd;
407 HashMapUtil.CreateRandomKeys(toAddCount, ref keys, ref bclContainer);
408 return container;
409 }
410
411 public void MeasureNativeContainer()
412 {
413 // Intentionally setting capacity small and growing by adding more items
414 for (int i = 0; i < toAdd; i++)
415 nativeContainer.Add(keys[i], i);
416 }
417 public void MeasureUnsafeContainer()
418 {
419 // Intentionally setting capacity small and growing by adding more items
420 for (int i = 0; i < toAdd; i++)
421 unsafeContainer.Add(keys[i], i);
422 }
423 public void MeasureBclContainer(object container)
424 {
425 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
426 // Intentionally setting capacity small and growing by adding more items
427 for (int i = 0; i < toAdd; i++)
428 bclContainer.Add(keys[i], i);
429 }
430 }
431
432 struct HashMapContains : IBenchmarkContainer
433 {
434 int capacity;
435 NativeHashMap<int, int> nativeContainer;
436 UnsafeHashMap<int, int> unsafeContainer;
437 UnsafeList<int> keys;
438 void IBenchmarkContainer.SetParams(int capacity, params int[] args) => this.capacity = capacity;
439
440 public void AllocNativeContainer(int capacity)
441 {
442 HashMapUtil.AllocInt(ref nativeContainer, capacity, false);
443 HashMapUtil.CreateRandomKeys(capacity, ref keys);
444 for (int i = 0; i < capacity; i++)
445 nativeContainer.TryAdd(keys[i], i);
446 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
447 }
448 public void AllocUnsafeContainer(int capacity)
449 {
450 HashMapUtil.AllocInt(ref unsafeContainer, capacity, false);
451 HashMapUtil.CreateRandomKeys(capacity, ref keys);
452 for (int i = 0; i < capacity; i++)
453 unsafeContainer.TryAdd(keys[i], i);
454 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
455 }
456 public object AllocBclContainer(int capacity)
457 {
458 object container = HashMapUtil.AllocBclContainer(capacity, false);
459 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
460 HashMapUtil.CreateRandomKeys(capacity, ref keys);
461 for (int i = 0; i < capacity; i++)
462 bclContainer.TryAdd(keys[i], i);
463 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
464 return container;
465 }
466
467 public void MeasureNativeContainer()
468 {
469 var reader = nativeContainer.AsReadOnly();
470 bool data = false;
471 for (int i = 0; i < capacity; i++)
472 Volatile.Write(ref data, reader.ContainsKey(keys[i]));
473 }
474 public void MeasureUnsafeContainer()
475 {
476 var reader = unsafeContainer.AsReadOnly();
477 bool data = false;
478 for (int i = 0; i < capacity; i++)
479 Volatile.Write(ref data, reader.ContainsKey(keys[i]));
480 }
481 public void MeasureBclContainer(object container)
482 {
483 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
484 bool data = false;
485 for (int i = 0; i < capacity; i++)
486 Volatile.Write(ref data, bclContainer.ContainsKey(keys[i]));
487 }
488 }
489
490 struct HashMapIndexedRead : IBenchmarkContainer
491 {
492 NativeHashMap<int, int> nativeContainer;
493 UnsafeHashMap<int, int> unsafeContainer;
494 UnsafeList<int> keys;
495
496 public void AllocNativeContainer(int capacity)
497 {
498 HashMapUtil.AllocInt(ref nativeContainer, capacity, false);
499 HashMapUtil.CreateRandomKeys(capacity, ref keys);
500 for (int i = 0; i < capacity; i++)
501 nativeContainer.TryAdd(keys[i], i);
502 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
503 }
504 public void AllocUnsafeContainer(int capacity)
505 {
506 HashMapUtil.AllocInt(ref unsafeContainer, capacity, false);
507 HashMapUtil.CreateRandomKeys(capacity, ref keys);
508 for (int i = 0; i < capacity; i++)
509 unsafeContainer.TryAdd(keys[i], i);
510 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
511 }
512 public object AllocBclContainer(int capacity)
513 {
514 object container = HashMapUtil.AllocBclContainer(capacity, false);
515 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
516 HashMapUtil.CreateRandomKeys(capacity, ref keys);
517 for (int i = 0; i < capacity; i++)
518 bclContainer.TryAdd(keys[i], i);
519 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
520 return container;
521 }
522
523 public void MeasureNativeContainer()
524 {
525 var reader = nativeContainer.AsReadOnly();
526 int insertions = keys.Length;
527 int value = 0;
528 for (int i = 0; i < insertions; i++)
529 Volatile.Write(ref value, reader[keys[i]]);
530 }
531 public void MeasureUnsafeContainer()
532 {
533 var reader = unsafeContainer.AsReadOnly();
534 int insertions = keys.Length;
535 int value = 0;
536 for (int i = 0; i < insertions; i++)
537 Volatile.Write(ref value, reader[keys[i]]);
538 }
539 public void MeasureBclContainer(object container)
540 {
541 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
542 int insertions = keys.Length;
543 int value = 0;
544 for (int i = 0; i < insertions; i++)
545 Volatile.Write(ref value, bclContainer[keys[i]]);
546 }
547 }
548
549 struct HashMapIndexedWrite : IBenchmarkContainer
550 {
551 NativeHashMap<int, int> nativeContainer;
552 UnsafeHashMap<int, int> unsafeContainer;
553 UnsafeList<int> keys;
554
555 public void AllocNativeContainer(int capacity)
556 {
557 HashMapUtil.AllocInt(ref nativeContainer, capacity, false);
558 HashMapUtil.CreateRandomKeys(capacity, ref keys);
559 for (int i = 0; i < capacity; i++)
560 nativeContainer.TryAdd(keys[i], i);
561 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
562 }
563 public void AllocUnsafeContainer(int capacity)
564 {
565 HashMapUtil.AllocInt(ref unsafeContainer, capacity, false);
566 HashMapUtil.CreateRandomKeys(capacity, ref keys);
567 for (int i = 0; i < capacity; i++)
568 unsafeContainer.TryAdd(keys[i], i);
569 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
570 }
571 public object AllocBclContainer(int capacity)
572 {
573 var container = HashMapUtil.AllocBclContainer(capacity, false);
574 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
575 HashMapUtil.CreateRandomKeys(capacity, ref keys);
576 for (int i = 0; i < capacity; i++)
577 bclContainer.TryAdd(keys[i], i);
578 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
579 return container;
580 }
581
582 public void MeasureNativeContainer()
583 {
584 int insertions = keys.Length;
585 for (int i = 0; i < insertions; i++)
586 nativeContainer[keys[i]] = i;
587 }
588 public void MeasureUnsafeContainer()
589 {
590 int insertions = keys.Length;
591 for (int i = 0; i < insertions; i++)
592 unsafeContainer[keys[i]] = i;
593 }
594 public void MeasureBclContainer(object container)
595 {
596 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
597 int insertions = keys.Length;
598 for (int i = 0; i < insertions; i++)
599 bclContainer[keys[i]] = i;
600 }
601 }
602
603 struct HashMapTryGetValue : IBenchmarkContainer
604 {
605 NativeHashMap<int, int> nativeContainer;
606 UnsafeHashMap<int, int> unsafeContainer;
607 UnsafeList<int> keys;
608
609 public void AllocNativeContainer(int capacity)
610 {
611 HashMapUtil.AllocInt(ref nativeContainer, capacity, false);
612 HashMapUtil.CreateRandomKeys(capacity, ref keys);
613 for (int i = 0; i < capacity; i++)
614 nativeContainer.TryAdd(keys[i], i);
615 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
616 }
617 public void AllocUnsafeContainer(int capacity)
618 {
619 HashMapUtil.AllocInt(ref unsafeContainer, capacity, false);
620 HashMapUtil.CreateRandomKeys(capacity, ref keys);
621 for (int i = 0; i < capacity; i++)
622 unsafeContainer.TryAdd(keys[i], i);
623 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
624 }
625 public object AllocBclContainer(int capacity)
626 {
627 object container = HashMapUtil.AllocBclContainer(capacity, false);
628 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
629 HashMapUtil.CreateRandomKeys(capacity, ref keys);
630 for (int i = 0; i < capacity; i++)
631 bclContainer.TryAdd(keys[i], i);
632 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
633 return container;
634 }
635
636 public void MeasureNativeContainer()
637 {
638 var reader = nativeContainer.AsReadOnly();
639 int insertions = keys.Length;
640 for (int i = 0; i < insertions; i++)
641 {
642 reader.TryGetValue(keys[i], out var value);
643 Volatile.Read(ref value);
644 }
645 }
646 public void MeasureUnsafeContainer()
647 {
648 var reader = unsafeContainer.AsReadOnly();
649 int insertions = keys.Length;
650 for (int i = 0; i < insertions; i++)
651 {
652 reader.TryGetValue(keys[i], out var value);
653 Volatile.Read(ref value);
654 }
655 }
656 public void MeasureBclContainer(object container)
657 {
658 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
659 int insertions = keys.Length;
660 for (int i = 0; i < insertions; i++)
661 {
662 bclContainer.TryGetValue(keys[i], out var value);
663 Volatile.Read(ref value);
664 }
665 }
666 }
667
668 struct HashMapRemove : IBenchmarkContainer
669 {
670 NativeHashMap<int, int> nativeContainer;
671 UnsafeHashMap<int, int> unsafeContainer;
672 UnsafeList<int> keys;
673
674 public void AllocNativeContainer(int capacity)
675 {
676 HashMapUtil.AllocInt(ref nativeContainer, capacity, false);
677 HashMapUtil.CreateRandomKeys(capacity, ref keys);
678 for (int i = 0; i < capacity; i++)
679 nativeContainer.TryAdd(keys[i], i);
680 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
681 }
682 public void AllocUnsafeContainer(int capacity)
683 {
684 HashMapUtil.AllocInt(ref unsafeContainer, capacity, false);
685 HashMapUtil.CreateRandomKeys(capacity, ref keys);
686 for (int i = 0; i < capacity; i++)
687 unsafeContainer.TryAdd(keys[i], i);
688 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
689 }
690 public object AllocBclContainer(int capacity)
691 {
692 object container = HashMapUtil.AllocBclContainer(capacity, false);
693 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
694 HashMapUtil.CreateRandomKeys(capacity, ref keys);
695 for (int i = 0; i < capacity; i++)
696 bclContainer.TryAdd(keys[i], i);
697 HashMapUtil.RandomlyShuffleKeys(capacity, ref keys);
698 return container;
699 }
700
701 public void MeasureNativeContainer()
702 {
703 int insertions = keys.Length;
704 for (int i = 0; i < insertions; i++)
705 nativeContainer.Remove(keys[i]);
706 }
707 public void MeasureUnsafeContainer()
708 {
709 int insertions = keys.Length;
710 for (int i = 0; i < insertions; i++)
711 unsafeContainer.Remove(keys[i]);
712 }
713 public void MeasureBclContainer(object container)
714 {
715 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
716 int insertions = keys.Length;
717 for (int i = 0; i < insertions; i++)
718 bclContainer.Remove(keys[i]);
719 }
720 }
721
722 struct HashMapForEach : IBenchmarkContainer
723 {
724 NativeHashMap<int, int> nativeContainer;
725 UnsafeHashMap<int, int> unsafeContainer;
726 public int total;
727
728 public void AllocNativeContainer(int capacity) => HashMapUtil.AllocInt(ref nativeContainer, capacity, true);
729 public void AllocUnsafeContainer(int capacity) => HashMapUtil.AllocInt(ref unsafeContainer, capacity, true);
730 public object AllocBclContainer(int capacity) => HashMapUtil.AllocBclContainer(capacity, true);
731
732 public void MeasureNativeContainer()
733 {
734 foreach (var pair in nativeContainer)
735 Volatile.Read(ref pair.Value);
736 }
737 public void MeasureUnsafeContainer()
738 {
739 foreach (var pair in unsafeContainer)
740 Volatile.Read(ref pair.Value);
741 }
742 public void MeasureBclContainer(object container)
743 {
744 int value = 0;
745 var bclContainer = (System.Collections.Generic.Dictionary<int, int>)container;
746 foreach (var pair in bclContainer)
747 Volatile.Write(ref value, pair.Value);
748 }
749 }
750
751
752 [Benchmark(typeof(BenchmarkContainerType))]
753 [BenchmarkNameOverride(BenchmarkContainerConfig.BCL, "Dictionary")]
754 class HashMap
755 {
756#if UNITY_EDITOR
757 [UnityEditor.MenuItem(BenchmarkContainerConfig.kMenuItemIndividual + nameof(HashMap))]
758 static void RunIndividual()
759 => BenchmarkContainerConfig.RunBenchmark(typeof(HashMap));
760#endif
761
762 [Test, Performance]
763 [Category("Performance")]
764 public unsafe void IsEmpty_x_100k(
765 [Values(0, 100)] int capacity,
766 [Values] BenchmarkContainerType type)
767 {
768 BenchmarkContainerRunner<HashMapIsEmpty100k>.Run(capacity, type);
769 }
770
771 [Test, Performance]
772 [Category("Performance")]
773 public unsafe void Count_x_100k(
774 [Values(0, 100)] int capacity,
775 [Values] BenchmarkContainerType type)
776 {
777 BenchmarkContainerRunner<HashMapCount100k>.Run(capacity, type);
778 }
779
780 [Test, Performance]
781 [Category("Performance")]
782 public unsafe void ToNativeArrayKeys(
783 [Values(10000, 100000, 1000000)] int capacity,
784 [Values] BenchmarkContainerType type)
785 {
786 BenchmarkContainerRunner<HashMapToNativeArrayKeys>.Run(capacity, type);
787 }
788
789 [Test, Performance]
790 [Category("Performance")]
791 public unsafe void ToNativeArrayValues(
792 [Values(10000, 100000, 1000000)] int capacity,
793 [Values] BenchmarkContainerType type)
794 {
795 BenchmarkContainerRunner<HashMapToNativeArrayValues>.Run(capacity, type);
796 }
797
798 [Test, Performance]
799 [Category("Performance")]
800 public unsafe void Insert(
801 [Values(10000, 100000, 1000000)] int insertions,
802 [Values] BenchmarkContainerType type)
803 {
804 BenchmarkContainerRunner<HashMapInsert>.Run(insertions, type);
805 }
806
807 [Test, Performance]
808 [Category("Performance")]
809 [BenchmarkTestFootnote("Incrementally grows from `capacity` until reaching size of `growTo`")]
810 public unsafe void AddGrow(
811 [Values(4, 65536)] int capacity,
812 [Values(1024 * 1024)] int growTo,
813 [Values] BenchmarkContainerType type)
814 {
815 BenchmarkContainerRunner<HashMapAddGrow>.Run(capacity, type, growTo);
816 }
817
818 [Test, Performance]
819 [Category("Performance")]
820 public unsafe void Contains(
821 [Values(10000, 100000, 1000000)] int insertions,
822 [Values] BenchmarkContainerType type)
823 {
824 BenchmarkContainerRunner<HashMapContains>.Run(insertions, type);
825 }
826
827 [Test, Performance]
828 [Category("Performance")]
829 public unsafe void IndexedRead(
830 [Values(10000, 100000, 1000000)] int insertions,
831 [Values] BenchmarkContainerType type)
832 {
833 BenchmarkContainerRunner<HashMapIndexedRead>.Run(insertions, type);
834 }
835
836 [Test, Performance]
837 [Category("Performance")]
838 public unsafe void IndexedWrite(
839 [Values(10000, 100000, 1000000)] int insertions,
840 [Values] BenchmarkContainerType type)
841 {
842 BenchmarkContainerRunner<HashMapIndexedWrite>.Run(insertions, type);
843 }
844
845 [Test, Performance]
846 [Category("Performance")]
847 public unsafe void TryGetValue(
848 [Values(10000, 100000, 1000000)] int insertions,
849 [Values] BenchmarkContainerType type)
850 {
851 BenchmarkContainerRunner<HashMapTryGetValue>.Run(insertions, type);
852 }
853
854 [Test, Performance]
855 [Category("Performance")]
856 public unsafe void Remove(
857 [Values(10000, 100000, 1000000)] int insertions,
858 [Values] BenchmarkContainerType type)
859 {
860 BenchmarkContainerRunner<HashMapRemove>.Run(insertions, type);
861 }
862
863 [Test, Performance]
864 [Category("Performance")]
865 public unsafe void Foreach(
866 [Values(10000, 100000, 1000000)] int insertions,
867 [Values] BenchmarkContainerType type)
868 {
869 BenchmarkContainerRunner<HashMapForEach>.Run(insertions, type);
870 }
871 }
872}