Skip to content
Snippets Groups Projects
Commit d0c1bfa5 authored by Jan Tattermusch's avatar Jan Tattermusch
Browse files

Provide performance workers for C#

parent 7fc77e06
No related branches found
No related tags found
No related merge requests found
Showing
with 4070 additions and 36 deletions
...@@ -41,7 +41,9 @@ namespace Grpc.Core.Profiling ...@@ -41,7 +41,9 @@ namespace Grpc.Core.Profiling
internal interface IProfiler internal interface IProfiler
{ {
void Begin(string tag); void Begin(string tag);
void End(string tag); void End(string tag);
void Mark(string tag); void Mark(string tag);
} }
} }
...@@ -40,7 +40,8 @@ namespace Grpc.Core.Profiling ...@@ -40,7 +40,8 @@ namespace Grpc.Core.Profiling
{ {
internal struct ProfilerEntry internal struct ProfilerEntry
{ {
public enum Type { public enum Type
{
BEGIN, BEGIN,
END, END,
MARK MARK
......
...@@ -40,12 +40,12 @@ namespace Grpc.Core.Profiling ...@@ -40,12 +40,12 @@ namespace Grpc.Core.Profiling
{ {
internal static class Profilers internal static class Profilers
{ {
static readonly NopProfiler defaultProfiler = new NopProfiler(); static readonly NopProfiler DefaultProfiler = new NopProfiler();
static readonly ThreadLocal<IProfiler> profilers = new ThreadLocal<IProfiler>(); static readonly ThreadLocal<IProfiler> profilers = new ThreadLocal<IProfiler>();
public static IProfiler ForCurrentThread() public static IProfiler ForCurrentThread()
{ {
return profilers.Value ?? defaultProfiler; return profilers.Value ?? DefaultProfiler;
} }
public static void SetForCurrentThread(IProfiler profiler) public static void SetForCurrentThread(IProfiler profiler)
...@@ -89,15 +89,18 @@ namespace Grpc.Core.Profiling ...@@ -89,15 +89,18 @@ namespace Grpc.Core.Profiling
this.entries = new ProfilerEntry[capacity]; this.entries = new ProfilerEntry[capacity];
} }
public void Begin(string tag) { public void Begin(string tag)
{
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.BEGIN, tag)); AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.BEGIN, tag));
} }
public void End(string tag) { public void End(string tag)
{
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.END, tag)); AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.END, tag));
} }
public void Mark(string tag) { public void Mark(string tag)
{
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.MARK, tag)); AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.MARK, tag));
} }
......
bin
obj
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Grpc.IntegrationTesting.QpsWorker</RootNamespace>
<AssemblyName>Grpc.IntegrationTesting.QpsWorker</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\ReleaseSigned</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
<Name>Grpc.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj">
<Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
<Name>Grpc.IntegrationTesting</Name>
</ProjectReference>
</ItemGroup>
</Project>
\ No newline at end of file
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using Grpc.IntegrationTesting;
namespace Grpc.IntegrationTesting
{
class Program
{
public static void Main(string[] args)
{
QpsWorker.Run(args);
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("Grpc.IntegrationTesting.QpsWorker")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Google.Protobuf;
using Grpc.Core;
using Grpc.Core.Utils;
namespace Grpc.Testing
{
/// <summary>
/// Implementation of BenchmarkService server
/// </summary>
public class BenchmarkServiceImpl : BenchmarkService.IBenchmarkService
{
private readonly int responseSize;
public BenchmarkServiceImpl(int responseSize)
{
this.responseSize = responseSize;
}
public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
{
var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
return Task.FromResult(response);
}
public async Task StreamingCall(IAsyncStreamReader<SimpleRequest> requestStream, IServerStreamWriter<SimpleResponse> responseStream, ServerCallContext context)
{
await requestStream.ForEachAsync(async request =>
{
var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
await responseStream.WriteAsync(response);
});
}
private static Payload CreateZerosPayload(int size)
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#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
{
/// <summary>
/// Helper methods to start client runners for performance testing.
/// </summary>
public static class ClientRunners
{
/// <summary>
/// Creates a started client runner.
/// </summary>
public static IClientRunner CreateStarted(ClientConfig config)
{
string target = config.ServerTargets.Single();
Grpc.Core.Utils.Preconditions.CheckArgument(config.LoadParams.LoadCase == LoadParams.LoadOneofCase.ClosedLoop);
var credentials = config.SecurityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure;
var channel = new Channel(target, credentials);
switch (config.RpcType)
{
case RpcType.UNARY:
return new SyncUnaryClientRunner(channel, config.PayloadConfig.SimpleParams.ReqSize);
case RpcType.STREAMING:
default:
throw new ArgumentException("Unsupported RpcType.");
}
}
}
/// <summary>
/// Client that starts synchronous unary calls in a closed loop.
/// </summary>
public class SyncUnaryClientRunner : IClientRunner
{
readonly Channel channel;
readonly int payloadSize;
readonly Histogram histogram;
readonly BenchmarkService.IBenchmarkServiceClient client;
readonly Task runnerTask;
readonly CancellationTokenSource stoppedCts;
readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
public SyncUnaryClientRunner(Channel channel, int payloadSize)
{
this.channel = Grpc.Core.Utils.Preconditions.CheckNotNull(channel);
this.payloadSize = payloadSize;
this.histogram = new Histogram(0.01, 60e9); // TODO: needs to be in sync with test/cpp/qps/histogram.h
this.stoppedCts = new CancellationTokenSource();
this.client = BenchmarkService.NewClient(channel);
this.runnerTask = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
}
public ClientStats GetStats(bool reset)
{
var histogramData = histogram.GetSnapshot(reset);
var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
// TODO: populate user time and system time
return new ClientStats
{
Latencies = histogramData,
TimeElapsed = secondsElapsed,
TimeUser = 0,
TimeSystem = 0
};
}
public async Task StopAsync()
{
stoppedCts.Cancel();
await runnerTask;
await channel.ShutdownAsync();
}
private void Run()
{
var request = new SimpleRequest
{
Payload = CreateZerosPayload(payloadSize)
};
var stopwatch = new Stopwatch();
while (!stoppedCts.Token.IsCancellationRequested)
{
stopwatch.Restart();
client.UnaryCall(request);
stopwatch.Stop();
// TODO: 1e9 needs to be in sync with C++ code
histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * 1e9);
}
}
private static Payload CreateZerosPayload(int size)
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
}
}
This diff is collapsed.
...@@ -38,55 +38,46 @@ ...@@ -38,55 +38,46 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
<Reference Include="CommandLine"> <Reference Include="CommandLine">
<HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath> <HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
</Reference> </Reference>
<Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> <Reference Include="nunit.framework">
<SpecificVersion>False</SpecificVersion> <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="BouncyCastle.Crypto">
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Auth">
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath> <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
</Reference> </Reference>
<Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> <Reference Include="Google.Apis.Auth.PlatformServices">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath> <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference> </Reference>
<Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> <Reference Include="Google.Apis.Core">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath> <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
</Reference> </Reference>
<Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL"> <Reference Include="Google.Protobuf">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath> <HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="Microsoft.Threading.Tasks">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="Microsoft.Threading.Tasks.Extensions">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference> </Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference> </Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs"> <Compile Include="..\Grpc.Core\Version.cs">
...@@ -104,6 +95,22 @@ ...@@ -104,6 +95,22 @@
<Compile Include="TestGrpc.cs" /> <Compile Include="TestGrpc.cs" />
<Compile Include="SslCredentialsTest.cs" /> <Compile Include="SslCredentialsTest.cs" />
<Compile Include="Test.cs" /> <Compile Include="Test.cs" />
<Compile Include="IClientRunner.cs" />
<Compile Include="ClientRunners.cs" />
<Compile Include="IServerRunner.cs" />
<Compile Include="ServerRunners.cs" />
<Compile Include="RunnerClientServerTest.cs" />
<Compile Include="Control.cs" />
<Compile Include="Payloads.cs" />
<Compile Include="Services.cs" />
<Compile Include="ServicesGrpc.cs" />
<Compile Include="Stats.cs" />
<Compile Include="BenchmarkServiceImpl.cs" />
<Compile Include="Histogram.cs" />
<Compile Include="HistogramTest.cs" />
<Compile Include="WorkerServiceImpl.cs" />
<Compile Include="QpsWorker.cs" />
<Compile Include="WallClockStopwatch.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
......
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#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
{
/// <summary>
/// Basic implementation of histogram based on grpc/support/histogram.h.
/// </summary>
public class Histogram
{
readonly SpinLock spinlock = new SpinLock();
readonly double multiplier;
readonly double oneOnLogMultiplier;
readonly double maxPossible;
readonly uint[] buckets;
int count;
double sum;
double sumOfSquares;
double min;
double max;
public Histogram(double resolution, double maxPossible)
{
Grpc.Core.Utils.Preconditions.CheckArgument(resolution > 0);
Grpc.Core.Utils.Preconditions.CheckArgument(maxPossible > 0);
this.maxPossible = maxPossible;
this.multiplier = 1.0 + resolution;
this.oneOnLogMultiplier = 1.0 / Math.Log(1.0 + resolution);
this.buckets = new uint[FindBucket(maxPossible) + 1];
ResetUnsafe();
}
public void AddObservation(double value)
{
bool lockTaken = false;
spinlock.Enter(ref lockTaken);
try
{
AddObservationUnsafe(value);
}
finally
{
if (lockTaken) spinlock.Exit();
}
}
/// <summary>
/// Gets snapshot of stats and reset
/// </summary>
public HistogramData GetSnapshot(bool reset = false)
{
bool lockTaken = false;
spinlock.Enter(ref lockTaken);
try
{
return GetSnapshotUnsafe(reset);
}
finally
{
if (lockTaken) spinlock.Exit();
}
}
/// <summary>
/// Finds bucket index to which given observation should go.
/// </summary>
private int FindBucket(double value)
{
value = Math.Max(value, 1.0);
value = Math.Min(value, this.maxPossible);
return (int)(Math.Log(value) * oneOnLogMultiplier);
}
private void AddObservationUnsafe(double value)
{
this.count++;
this.sum += value;
this.sumOfSquares += value * value;
this.min = Math.Min(this.min, value);
this.max = Math.Max(this.max, value);
this.buckets[FindBucket(value)]++;
}
private HistogramData GetSnapshotUnsafe(bool reset)
{
var data = new HistogramData
{
Count = count,
Sum = sum,
SumOfSquares = sumOfSquares,
MinSeen = min,
MaxSeen = max,
Bucket = { buckets }
};
if (reset)
{
ResetUnsafe();
}
return data;
}
private void ResetUnsafe()
{
this.count = 0;
this.sum = 0;
this.sumOfSquares = 0;
this.min = double.PositiveInfinity;
this.max = double.NegativeInfinity;
for (int i = 0; i < this.buckets.Length; i++)
{
this.buckets[i] = 0;
}
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
{
public class HistogramTest
{
[Test]
public void Simple()
{
var hist = new Histogram(0.01, 60e9);
hist.AddObservation(10000);
hist.AddObservation(10000);
hist.AddObservation(11000);
hist.AddObservation(11000);
var data = hist.GetSnapshot();
Assert.AreEqual(4, data.Count);
Assert.AreEqual(42000.0, data.Sum, 1e-6);
Assert.AreEqual(10000, data.MinSeen);
Assert.AreEqual(11000, data.MaxSeen);
Assert.AreEqual(2.0*10000*10000 + 2.0*11000*11000, data.SumOfSquares, 1e-6);
// 1.01^925 < 10000 < 1.01^926
Assert.AreEqual(2, data.Bucket[925]);
Assert.AreEqual(2, data.Bucket[935]);
}
[Test]
public void ExtremeObservations()
{
var hist = new Histogram(0.01, 60e9);
hist.AddObservation(-0.5); // should be in the first bucket
hist.AddObservation(1e12); // should be in the last bucket
var data = hist.GetSnapshot();
Assert.AreEqual(1, data.Bucket[0]);
Assert.AreEqual(1, data.Bucket[data.Bucket.Count - 1]);
}
[Test]
public void Reset()
{
var hist = new Histogram(0.01, 60e9);
hist.AddObservation(10000);
hist.AddObservation(11000);
var data = hist.GetSnapshot(true); // snapshot contains data before reset
Assert.AreEqual(2, data.Count);
Assert.AreEqual(10000, data.MinSeen);
Assert.AreEqual(11000, data.MaxSeen);
data = hist.GetSnapshot(); // snapshot contains state after reset
Assert.AreEqual(0, data.Count);
Assert.AreEqual(double.PositiveInfinity, data.MinSeen);
Assert.AreEqual(double.NegativeInfinity, data.MaxSeen);
Assert.AreEqual(0, data.Sum);
Assert.AreEqual(0, data.SumOfSquares);
CollectionAssert.AreEqual(new uint[data.Bucket.Count], data.Bucket);
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Google.Protobuf;
using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
using Grpc.Testing;
namespace Grpc.IntegrationTesting
{
/// <summary>
/// Abstract client runner.
/// </summary>
public interface IClientRunner
{
/// <summary>
/// Gets stats snapshot.
/// </summary>
/// <returns>The stats.</returns>
ClientStats GetStats(bool reset);
/// <summary>
/// Asynchronously stops the client.
/// </summary>
/// <returns>Task that finishes when client has come to a full stop.</returns>
Task StopAsync();
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Google.Protobuf;
using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
using Grpc.Testing;
namespace Grpc.IntegrationTesting
{
/// <summary>
/// Abstract server runner.
/// </summary>
public interface IServerRunner
{
/// <summary>
/// Port on which the server is listening.
/// </summary>
int BoundPort { get; }
/// <summary>
/// Gets server stats.
/// </summary>
/// <returns>The stats.</returns>
ServerStats GetStats(bool reset);
/// <summary>
/// Asynchronously stops the server.
/// </summary>
/// <returns>Task that finishes when server has shutdown.</returns>
Task StopAsync();
}
}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: test/proto/benchmarks/payloads.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Grpc.Testing {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Payloads {
#region Descriptor
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static Payloads() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"CiR0ZXN0L3Byb3RvL2JlbmNobWFya3MvcGF5bG9hZHMucHJvdG8SDGdycGMu",
"dGVzdGluZyI3ChBCeXRlQnVmZmVyUGFyYW1zEhAKCHJlcV9zaXplGAEgASgF",
"EhEKCXJlc3Bfc2l6ZRgCIAEoBSI4ChFTaW1wbGVQcm90b1BhcmFtcxIQCghy",
"ZXFfc2l6ZRgBIAEoBRIRCglyZXNwX3NpemUYAiABKAUiFAoSQ29tcGxleFBy",
"b3RvUGFyYW1zIsoBCg1QYXlsb2FkQ29uZmlnEjgKDmJ5dGVidWZfcGFyYW1z",
"GAEgASgLMh4uZ3JwYy50ZXN0aW5nLkJ5dGVCdWZmZXJQYXJhbXNIABI4Cg1z",
"aW1wbGVfcGFyYW1zGAIgASgLMh8uZ3JwYy50ZXN0aW5nLlNpbXBsZVByb3Rv",
"UGFyYW1zSAASOgoOY29tcGxleF9wYXJhbXMYAyABKAsyIC5ncnBjLnRlc3Rp",
"bmcuQ29tcGxleFByb3RvUGFyYW1zSABCCQoHcGF5bG9hZGIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ByteBufferParams), new[]{ "ReqSize", "RespSize" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleProtoParams), new[]{ "ReqSize", "RespSize" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ComplexProtoParams), null, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.PayloadConfig), new[]{ "BytebufParams", "SimpleParams", "ComplexParams" }, new[]{ "Payload" }, null, null)
}));
}
#endregion
}
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class ByteBufferParams : pb::IMessage<ByteBufferParams> {
private static readonly pb::MessageParser<ByteBufferParams> _parser = new pb::MessageParser<ByteBufferParams>(() => new ByteBufferParams());
public static pb::MessageParser<ByteBufferParams> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[0]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
public ByteBufferParams() {
OnConstruction();
}
partial void OnConstruction();
public ByteBufferParams(ByteBufferParams other) : this() {
reqSize_ = other.reqSize_;
respSize_ = other.respSize_;
}
public ByteBufferParams Clone() {
return new ByteBufferParams(this);
}
public const int ReqSizeFieldNumber = 1;
private int reqSize_;
public int ReqSize {
get { return reqSize_; }
set {
reqSize_ = value;
}
}
public const int RespSizeFieldNumber = 2;
private int respSize_;
public int RespSize {
get { return respSize_; }
set {
respSize_ = value;
}
}
public override bool Equals(object other) {
return Equals(other as ByteBufferParams);
}
public bool Equals(ByteBufferParams other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (ReqSize != other.ReqSize) return false;
if (RespSize != other.RespSize) return false;
return true;
}
public override int GetHashCode() {
int hash = 1;
if (ReqSize != 0) hash ^= ReqSize.GetHashCode();
if (RespSize != 0) hash ^= RespSize.GetHashCode();
return hash;
}
public override string ToString() {
return pb::JsonFormatter.Default.Format(this);
}
public void WriteTo(pb::CodedOutputStream output) {
if (ReqSize != 0) {
output.WriteRawTag(8);
output.WriteInt32(ReqSize);
}
if (RespSize != 0) {
output.WriteRawTag(16);
output.WriteInt32(RespSize);
}
}
public int CalculateSize() {
int size = 0;
if (ReqSize != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize);
}
if (RespSize != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize);
}
return size;
}
public void MergeFrom(ByteBufferParams other) {
if (other == null) {
return;
}
if (other.ReqSize != 0) {
ReqSize = other.ReqSize;
}
if (other.RespSize != 0) {
RespSize = other.RespSize;
}
}
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 8: {
ReqSize = input.ReadInt32();
break;
}
case 16: {
RespSize = input.ReadInt32();
break;
}
}
}
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class SimpleProtoParams : pb::IMessage<SimpleProtoParams> {
private static readonly pb::MessageParser<SimpleProtoParams> _parser = new pb::MessageParser<SimpleProtoParams>(() => new SimpleProtoParams());
public static pb::MessageParser<SimpleProtoParams> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[1]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
public SimpleProtoParams() {
OnConstruction();
}
partial void OnConstruction();
public SimpleProtoParams(SimpleProtoParams other) : this() {
reqSize_ = other.reqSize_;
respSize_ = other.respSize_;
}
public SimpleProtoParams Clone() {
return new SimpleProtoParams(this);
}
public const int ReqSizeFieldNumber = 1;
private int reqSize_;
public int ReqSize {
get { return reqSize_; }
set {
reqSize_ = value;
}
}
public const int RespSizeFieldNumber = 2;
private int respSize_;
public int RespSize {
get { return respSize_; }
set {
respSize_ = value;
}
}
public override bool Equals(object other) {
return Equals(other as SimpleProtoParams);
}
public bool Equals(SimpleProtoParams other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (ReqSize != other.ReqSize) return false;
if (RespSize != other.RespSize) return false;
return true;
}
public override int GetHashCode() {
int hash = 1;
if (ReqSize != 0) hash ^= ReqSize.GetHashCode();
if (RespSize != 0) hash ^= RespSize.GetHashCode();
return hash;
}
public override string ToString() {
return pb::JsonFormatter.Default.Format(this);
}
public void WriteTo(pb::CodedOutputStream output) {
if (ReqSize != 0) {
output.WriteRawTag(8);
output.WriteInt32(ReqSize);
}
if (RespSize != 0) {
output.WriteRawTag(16);
output.WriteInt32(RespSize);
}
}
public int CalculateSize() {
int size = 0;
if (ReqSize != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize);
}
if (RespSize != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize);
}
return size;
}
public void MergeFrom(SimpleProtoParams other) {
if (other == null) {
return;
}
if (other.ReqSize != 0) {
ReqSize = other.ReqSize;
}
if (other.RespSize != 0) {
RespSize = other.RespSize;
}
}
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 8: {
ReqSize = input.ReadInt32();
break;
}
case 16: {
RespSize = input.ReadInt32();
break;
}
}
}
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class ComplexProtoParams : pb::IMessage<ComplexProtoParams> {
private static readonly pb::MessageParser<ComplexProtoParams> _parser = new pb::MessageParser<ComplexProtoParams>(() => new ComplexProtoParams());
public static pb::MessageParser<ComplexProtoParams> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[2]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
public ComplexProtoParams() {
OnConstruction();
}
partial void OnConstruction();
public ComplexProtoParams(ComplexProtoParams other) : this() {
}
public ComplexProtoParams Clone() {
return new ComplexProtoParams(this);
}
public override bool Equals(object other) {
return Equals(other as ComplexProtoParams);
}
public bool Equals(ComplexProtoParams other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
return true;
}
public override int GetHashCode() {
int hash = 1;
return hash;
}
public override string ToString() {
return pb::JsonFormatter.Default.Format(this);
}
public void WriteTo(pb::CodedOutputStream output) {
}
public int CalculateSize() {
int size = 0;
return size;
}
public void MergeFrom(ComplexProtoParams other) {
if (other == null) {
return;
}
}
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
}
}
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class PayloadConfig : pb::IMessage<PayloadConfig> {
private static readonly pb::MessageParser<PayloadConfig> _parser = new pb::MessageParser<PayloadConfig>(() => new PayloadConfig());
public static pb::MessageParser<PayloadConfig> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[3]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
public PayloadConfig() {
OnConstruction();
}
partial void OnConstruction();
public PayloadConfig(PayloadConfig other) : this() {
switch (other.PayloadCase) {
case PayloadOneofCase.BytebufParams:
BytebufParams = other.BytebufParams.Clone();
break;
case PayloadOneofCase.SimpleParams:
SimpleParams = other.SimpleParams.Clone();
break;
case PayloadOneofCase.ComplexParams:
ComplexParams = other.ComplexParams.Clone();
break;
}
}
public PayloadConfig Clone() {
return new PayloadConfig(this);
}
public const int BytebufParamsFieldNumber = 1;
public global::Grpc.Testing.ByteBufferParams BytebufParams {
get { return payloadCase_ == PayloadOneofCase.BytebufParams ? (global::Grpc.Testing.ByteBufferParams) payload_ : null; }
set {
payload_ = value;
payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BytebufParams;
}
}
public const int SimpleParamsFieldNumber = 2;
public global::Grpc.Testing.SimpleProtoParams SimpleParams {
get { return payloadCase_ == PayloadOneofCase.SimpleParams ? (global::Grpc.Testing.SimpleProtoParams) payload_ : null; }
set {
payload_ = value;
payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.SimpleParams;
}
}
public const int ComplexParamsFieldNumber = 3;
public global::Grpc.Testing.ComplexProtoParams ComplexParams {
get { return payloadCase_ == PayloadOneofCase.ComplexParams ? (global::Grpc.Testing.ComplexProtoParams) payload_ : null; }
set {
payload_ = value;
payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.ComplexParams;
}
}
private object payload_;
public enum PayloadOneofCase {
None = 0,
BytebufParams = 1,
SimpleParams = 2,
ComplexParams = 3,
}
private PayloadOneofCase payloadCase_ = PayloadOneofCase.None;
public PayloadOneofCase PayloadCase {
get { return payloadCase_; }
}
public void ClearPayload() {
payloadCase_ = PayloadOneofCase.None;
payload_ = null;
}
public override bool Equals(object other) {
return Equals(other as PayloadConfig);
}
public bool Equals(PayloadConfig other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(BytebufParams, other.BytebufParams)) return false;
if (!object.Equals(SimpleParams, other.SimpleParams)) return false;
if (!object.Equals(ComplexParams, other.ComplexParams)) return false;
return true;
}
public override int GetHashCode() {
int hash = 1;
if (payloadCase_ == PayloadOneofCase.BytebufParams) hash ^= BytebufParams.GetHashCode();
if (payloadCase_ == PayloadOneofCase.SimpleParams) hash ^= SimpleParams.GetHashCode();
if (payloadCase_ == PayloadOneofCase.ComplexParams) hash ^= ComplexParams.GetHashCode();
return hash;
}
public override string ToString() {
return pb::JsonFormatter.Default.Format(this);
}
public void WriteTo(pb::CodedOutputStream output) {
if (payloadCase_ == PayloadOneofCase.BytebufParams) {
output.WriteRawTag(10);
output.WriteMessage(BytebufParams);
}
if (payloadCase_ == PayloadOneofCase.SimpleParams) {
output.WriteRawTag(18);
output.WriteMessage(SimpleParams);
}
if (payloadCase_ == PayloadOneofCase.ComplexParams) {
output.WriteRawTag(26);
output.WriteMessage(ComplexParams);
}
}
public int CalculateSize() {
int size = 0;
if (payloadCase_ == PayloadOneofCase.BytebufParams) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(BytebufParams);
}
if (payloadCase_ == PayloadOneofCase.SimpleParams) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(SimpleParams);
}
if (payloadCase_ == PayloadOneofCase.ComplexParams) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ComplexParams);
}
return size;
}
public void MergeFrom(PayloadConfig other) {
if (other == null) {
return;
}
switch (other.PayloadCase) {
case PayloadOneofCase.BytebufParams:
BytebufParams = other.BytebufParams;
break;
case PayloadOneofCase.SimpleParams:
SimpleParams = other.SimpleParams;
break;
case PayloadOneofCase.ComplexParams:
ComplexParams = other.ComplexParams;
break;
}
}
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
global::Grpc.Testing.ByteBufferParams subBuilder = new global::Grpc.Testing.ByteBufferParams();
if (payloadCase_ == PayloadOneofCase.BytebufParams) {
subBuilder.MergeFrom(BytebufParams);
}
input.ReadMessage(subBuilder);
BytebufParams = subBuilder;
break;
}
case 18: {
global::Grpc.Testing.SimpleProtoParams subBuilder = new global::Grpc.Testing.SimpleProtoParams();
if (payloadCase_ == PayloadOneofCase.SimpleParams) {
subBuilder.MergeFrom(SimpleParams);
}
input.ReadMessage(subBuilder);
SimpleParams = subBuilder;
break;
}
case 26: {
global::Grpc.Testing.ComplexProtoParams subBuilder = new global::Grpc.Testing.ComplexProtoParams();
if (payloadCase_ == PayloadOneofCase.ComplexParams) {
subBuilder.MergeFrom(ComplexParams);
}
input.ReadMessage(subBuilder);
ComplexParams = subBuilder;
break;
}
}
}
}
}
#endregion
}
#endregion Designer generated code
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using CommandLine;
using CommandLine.Text;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
{
public class QpsWorker
{
private class ServerOptions
{
[Option("driver_port", DefaultValue = 0)]
public int DriverPort { get; set; }
[HelpOption]
public string GetUsage()
{
var help = new HelpText
{
Heading = "gRPC C# performance testing worker",
AddDashesToOption = true
};
help.AddPreOptionsLine("Usage:");
help.AddOptions(this);
return help;
}
}
ServerOptions options;
private QpsWorker(ServerOptions options)
{
this.options = options;
}
public static void Run(string[] args)
{
var options = new ServerOptions();
if (!Parser.Default.ParseArguments(args, options))
{
Environment.Exit(1);
}
var workerServer = new QpsWorker(options);
workerServer.Run();
}
private void Run()
{
string host = "0.0.0.0";
int port = options.DriverPort;
var server = new Server
{
Services = { WorkerService.BindService(new WorkerServiceImpl()) },
Ports = { new ServerPort(host, options.DriverPort, ServerCredentials.Insecure )}
};
int boundPort = server.Ports.Single().BoundPort;
Console.WriteLine("Running qps worker server on " + string.Format("{0}:{1}", host, boundPort));
server.Start();
server.ShutdownTask.Wait();
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
{
/// <summary>
/// Runs performance tests in-process.
/// </summary>
public class RunnerClientServerTest
{
const string Host = "localhost";
IServerRunner serverRunner;
[TestFixtureSetUp]
public void Init()
{
var serverConfig = new ServerConfig
{
ServerType = ServerType.ASYNC_SERVER,
PayloadConfig = new PayloadConfig
{
SimpleParams = new SimpleProtoParams
{
RespSize = 100
}
}
};
serverRunner = ServerRunners.CreateStarted(serverConfig);
}
[TestFixtureTearDown]
public void Cleanup()
{
serverRunner.StopAsync().Wait();
}
[Test]
public async Task ClientServerRunner()
{
var config = new ClientConfig
{
ServerTargets = { string.Format("{0}:{1}", Host, serverRunner.BoundPort) },
RpcType = RpcType.UNARY,
LoadParams = new LoadParams { ClosedLoop = new ClosedLoopParams() },
PayloadConfig = new PayloadConfig
{
SimpleParams = new SimpleProtoParams
{
ReqSize = 100
}
}
};
var runner = ClientRunners.CreateStarted(config);
System.Console.WriteLine("Warming up");
await Task.Delay(3000);
runner.GetStats(true); // throw away warm-up data
System.Console.WriteLine("Benchmarking");
await Task.Delay(3000);
var stats = runner.GetStats(true);
await runner.StopAsync();
System.Console.WriteLine(stats);
System.Console.WriteLine("avg micros/call " + (long) ((stats.Latencies.Sum / stats.Latencies.Count) * 1000000));
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#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
{
/// <summary>
/// Helper methods to start server runners for performance testing.
/// </summary>
public static class ServerRunners
{
/// <summary>
/// Creates a started server runner.
/// </summary>
public static IServerRunner CreateStarted(ServerConfig config)
{
Grpc.Core.Utils.Preconditions.CheckArgument(config.ServerType == ServerType.ASYNC_SERVER);
var credentials = config.SecurityParams != null ? TestCredentials.CreateSslServerCredentials() : ServerCredentials.Insecure;
// TODO: qps_driver needs to setup payload properly...
int responseSize = config.PayloadConfig != null ? config.PayloadConfig.SimpleParams.RespSize : 0;
var server = new Server
{
Services = { BenchmarkService.BindService(new BenchmarkServiceImpl(responseSize)) },
Ports = { new ServerPort("0.0.0.0", config.Port, credentials) }
};
server.Start();
return new ServerRunnerImpl(server);
}
}
/// <summary>
/// Server runner.
/// </summary>
public class ServerRunnerImpl : IServerRunner
{
readonly Server server;
readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
public ServerRunnerImpl(Server server)
{
this.server = Grpc.Core.Utils.Preconditions.CheckNotNull(server);
}
public int BoundPort
{
get
{
return server.Ports.Single().BoundPort;
}
}
/// <summary>
/// Gets server stats.
/// </summary>
/// <returns>The stats.</returns>
public ServerStats GetStats(bool reset)
{
var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
// TODO: populate user time and system time
return new ServerStats
{
TimeElapsed = secondsElapsed,
TimeUser = 0,
TimeSystem = 0
};
}
/// <summary>
/// Asynchronously stops the server.
/// </summary>
/// <returns>Task that finishes when server has shutdown.</returns>
public Task StopAsync()
{
return server.ShutdownAsync();
}
}
}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: test/proto/benchmarks/services.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Grpc.Testing {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Services {
#region Descriptor
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static Services() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"CiR0ZXN0L3Byb3RvL2JlbmNobWFya3Mvc2VydmljZXMucHJvdG8SDGdycGMu",
"dGVzdGluZxoZdGVzdC9wcm90by9tZXNzYWdlcy5wcm90bxojdGVzdC9wcm90",
"by9iZW5jaG1hcmtzL2NvbnRyb2wucHJvdG8yqgEKEEJlbmNobWFya1NlcnZp",
"Y2USRgoJVW5hcnlDYWxsEhsuZ3JwYy50ZXN0aW5nLlNpbXBsZVJlcXVlc3Qa",
"HC5ncnBjLnRlc3RpbmcuU2ltcGxlUmVzcG9uc2USTgoNU3RyZWFtaW5nQ2Fs",
"bBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0aW5n",
"LlNpbXBsZVJlc3BvbnNlKAEwATKdAQoNV29ya2VyU2VydmljZRJFCglSdW5T",
"ZXJ2ZXISGC5ncnBjLnRlc3RpbmcuU2VydmVyQXJncxoaLmdycGMudGVzdGlu",
"Zy5TZXJ2ZXJTdGF0dXMoATABEkUKCVJ1bkNsaWVudBIYLmdycGMudGVzdGlu",
"Zy5DbGllbnRBcmdzGhouZ3JwYy50ZXN0aW5nLkNsaWVudFN0YXR1cygBMAFi",
"BnByb3RvMw=="));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.Messages.Descriptor, global::Grpc.Testing.Control.Descriptor, },
new pbr::GeneratedCodeInfo(null, null));
}
#endregion
}
}
#endregion Designer generated code
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment