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 ArrayUtil
12 {
13 static public void AllocInt(ref NativeArray<int> container, int capacity, bool addValues)
14 {
15 if (capacity >= 0)
16 {
17 Random.InitState(0);
18 container = new NativeArray<int>(capacity, Allocator.Persistent);
19 if (addValues)
20 {
21 for (int i = 0; i < capacity; i++)
22 container[i] = i;
23 }
24 }
25 else
26 container.Dispose();
27 }
28 static public object AllocBclContainer(int capacity, bool addValues)
29 {
30 if (capacity < 0)
31 return null;
32
33 Random.InitState(0);
34 var bclContainer = new int[capacity];
35 if (addValues)
36 {
37 for (int i = 0; i < capacity; i++)
38 bclContainer[i] = i;
39 }
40 return bclContainer;
41 }
42
43 static public void CreateRandomValues(int capacity, ref UnsafeList<int> values)
44 {
45 if (capacity >= 0)
46 {
47 values = new UnsafeList<int>(capacity, Allocator.Persistent);
48 Random.InitState(0);
49 for (int i = 0; i < capacity; i++)
50 {
51 int randKey = Random.Range(0, capacity);
52 values.Add(randKey);
53 }
54 }
55 else
56 values.Dispose();
57 }
58 }
59
60
61 struct ArrayLength100k : IBenchmarkContainer
62 {
63 const int kIterations = 100_000;
64 NativeArray<int> nativeContainer;
65
66 public void AllocNativeContainer(int capacity) => ArrayUtil.AllocInt(ref nativeContainer, capacity, true);
67 public void AllocUnsafeContainer(int capacity) { }
68 public object AllocBclContainer(int capacity) => ArrayUtil.AllocBclContainer(capacity, true);
69
70 [MethodImpl(MethodImplOptions.NoOptimization)]
71 public void MeasureNativeContainer()
72 {
73 var reader = nativeContainer.AsReadOnly();
74 for (int i = 0; i < kIterations; i++)
75 _ = reader.Length;
76 }
77 [MethodImpl(MethodImplOptions.NoOptimization)]
78 public void MeasureUnsafeContainer() { }
79 [MethodImpl(MethodImplOptions.NoOptimization)]
80 public void MeasureBclContainer(object container)
81 {
82 var bclContainer = (int[])container;
83 for (int i = 0; i < kIterations; i++)
84 _ = bclContainer.Length;
85 }
86 }
87
88 struct ArrayIndexedRead : IBenchmarkContainer
89 {
90 NativeArray<int> nativeContainer;
91 UnsafeList<int> values;
92
93 public void AllocNativeContainer(int capacity)
94 {
95 ArrayUtil.AllocInt(ref nativeContainer, capacity, true);
96 ArrayUtil.CreateRandomValues(capacity, ref values);
97 }
98 public void AllocUnsafeContainer(int capacity) { }
99 public object AllocBclContainer(int capacity)
100 {
101 object container = ArrayUtil.AllocBclContainer(capacity, true);
102 ArrayUtil.CreateRandomValues(capacity, ref values);
103 return container;
104 }
105
106 public void MeasureNativeContainer()
107 {
108 var reader = nativeContainer.AsReadOnly();
109 int insertions = values.Length;
110 int value = 0;
111 for (int i = 0; i < insertions; i++)
112 Volatile.Write(ref value, reader[values[i]]);
113 }
114 public void MeasureUnsafeContainer() { }
115 public void MeasureBclContainer(object container)
116 {
117 var bclContainer = (int[])container;
118 int insertions = values.Length;
119 int value = 0;
120 for (int i = 0; i < insertions; i++)
121 Volatile.Write(ref value, bclContainer[values[i]]);
122 }
123 }
124
125 struct ArrayIndexedWrite : IBenchmarkContainer
126 {
127 NativeArray<int> nativeContainer;
128 UnsafeList<int> values;
129
130 public void AllocNativeContainer(int capacity)
131 {
132 ArrayUtil.AllocInt(ref nativeContainer, capacity, true);
133 ArrayUtil.CreateRandomValues(capacity, ref values);
134 }
135 public void AllocUnsafeContainer(int capacity) { }
136 public object AllocBclContainer(int capacity)
137 {
138 object container = ArrayUtil.AllocBclContainer(capacity, true);
139 ArrayUtil.CreateRandomValues(capacity, ref values);
140 return container;
141 }
142
143 public void MeasureNativeContainer()
144 {
145 int insertions = values.Length;
146 for (int i = 0; i < insertions; i++)
147 nativeContainer[values[i]] = i;
148 }
149 public void MeasureUnsafeContainer() { }
150 public void MeasureBclContainer(object container)
151 {
152 var bclContainer = (int[])container;
153 int insertions = values.Length;
154 for (int i = 0; i < insertions; i++)
155 bclContainer[values[i]] = i;
156 }
157 }
158
159 struct ArrayForEach : IBenchmarkContainer
160 {
161 NativeArray<int> nativeContainer;
162 public int total;
163
164 public void AllocNativeContainer(int capacity) => ArrayUtil.AllocInt(ref nativeContainer, capacity, true);
165 public void AllocUnsafeContainer(int capacity) { }
166 public object AllocBclContainer(int capacity) => ArrayUtil.AllocBclContainer(capacity, true);
167
168 public void MeasureNativeContainer()
169 {
170 int value = 0;
171 foreach (var element in nativeContainer)
172 Volatile.Write(ref value, element);
173 }
174 public void MeasureUnsafeContainer() { }
175 public void MeasureBclContainer(object container)
176 {
177 int value = 0;
178 var bclContainer = (int[])container;
179 foreach (var element in bclContainer)
180 Volatile.Write(ref value, element);
181 }
182 }
183
184 [Benchmark(typeof(BenchmarkContainerType), true)]
185 class Array
186 {
187#if UNITY_EDITOR
188 [UnityEditor.MenuItem(BenchmarkContainerConfig.kMenuItemIndividual + nameof(Array))]
189 static void RunIndividual()
190 => BenchmarkContainerConfig.RunBenchmark(typeof(Array));
191#endif
192
193 [Test, Performance]
194 [Category("Performance")]
195 public unsafe void Length_x_100k(
196 [Values(0, 100)] int capacity,
197 [Values(BenchmarkContainerType.Native, BenchmarkContainerType.NativeBurstSafety,
198 BenchmarkContainerType.NativeBurstNoSafety)] BenchmarkContainerType type)
199 {
200 BenchmarkContainerRunner<ArrayLength100k>.Run(capacity, type);
201 }
202
203 [Test, Performance]
204 [Category("Performance")]
205 public unsafe void IndexedRead(
206 [Values(10000, 100000, 1000000)] int insertions,
207 [Values(BenchmarkContainerType.Native, BenchmarkContainerType.NativeBurstSafety,
208 BenchmarkContainerType.NativeBurstNoSafety)] BenchmarkContainerType type)
209 {
210 BenchmarkContainerRunner<ArrayIndexedRead>.Run(insertions, type);
211 }
212
213 [Test, Performance]
214 [Category("Performance")]
215 public unsafe void IndexedWrite(
216 [Values(10000, 100000, 1000000)] int insertions,
217 [Values(BenchmarkContainerType.Native, BenchmarkContainerType.NativeBurstSafety,
218 BenchmarkContainerType.NativeBurstNoSafety)] BenchmarkContainerType type)
219 {
220 BenchmarkContainerRunner<ArrayIndexedWrite>.Run(insertions, type);
221 }
222
223 [Test, Performance]
224 [Category("Performance")]
225 public unsafe void Foreach(
226 [Values(10000, 100000, 1000000)] int insertions,
227 [Values(BenchmarkContainerType.Native, BenchmarkContainerType.NativeBurstSafety,
228 BenchmarkContainerType.NativeBurstNoSafety)] BenchmarkContainerType type)
229 {
230 BenchmarkContainerRunner<ArrayForEach>.Run(insertions, type);
231 }
232 }
233}