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 23 namespace Grpc.Microbenchmarks 24 { 25 // this test creates a real server and client, measuring the inherent inbuilt 26 // platform overheads; the marshallers **DO NOT ALLOCATE**, so any allocations 27 // are from the framework, not the messages themselves 28 29 // important: allocs are not reliable on .NET Core until .NET Core 3, since 30 // this test involves multiple threads 31 32 [ClrJob, CoreJob] // test .NET Core and .NET Framework 33 [MemoryDiagnoser] // allocations 34 public class PingBenchmark 35 { 36 private static readonly Task<string> CompletedString = Task.FromResult(""); 37 private static readonly byte[] EmptyBlob = new byte[0]; 38 private static readonly Marshaller<string> EmptyMarshaller = new Marshaller<string>(_ => EmptyBlob, _ => ""); 39 private static readonly Method<string, string> PingMethod = new Method<string, string>(MethodType.Unary, nameof(PingBenchmark), "Ping", EmptyMarshaller, EmptyMarshaller); 40 41 42 [Benchmark] PingAsync()43 public async ValueTask<string> PingAsync() 44 { 45 using (var result = client.PingAsync("", new CallOptions())) 46 { 47 return await result.ResponseAsync; 48 } 49 } 50 51 [Benchmark] Ping()52 public string Ping() 53 { 54 return client.Ping("", new CallOptions()); 55 } 56 ServerMethod(string request, ServerCallContext context)57 private Task<string> ServerMethod(string request, ServerCallContext context) 58 { 59 return CompletedString; 60 } 61 62 Server server; 63 Channel channel; 64 PingClient client; 65 66 [GlobalSetup] Setup()67 public async Task Setup() 68 { 69 // create server 70 server = new Server { 71 Ports = { new ServerPort("localhost", 10042, ServerCredentials.Insecure) }, 72 Services = { ServerServiceDefinition.CreateBuilder().AddMethod(PingMethod, ServerMethod).Build() }, 73 }; 74 server.Start(); 75 76 // create client 77 channel = new Channel("localhost", 10042, ChannelCredentials.Insecure); 78 await channel.ConnectAsync(); 79 client = new PingClient(new DefaultCallInvoker(channel)); 80 } 81 82 [GlobalCleanup] Cleanup()83 public async Task Cleanup() 84 { 85 await channel.ShutdownAsync(); 86 await server.ShutdownAsync(); 87 } 88 89 class PingClient : ClientBase 90 { PingClient(CallInvoker callInvoker)91 public PingClient(CallInvoker callInvoker) : base(callInvoker) { } PingAsync(string request, CallOptions options)92 public AsyncUnaryCall<string> PingAsync(string request, CallOptions options) 93 { 94 return CallInvoker.AsyncUnaryCall(PingMethod, null, options, request); 95 } Ping(string request, CallOptions options)96 public string Ping(string request, CallOptions options) 97 { 98 return CallInvoker.BlockingUnaryCall(PingMethod, null, options, request); 99 } 100 } 101 } 102 } 103