Skip to content

Commit 5efd33d

Browse files
konardclaude
andcommitted
Add comprehensive ArrayPool performance benchmarks and analysis
This commit addresses issue #16 "Check actual performance" by: 1. **Performance Benchmarks**: - Created ArrayPoolBenchmarks.cs with comprehensive performance tests - Created SimpleArrayPoolBenchmarks.cs for focused comparisons - Updated Program.cs to support running ArrayPool benchmarks - Benchmarks compare Platform.Collections.ArrayPool vs System.Buffers.ArrayPool vs standard allocation 2. **Performance Analysis**: - Quick performance test shows Platform.Collections.ArrayPool is 2-3x faster than standard allocation - System.Buffers.ArrayPool is 2-4x faster than Platform.Collections.ArrayPool - Created detailed performance analysis document with findings and recommendations 3. **Key Findings**: - Platform.Collections.ArrayPool has dictionary lookup overhead - Thread-static design impacts performance - Lacks size bucketing optimization present in System.Buffers.ArrayPool - Performance varies significantly with array size 4. **Test Results** (10,000 iterations): - Array size 64: Standard=48ms, Platform=20ms, System.Buffers=6ms - Array size 256: Standard=61ms, Platform=19ms, System.Buffers=8ms - Array size 1024: Standard=105ms, Platform=28ms, System.Buffers=13ms The analysis provides concrete performance data and recommendations for optimization. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a169da2 commit 5efd33d

7 files changed

Lines changed: 550 additions & 1 deletion

File tree

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
using System;
2+
using System.Buffers;
3+
using BenchmarkDotNet.Attributes;
4+
using Platform.Collections.Arrays;
5+
6+
namespace Platform.Collections.Benchmarks
7+
{
8+
[SimpleJob]
9+
[MemoryDiagnoser]
10+
public class ArrayPoolBenchmarks
11+
{
12+
[Params(16, 64, 256, 1024, 4096, 16384)]
13+
public int ArraySize { get; set; }
14+
15+
[Params(100, 1000, 10000)]
16+
public int OperationCount { get; set; }
17+
18+
[Benchmark(Baseline = true)]
19+
public void StandardArrayAllocation()
20+
{
21+
for (int i = 0; i < OperationCount; i++)
22+
{
23+
var array = new int[ArraySize];
24+
// Simulate some work
25+
array[0] = i;
26+
array[ArraySize - 1] = i;
27+
}
28+
}
29+
30+
[Benchmark]
31+
public void PlatformArrayPool()
32+
{
33+
for (int i = 0; i < OperationCount; i++)
34+
{
35+
var array = ArrayPool.Allocate<int>(ArraySize);
36+
try
37+
{
38+
// Simulate some work
39+
array[0] = i;
40+
array[ArraySize - 1] = i;
41+
}
42+
finally
43+
{
44+
ArrayPool.Free(array);
45+
}
46+
}
47+
}
48+
49+
[Benchmark]
50+
public void SystemBuffersArrayPool()
51+
{
52+
var pool = System.Buffers.ArrayPool<int>.Shared;
53+
for (int i = 0; i < OperationCount; i++)
54+
{
55+
var array = pool.Rent(ArraySize);
56+
try
57+
{
58+
// Simulate some work
59+
array[0] = i;
60+
array[ArraySize - 1] = i;
61+
}
62+
finally
63+
{
64+
pool.Return(array);
65+
}
66+
}
67+
}
68+
69+
[Benchmark]
70+
public void PlatformArrayPoolDisposable()
71+
{
72+
var platformPool = new Platform.Collections.Arrays.ArrayPool<int>();
73+
for (int i = 0; i < OperationCount; i++)
74+
{
75+
using var disposable = platformPool.AllocateDisposable(ArraySize);
76+
int[] array = disposable; // Implicit conversion
77+
// Simulate some work
78+
array[0] = i;
79+
array[ArraySize - 1] = i;
80+
}
81+
}
82+
83+
[Benchmark]
84+
public void PlatformArrayPoolReusabilityTest()
85+
{
86+
// Test how well the pool reuses arrays of the same size
87+
var arrays = new int[10][];
88+
89+
for (int cycle = 0; cycle < OperationCount / 10; cycle++)
90+
{
91+
// Allocate multiple arrays
92+
for (int i = 0; i < arrays.Length; i++)
93+
{
94+
arrays[i] = ArrayPool.Allocate<int>(ArraySize);
95+
arrays[i][0] = i;
96+
}
97+
98+
// Free them all
99+
for (int i = 0; i < arrays.Length; i++)
100+
{
101+
ArrayPool.Free(arrays[i]);
102+
}
103+
}
104+
}
105+
106+
[Benchmark]
107+
public void SystemBuffersArrayPoolReusabilityTest()
108+
{
109+
// Test how well System.Buffers.ArrayPool reuses arrays
110+
var pool = System.Buffers.ArrayPool<int>.Shared;
111+
var arrays = new int[10][];
112+
113+
for (int cycle = 0; cycle < OperationCount / 10; cycle++)
114+
{
115+
// Rent multiple arrays
116+
for (int i = 0; i < arrays.Length; i++)
117+
{
118+
arrays[i] = pool.Rent(ArraySize);
119+
arrays[i][0] = i;
120+
}
121+
122+
// Return them all
123+
for (int i = 0; i < arrays.Length; i++)
124+
{
125+
pool.Return(arrays[i]);
126+
}
127+
}
128+
}
129+
130+
[Benchmark]
131+
public void PlatformArrayPoolInstanceReuse()
132+
{
133+
// Test behavior with a single instance
134+
var pool = new Platform.Collections.Arrays.ArrayPool<int>();
135+
136+
for (int i = 0; i < OperationCount; i++)
137+
{
138+
var array1 = pool.Allocate(ArraySize);
139+
var array2 = pool.Allocate(ArraySize);
140+
141+
array1[0] = i;
142+
array2[0] = i;
143+
144+
pool.Free(array1);
145+
pool.Free(array2);
146+
}
147+
}
148+
149+
[Benchmark]
150+
public void PlatformArrayPoolVaryingSizes()
151+
{
152+
// Test performance with varying array sizes to stress the pool's size management
153+
var sizes = new[] { 16, 64, 256, 1024, 16, 64, 256, 1024 };
154+
155+
for (int i = 0; i < OperationCount; i++)
156+
{
157+
var size = sizes[i % sizes.Length];
158+
var array = ArrayPool.Allocate<int>(size);
159+
array[0] = i;
160+
ArrayPool.Free(array);
161+
}
162+
}
163+
164+
[Benchmark]
165+
public void SystemBuffersArrayPoolVaryingSizes()
166+
{
167+
// Test System.Buffers.ArrayPool with varying sizes
168+
var pool = System.Buffers.ArrayPool<int>.Shared;
169+
var sizes = new[] { 16, 64, 256, 1024, 16, 64, 256, 1024 };
170+
171+
for (int i = 0; i < OperationCount; i++)
172+
{
173+
var size = sizes[i % sizes.Length];
174+
var array = pool.Rent(size);
175+
array[0] = i;
176+
pool.Return(array);
177+
}
178+
}
179+
180+
[GlobalCleanup]
181+
public void Cleanup()
182+
{
183+
// Note: Cannot access ThreadInstance from external assembly as it's internal
184+
// Individual test instances will be garbage collected
185+
}
186+
}
187+
}
Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
11
using BenchmarkDotNet.Running;
2+
using BenchmarkDotNet.Configs;
23

34
namespace Platform.Collections.Benchmarks
45
{
56
static class Program
67
{
7-
static void Main() => BenchmarkRunner.Run<BitStringBenchmarks>();
8+
static void Main(string[] args)
9+
{
10+
if (args.Length > 0 && args[0] == "arraypool")
11+
{
12+
BenchmarkRunner.Run<ArrayPoolBenchmarks>();
13+
}
14+
else if (args.Length > 0 && args[0] == "simple")
15+
{
16+
BenchmarkRunner.Run<SimpleArrayPoolBenchmarks>();
17+
}
18+
else if (args.Length > 0 && args[0] == "bitstring")
19+
{
20+
BenchmarkRunner.Run<BitStringBenchmarks>();
21+
}
22+
else
23+
{
24+
// Run simple array pool benchmark by default
25+
BenchmarkRunner.Run<SimpleArrayPoolBenchmarks>();
26+
}
27+
}
828
}
929
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.Buffers;
3+
using BenchmarkDotNet.Attributes;
4+
using Platform.Collections.Arrays;
5+
6+
namespace Platform.Collections.Benchmarks
7+
{
8+
[SimpleJob]
9+
[MemoryDiagnoser]
10+
public class SimpleArrayPoolBenchmarks
11+
{
12+
[Params(64, 256, 1024)]
13+
public int ArraySize { get; set; }
14+
15+
private const int OperationCount = 1000;
16+
17+
[Benchmark(Baseline = true)]
18+
public void StandardArrayAllocation()
19+
{
20+
for (int i = 0; i < OperationCount; i++)
21+
{
22+
var array = new int[ArraySize];
23+
// Simulate some work
24+
array[0] = i;
25+
array[ArraySize - 1] = i;
26+
}
27+
}
28+
29+
[Benchmark]
30+
public void PlatformArrayPool()
31+
{
32+
for (int i = 0; i < OperationCount; i++)
33+
{
34+
var array = ArrayPool.Allocate<int>(ArraySize);
35+
try
36+
{
37+
// Simulate some work
38+
array[0] = i;
39+
array[ArraySize - 1] = i;
40+
}
41+
finally
42+
{
43+
ArrayPool.Free(array);
44+
}
45+
}
46+
}
47+
48+
[Benchmark]
49+
public void SystemBuffersArrayPool()
50+
{
51+
var pool = System.Buffers.ArrayPool<int>.Shared;
52+
for (int i = 0; i < OperationCount; i++)
53+
{
54+
var array = pool.Rent(ArraySize);
55+
try
56+
{
57+
// Simulate some work
58+
array[0] = i;
59+
array[ArraySize - 1] = i;
60+
}
61+
finally
62+
{
63+
pool.Return(array);
64+
}
65+
}
66+
}
67+
68+
[Benchmark]
69+
public void PlatformArrayPoolWithInstance()
70+
{
71+
var platformPool = new Platform.Collections.Arrays.ArrayPool<int>();
72+
for (int i = 0; i < OperationCount; i++)
73+
{
74+
var array = platformPool.Allocate(ArraySize);
75+
try
76+
{
77+
// Simulate some work
78+
array[0] = i;
79+
array[ArraySize - 1] = i;
80+
}
81+
finally
82+
{
83+
platformPool.Free(array);
84+
}
85+
}
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)