1 #region Copyright notice and license 2 3 // Copyright 2015 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #endregion 18 19 using System; 20 using BenchmarkDotNet.Attributes; 21 using Grpc.Core; 22 using Grpc.Core.Internal; 23 24 namespace Grpc.Microbenchmarks 25 { 26 public class SendMessageBenchmark : CommonThreadedBase 27 { 28 static readonly NativeMethods Native = NativeMethods.Get(); 29 Setup()30 public override void Setup() 31 { 32 Native.grpcsharp_test_override_method("grpcsharp_call_start_batch", "nop"); 33 base.Setup(); 34 } 35 36 [Params(0)] 37 public int PayloadSize { get; set; } 38 39 const int Iterations = 5 * 1000 * 1000; // High number to make the overhead of RunConcurrent negligible. 40 [Benchmark(OperationsPerInvoke = Iterations)] SendMessage()41 public void SendMessage() 42 { 43 RunConcurrent(RunBody); 44 } 45 RunBody()46 private void RunBody() 47 { 48 var completionRegistry = new CompletionRegistry(Environment, () => Environment.BatchContextPool.Lease(), () => throw new NotImplementedException()); 49 var cq = CompletionQueueSafeHandle.CreateAsync(completionRegistry); 50 var call = CreateFakeCall(cq); 51 52 var sendCompletionCallback = new NopSendCompletionCallback(); 53 var sliceBuffer = SliceBufferSafeHandle.Create(); 54 var writeFlags = default(WriteFlags); 55 56 for (int i = 0; i < Iterations; i++) 57 { 58 // SendMessage steals the slices from the slice buffer, so we need to repopulate in each iteration. 59 sliceBuffer.Reset(); 60 sliceBuffer.GetSpan(PayloadSize); 61 sliceBuffer.Advance(PayloadSize); 62 63 call.StartSendMessage(sendCompletionCallback, sliceBuffer, writeFlags, false); 64 var callback = completionRegistry.Extract(completionRegistry.LastRegisteredKey); 65 callback.OnComplete(true); 66 } 67 sliceBuffer.Dispose(); 68 cq.Dispose(); 69 } 70 CreateFakeCall(CompletionQueueSafeHandle cq)71 private static CallSafeHandle CreateFakeCall(CompletionQueueSafeHandle cq) 72 { 73 var call = CallSafeHandle.CreateFake(new IntPtr(0xdead), cq); 74 bool success = false; 75 while (!success) 76 { 77 // avoid calling destroy on a nonexistent grpc_call pointer 78 call.DangerousAddRef(ref success); 79 } 80 return call; 81 } 82 83 private class NopSendCompletionCallback : ISendCompletionCallback 84 { OnSendCompletion(bool success)85 public void OnSendCompletion(bool success) 86 { 87 // NOP 88 } 89 } 90 } 91 } 92