From 3267108e5253f43b22cca1061ba9816c0d345b38 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 30 Nov 2017 09:06:20 +0100 Subject: [PATCH] C# benchmarks provide userTime and systemTime info --- .../Grpc.IntegrationTesting/ClientRunners.cs | 13 ++- .../Grpc.IntegrationTesting/ServerRunners.cs | 13 ++- .../StressTestClient.cs | 6 +- .../Grpc.IntegrationTesting/TimeStats.cs | 90 +++++++++++++++++++ .../WallClockStopwatch.cs | 63 ------------- 5 files changed, 105 insertions(+), 80 deletions(-) create mode 100644 src/csharp/Grpc.IntegrationTesting/TimeStats.cs delete mode 100644 src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs diff --git a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs index 48905a27154..9d41d34414a 100644 --- a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs +++ b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs @@ -131,7 +131,7 @@ namespace Grpc.IntegrationTesting readonly List runnerTasks; readonly CancellationTokenSource stoppedCts = new CancellationTokenSource(); - readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch(); + readonly TimeStats timeStats = new TimeStats(); readonly AtomicCounter statsResetCount = new AtomicCounter(); public ClientRunnerImpl(List channels, ClientType clientType, RpcType rpcType, int outstandingRpcsPerChannel, LoadParams loadParams, PayloadConfig payloadConfig, HistogramParams histogramParams, Func profilerFactory) @@ -165,7 +165,7 @@ namespace Grpc.IntegrationTesting hist.GetSnapshot(histogramData, reset); } - var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds; + var timeSnapshot = timeStats.GetSnapshot(reset); if (reset) { @@ -173,15 +173,14 @@ namespace Grpc.IntegrationTesting } GrpcEnvironment.Logger.Info("[ClientRunnerImpl.GetStats] GC collection counts: gen0 {0}, gen1 {1}, gen2 {2}, (histogram reset count:{3}, seconds since reset: {4})", - GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2), statsResetCount.Count, secondsElapsed); + GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2), statsResetCount.Count, timeSnapshot.WallClockTime.TotalSeconds); - // TODO: populate user time and system time return new ClientStats { Latencies = histogramData, - TimeElapsed = secondsElapsed, - TimeUser = 0, - TimeSystem = 0 + TimeElapsed = timeSnapshot.WallClockTime.TotalSeconds, + TimeUser = timeSnapshot.UserProcessorTime.TotalSeconds, + TimeSystem = timeSnapshot.PrivilegedProcessorTime.TotalSeconds }; } diff --git a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs index e1b47744d50..ea29bd74e50 100644 --- a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs +++ b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs @@ -117,7 +117,7 @@ namespace Grpc.IntegrationTesting public class ServerRunnerImpl : IServerRunner { readonly Server server; - readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch(); + readonly TimeStats timeStats = new TimeStats(); public ServerRunnerImpl(Server server) { @@ -138,17 +138,16 @@ namespace Grpc.IntegrationTesting /// The stats. public ServerStats GetStats(bool reset) { - var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds; + var timeSnapshot = timeStats.GetSnapshot(reset); GrpcEnvironment.Logger.Info("[ServerRunner.GetStats] GC collection counts: gen0 {0}, gen1 {1}, gen2 {2}, (seconds since last reset {3})", - GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2), secondsElapsed); + GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2), timeSnapshot.WallClockTime.TotalSeconds); - // TODO: populate user time and system time return new ServerStats { - TimeElapsed = secondsElapsed, - TimeUser = 0, - TimeSystem = 0 + TimeElapsed = timeSnapshot.WallClockTime.TotalSeconds, + TimeUser = timeSnapshot.UserProcessorTime.TotalSeconds, + TimeSystem = timeSnapshot.PrivilegedProcessorTime.TotalSeconds }; } diff --git a/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs index 11956e4ac8f..0c623807681 100644 --- a/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs @@ -243,7 +243,7 @@ namespace Grpc.IntegrationTesting const string GaugeName = "csharp_overall_qps"; readonly Histogram histogram; - readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch(); + readonly TimeStats timeStats = new TimeStats(); public MetricsServiceImpl(Histogram histogram) { @@ -280,9 +280,9 @@ namespace Grpc.IntegrationTesting long GetQpsAndReset() { var snapshot = histogram.GetSnapshot(true); - var elapsedSnapshot = wallClockStopwatch.GetElapsedSnapshot(true); + var timeSnapshot = timeStats.GetSnapshot(true); - return (long) (snapshot.Count / elapsedSnapshot.TotalSeconds); + return (long) (snapshot.Count / timeSnapshot.WallClockTime.TotalSeconds); } } } diff --git a/src/csharp/Grpc.IntegrationTesting/TimeStats.cs b/src/csharp/Grpc.IntegrationTesting/TimeStats.cs new file mode 100644 index 00000000000..6aba04c1949 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/TimeStats.cs @@ -0,0 +1,90 @@ +#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.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; +using NUnit.Framework; +using Grpc.Testing; + +namespace Grpc.IntegrationTesting +{ + /// + /// Snapshottable time statistics. + /// + public class TimeStats + { + readonly object myLock = new object(); + DateTime lastWallClock; + TimeSpan lastUserTime; + TimeSpan lastPrivilegedTime; + + public TimeStats() + { + lastWallClock = DateTime.UtcNow; + lastUserTime = Process.GetCurrentProcess().UserProcessorTime; + lastPrivilegedTime = Process.GetCurrentProcess().PrivilegedProcessorTime; + } + + public Snapshot GetSnapshot(bool reset) + { + lock (myLock) + { + var wallClock = DateTime.UtcNow; + var userTime = Process.GetCurrentProcess().UserProcessorTime; + var privilegedTime = Process.GetCurrentProcess().PrivilegedProcessorTime; + var snapshot = new Snapshot(wallClock - lastWallClock, userTime - lastUserTime, privilegedTime - lastPrivilegedTime); + + if (reset) + { + lastWallClock = wallClock; + lastUserTime = userTime; + lastPrivilegedTime = privilegedTime; + } + return snapshot; + } + } + + public class Snapshot + { + public TimeSpan WallClockTime { get; } + public TimeSpan UserProcessorTime { get; } + public TimeSpan PrivilegedProcessorTime { get; } + + public Snapshot(TimeSpan wallClockTime, TimeSpan userProcessorTime, TimeSpan privilegedProcessorTime) + { + this.WallClockTime = wallClockTime; + this.UserProcessorTime = userProcessorTime; + this.PrivilegedProcessorTime = privilegedProcessorTime; + } + + public override string ToString() + { + return string.Format("[TimeStats.Snapshot: wallClock {0}, userProcessor {1}, privilegedProcessor {2}]", WallClockTime, UserProcessorTime, PrivilegedProcessorTime); + } + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs b/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs deleted file mode 100644 index 38b58f296c0..00000000000 --- a/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs +++ /dev/null @@ -1,63 +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.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; -using Google.Protobuf; -using Grpc.Core; -using Grpc.Core.Utils; -using NUnit.Framework; -using Grpc.Testing; - -namespace Grpc.IntegrationTesting -{ - /// - /// Snapshottable wall clock stopwatch. - /// - public class WallClockStopwatch - { - long startTicks; - - public WallClockStopwatch() - { - this.startTicks = DateTime.UtcNow.Ticks; - } - - public TimeSpan GetElapsedSnapshot(bool reset) - { - var utcNow = DateTime.UtcNow; - - long oldStartTicks; - if (reset) - { - oldStartTicks = Interlocked.Exchange(ref this.startTicks, utcNow.Ticks); - } - else - { - oldStartTicks = this.startTicks; - } - return utcNow - new DateTime(oldStartTicks, DateTimeKind.Utc); - } - } -}