Skip to content

Commit 07d4c4c

Browse files
committed
Updated MemoryDiagnoserIsAccurateForMultiThreadedBenchmarks test.
1 parent 2c94c02 commit 07d4c4c

File tree

1 file changed

+35
-11
lines changed

1 file changed

+35
-11
lines changed

tests/BenchmarkDotNet.IntegrationTests/MemoryDiagnoserTests.cs

+35-11
Original file line numberDiff line numberDiff line change
@@ -253,44 +253,68 @@ public void AllocationQuantumIsNotAnIssueForNetCore21Plus(IToolchain toolchain)
253253

254254
public class MultiThreadedAllocation
255255
{
256-
public const int Size = 1_000_000;
256+
public const int Size = 1024;
257257
public const int ThreadsCount = 10;
258258

259+
// We cache the threads in GlobalSetup and reuse them for each benchmark invocation
260+
// to avoid measuring the cost of thread start and join, which varies across different runtimes.
259261
private Thread[] threads;
262+
private volatile bool keepRunning = true;
263+
private readonly Barrier barrier = new (ThreadsCount + 1);
264+
private readonly CountdownEvent countdownEvent = new (ThreadsCount);
260265

261-
[IterationSetup]
262-
public void SetupIteration()
266+
[GlobalSetup]
267+
public void Setup()
263268
{
264269
threads = Enumerable.Range(0, ThreadsCount)
265-
.Select(_ => new Thread(() => GC.KeepAlive(new byte[Size])))
270+
.Select(_ => new Thread(() =>
271+
{
272+
while (keepRunning)
273+
{
274+
barrier.SignalAndWait();
275+
GC.KeepAlive(new byte[Size]);
276+
countdownEvent.Signal();
277+
}
278+
}))
266279
.ToArray();
280+
foreach (var thread in threads)
281+
{
282+
thread.Start();
283+
}
267284
}
268285

269-
[Benchmark]
270-
public void Allocate()
286+
[GlobalCleanup]
287+
public void Cleanup()
271288
{
289+
keepRunning = false;
290+
barrier.SignalAndWait();
272291
foreach (var thread in threads)
273292
{
274-
thread.Start();
275293
thread.Join();
276294
}
277295
}
296+
297+
[Benchmark]
298+
public void Allocate()
299+
{
300+
countdownEvent.Reset(ThreadsCount);
301+
barrier.SignalAndWait();
302+
countdownEvent.Wait();
303+
}
278304
}
279305

280-
[Theory(Skip = "Test is currently failing on all toolchains.")]
306+
[TheoryEnvSpecific("Full Framework cannot measure precisely enough", EnvRequirement.DotNetCoreOnly)]
281307
[MemberData(nameof(GetToolchains))]
282308
[Trait(Constants.Category, Constants.BackwardCompatibilityCategory)]
283309
public void MemoryDiagnoserIsAccurateForMultiThreadedBenchmarks(IToolchain toolchain)
284310
{
285311
long objectAllocationOverhead = IntPtr.Size * 2; // pointer to method table + object header word
286312
long arraySizeOverhead = IntPtr.Size; // array length
287313
long memoryAllocatedPerArray = (MultiThreadedAllocation.Size + objectAllocationOverhead + arraySizeOverhead);
288-
long threadStartAndJoinOverhead = 112; // this is more or less a magic number taken from memory profiler
289-
long allocatedMemoryPerThread = memoryAllocatedPerArray + threadStartAndJoinOverhead;
290314

291315
AssertAllocations(toolchain, typeof(MultiThreadedAllocation), new Dictionary<string, long>
292316
{
293-
{ nameof(MultiThreadedAllocation.Allocate), allocatedMemoryPerThread * MultiThreadedAllocation.ThreadsCount }
317+
{ nameof(MultiThreadedAllocation.Allocate), memoryAllocatedPerArray * MultiThreadedAllocation.ThreadsCount }
294318
});
295319
}
296320

0 commit comments

Comments
 (0)