Skip to content

Instantly share code, notes, and snippets.

@filipnavara
Created February 5, 2019 16:14
Show Gist options
  • Save filipnavara/8e6aa10131e68d313934b006aea82abd to your computer and use it in GitHub Desktop.
Save filipnavara/8e6aa10131e68d313934b006aea82abd to your computer and use it in GitHub Desktop.
using System;
using System.Threading;
namespace ThreadPoolBenchmark
{
static class DelayHelper
{
public static uint RandomShortDelay(Random rng) => (uint)rng.Next(4, 10);
public static uint RandomMediumDelay(Random rng) => (uint)rng.Next(10, 15);
public static uint RandomLongDelay(Random rng) => (uint)rng.Next(15, 20);
private static int[] s_delayValues = new int[32];
public static void Delay(uint n)
{
Interlocked.MemoryBarrier();
s_delayValues[16] += (int)Fib(n);
}
private static uint Fib(uint n)
{
if (n <= 1)
return n;
return Fib(n - 2) + Fib(n - 1);
}
}
}
using System;
using BenchmarkDotNet.Analysers;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Exporters.Csv;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Toolchains.CoreRt;
using BenchmarkDotNet.Toolchains.CsProj;
using BenchmarkDotNet.Toolchains.CustomCoreClr;
using BenchmarkDotNet.Toolchains.DotNetCli;
namespace ThreadPoolBenchmark
{
class Program
{
static void Main(string[] args)
{
var config = DefaultConfig.Instance
.With(Job.CoreRT
.With(CoreRtToolchain.CreateBuilder()
.UseCoreRtLocal(@"/Volumes/TRANSCEND1/Projects/corert/bin/OSX.x64.Release") // IlcPath
.DisplayName("Base")
.ToToolchain()))
.With(Job.CoreRT
.With(CoreRtToolchain.CreateBuilder()
.UseCoreRtLocal(@"/Volumes/TRANSCEND1/Projects/corert.lls/bin/OSX.x64.Release") // IlcPath
.DisplayName("PR")
.ToToolchain()));
BenchmarkRunner.Run<ThreadPoolTest>(config);
/*var dotnetCli = NetCoreAppSettings
.NetCoreApp30
.WithCustomDotNetCliPath(@"C:\Program Files (x86)\dotnet\dotnet.exe", "32 bit cli");
BenchmarkRunner.Run<ThreadPoolTest>(
ManualConfig.Create(DefaultConfig.Instance).
With(Job.RyuJitX86.With(CsProjCoreToolchain.From(dotnetCli))));*/
}
}
}
using BenchmarkDotNet.Attributes;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace ThreadPoolBenchmark
{
public class ThreadPoolTest
{
[ThreadStatic]
private static Random t_rng;
[ThreadStatic]
private static int t_rngGeneration;
private static int s_rngGeneration = 0;
//[Params(1, 2, 4)]
//public int ThreadCount { get; set; }
[Params(100000)]
public int Operations { get; set; }
/*[GlobalSetup]
public void GlobalSetup()
{
ThreadPool.SetMinThreads(ThreadCount, ThreadCount);
ThreadPool.SetMaxThreads(ThreadCount, ThreadCount);
}*/
[Benchmark]
public void ThreadPoolSustainedWorkThroughput()
{
var endTest = new ManualResetEvent(false);
var operationsToDo = Operations;
// Ensure consistent random seeds
s_rngGeneration++;
WaitCallback workItemStart = null;
workItemStart = data =>
{
if (Interlocked.Decrement(ref operationsToDo) <= 0)
{
endTest.Set();
return;
}
ThreadPool.QueueUserWorkItem(workItemStart);
var rng = t_rng;
if (rng == null || t_rngGeneration != s_rngGeneration)
{
t_rng = rng = new Random(0);
t_rngGeneration = s_rngGeneration;
}
DelayHelper.Delay(DelayHelper.RandomShortDelay(rng));
};
var localWorkItemStart = workItemStart;
int initialWorkItemCount = Environment.ProcessorCount /*+ ThreadCount*/;
for (int i = 0; i < initialWorkItemCount; ++i)
ThreadPool.QueueUserWorkItem(localWorkItemStart);
endTest.WaitOne();
}
[Benchmark]
[Arguments(1)]
[Arguments(10)]
[Arguments(100)]
public void ThreadPoolBurstWorkThroughput(int maxWorkItemCount)
{
var workComplete = new AutoResetEvent(false);
int workItemCountToQueue = 0;
int workItemCountToComplete = 0;
var operationsToDo = Operations;
// Ensure consistent random seeds
s_rngGeneration++;
WaitCallback workItemStart = null;
workItemStart = data =>
{
if (Interlocked.Decrement(ref operationsToDo) <= 0)
{
workComplete.Set();
return;
}
if (Interlocked.Decrement(ref workItemCountToQueue) >= 0)
ThreadPool.QueueUserWorkItem(workItemStart);
var rng = t_rng;
if (rng == null || t_rngGeneration != s_rngGeneration)
{
t_rng = rng = new Random(0);
t_rngGeneration = s_rngGeneration;
}
DelayHelper.Delay(DelayHelper.RandomShortDelay(rng));
if (Interlocked.Decrement(ref workItemCountToComplete) == 0)
workComplete.Set();
};
var localMaxWorkItemCount = maxWorkItemCount;
var localWorkItemStart = workItemStart;
int initialWorkItemCount = Math.Min(Environment.ProcessorCount, localMaxWorkItemCount);
while (Thread.VolatileRead(ref operationsToDo) >= 0)
{
workItemCountToQueue = localMaxWorkItemCount - initialWorkItemCount;
workItemCountToComplete = localMaxWorkItemCount;
for (int i = 0; i < initialWorkItemCount; ++i)
ThreadPool.QueueUserWorkItem(localWorkItemStart);
workComplete.WaitOne();
}
}
/*[Benchmark]
public void ThreadPoolSetMinThreads()
{
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(2, 2);
}*/
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment