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}