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}