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 RingQueueUtil
12 {
13 static public void AllocInt(ref NativeRingQueue<int> container, int capacity, bool addValues)
14 {
15 if (capacity >= 0)
16 {
17 Random.InitState(0);
18 container = new NativeRingQueue<int>(capacity, 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 UnsafeRingQueue<int> container, int capacity, bool addValues)
29 {
30 if (capacity >= 0)
31 {
32 Random.InitState(0);
33 container = new UnsafeRingQueue<int>(capacity, 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>(capacity);
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 RingQueueIsEmpty100k : IBenchmarkContainer
76 {
77 const int kIterations = 100_000;
78 NativeRingQueue<int> nativeContainer;
79 UnsafeRingQueue<int> unsafeContainer;
80
81 public void AllocNativeContainer(int capacity) => RingQueueUtil.AllocInt(ref nativeContainer, capacity, true);
82 public void AllocUnsafeContainer(int capacity) => RingQueueUtil.AllocInt(ref unsafeContainer, capacity, true);
83 public object AllocBclContainer(int capacity) => RingQueueUtil.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 [MethodImpl(MethodImplOptions.NoOptimization)]
92 public void MeasureUnsafeContainer()
93 {
94 for (int i = 0; i < kIterations; i++)
95 _ = unsafeContainer.IsEmpty;
96 }
97 [MethodImpl(MethodImplOptions.NoOptimization)]
98 public void MeasureBclContainer(object container)
99 {
100 var bclContainer = (System.Collections.Generic.Queue<int>)container;
101 for (int i = 0; i < kIterations; i++)
102 _ = bclContainer.Count == 0;
103 }
104 }
105
106 struct RingQueueCount100k : IBenchmarkContainer
107 {
108 const int kIterations = 100_000;
109 NativeRingQueue<int> nativeContainer;
110 UnsafeRingQueue<int> unsafeContainer;
111
112 public void AllocNativeContainer(int capacity) => RingQueueUtil.AllocInt(ref nativeContainer, capacity, true);
113 public void AllocUnsafeContainer(int capacity) => RingQueueUtil.AllocInt(ref unsafeContainer, capacity, true);
114 public object AllocBclContainer(int capacity) => RingQueueUtil.AllocBclContainer(capacity, true);
115
116 [MethodImpl(MethodImplOptions.NoOptimization)]
117 public void MeasureNativeContainer()
118 {
119 for (int i = 0; i < kIterations; i++)
120 _ = nativeContainer.Length;
121 }
122 [MethodImpl(MethodImplOptions.NoOptimization)]
123 public void MeasureUnsafeContainer()
124 {
125 for (int i = 0; i < kIterations; i++)
126 _ = unsafeContainer.Length;
127 }
128 [MethodImpl(MethodImplOptions.NoOptimization)]
129 public void MeasureBclContainer(object container)
130 {
131 var bclContainer = (System.Collections.Generic.Queue<int>)container;
132 for (int i = 0; i < kIterations; i++)
133 _ = bclContainer.Count;
134 }
135 }
136
137 struct RingQueueEnqueue : IBenchmarkContainer
138 {
139 int capacity;
140 NativeRingQueue<int> nativeContainer;
141 UnsafeRingQueue<int> unsafeContainer;
142
143 void IBenchmarkContainer.SetParams(int capacity, params int[] args) => this.capacity = capacity;
144
145 public void AllocNativeContainer(int capacity) => RingQueueUtil.AllocInt(ref nativeContainer, capacity, false);
146 public void AllocUnsafeContainer(int capacity) => RingQueueUtil.AllocInt(ref unsafeContainer, capacity, false);
147 public object AllocBclContainer(int capacity) => RingQueueUtil.AllocBclContainer(capacity, false);
148
149 public void MeasureNativeContainer()
150 {
151 for (int i = 0; i < capacity; i++)
152 nativeContainer.Enqueue(i);
153 }
154 public void MeasureUnsafeContainer()
155 {
156 for (int i = 0; i < capacity; i++)
157 unsafeContainer.Enqueue(i);
158 }
159 public void MeasureBclContainer(object container)
160 {
161 var bclContainer = (System.Collections.Generic.Queue<int>)container;
162 for (int i = 0; i < capacity; i++)
163 bclContainer.Enqueue(i);
164 }
165 }
166
167 struct RingQueueDequeue : IBenchmarkContainer
168 {
169 int capacity;
170 NativeRingQueue<int> nativeContainer;
171 UnsafeRingQueue<int> unsafeContainer;
172
173 void IBenchmarkContainer.SetParams(int capacity, params int[] args) => this.capacity = capacity;
174
175 public void AllocNativeContainer(int capacity) => RingQueueUtil.AllocInt(ref nativeContainer, capacity, true);
176 public void AllocUnsafeContainer(int capacity) => RingQueueUtil.AllocInt(ref unsafeContainer, capacity, true);
177 public object AllocBclContainer(int capacity) => RingQueueUtil.AllocBclContainer(capacity, true);
178
179 public void MeasureNativeContainer()
180 {
181 int keep = 0;
182 for (int i = 0; i < capacity; i++)
183 Volatile.Write(ref keep, nativeContainer.Dequeue());
184 }
185 public void MeasureUnsafeContainer()
186 {
187 int keep = 0;
188 for (int i = 0; i < capacity; i++)
189 Volatile.Write(ref keep, unsafeContainer.Dequeue());
190 }
191 public void MeasureBclContainer(object container)
192 {
193 int keep = 0;
194 var bclContainer = (System.Collections.Generic.Queue<int>)container;
195 for (int i = 0; i < capacity; i++)
196 Volatile.Write(ref keep, bclContainer.Dequeue());
197 }
198 }
199
200 [Benchmark(typeof(BenchmarkContainerType))]
201 [BenchmarkNameOverride(BenchmarkContainerConfig.BCL, "Queue")]
202 class RingQueue
203 {
204#if UNITY_EDITOR
205 [UnityEditor.MenuItem(BenchmarkContainerConfig.kMenuItemIndividual + nameof(RingQueue))]
206 static void RunIndividual()
207 => BenchmarkContainerConfig.RunBenchmark(typeof(RingQueue));
208#endif
209
210 [Test, Performance]
211 [Category("Performance")]
212 public unsafe void IsEmpty_x_100k(
213 [Values(0, 100)] int capacity,
214 [Values] BenchmarkContainerType type)
215 {
216 BenchmarkContainerRunner<RingQueueIsEmpty100k>.Run(capacity, type);
217 }
218
219 [Test, Performance]
220 [Category("Performance")]
221 public unsafe void Count_x_100k(
222 [Values(0, 100)] int capacity,
223 [Values] BenchmarkContainerType type)
224 {
225 BenchmarkContainerRunner<RingQueueCount100k>.Run(capacity, type);
226 }
227
228 [Test, Performance]
229 [Category("Performance")]
230 public unsafe void Enqueue(
231 [Values(10000, 100000, 1000000)] int insertions,
232 [Values] BenchmarkContainerType type)
233 {
234 BenchmarkContainerRunner<RingQueueEnqueue>.Run(insertions, type);
235 }
236
237 [Test, Performance]
238 [Category("Performance")]
239 public unsafe void Dequeue(
240 [Values(10000, 100000, 1000000)] int insertions,
241 [Values] BenchmarkContainerType type)
242 {
243 BenchmarkContainerRunner<RingQueueDequeue>.Run(insertions, type);
244 }
245 }
246}