Merge pull request #13475 from jtattermusch/better_completion_registry_benchmark

Use spinlock in CompletionRegistry (and improve the benchmark).
pull/13452/head^2
Jan Tattermusch 7 years ago committed by GitHub
commit 1304cf8174
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
  2. 13
      src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs
  3. 5
      src/csharp/Grpc.Microbenchmarks/Program.cs

@ -19,7 +19,9 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Grpc.Core.Logging;
using Grpc.Core.Utils;
@ -35,7 +37,7 @@ namespace Grpc.Core.Internal
readonly GrpcEnvironment environment;
readonly Dictionary<IntPtr, IOpCompletionCallback> dict = new Dictionary<IntPtr, IOpCompletionCallback>(new IntPtrComparer());
readonly object myLock = new object();
SpinLock spinLock = new SpinLock(Debugger.IsAttached);
IntPtr lastRegisteredKey; // only for testing
public CompletionRegistry(GrpcEnvironment environment)
@ -46,11 +48,19 @@ namespace Grpc.Core.Internal
public void Register(IntPtr key, IOpCompletionCallback callback)
{
environment.DebugStats.PendingBatchCompletions.Increment();
lock (myLock)
bool lockTaken = false;
try
{
spinLock.Enter(ref lockTaken);
dict.Add(key, callback);
this.lastRegisteredKey = key;
}
finally
{
if (lockTaken) spinLock.Exit();
}
}
public void RegisterBatchCompletion(BatchContextSafeHandle ctx, BatchCompletionDelegate callback, object state)
@ -68,11 +78,18 @@ namespace Grpc.Core.Internal
public IOpCompletionCallback Extract(IntPtr key)
{
IOpCompletionCallback value = null;
lock (myLock)
bool lockTaken = false;
try
{
spinLock.Enter(ref lockTaken);
value = dict[key];
dict.Remove(key);
}
finally
{
if (lockTaken) spinLock.Exit();
}
environment.DebugStats.PendingBatchCompletions.Decrement();
return value;
}

@ -40,24 +40,25 @@ namespace Grpc.Microbenchmarks
GrpcEnvironment.ReleaseAsync().Wait();
}
public void Run(int threadCount, int iterations)
public void Run(int threadCount, int iterations, bool useSharedRegistry)
{
Console.WriteLine(string.Format("CompletionRegistryBenchmark: threads={0}, iterations={1}", threadCount, iterations));
var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations));
Console.WriteLine(string.Format("CompletionRegistryBenchmark: threads={0}, iterations={1}, useSharedRegistry={2}", threadCount, iterations, useSharedRegistry));
CompletionRegistry sharedRegistry = useSharedRegistry ? new CompletionRegistry(environment) : null;
var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, sharedRegistry));
threadedBenchmark.Run();
// TODO: parametrize by number of pending completions
}
private void ThreadBody(int iterations)
private void ThreadBody(int iterations, CompletionRegistry optionalSharedRegistry)
{
var completionRegistry = new CompletionRegistry(environment);
var completionRegistry = optionalSharedRegistry ?? new CompletionRegistry(environment);
var ctx = BatchContextSafeHandle.Create();
var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
completionRegistry.Register(ctx.Handle, ctx);
var callback = completionRegistry.Extract(completionRegistry.LastRegisteredKey);
var callback = completionRegistry.Extract(ctx.Handle);
// NOTE: we are not calling the callback to avoid disposing ctx.
}
stopwatch.Stop();

@ -77,7 +77,10 @@ namespace Grpc.Microbenchmarks
benchmark.Init();
foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12})
{
benchmark.Run(threadCount, 4 * 1000 * 1000);
foreach (bool useSharedRegistry in new bool[] {false, true})
{
benchmark.Run(threadCount, 4 * 1000 * 1000, useSharedRegistry);
}
}
benchmark.Cleanup();
}

Loading…
Cancel
Save