• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 
3 // Copyright 2019 The 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.Threading.Tasks;
20 using BenchmarkDotNet.Attributes;
21 using Grpc.Core;
22 using Grpc.Core.Internal;
23 using System;
24 
25 namespace Grpc.Microbenchmarks
26 {
27     // this test measures the overhead of C# wrapping layer when invoking calls;
28     // the marshallers **DO NOT ALLOCATE**, so any allocations
29     // are from the framework, not the messages themselves
30 
31     [ClrJob, CoreJob] // test .NET Core and .NET Framework
32     [MemoryDiagnoser] // allocations
33     public class UnaryCallOverheadBenchmark
34     {
35         private static readonly Task<string> CompletedString = Task.FromResult("");
36         private static readonly Marshaller<byte[]> IdentityMarshaller = new Marshaller<byte[]>(msg => msg, payload => payload);
37         private static readonly Method<byte[], byte[]> PingMethod = new Method<byte[], byte[]>(MethodType.Unary, nameof(PingBenchmark), "Ping", IdentityMarshaller, IdentityMarshaller);
38 
39         private int payloadSize;
40         private byte[] payload;
41 
42         // size of payload that is sent as request and received as response.
43         [Params(0, 1, 10, 100, 1000)]
44         public int PayloadSize
45         {
46             get { return payloadSize; }
47             set
48             {
49                 payloadSize = value;
50                 payload = new byte[value];
51             }
52         }
53 
54         [Benchmark]
SyncUnaryCallOverhead()55         public byte[] SyncUnaryCallOverhead()
56         {
57             return client.Ping(payload, new CallOptions());
58         }
59 
60         Channel channel;
61         PingClient client;
62 
63         [GlobalSetup]
Setup()64         public void Setup()
65         {
66             // create client, the channel will actually never connect because call logic will be short-circuited
67             channel = new Channel("localhost", 10042, ChannelCredentials.Insecure);
68             client = new PingClient(new DefaultCallInvoker(channel));
69 
70             var native = NativeMethods.Get();
71 
72             // replace the implementation of a native method with a fake
73             NativeMethods.Delegates.grpcsharp_call_start_unary_delegate fakeCallStartUnary = (CallSafeHandle call, BatchContextSafeHandle ctx, SliceBufferSafeHandle sendBuffer, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags) => {
74                 return native.grpcsharp_test_call_start_unary_echo(call, ctx, sendBuffer, writeFlags, metadataArray, metadataFlags);
75             };
76             native.GetType().GetField(nameof(native.grpcsharp_call_start_unary)).SetValue(native, fakeCallStartUnary);
77 
78             NativeMethods.Delegates.grpcsharp_completion_queue_pluck_delegate fakeCqPluck = (CompletionQueueSafeHandle cq, IntPtr tag) => {
79                 return new CompletionQueueEvent {
80                     type = CompletionQueueEvent.CompletionType.OpComplete,
81                     success = 1,
82                     tag = tag
83                 };
84             };
85             native.GetType().GetField(nameof(native.grpcsharp_completion_queue_pluck)).SetValue(native, fakeCqPluck);
86         }
87 
88         [GlobalCleanup]
Cleanup()89         public async Task Cleanup()
90         {
91             await channel.ShutdownAsync();
92         }
93 
94         class PingClient : ClientBase
95         {
PingClient(CallInvoker callInvoker)96             public PingClient(CallInvoker callInvoker) : base(callInvoker) { }
97 
Ping(byte[] request, CallOptions options)98             public byte[] Ping(byte[] request, CallOptions options)
99             {
100                 return CallInvoker.BlockingUnaryCall(PingMethod, null, options, request);
101             }
102         }
103     }
104 }
105