From 4c96998eb1cd263396d0f3b1c4af43bfbbc859c3 Mon Sep 17 00:00:00 2001 From: Juanli Shen Date: Wed, 26 Jun 2019 16:07:03 -0700 Subject: [PATCH 01/25] Fix typo --- .../dns/c_ares/grpc_ares_ev_driver_windows.cc | 19 ++++++++++--------- src/core/lib/iomgr/iocp_windows.cc | 4 ++-- src/core/lib/iomgr/socket_windows.h | 2 +- src/core/lib/iomgr/tcp_windows.cc | 14 +++++++------- tools/interop_matrix/client_matrix.py | 2 +- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc index d24c111448c..addae23dc3e 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc @@ -459,12 +459,13 @@ class GrpcPolledFdWindows : public GrpcPolledFd { connect_done_ = true; GPR_ASSERT(wsa_connect_error_ == 0); if (error == GRPC_ERROR_NONE) { - DWORD transfered_bytes = 0; + DWORD transferred_bytes = 0; DWORD flags; - BOOL wsa_success = WSAGetOverlappedResult( - grpc_winsocket_wrapped_socket(winsocket_), - &winsocket_->write_info.overlapped, &transfered_bytes, FALSE, &flags); - GPR_ASSERT(transfered_bytes == 0); + BOOL wsa_success = + WSAGetOverlappedResult(grpc_winsocket_wrapped_socket(winsocket_), + &winsocket_->write_info.overlapped, + &transferred_bytes, FALSE, &flags); + GPR_ASSERT(transferred_bytes == 0); if (!wsa_success) { wsa_connect_error_ = WSAGetLastError(); char* msg = gpr_format_message(wsa_connect_error_); @@ -620,8 +621,8 @@ class GrpcPolledFdWindows : public GrpcPolledFd { } } if (error == GRPC_ERROR_NONE) { - read_buf_ = grpc_slice_sub_no_ref(read_buf_, 0, - winsocket_->read_info.bytes_transfered); + read_buf_ = grpc_slice_sub_no_ref( + read_buf_, 0, winsocket_->read_info.bytes_transferred); read_buf_has_data_ = true; } else { grpc_slice_unref_internal(read_buf_); @@ -657,9 +658,9 @@ class GrpcPolledFdWindows : public GrpcPolledFd { if (error == GRPC_ERROR_NONE) { tcp_write_state_ = WRITE_WAITING_FOR_VERIFICATION_UPON_RETRY; write_buf_ = grpc_slice_sub_no_ref( - write_buf_, 0, winsocket_->write_info.bytes_transfered); + write_buf_, 0, winsocket_->write_info.bytes_transferred); GRPC_CARES_TRACE_LOG("fd:|%s| OnIocpWriteableInner. bytes transferred:%d", - GetName(), winsocket_->write_info.bytes_transfered); + GetName(), winsocket_->write_info.bytes_transferred); } else { grpc_slice_unref_internal(write_buf_); write_buf_ = grpc_empty_slice(); diff --git a/src/core/lib/iomgr/iocp_windows.cc b/src/core/lib/iomgr/iocp_windows.cc index ad325fe2156..29a05ee3099 100644 --- a/src/core/lib/iomgr/iocp_windows.cc +++ b/src/core/lib/iomgr/iocp_windows.cc @@ -90,12 +90,12 @@ grpc_iocp_work_status grpc_iocp_work(grpc_millis deadline) { abort(); } if (socket->shutdown_called) { - info->bytes_transfered = 0; + info->bytes_transferred = 0; info->wsa_error = WSA_OPERATION_ABORTED; } else { success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes, FALSE, &flags); - info->bytes_transfered = bytes; + info->bytes_transferred = bytes; info->wsa_error = success ? 0 : WSAGetLastError(); } GPR_ASSERT(overlapped == &info->overlapped); diff --git a/src/core/lib/iomgr/socket_windows.h b/src/core/lib/iomgr/socket_windows.h index 5fed6909e6f..78f79453c6c 100644 --- a/src/core/lib/iomgr/socket_windows.h +++ b/src/core/lib/iomgr/socket_windows.h @@ -59,7 +59,7 @@ typedef struct grpc_winsocket_callback_info { to hold a mutex for a long amount of time. */ int has_pending_iocp; /* The results of the overlapped operation. */ - DWORD bytes_transfered; + DWORD bytes_transferred; int wsa_error; } grpc_winsocket_callback_info; diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc index ae6b2b68e62..32d0bb36ea7 100644 --- a/src/core/lib/iomgr/tcp_windows.cc +++ b/src/core/lib/iomgr/tcp_windows.cc @@ -196,17 +196,17 @@ static void on_read(void* tcpp, grpc_error* error) { gpr_free(utf8_message); grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices); } else { - if (info->bytes_transfered != 0 && !tcp->shutting_down) { - GPR_ASSERT((size_t)info->bytes_transfered <= tcp->read_slices->length); - if (static_cast(info->bytes_transfered) != + if (info->bytes_transferred != 0 && !tcp->shutting_down) { + GPR_ASSERT((size_t)info->bytes_transferred <= tcp->read_slices->length); + if (static_cast(info->bytes_transferred) != tcp->read_slices->length) { grpc_slice_buffer_trim_end( tcp->read_slices, tcp->read_slices->length - - static_cast(info->bytes_transfered), + static_cast(info->bytes_transferred), &tcp->last_read_buffer); } - GPR_ASSERT((size_t)info->bytes_transfered == tcp->read_slices->length); + GPR_ASSERT((size_t)info->bytes_transferred == tcp->read_slices->length); if (grpc_tcp_trace.enabled()) { size_t i; @@ -288,7 +288,7 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, /* Did we get data immediately ? Yay. */ if (info->wsa_error != WSAEWOULDBLOCK) { - info->bytes_transfered = bytes_read; + info->bytes_transferred = bytes_read; GRPC_CLOSURE_SCHED(&tcp->on_read, GRPC_ERROR_NONE); return; } @@ -333,7 +333,7 @@ static void on_write(void* tcpp, grpc_error* error) { if (info->wsa_error != 0) { error = GRPC_WSA_ERROR(info->wsa_error, "WSASend"); } else { - GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length); + GPR_ASSERT(info->bytes_transferred == tcp->write_slices->length); } } diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py index 7bcfa075559..d6d0612b4e4 100644 --- a/tools/interop_matrix/client_matrix.py +++ b/tools/interop_matrix/client_matrix.py @@ -284,7 +284,7 @@ LANG_RELEASE_MATRIX = { ('v1.16.0', ReleaseInfo(testcases_file='php__v1.0.1')), ('v1.17.1', ReleaseInfo(testcases_file='php__v1.0.1')), ('v1.18.0', ReleaseInfo()), - # v1.19 and v1.20 were deliberately ommitted here because of an issue. + # v1.19 and v1.20 were deliberately omitted here because of an issue. # See https://github.com/grpc/grpc/issues/18264 ('v1.21.4', ReleaseInfo()), ]), From 05a0dd20e4be4f0715be74ee092040fd6b05f173 Mon Sep 17 00:00:00 2001 From: mgravell Date: Mon, 1 Jul 2019 14:58:11 +0100 Subject: [PATCH 02/25] convert micro-benchmarks to benchmarkdotnet --- .gitignore | 3 + .../CommonThreadedBase.cs | 67 ++++++++++++++ .../CompletionRegistryBenchmark.cs | 56 ++++-------- src/csharp/Grpc.Microbenchmarks/GCStats.cs | 69 -------------- .../Grpc.Microbenchmarks.csproj | 7 +- .../PInvokeByteArrayBenchmark.cs | 38 +++----- src/csharp/Grpc.Microbenchmarks/Program.cs | 89 ++----------------- .../SendMessageBenchmark.cs | 39 +++----- .../Grpc.Microbenchmarks/ThreadedBenchmark.cs | 65 -------------- 9 files changed, 123 insertions(+), 310 deletions(-) create mode 100644 src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs delete mode 100644 src/csharp/Grpc.Microbenchmarks/GCStats.cs delete mode 100644 src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs diff --git a/.gitignore b/.gitignore index a8c58277c34..4a400b4e3b4 100644 --- a/.gitignore +++ b/.gitignore @@ -146,3 +146,6 @@ bm_*.json # Clion artifacts cmake-build-debug/ + +# Benchmark outputs +BenchmarkDotNet.Artifacts/ \ No newline at end of file diff --git a/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs b/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs new file mode 100644 index 00000000000..d8724f1eaad --- /dev/null +++ b/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs @@ -0,0 +1,67 @@ +#region Copyright notice and license + +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System; +using System.Threading; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using Grpc.Core; + +namespace Grpc.Microbenchmarks +{ + + // common base-type for tests that need to run with some level of concurrency; + // note there's nothing *special* about this type - it is just to save some + // boilerplate + + [ClrJob, CoreJob] // test .NET Core and .NET Framework + [MemoryDiagnoser] // allocations + [ShortRunJob] // don't take too long + public abstract class CommonThreadedBase + { + protected virtual bool NeedsEnvironment => true; + + [Params(1, 1, 2, 4, 8, 12)] + public int ThreadCount { get; set; } + + protected GrpcEnvironment Environment { get; private set; } + + [GlobalSetup] + public virtual void Setup() + { + ThreadPool.GetMinThreads(out var workers, out var iocp); + if (workers <= ThreadCount) ThreadPool.SetMinThreads(ThreadCount + 1, iocp); + if (NeedsEnvironment) Environment = GrpcEnvironment.AddRef(); + } + + [GlobalCleanup] + public virtual void Cleanup() + { + if (Environment != null) + { + Environment = null; + GrpcEnvironment.ReleaseAsync().Wait(); + } + } + + protected void RunConcurrent(Action operation) + { + Parallel.For(0, ThreadCount, _ => operation()); + } + } +} diff --git a/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs index bb57a6968fa..58ba29927cc 100644 --- a/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs @@ -1,4 +1,4 @@ -#region Copyright notice and license +#region Copyright notice and license // Copyright 2015 gRPC authors. // @@ -17,62 +17,38 @@ #endregion using System; -using System.Runtime.InteropServices; -using System.Threading; -using Grpc.Core; +using BenchmarkDotNet.Attributes; using Grpc.Core.Internal; -using System.Collections.Generic; -using System.Diagnostics; namespace Grpc.Microbenchmarks { - public class CompletionRegistryBenchmark + public class CompletionRegistryBenchmarks : CommonThreadedBase { - GrpcEnvironment environment; + [Params(false, true)] + public bool UseSharedRegistry { get; set; } - public void Init() + const int Iterations = 1000; + [Benchmark(OperationsPerInvoke = Iterations)] + public void Run() { - environment = GrpcEnvironment.AddRef(); + RunConcurrent(() => { + CompletionRegistry sharedRegistry = UseSharedRegistry ? new CompletionRegistry(Environment, () => BatchContextSafeHandle.Create(), () => RequestCallContextSafeHandle.Create()) : null; + RunBody(sharedRegistry); + }); } - public void Cleanup() + private void RunBody(CompletionRegistry optionalSharedRegistry) { - GrpcEnvironment.ReleaseAsync().Wait(); - } - - public void Run(int threadCount, int iterations, bool useSharedRegistry) - { - Console.WriteLine(string.Format("CompletionRegistryBenchmark: threads={0}, iterations={1}, useSharedRegistry={2}", threadCount, iterations, useSharedRegistry)); - CompletionRegistry sharedRegistry = useSharedRegistry ? new CompletionRegistry(environment, () => BatchContextSafeHandle.Create(), () => RequestCallContextSafeHandle.Create()) : null; - var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, sharedRegistry)); - threadedBenchmark.Run(); - // TODO: parametrize by number of pending completions - } - - private void ThreadBody(int iterations, CompletionRegistry optionalSharedRegistry) - { - var completionRegistry = optionalSharedRegistry ?? new CompletionRegistry(environment, () => throw new NotImplementedException(), () => throw new NotImplementedException()); + var completionRegistry = optionalSharedRegistry ?? new CompletionRegistry(Environment, () => throw new NotImplementedException(), () => throw new NotImplementedException()); var ctx = BatchContextSafeHandle.Create(); - - var stopwatch = Stopwatch.StartNew(); - for (int i = 0; i < iterations; i++) + + for (int i = 0; i < Iterations; i++) { completionRegistry.Register(ctx.Handle, ctx); var callback = completionRegistry.Extract(ctx.Handle); // NOTE: we are not calling the callback to avoid disposing ctx. } - stopwatch.Stop(); - Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds); - ctx.Recycle(); } - - private class NopCompletionCallback : IOpCompletionCallback - { - public void OnComplete(bool success) - { - - } - } } } diff --git a/src/csharp/Grpc.Microbenchmarks/GCStats.cs b/src/csharp/Grpc.Microbenchmarks/GCStats.cs deleted file mode 100644 index ca7051ec4e5..00000000000 --- a/src/csharp/Grpc.Microbenchmarks/GCStats.cs +++ /dev/null @@ -1,69 +0,0 @@ -#region Copyright notice and license - -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#endregion - -using System; -using Grpc.Core; -using Grpc.Core.Internal; - -namespace Grpc.Microbenchmarks -{ - internal class GCStats - { - readonly object myLock = new object(); - GCStatsSnapshot lastSnapshot; - - public GCStats() - { - lastSnapshot = new GCStatsSnapshot(GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2)); - } - - public GCStatsSnapshot GetSnapshot(bool reset = false) - { - lock (myLock) - { - var newSnapshot = new GCStatsSnapshot(GC.CollectionCount(0) - lastSnapshot.Gen0, - GC.CollectionCount(1) - lastSnapshot.Gen1, - GC.CollectionCount(2) - lastSnapshot.Gen2); - if (reset) - { - lastSnapshot = newSnapshot; - } - return newSnapshot; - } - } - } - - public class GCStatsSnapshot - { - public GCStatsSnapshot(int gen0, int gen1, int gen2) - { - this.Gen0 = gen0; - this.Gen1 = gen1; - this.Gen2 = gen2; - } - - public int Gen0 { get; } - public int Gen1 { get; } - public int Gen2 { get; } - - public override string ToString() - { - return string.Format("[GCCollectionCount: gen0 {0}, gen1 {1}, gen2 {2}]", Gen0, Gen1, Gen2); - } - } -} diff --git a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj index e0fcdecd9ac..899e41ce532 100644 --- a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj +++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj @@ -3,7 +3,7 @@ - net45;netcoreapp2.1 + net461;netcoreapp2.1 Exe true @@ -13,10 +13,10 @@ - + - + @@ -24,5 +24,4 @@ - diff --git a/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs index 787b5508fba..412f9ad1cb4 100644 --- a/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs @@ -1,4 +1,4 @@ -#region Copyright notice and license +#region Copyright notice and license // Copyright 2015 gRPC authors. // @@ -16,49 +16,39 @@ #endregion -using System; using System.Runtime.InteropServices; -using System.Threading; -using Grpc.Core; +using BenchmarkDotNet.Attributes; using Grpc.Core.Internal; -using System.Collections.Generic; -using System.Diagnostics; namespace Grpc.Microbenchmarks { - public class PInvokeByteArrayBenchmark + public class PInvokeByteArrayBenchmark : CommonThreadedBase { static readonly NativeMethods Native = NativeMethods.Get(); - public void Init() - { - } + protected override bool NeedsEnvironment => false; - public void Cleanup() - { - } - public void Run(int threadCount, int iterations, int payloadSize) + [Params(0)] + public int PayloadSize { get; set; } + + const int Iterations = 1000; + [Benchmark(OperationsPerInvoke = Iterations)] + public void Run() { - Console.WriteLine(string.Format("PInvokeByteArrayBenchmark: threads={0}, iterations={1}, payloadSize={2}", threadCount, iterations, payloadSize)); - var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, payloadSize)); - threadedBenchmark.Run(); + RunConcurrent(RunBody); } - private void ThreadBody(int iterations, int payloadSize) + private void RunBody() { - var payload = new byte[payloadSize]; - - var stopwatch = Stopwatch.StartNew(); - for (int i = 0; i < iterations; i++) + var payload = new byte[PayloadSize]; + for (int i = 0; i < Iterations; i++) { var gcHandle = GCHandle.Alloc(payload, GCHandleType.Pinned); var payloadPtr = gcHandle.AddrOfPinnedObject(); Native.grpcsharp_test_nop(payloadPtr); gcHandle.Free(); } - stopwatch.Stop(); - Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds); } } } diff --git a/src/csharp/Grpc.Microbenchmarks/Program.cs b/src/csharp/Grpc.Microbenchmarks/Program.cs index a64c2979abe..71e549f76ff 100644 --- a/src/csharp/Grpc.Microbenchmarks/Program.cs +++ b/src/csharp/Grpc.Microbenchmarks/Program.cs @@ -1,4 +1,4 @@ -#region Copyright notice and license +#region Copyright notice and license // Copyright 2015 gRPC authors. // @@ -16,95 +16,18 @@ #endregion -using System; -using Grpc.Core; -using Grpc.Core.Internal; -using Grpc.Core.Logging; -using CommandLine; -using CommandLine.Text; +using BenchmarkDotNet.Running; namespace Grpc.Microbenchmarks { class Program { - public enum MicrobenchmarkType - { - CompletionRegistry, - PInvokeByteArray, - SendMessage - } - - private class BenchmarkOptions - { - [Option("benchmark", Required = true, HelpText = "Benchmark to run")] - public MicrobenchmarkType Benchmark { get; set; } - } - + // typical usage: dotnet run -c Release -f netcoreapp2.1 + // (this will profile both .net core and .net framework; for some reason + // if you start from "-f net461", it goes horribly wrong) public static void Main(string[] args) { - GrpcEnvironment.SetLogger(new ConsoleLogger()); - var parserResult = Parser.Default.ParseArguments(args) - .WithNotParsed(errors => { - Console.WriteLine("Supported benchmarks:"); - foreach (var enumValue in Enum.GetValues(typeof(MicrobenchmarkType))) - { - Console.WriteLine(" " + enumValue); - } - Environment.Exit(1); - }) - .WithParsed(options => - { - switch (options.Benchmark) - { - case MicrobenchmarkType.CompletionRegistry: - RunCompletionRegistryBenchmark(); - break; - case MicrobenchmarkType.PInvokeByteArray: - RunPInvokeByteArrayBenchmark(); - break; - case MicrobenchmarkType.SendMessage: - RunSendMessageBenchmark(); - break; - default: - throw new ArgumentException("Unsupported benchmark."); - } - }); - } - - static void RunCompletionRegistryBenchmark() - { - var benchmark = new CompletionRegistryBenchmark(); - benchmark.Init(); - foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12}) - { - foreach (bool useSharedRegistry in new bool[] {false, true}) - { - benchmark.Run(threadCount, 4 * 1000 * 1000, useSharedRegistry); - } - } - benchmark.Cleanup(); - } - - static void RunPInvokeByteArrayBenchmark() - { - var benchmark = new PInvokeByteArrayBenchmark(); - benchmark.Init(); - foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12}) - { - benchmark.Run(threadCount, 4 * 1000 * 1000, 0); - } - benchmark.Cleanup(); - } - - static void RunSendMessageBenchmark() - { - var benchmark = new SendMessageBenchmark(); - benchmark.Init(); - foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12}) - { - benchmark.Run(threadCount, 4 * 1000 * 1000, 0); - } - benchmark.Cleanup(); + BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); } } } diff --git a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs index 390c062298d..fa06e7a8230 100644 --- a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs @@ -17,59 +17,48 @@ #endregion using System; -using System.Threading; +using BenchmarkDotNet.Attributes; using Grpc.Core; using Grpc.Core.Internal; -using System.Collections.Generic; -using System.Diagnostics; namespace Grpc.Microbenchmarks { - public class SendMessageBenchmark + public class SendMessageBenchmark : CommonThreadedBase { static readonly NativeMethods Native = NativeMethods.Get(); - GrpcEnvironment environment; - - public void Init() + public override void Setup() { Native.grpcsharp_test_override_method("grpcsharp_call_start_batch", "nop"); - environment = GrpcEnvironment.AddRef(); + base.Setup(); } - public void Cleanup() - { - GrpcEnvironment.ReleaseAsync().Wait(); - // TODO(jtattermusch): track GC stats - } + [Params(0)] + public int PayloadSize { get; set; } - public void Run(int threadCount, int iterations, int payloadSize) + const int Iterations = 1000; + [Benchmark(OperationsPerInvoke = Iterations)] + public void Run() { - Console.WriteLine(string.Format("SendMessageBenchmark: threads={0}, iterations={1}, payloadSize={2}", threadCount, iterations, payloadSize)); - var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, payloadSize)); - threadedBenchmark.Run(); + RunConcurrent(RunBody); } - private void ThreadBody(int iterations, int payloadSize) + private void RunBody() { - var completionRegistry = new CompletionRegistry(environment, () => environment.BatchContextPool.Lease(), () => throw new NotImplementedException()); + var completionRegistry = new CompletionRegistry(Environment, () => Environment.BatchContextPool.Lease(), () => throw new NotImplementedException()); var cq = CompletionQueueSafeHandle.CreateAsync(completionRegistry); var call = CreateFakeCall(cq); var sendCompletionCallback = new NopSendCompletionCallback(); - var payload = new byte[payloadSize]; + var payload = new byte[PayloadSize]; var writeFlags = default(WriteFlags); - var stopwatch = Stopwatch.StartNew(); - for (int i = 0; i < iterations; i++) + for (int i = 0; i < Iterations; i++) { call.StartSendMessage(sendCompletionCallback, payload, writeFlags, false); var callback = completionRegistry.Extract(completionRegistry.LastRegisteredKey); callback.OnComplete(true); } - stopwatch.Stop(); - Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds); - cq.Dispose(); } diff --git a/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs deleted file mode 100644 index 95b9aaaf3f9..00000000000 --- a/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs +++ /dev/null @@ -1,65 +0,0 @@ -#region Copyright notice and license - -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#endregion - -using System; -using System.Threading; -using Grpc.Core; -using Grpc.Core.Internal; -using System.Collections.Generic; -using System.Diagnostics; - -namespace Grpc.Microbenchmarks -{ - public class ThreadedBenchmark - { - List runners; - - public ThreadedBenchmark(IEnumerable runners) - { - this.runners = new List(runners); - } - - public ThreadedBenchmark(int threadCount, Action threadBody) - { - this.runners = new List(); - for (int i = 0; i < threadCount; i++) - { - this.runners.Add(new ThreadStart(() => threadBody())); - } - } - - public void Run() - { - Console.WriteLine("Running threads."); - var gcStats = new GCStats(); - var threads = new List(); - for (int i = 0; i < runners.Count; i++) - { - var thread = new Thread(runners[i]); - thread.Start(); - threads.Add(thread); - } - - foreach (var thread in threads) - { - thread.Join(); - } - Console.WriteLine("All threads finished (GC Stats Delta: " + gcStats.GetSnapshot() + ")"); - } - } -} From 52de8a0a17ebcfe414cbb777c3861cb3142577ec Mon Sep 17 00:00:00 2001 From: mgravell Date: Mon, 1 Jul 2019 15:25:22 +0100 Subject: [PATCH 03/25] ShortRunJob *added* a test! --- src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs b/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs index d8724f1eaad..4b6174eeef8 100644 --- a/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs +++ b/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs @@ -31,7 +31,6 @@ namespace Grpc.Microbenchmarks [ClrJob, CoreJob] // test .NET Core and .NET Framework [MemoryDiagnoser] // allocations - [ShortRunJob] // don't take too long public abstract class CommonThreadedBase { protected virtual bool NeedsEnvironment => true; From f5091b2622d57fb34fc30fec1f609fe7b8d74800 Mon Sep 17 00:00:00 2001 From: mgravell Date: Mon, 1 Jul 2019 16:16:00 +0100 Subject: [PATCH 04/25] add UTF8-decode benchmark | Method | Job | Runtime | PayloadSize | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | |------- |----- |-------- |------------ |-------------:|-----------:|-----------:|-------:|------:|------:|----------:| | Run | Clr | Clr | 0 | 1.736 ns | 0.0101 ns | 0.0094 ns | - | - | - | - | | Run | Core | Core | 0 | 1.306 ns | 0.0108 ns | 0.0095 ns | - | - | - | - | | Run | Clr | Clr | 1 | 35.384 ns | 0.2282 ns | 0.2135 ns | 0.0101 | - | - | 64 B | | Run | Core | Core | 1 | 32.388 ns | 0.3333 ns | 0.2955 ns | 0.0101 | - | - | 64 B | | Run | Clr | Clr | 4 | 57.736 ns | 0.3889 ns | 0.3448 ns | 0.0114 | - | - | 72 B | | Run | Core | Core | 4 | 52.878 ns | 0.2802 ns | 0.2621 ns | 0.0114 | - | - | 72 B | | Run | Clr | Clr | 128 | 554.819 ns | 4.4341 ns | 4.1477 ns | 0.0830 | - | - | 530 B | | Run | Core | Core | 128 | 336.356 ns | 1.6148 ns | 1.4315 ns | 0.0835 | - | - | 528 B | | Run | Clr | Clr | 1024 | 4,050.850 ns | 28.9245 ns | 25.6408 ns | 0.6016 | - | - | 3820 B | | Run | Core | Core | 1024 | 2,272.534 ns | 33.8963 ns | 31.7066 ns | 0.6016 | - | - | 3808 B | --- .../Grpc.Microbenchmarks.csproj | 1 + src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs diff --git a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj index 899e41ce532..f775e4c85fb 100644 --- a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj +++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj @@ -6,6 +6,7 @@ net461;netcoreapp2.1 Exe true + true diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs new file mode 100644 index 00000000000..1c3f4d261ee --- /dev/null +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; +using BenchmarkDotNet.Attributes; +using Grpc.Core.Internal; + +namespace Grpc.Microbenchmarks +{ + [ClrJob, CoreJob] // test .NET Core and .NET Framework + [MemoryDiagnoser] // allocations + public class Utf8Decode + { + [Params(0, 1, 4, 128, 1024)] + public int PayloadSize { get; set; } + + static readonly Dictionary Payloads = new Dictionary { + { 0, Invent(0) }, + { 1, Invent(1) }, + { 4, Invent(4) }, + { 128, Invent(128) }, + { 1024, Invent(1024) }, + }; + + static byte[] Invent(int length) + { + var rand = new Random(Seed: length); + var chars = new char[length]; + for(int i = 0; i < chars.Length; i++) + { + chars[i] = (char)rand.Next(32, 300); + } + return Encoding.UTF8.GetBytes(chars); + } + + const int Iterations = 1000; + [Benchmark(OperationsPerInvoke = Iterations)] + public unsafe void Run() + { + byte[] payload = Payloads[PayloadSize]; + fixed (byte* ptr = payload) + { + var iPtr = new IntPtr(ptr); + for (int i = 0; i < Iterations; i++) + { + MarshalUtils.PtrToStringUTF8(iPtr, payload.Length); + } + } + } + } +} From dbef6c9c70898451dbc1eadfb7e1bab0a9d18a42 Mon Sep 17 00:00:00 2001 From: mgravell Date: Mon, 1 Jul 2019 16:36:46 +0100 Subject: [PATCH 05/25] add utf-8 encode benchmark --- .../Properties/AssemblyInfo.cs | 6 ++ .../Grpc.Microbenchmarks.csproj | 1 + src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs | 72 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs diff --git a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs index af264c9be5d..e19010f0509 100644 --- a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs @@ -27,3 +27,9 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] + +[assembly: InternalsVisibleTo("Grpc.Microbenchmarks,PublicKey=" + + "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" + + "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" + + "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" + + "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")] diff --git a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj index f775e4c85fb..89597e139ec 100644 --- a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj +++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj @@ -11,6 +11,7 @@ + diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs new file mode 100644 index 00000000000..cbb4091122b --- /dev/null +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Text; +using BenchmarkDotNet.Attributes; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Internal.Tests; + +namespace Grpc.Microbenchmarks +{ + [ClrJob, CoreJob] // test .NET Core and .NET Framework + [MemoryDiagnoser] // allocations + public class Utf8Encode : ISendStatusFromServerCompletionCallback + { + static readonly NativeMethods Native = NativeMethods.Get(); + + [Params(0, 1, 4, 128, 1024)] + public int PayloadSize { get; set; } + + static readonly Dictionary Payloads = new Dictionary { + { 0, Invent(0) }, + { 1, Invent(1) }, + { 4, Invent(4) }, + { 128, Invent(128) }, + { 1024, Invent(1024) }, + }; + + static string Invent(int length) + { + var rand = new Random(Seed: length); + var chars = new char[length]; + for(int i = 0; i < chars.Length; i++) + { + chars[i] = (char)rand.Next(32, 300); + } + return new string(chars); + } + + [GlobalSetup] + public void Setup() + { + Native.grpcsharp_test_override_method("grpcsharp_call_start_batch", "nop"); + metadata = MetadataArraySafeHandle.Create(Metadata.Empty); + call = new FakeNativeCall(); + } + + public void Cleanup() + { + metadata.Dispose(); + metadata = null; + call.Dispose(); + call = null; + } + private INativeCall call; + private MetadataArraySafeHandle metadata; + + const int Iterations = 1000; + [Benchmark(OperationsPerInvoke = Iterations)] + public unsafe void Run() + { + string payload = Payloads[PayloadSize]; + var status = new Status(StatusCode.OK, payload); + for (int i = 0; i < Iterations; i++) + { + call.StartSendStatusFromServer(this, status, + metadata, false, null, WriteFlags.NoCompress); + } + } + + void ISendStatusFromServerCompletionCallback.OnSendStatusFromServerCompletion(bool success) { } + } +} From f53d844da9c6d070b52b8e05192fbcb11cea94db Mon Sep 17 00:00:00 2001 From: mgravell Date: Mon, 1 Jul 2019 17:07:15 +0100 Subject: [PATCH 06/25] attempt to fix the utf-8 encode benchmark; not currently working --- plugins.vcxproj.filters | 17 +++++++ .../Properties/AssemblyInfo.cs | 6 --- .../Grpc.Microbenchmarks.csproj | 1 - src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs | 47 ++++++++++++++----- 4 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 plugins.vcxproj.filters diff --git a/plugins.vcxproj.filters b/plugins.vcxproj.filters new file mode 100644 index 00000000000..5ce08010501 --- /dev/null +++ b/plugins.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + CMake Rules + + + + + + + + + {870DBD13-69C5-3F27-A253-623E8947E2E7} + + + diff --git a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs index e19010f0509..af264c9be5d 100644 --- a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs @@ -27,9 +27,3 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] - -[assembly: InternalsVisibleTo("Grpc.Microbenchmarks,PublicKey=" + - "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" + - "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" + - "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" + - "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")] diff --git a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj index 89597e139ec..f775e4c85fb 100644 --- a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj +++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj @@ -11,7 +11,6 @@ - diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs index cbb4091122b..4061a1a0f02 100644 --- a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Text; using BenchmarkDotNet.Attributes; using Grpc.Core; using Grpc.Core.Internal; -using Grpc.Core.Internal.Tests; namespace Grpc.Microbenchmarks { @@ -12,9 +10,7 @@ namespace Grpc.Microbenchmarks [MemoryDiagnoser] // allocations public class Utf8Encode : ISendStatusFromServerCompletionCallback { - static readonly NativeMethods Native = NativeMethods.Get(); - - [Params(0, 1, 4, 128, 1024)] + [Params(0)] //, 1, 4, 128, 1024)] public int PayloadSize { get; set; } static readonly Dictionary Payloads = new Dictionary { @@ -36,22 +32,50 @@ namespace Grpc.Microbenchmarks return new string(chars); } + private GrpcEnvironment environment; + [GlobalSetup] public void Setup() { - Native.grpcsharp_test_override_method("grpcsharp_call_start_batch", "nop"); + var native = NativeMethods.Get(); + + // ??? throws ??? + native.grpcsharp_test_override_method(nameof(NativeMethods.grpcsharp_call_send_status_from_server), "nop"); + + environment = GrpcEnvironment.AddRef(); metadata = MetadataArraySafeHandle.Create(Metadata.Empty); - call = new FakeNativeCall(); + var completionRegistry = new CompletionRegistry(environment, () => environment.BatchContextPool.Lease(), () => throw new NotImplementedException()); + var cq = CompletionQueueSafeHandle.CreateAsync(completionRegistry); + call = CreateFakeCall(cq); + } + + private static CallSafeHandle CreateFakeCall(CompletionQueueSafeHandle cq) + { + var call = CallSafeHandle.CreateFake(new IntPtr(0xdead), cq); + bool success = false; + while (!success) + { + // avoid calling destroy on a nonexistent grpc_call pointer + call.DangerousAddRef(ref success); + } + return call; } + [GlobalCleanup] public void Cleanup() { - metadata.Dispose(); + metadata?.Dispose(); metadata = null; - call.Dispose(); + call?.Dispose(); call = null; + + if (environment != null) + { + environment = null; + GrpcEnvironment.ReleaseAsync().Wait(); + } } - private INativeCall call; + private CallSafeHandle call; private MetadataArraySafeHandle metadata; const int Iterations = 1000; @@ -62,8 +86,7 @@ namespace Grpc.Microbenchmarks var status = new Status(StatusCode.OK, payload); for (int i = 0; i < Iterations; i++) { - call.StartSendStatusFromServer(this, status, - metadata, false, null, WriteFlags.NoCompress); + call.StartSendStatusFromServer(this, status, metadata, false, null, WriteFlags.NoCompress); } } From e4411e03e65a7f69acc48b22403f6453c37e207e Mon Sep 17 00:00:00 2001 From: mgravell Date: Mon, 1 Jul 2019 17:11:26 +0100 Subject: [PATCH 07/25] added by mistake --- plugins.vcxproj.filters | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 plugins.vcxproj.filters diff --git a/plugins.vcxproj.filters b/plugins.vcxproj.filters deleted file mode 100644 index 5ce08010501..00000000000 --- a/plugins.vcxproj.filters +++ /dev/null @@ -1,17 +0,0 @@ - - - - - CMake Rules - - - - - - - - - {870DBD13-69C5-3F27-A253-623E8947E2E7} - - - From 0a1147b58c17de641082bbb58859a3b21fcbd34d Mon Sep 17 00:00:00 2001 From: mgravell Date: Mon, 1 Jul 2019 17:28:47 +0100 Subject: [PATCH 08/25] found another way to nop the native-call --- src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs index 4061a1a0f02..0c9370679a4 100644 --- a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs @@ -39,8 +39,9 @@ namespace Grpc.Microbenchmarks { var native = NativeMethods.Get(); - // ??? throws ??? - native.grpcsharp_test_override_method(nameof(NativeMethods.grpcsharp_call_send_status_from_server), "nop"); + // nop the native-call via reflection + NativeMethods.Delegates.grpcsharp_call_send_status_from_server_delegate nop = (CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags) => CallError.OK; + native.GetType().GetField(nameof(native.grpcsharp_call_send_status_from_server)).SetValue(native, nop); environment = GrpcEnvironment.AddRef(); metadata = MetadataArraySafeHandle.Create(Metadata.Empty); From 464f558a456f8dd43609df066722cc5f0a0257bc Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Mon, 1 Jul 2019 10:12:23 -0700 Subject: [PATCH 09/25] Increase the control message size --- src/core/lib/iomgr/tcp_posix.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index 889272f6299..0a2ef767598 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -435,7 +435,9 @@ static void tcp_do_read(grpc_tcp* tcp) { GPR_TIMER_SCOPE("tcp_do_read", 0); struct msghdr msg; struct iovec iov[MAX_READ_IOVEC]; - char cmsgbuf[24 /*CMSG_SPACE(sizeof(int))*/]; + char cmsgbuf + [128 /*CMSG_SPACE(sizeof(grpc_core::scm_timestamping)) + CMSG_SPACE(sizeof(int))*/ + ]; ssize_t read_bytes; size_t total_read_bytes = 0; From 420d5413c7d9816df16cf24018c1f8b8dc2e8d09 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Mon, 1 Jul 2019 10:50:47 -0700 Subject: [PATCH 10/25] Use the actual formula --- src/core/lib/iomgr/tcp_posix.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index 0a2ef767598..606e033a21e 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -435,9 +435,9 @@ static void tcp_do_read(grpc_tcp* tcp) { GPR_TIMER_SCOPE("tcp_do_read", 0); struct msghdr msg; struct iovec iov[MAX_READ_IOVEC]; - char cmsgbuf - [128 /*CMSG_SPACE(sizeof(grpc_core::scm_timestamping)) + CMSG_SPACE(sizeof(int))*/ - ]; + constexpr size_t cmsg_alloc_space = + CMSG_SPACE(sizeof(grpc_core::scm_timestamping)) + CMSG_SPACE(sizeof(int)); + char cmsgbuf[cmsg_alloc_space]; ssize_t read_bytes; size_t total_read_bytes = 0; From f44e0c07a709c81211fb32d5010906a8451f63ca Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Mon, 1 Jul 2019 10:55:11 -0700 Subject: [PATCH 11/25] Reviewer comments --- src/core/lib/iomgr/tcp_posix.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index 606e033a21e..031f681baa3 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -526,6 +526,7 @@ static void tcp_do_read(grpc_tcp* tcp) { if (cmsg->cmsg_level == SOL_TCP && cmsg->cmsg_type == TCP_CM_INQ && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { tcp->inq = *reinterpret_cast(CMSG_DATA(cmsg)); + break; } } } From 7cb861ce294edae5d40e8ea0c597687e989eec17 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Mon, 1 Jul 2019 11:00:55 -0700 Subject: [PATCH 12/25] Reviewer comments --- src/core/lib/iomgr/tcp_posix.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index 031f681baa3..79c56d5f3df 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -437,12 +437,12 @@ static void tcp_do_read(grpc_tcp* tcp) { struct iovec iov[MAX_READ_IOVEC]; constexpr size_t cmsg_alloc_space = CMSG_SPACE(sizeof(grpc_core::scm_timestamping)) + CMSG_SPACE(sizeof(int)); - char cmsgbuf[cmsg_alloc_space]; ssize_t read_bytes; size_t total_read_bytes = 0; - size_t iov_len = std::min(MAX_READ_IOVEC, tcp->incoming_buffer->count); + char cmsgbuf[cmsg_alloc_space]; + for (size_t i = 0; i < iov_len; i++) { iov[i].iov_base = GRPC_SLICE_START_PTR(tcp->incoming_buffer->slices[i]); iov[i].iov_len = GRPC_SLICE_LENGTH(tcp->incoming_buffer->slices[i]); From a94e00dccf732e19ec33e22ca184a99d44ace042 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Mon, 1 Jul 2019 11:15:40 -0700 Subject: [PATCH 13/25] Reviewer comments --- src/core/lib/iomgr/tcp_posix.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index 79c56d5f3df..94a9da2ee49 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -435,14 +435,13 @@ static void tcp_do_read(grpc_tcp* tcp) { GPR_TIMER_SCOPE("tcp_do_read", 0); struct msghdr msg; struct iovec iov[MAX_READ_IOVEC]; - constexpr size_t cmsg_alloc_space = - CMSG_SPACE(sizeof(grpc_core::scm_timestamping)) + CMSG_SPACE(sizeof(int)); ssize_t read_bytes; size_t total_read_bytes = 0; size_t iov_len = std::min(MAX_READ_IOVEC, tcp->incoming_buffer->count); + constexpr size_t cmsg_alloc_space = + CMSG_SPACE(sizeof(grpc_core::scm_timestamping)) + CMSG_SPACE(sizeof(int)); char cmsgbuf[cmsg_alloc_space]; - for (size_t i = 0; i < iov_len; i++) { iov[i].iov_base = GRPC_SLICE_START_PTR(tcp->incoming_buffer->slices[i]); iov[i].iov_len = GRPC_SLICE_LENGTH(tcp->incoming_buffer->slices[i]); From 02ff96bd31f33a0c193f0766d87bb57ba438b2ef Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Mon, 1 Jul 2019 11:46:52 -0700 Subject: [PATCH 14/25] No need to allocate space for receive timestamp if errqueue is not present --- src/core/lib/iomgr/tcp_posix.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index 94a9da2ee49..0e153679ad7 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -439,8 +439,12 @@ static void tcp_do_read(grpc_tcp* tcp) { size_t total_read_bytes = 0; size_t iov_len = std::min(MAX_READ_IOVEC, tcp->incoming_buffer->count); +#ifdef GRPC_LINUX_ERRQUEUE constexpr size_t cmsg_alloc_space = CMSG_SPACE(sizeof(grpc_core::scm_timestamping)) + CMSG_SPACE(sizeof(int)); +#else + constexpr size_t cmsg_alloc_space = CMSG_SPACE(sizeof(int)); +#endif /* GRPC_LINUX_ERRQUEUE */ char cmsgbuf[cmsg_alloc_space]; for (size_t i = 0; i < iov_len; i++) { iov[i].iov_base = GRPC_SLICE_START_PTR(tcp->incoming_buffer->slices[i]); From 1487ac42cc992e5e9a9e8dfa0742a74c14593db6 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Mon, 1 Jul 2019 14:11:44 -0700 Subject: [PATCH 15/25] Remove CMSG_SPACE for macos --- src/core/lib/iomgr/tcp_posix.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index 0e153679ad7..819c5284256 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -443,7 +443,7 @@ static void tcp_do_read(grpc_tcp* tcp) { constexpr size_t cmsg_alloc_space = CMSG_SPACE(sizeof(grpc_core::scm_timestamping)) + CMSG_SPACE(sizeof(int)); #else - constexpr size_t cmsg_alloc_space = CMSG_SPACE(sizeof(int)); + constexpr size_t cmsg_alloc_space = 24 /* CMSG_SPACE(sizeof(int)) */; #endif /* GRPC_LINUX_ERRQUEUE */ char cmsgbuf[cmsg_alloc_space]; for (size_t i = 0; i < iov_len; i++) { From 01b82d3a39f2d4455025e9176dae7917a82babb2 Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Mon, 1 Jul 2019 18:29:54 -0400 Subject: [PATCH 16/25] Return empty strings on optional ports for backward compatibility. gpr_split_host_port returns an empty string for the port when given "0.0.0.0:" as the input. Change the emptiness check to an explicit argument called has_port, to remain backward compatible. Added a test to cover both v4 and v6. --- src/core/lib/gprpp/host_port.cc | 18 +++++++++++++++--- test/core/gprpp/host_port_test.cc | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/core/lib/gprpp/host_port.cc b/src/core/lib/gprpp/host_port.cc index 13b63eb902b..3fa4719f49a 100644 --- a/src/core/lib/gprpp/host_port.cc +++ b/src/core/lib/gprpp/host_port.cc @@ -44,7 +44,10 @@ int JoinHostPort(UniquePtr* out, const char* host, int port) { return ret; } -bool SplitHostPort(StringView name, StringView* host, StringView* port) { +namespace { +bool DoSplitHostPort(StringView name, StringView* host, StringView* port, + bool* has_port) { + *has_port = false; if (name[0] == '[') { /* Parse a bracketed host, typically an IPv6 literal. */ const size_t rbracket = name.find(']', 1); @@ -58,6 +61,7 @@ bool SplitHostPort(StringView name, StringView* host, StringView* port) { } else if (name[rbracket + 1] == ':') { /* ]: */ *port = name.substr(rbracket + 2, name.size() - rbracket - 2); + *has_port = true; } else { /* ] */ return false; @@ -76,6 +80,7 @@ bool SplitHostPort(StringView name, StringView* host, StringView* port) { /* Exactly 1 colon. Split into host:port. */ *host = name.substr(0, colon); *port = name.substr(colon + 1, name.size() - colon - 1); + *has_port = true; } else { /* 0 or 2+ colons. Bare hostname or IPv6 litearal. */ *host = name; @@ -84,6 +89,12 @@ bool SplitHostPort(StringView name, StringView* host, StringView* port) { } return true; } +} // namespace + +bool SplitHostPort(StringView name, StringView* host, StringView* port) { + bool unused; + return DoSplitHostPort(name, host, port, &unused); +} bool SplitHostPort(StringView name, UniquePtr* host, UniquePtr* port) { @@ -91,12 +102,13 @@ bool SplitHostPort(StringView name, UniquePtr* host, GPR_DEBUG_ASSERT(port != nullptr && *port == nullptr); StringView host_view; StringView port_view; - const bool ret = SplitHostPort(name, &host_view, &port_view); + bool has_port; + const bool ret = DoSplitHostPort(name, &host_view, &port_view, &has_port); if (ret) { // We always set the host, but port is set only when it's non-empty, // to remain backward compatible with the old split_host_port API. *host = host_view.dup(); - if (!port_view.empty()) { + if (has_port) { *port = port_view.dup(); } } diff --git a/test/core/gprpp/host_port_test.cc b/test/core/gprpp/host_port_test.cc index 3b392da66e8..cfe0eddb036 100644 --- a/test/core/gprpp/host_port_test.cc +++ b/test/core/gprpp/host_port_test.cc @@ -71,7 +71,9 @@ static void test_split_host_port() { split_host_port_expect("", "", nullptr, true); split_host_port_expect("[a:b]", "a:b", nullptr, true); split_host_port_expect("1.2.3.4", "1.2.3.4", nullptr, true); + split_host_port_expect("0.0.0.0:", "0.0.0.0", "", true); split_host_port_expect("a:b:c::", "a:b:c::", nullptr, true); + split_host_port_expect("[a:b:c::]:", "a:b:c::", "", true); split_host_port_expect("[a:b]:30", "a:b", "30", true); split_host_port_expect("1.2.3.4:30", "1.2.3.4", "30", true); split_host_port_expect(":30", "", "30", true); From bf9b4c257bdd5f5765fcd9b6c9402d170f75fea8 Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Mon, 1 Jul 2019 19:13:26 -0400 Subject: [PATCH 17/25] Fix stale comment in split host port. --- src/core/lib/gprpp/host_port.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/lib/gprpp/host_port.cc b/src/core/lib/gprpp/host_port.cc index 3fa4719f49a..e7f0e4461e9 100644 --- a/src/core/lib/gprpp/host_port.cc +++ b/src/core/lib/gprpp/host_port.cc @@ -105,8 +105,9 @@ bool SplitHostPort(StringView name, UniquePtr* host, bool has_port; const bool ret = DoSplitHostPort(name, &host_view, &port_view, &has_port); if (ret) { - // We always set the host, but port is set only when it's non-empty, - // to remain backward compatible with the old split_host_port API. + // We always set the host, but port is set only when DoSplitHostPort find a + // port in the string, to remain backward compatible with the old + // gpr_split_host_port API. *host = host_view.dup(); if (has_port) { *port = port_view.dup(); From aa535356e8a95d686396f79370f500c3be8e6233 Mon Sep 17 00:00:00 2001 From: mgravell Date: Tue, 2 Jul 2019 08:28:44 +0100 Subject: [PATCH 18/25] fix encode benchmark (and simplify decode benchmark) --- src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs | 20 +++---- src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs | 54 +++++++++++-------- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs index 1c3f4d261ee..070f8ec03ce 100644 --- a/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs @@ -11,15 +11,18 @@ namespace Grpc.Microbenchmarks public class Utf8Decode { [Params(0, 1, 4, 128, 1024)] - public int PayloadSize { get; set; } + public int PayloadSize + { + get { return payloadSize; } + set + { + payloadSize = value; + payload = Invent(value); + } + } - static readonly Dictionary Payloads = new Dictionary { - { 0, Invent(0) }, - { 1, Invent(1) }, - { 4, Invent(4) }, - { 128, Invent(128) }, - { 1024, Invent(1024) }, - }; + private int payloadSize; + private byte[] payload; static byte[] Invent(int length) { @@ -36,7 +39,6 @@ namespace Grpc.Microbenchmarks [Benchmark(OperationsPerInvoke = Iterations)] public unsafe void Run() { - byte[] payload = Payloads[PayloadSize]; fixed (byte* ptr = payload) { var iPtr = new IntPtr(ptr); diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs index 0c9370679a4..bf9fe68e467 100644 --- a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs @@ -10,16 +10,19 @@ namespace Grpc.Microbenchmarks [MemoryDiagnoser] // allocations public class Utf8Encode : ISendStatusFromServerCompletionCallback { - [Params(0)] //, 1, 4, 128, 1024)] - public int PayloadSize { get; set; } + [Params(0, 1, 4, 128, 1024)] + public int PayloadSize + { + get { return payloadSize; } + set + { + payloadSize = value; + status = new Status(StatusCode.OK, Invent(value)); + } + } - static readonly Dictionary Payloads = new Dictionary { - { 0, Invent(0) }, - { 1, Invent(1) }, - { 4, Invent(4) }, - { 128, Invent(128) }, - { 1024, Invent(1024) }, - }; + private int payloadSize; + private Status status; static string Invent(int length) { @@ -33,19 +36,22 @@ namespace Grpc.Microbenchmarks } private GrpcEnvironment environment; - + private CompletionRegistry completionRegistry; [GlobalSetup] public void Setup() { var native = NativeMethods.Get(); // nop the native-call via reflection - NativeMethods.Delegates.grpcsharp_call_send_status_from_server_delegate nop = (CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags) => CallError.OK; + NativeMethods.Delegates.grpcsharp_call_send_status_from_server_delegate nop = (CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags) => { + completionRegistry.Extract(ctx.Handle).OnComplete(true); // drain the dictionary as we go + return CallError.OK; + }; native.GetType().GetField(nameof(native.grpcsharp_call_send_status_from_server)).SetValue(native, nop); environment = GrpcEnvironment.AddRef(); metadata = MetadataArraySafeHandle.Create(Metadata.Empty); - var completionRegistry = new CompletionRegistry(environment, () => environment.BatchContextPool.Lease(), () => throw new NotImplementedException()); + completionRegistry = new CompletionRegistry(environment, () => environment.BatchContextPool.Lease(), () => throw new NotImplementedException()); var cq = CompletionQueueSafeHandle.CreateAsync(completionRegistry); call = CreateFakeCall(cq); } @@ -65,15 +71,23 @@ namespace Grpc.Microbenchmarks [GlobalCleanup] public void Cleanup() { - metadata?.Dispose(); - metadata = null; - call?.Dispose(); - call = null; + try + { + metadata?.Dispose(); + metadata = null; + call?.Dispose(); + call = null; - if (environment != null) + if (environment != null) + { + environment = null; + // cleanup seems... unreliable on CLR + // GrpcEnvironment.ReleaseAsync().Wait(1000); + } + } + catch (Exception ex) { - environment = null; - GrpcEnvironment.ReleaseAsync().Wait(); + Console.Error.WriteLine(ex.Message); } } private CallSafeHandle call; @@ -83,8 +97,6 @@ namespace Grpc.Microbenchmarks [Benchmark(OperationsPerInvoke = Iterations)] public unsafe void Run() { - string payload = Payloads[PayloadSize]; - var status = new Status(StatusCode.OK, payload); for (int i = 0; i < Iterations; i++) { call.StartSendStatusFromServer(this, status, metadata, false, null, WriteFlags.NoCompress); From 36c1a11d84771eec759a92670c071744c7541c96 Mon Sep 17 00:00:00 2001 From: mgravell Date: Tue, 2 Jul 2019 08:48:24 +0100 Subject: [PATCH 19/25] give useful names to benchmarks --- grpcpp_channelz.vcxproj.filters | 42 +++++++++++++++++++ .../CompletionRegistryBenchmark.cs | 2 +- .../PInvokeByteArrayBenchmark.cs | 2 +- .../SendMessageBenchmark.cs | 4 +- src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs | 2 +- src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs | 2 +- 6 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 grpcpp_channelz.vcxproj.filters diff --git a/grpcpp_channelz.vcxproj.filters b/grpcpp_channelz.vcxproj.filters new file mode 100644 index 00000000000..9f37e96eb69 --- /dev/null +++ b/grpcpp_channelz.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + + + CMake Rules + + + + + + {870DBD13-69C5-3F27-A253-623E8947E2E7} + + + {67AA517E-A3B4-3BFF-B690-252465A3B876} + + + {B3AFD131-5BE8-3F8D-8C68-1BD558A25862} + + + diff --git a/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs index 58ba29927cc..ac252a95d89 100644 --- a/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs @@ -29,7 +29,7 @@ namespace Grpc.Microbenchmarks const int Iterations = 1000; [Benchmark(OperationsPerInvoke = Iterations)] - public void Run() + public void RegisterExtract() { RunConcurrent(() => { CompletionRegistry sharedRegistry = UseSharedRegistry ? new CompletionRegistry(Environment, () => BatchContextSafeHandle.Create(), () => RequestCallContextSafeHandle.Create()) : null; diff --git a/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs index 412f9ad1cb4..b217aef2068 100644 --- a/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs @@ -34,7 +34,7 @@ namespace Grpc.Microbenchmarks const int Iterations = 1000; [Benchmark(OperationsPerInvoke = Iterations)] - public void Run() + public void AllocFree() { RunConcurrent(RunBody); } diff --git a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs index fa06e7a8230..56ae838a4f4 100644 --- a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs @@ -1,4 +1,4 @@ -#region Copyright notice and license +#region Copyright notice and license // Copyright 2015 gRPC authors. // @@ -38,7 +38,7 @@ namespace Grpc.Microbenchmarks const int Iterations = 1000; [Benchmark(OperationsPerInvoke = Iterations)] - public void Run() + public void SendMessage() { RunConcurrent(RunBody); } diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs index 070f8ec03ce..5c5c927a260 100644 --- a/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs @@ -37,7 +37,7 @@ namespace Grpc.Microbenchmarks const int Iterations = 1000; [Benchmark(OperationsPerInvoke = Iterations)] - public unsafe void Run() + public unsafe void Decode() { fixed (byte* ptr = payload) { diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs index bf9fe68e467..95e7ad45841 100644 --- a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs @@ -95,7 +95,7 @@ namespace Grpc.Microbenchmarks const int Iterations = 1000; [Benchmark(OperationsPerInvoke = Iterations)] - public unsafe void Run() + public unsafe void SendStatus() { for (int i = 0; i < Iterations; i++) { From dd5f19765ea382b6ae1b08b786c448c923597a5c Mon Sep 17 00:00:00 2001 From: mgravell Date: Tue, 2 Jul 2019 09:11:14 +0100 Subject: [PATCH 20/25] add framework overhead "PingBenchmark" --- .../Grpc.Microbenchmarks/PingBenchmark.cs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs diff --git a/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs new file mode 100644 index 00000000000..25996fb6868 --- /dev/null +++ b/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs @@ -0,0 +1,84 @@ +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using Grpc.Core; + +namespace Grpc.Microbenchmarks +{ + // this test creates a real server and client, measuring the inherent inbuilt + // platform overheads; the marshallers **DO NOT ALLOCATE**, so any allocations + // are from the framework, not the messages themselves + + // important: allocs are not reliable on .NET Core until .NET Core 3, since + // this test involves multiple threads + + [ClrJob, CoreJob] // test .NET Core and .NET Framework + [MemoryDiagnoser] // allocations + public class PingBenchmark + { + private static readonly Task CompletedString = Task.FromResult(""); + private static readonly byte[] EmptyBlob = new byte[0]; + private static readonly Marshaller EmptyMarshaller = new Marshaller(_ => EmptyBlob, _ => ""); + private static readonly Method PingMethod = new Method(MethodType.Unary, nameof(PingBenchmark), "Ping", EmptyMarshaller, EmptyMarshaller); + + + [Benchmark] + public async ValueTask PingAsync() + { + using (var result = client.PingAsync("")) + { + return await result.ResponseAsync; + } + } + + [Benchmark] + public string Ping() + { + return client.Ping(""); + } + + private Task ServerMethod(string request, ServerCallContext context) + { + return CompletedString; + } + + Server server; + Channel channel; + PingClient client; + + [GlobalSetup] + public async Task Setup() + { + // create server + server = new Server { + Ports = { new ServerPort("localhost", 10042, ServerCredentials.Insecure) }, + Services = { ServerServiceDefinition.CreateBuilder().AddMethod(PingMethod, ServerMethod).Build() }, + }; + server.Start(); + + // create client + channel = new Channel("localhost", 10042, ChannelCredentials.Insecure); + await channel.ConnectAsync(); + client = new PingClient(new DefaultCallInvoker(channel)); + } + + [GlobalCleanup] + public async Task Cleanup() + { + await channel.ShutdownAsync(); + await server.ShutdownAsync(); + } + + class PingClient : LiteClientBase + { + public PingClient(CallInvoker callInvoker) : base(callInvoker) { } + public AsyncUnaryCall PingAsync(string request, CallOptions options = default) + { + return CallInvoker.AsyncUnaryCall(PingMethod, null, options, request); + } + public string Ping(string request, CallOptions options = default) + { + return CallInvoker.BlockingUnaryCall(PingMethod, null, options, request); + } + } + } +} From ffac31b10830c763c2e04c71d7eaf038e405d318 Mon Sep 17 00:00:00 2001 From: mgravell Date: Tue, 2 Jul 2019 09:30:26 +0100 Subject: [PATCH 21/25] incorrectly added --- grpcpp_channelz.vcxproj.filters | 42 --------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 grpcpp_channelz.vcxproj.filters diff --git a/grpcpp_channelz.vcxproj.filters b/grpcpp_channelz.vcxproj.filters deleted file mode 100644 index 9f37e96eb69..00000000000 --- a/grpcpp_channelz.vcxproj.filters +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - - - CMake Rules - - - - - - {870DBD13-69C5-3F27-A253-623E8947E2E7} - - - {67AA517E-A3B4-3BFF-B690-252465A3B876} - - - {B3AFD131-5BE8-3F8D-8C68-1BD558A25862} - - - From a56998bdffa4ed97615649d5f9e6ba908ced4260 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 2 Jul 2019 03:35:12 -0400 Subject: [PATCH 22/25] fix small nits --- src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs | 2 +- src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs b/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs index 4b6174eeef8..c6bdf471b8a 100644 --- a/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs +++ b/src/csharp/Grpc.Microbenchmarks/CommonThreadedBase.cs @@ -35,7 +35,7 @@ namespace Grpc.Microbenchmarks { protected virtual bool NeedsEnvironment => true; - [Params(1, 1, 2, 4, 8, 12)] + [Params(1, 2, 4, 8, 12)] public int ThreadCount { get; set; } protected GrpcEnvironment Environment { get; private set; } diff --git a/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs index ac252a95d89..62665925f62 100644 --- a/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs @@ -22,7 +22,7 @@ using Grpc.Core.Internal; namespace Grpc.Microbenchmarks { - public class CompletionRegistryBenchmarks : CommonThreadedBase + public class CompletionRegistryBenchmark : CommonThreadedBase { [Params(false, true)] public bool UseSharedRegistry { get; set; } From 43240238d2eb0b5df40ee0ca5b8c570ad9e4faec Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 2 Jul 2019 07:17:05 -0400 Subject: [PATCH 23/25] tweak iteration counts for multithreaded benchmarks --- src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs | 2 +- src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs | 2 +- src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs index 62665925f62..e4cd7eeb1f6 100644 --- a/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs @@ -27,7 +27,7 @@ namespace Grpc.Microbenchmarks [Params(false, true)] public bool UseSharedRegistry { get; set; } - const int Iterations = 1000; + const int Iterations = 1000000; // High number to make the overhead of RunConcurrent negligible. [Benchmark(OperationsPerInvoke = Iterations)] public void RegisterExtract() { diff --git a/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs index b217aef2068..de4e635580f 100644 --- a/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs @@ -32,7 +32,7 @@ namespace Grpc.Microbenchmarks [Params(0)] public int PayloadSize { get; set; } - const int Iterations = 1000; + const int Iterations = 1000000; // High number to make the overhead of RunConcurrent negligible. [Benchmark(OperationsPerInvoke = Iterations)] public void AllocFree() { diff --git a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs index 56ae838a4f4..d9554db00db 100644 --- a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs @@ -36,7 +36,7 @@ namespace Grpc.Microbenchmarks [Params(0)] public int PayloadSize { get; set; } - const int Iterations = 1000; + const int Iterations = 1000000; // High number to make the overhead of RunConcurrent negligible. [Benchmark(OperationsPerInvoke = Iterations)] public void SendMessage() { From 3ba99a685ed548c236f9bcad3061b34dd6e905b5 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 2 Jul 2019 07:20:28 -0400 Subject: [PATCH 24/25] make pingbenchmark compile --- src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs index 25996fb6868..f22c52c8927 100644 --- a/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs @@ -24,7 +24,7 @@ namespace Grpc.Microbenchmarks [Benchmark] public async ValueTask PingAsync() { - using (var result = client.PingAsync("")) + using (var result = client.PingAsync("", new CallOptions())) { return await result.ResponseAsync; } @@ -33,7 +33,7 @@ namespace Grpc.Microbenchmarks [Benchmark] public string Ping() { - return client.Ping(""); + return client.Ping("", new CallOptions()); } private Task ServerMethod(string request, ServerCallContext context) @@ -71,11 +71,11 @@ namespace Grpc.Microbenchmarks class PingClient : LiteClientBase { public PingClient(CallInvoker callInvoker) : base(callInvoker) { } - public AsyncUnaryCall PingAsync(string request, CallOptions options = default) + public AsyncUnaryCall PingAsync(string request, CallOptions options) { return CallInvoker.AsyncUnaryCall(PingMethod, null, options, request); } - public string Ping(string request, CallOptions options = default) + public string Ping(string request, CallOptions options) { return CallInvoker.BlockingUnaryCall(PingMethod, null, options, request); } From 47287e8ed7c3d458bbbf326a2434621c20526fdc Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 2 Jul 2019 08:02:23 -0400 Subject: [PATCH 25/25] add license headers --- .../Grpc.Microbenchmarks/PingBenchmark.cs | 18 ++++++++++++++++++ src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs | 18 ++++++++++++++++++ src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs index f22c52c8927..3949040aac0 100644 --- a/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/PingBenchmark.cs @@ -1,3 +1,21 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Grpc.Core; diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs index 5c5c927a260..70bbae6f400 100644 --- a/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Decode.cs @@ -1,3 +1,21 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + using System; using System.Collections.Generic; using System.Text; diff --git a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs index 95e7ad45841..3eddb33788a 100644 --- a/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs +++ b/src/csharp/Grpc.Microbenchmarks/Utf8Encode.cs @@ -1,3 +1,21 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + using System; using System.Collections.Generic; using BenchmarkDotNet.Attributes;