Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
TlsOverPerCoreLockedStacksArrayPool.cs
Go to the documentation of this file.
5
6namespace System.Buffers;
7
8internal sealed class TlsOverPerCoreLockedStacksArrayPool<T> : ArrayPool<T>
9{
10 private sealed class PerCoreLockedStacks
11 {
12 private static readonly int s_lockedStackCount = Math.Min(Environment.ProcessorCount, 64);
13
14 private readonly LockedStack[] _perCoreStacks;
15
17 {
19 for (int i = 0; i < array.Length; i++)
20 {
21 array[i] = new LockedStack();
22 }
24 }
25
26 [MethodImpl(MethodImplOptions.AggressiveInlining)]
27 public bool TryPush(T[] array)
28 {
30 int num = (int)((uint)Thread.GetCurrentProcessorId() % (uint)s_lockedStackCount);
31 for (int i = 0; i < perCoreStacks.Length; i++)
32 {
33 if (perCoreStacks[num].TryPush(array))
34 {
35 return true;
36 }
37 if (++num == perCoreStacks.Length)
38 {
39 num = 0;
40 }
41 }
42 return false;
43 }
44
45 [MethodImpl(MethodImplOptions.AggressiveInlining)]
46 public T[] TryPop()
47 {
49 int num = (int)((uint)Thread.GetCurrentProcessorId() % (uint)s_lockedStackCount);
50 for (int i = 0; i < perCoreStacks.Length; i++)
51 {
52 T[] result;
53 if ((result = perCoreStacks[num].TryPop()) != null)
54 {
55 return result;
56 }
57 if (++num == perCoreStacks.Length)
58 {
59 num = 0;
60 }
61 }
62 return null;
63 }
64
66 {
68 for (int i = 0; i < perCoreStacks.Length; i++)
69 {
71 }
72 }
73 }
74
75 private sealed class LockedStack
76 {
77 private readonly T[][] _arrays = new T[8][];
78
79 private int _count;
80
82
83 [MethodImpl(MethodImplOptions.AggressiveInlining)]
84 public bool TryPush(T[] array)
85 {
86 bool result = false;
87 Monitor.Enter(this);
88 T[][] arrays = _arrays;
89 int count = _count;
90 if ((uint)count < (uint)arrays.Length)
91 {
92 if (count == 0)
93 {
95 }
97 _count = count + 1;
98 result = true;
99 }
100 Monitor.Exit(this);
101 return result;
102 }
103
104 [MethodImpl(MethodImplOptions.AggressiveInlining)]
105 public T[] TryPop()
106 {
107 T[] result = null;
108 Monitor.Enter(this);
109 T[][] arrays = _arrays;
110 int num = _count - 1;
111 if ((uint)num < (uint)arrays.Length)
112 {
113 result = arrays[num];
114 arrays[num] = null;
115 _count = num;
116 }
117 Monitor.Exit(this);
118 return result;
119 }
120
122 {
123 if (_count == 0)
124 {
125 return;
126 }
127 int num = ((pressure == Utilities.MemoryPressure.High) ? 10000 : 60000);
128 lock (this)
129 {
130 if (_count == 0)
131 {
132 return;
133 }
134 if (_millisecondsTimestamp == 0)
135 {
137 }
138 else
139 {
141 {
142 return;
143 }
145 int num2 = 1;
146 switch (pressure)
147 {
148 case Utilities.MemoryPressure.High:
149 num2 = 8;
150 if (bucketSize > 16384)
151 {
152 num2++;
153 }
154 if (Unsafe.SizeOf<T>() > 16)
155 {
156 num2++;
157 }
158 if (Unsafe.SizeOf<T>() > 32)
159 {
160 num2++;
161 }
162 break;
163 case Utilities.MemoryPressure.Medium:
164 num2 = 2;
165 break;
166 }
167 while (_count > 0 && num2-- > 0)
168 {
169 T[] array = _arrays[--_count];
170 _arrays[_count] = null;
171 if (log.IsEnabled())
172 {
173 log.BufferTrimmed(array.GetHashCode(), array.Length, id);
174 }
175 }
176 _millisecondsTimestamp = ((_count > 0) ? (_millisecondsTimestamp + num / 4) : 0);
177 }
178 }
179 }
180 }
181
182 private struct ThreadLocalArray
183 {
184 public T[] Array;
185
187
189 {
190 Array = array;
192 }
193 }
194
197
199
201
203
204 private int Id => GetHashCode();
205
211
212 public override T[] Rent(int minimumLength)
213 {
217 T[] array2;
218 if (array != null && (uint)num < (uint)array.Length)
219 {
220 array2 = array[num].Array;
221 if (array2 != null)
222 {
223 array[num].Array = null;
224 if (log.IsEnabled())
225 {
226 log.BufferRented(array2.GetHashCode(), array2.Length, Id, num);
227 }
228 return array2;
229 }
230 }
231 PerCoreLockedStacks[] buckets = _buckets;
232 if ((uint)num < (uint)buckets.Length)
233 {
235 if (perCoreLockedStacks != null)
236 {
237 array2 = perCoreLockedStacks.TryPop();
238 if (array2 != null)
239 {
240 if (log.IsEnabled())
241 {
242 log.BufferRented(array2.GetHashCode(), array2.Length, Id, num);
243 }
244 return array2;
245 }
246 }
248 }
249 else
250 {
251 if (minimumLength == 0)
252 {
253 return Array.Empty<T>();
254 }
255 if (minimumLength < 0)
256 {
257 throw new ArgumentOutOfRangeException("minimumLength");
258 }
259 }
260 array2 = GC.AllocateUninitializedArray<T>(minimumLength);
261 if (log.IsEnabled())
262 {
263 int hashCode = array2.GetHashCode();
264 log.BufferRented(hashCode, array2.Length, Id, -1);
265 log.BufferAllocated(hashCode, array2.Length, Id, -1, (num >= _buckets.Length) ? ArrayPoolEventSource.BufferAllocatedReason.OverMaximumSize : ArrayPoolEventSource.BufferAllocatedReason.PoolExhausted);
266 }
267 return array2;
268 }
269
270 public override void Return(T[] array, bool clearArray = false)
271 {
272 if (array == null)
273 {
275 }
276 int num = Utilities.SelectBucketIndex(array.Length);
278 bool flag = false;
279 bool flag2 = true;
280 if ((uint)num < (uint)array2.Length)
281 {
282 flag = true;
283 if (clearArray)
284 {
286 }
287 if (array.Length != Utilities.GetMaxSizeForBucket(num))
288 {
290 }
292 T[] array3 = reference.Array;
294 if (array3 != null)
295 {
298 }
299 }
301 if (log.IsEnabled() && array.Length != 0)
302 {
303 log.BufferReturned(array.GetHashCode(), array.Length, Id);
304 if (!(flag && flag2))
305 {
306 log.BufferDropped(array.GetHashCode(), array.Length, Id, flag ? num : (-1), (!flag) ? ArrayPoolEventSource.BufferDroppedReason.OverMaximumSize : ArrayPoolEventSource.BufferDroppedReason.Full);
307 }
308 }
309 }
310
311 public bool Trim()
312 {
313 int tickCount = Environment.TickCount;
316 if (log.IsEnabled())
317 {
318 log.BufferTrimPoll(tickCount, (int)memoryPressure);
319 }
320 PerCoreLockedStacks[] buckets = _buckets;
321 for (int i = 0; i < buckets.Length; i++)
322 {
323 buckets[i]?.Trim(tickCount, Id, memoryPressure, Utilities.GetMaxSizeForBucket(i));
324 }
326 {
327 if (log.IsEnabled())
328 {
330 {
331 ThreadLocalArray[] key = item.Key;
332 for (int j = 0; j < key.Length; j++)
333 {
334 T[] array = Interlocked.Exchange(ref key[j].Array, null);
335 if (array != null)
336 {
337 log.BufferTrimmed(array.GetHashCode(), array.Length, Id);
338 }
339 }
340 }
341 }
342 else
343 {
345 {
346 Array.Clear(item2.Key);
347 }
348 }
349 }
350 else
351 {
352 uint num = ((memoryPressure != Utilities.MemoryPressure.Medium) ? 30000u : 15000u);
353 uint num2 = num;
355 {
357 for (int k = 0; k < key2.Length; k++)
358 {
359 if (key2[k].Array == null)
360 {
361 continue;
362 }
363 int millisecondsTimeStamp = key2[k].MillisecondsTimeStamp;
364 if (millisecondsTimeStamp == 0)
365 {
366 key2[k].MillisecondsTimeStamp = tickCount;
367 }
368 else if (tickCount - millisecondsTimeStamp >= num2)
369 {
370 T[] array2 = Interlocked.Exchange(ref key2[k].Array, null);
371 if (array2 != null && log.IsEnabled())
372 {
373 log.BufferTrimmed(array2.GetHashCode(), array2.Length, Id);
374 }
375 }
376 }
377 }
378 }
379 return true;
380 }
381
392}
static unsafe void Clear(Array array)
Definition Array.cs:755
static readonly ArrayPoolEventSource Log
void Trim(int currentMilliseconds, int id, Utilities.MemoryPressure pressure, int bucketSize)
void Trim(int currentMilliseconds, int id, Utilities.MemoryPressure pressure, int bucketSize)
readonly ConditionalWeakTable< ThreadLocalArray[], object > _allTlsBuckets
static int GetMaxSizeForBucket(int binIndex)
Definition Utilities.cs:22
static int SelectBucketIndex(int bufferSize)
Definition Utilities.cs:16
static MemoryPressure GetMemoryPressure()
Definition Utilities.cs:27
void Add(TKey key, TValue value)
static int ProcessorCount
static int TickCount
Definition GC.cs:8
static void Register(Func< bool > callback)
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static string ArgumentException_BufferNotFromPool
Definition SR.cs:916
Definition SR.cs:7
static int CompareExchange(ref int location1, int value, int comparand)
static int Exchange(ref int location1, int value)
static void Exit(object obj)
static void Enter(object obj)
static int GetCurrentProcessorId()
Definition Thread.cs:501
static void ThrowArgumentNullException(string name)