No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

HashMapPerformanceTests.cs 33KB

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