Skip to content

Commit 517fce6

Browse files
committed
Add named pipes to benchmark apps
1 parent 83a04db commit 517fce6

File tree

5 files changed

+98
-13
lines changed

5 files changed

+98
-13
lines changed

perf/benchmarkapps/GrpcAspNetCoreServer/Program.cs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,9 @@ public static IHostBuilder CreateHostBuilder(string[] args)
6767
{
6868
var endPoint = config.CreateIPEndPoint();
6969
var udsFileName = config["udsFileName"];
70+
var namedPipeName = config["namedPipeName"];
7071

71-
if (string.IsNullOrEmpty(udsFileName))
72-
{
73-
// ListenAnyIP will work with IPv4 and IPv6.
74-
// Chosen over Listen+IPAddress.Loopback, which would have a 2 second delay when
75-
// creating a connection on a local Windows machine.
76-
options.ListenAnyIP(endPoint.Port, listenOptions =>
77-
{
78-
ConfigureListenOptions(listenOptions, config, endPoint);
79-
});
80-
}
81-
else
72+
if (!string.IsNullOrEmpty(udsFileName))
8273
{
8374
var socketPath = ResolveUdsPath(udsFileName);
8475
if (File.Exists(socketPath))
@@ -93,6 +84,24 @@ public static IHostBuilder CreateHostBuilder(string[] args)
9384
ConfigureListenOptions(listenOptions, config, endPoint);
9485
});
9586
}
87+
else if (!string.IsNullOrEmpty(namedPipeName))
88+
{
89+
Console.WriteLine($"Named pipe name: {namedPipeName}");
90+
options.ListenNamedPipe(namedPipeName, listenOptions =>
91+
{
92+
ConfigureListenOptions(listenOptions, config, endPoint);
93+
});
94+
}
95+
else
96+
{
97+
// ListenAnyIP will work with IPv4 and IPv6.
98+
// Chosen over Listen+IPAddress.Loopback, which would have a 2 second delay when
99+
// creating a connection on a local Windows machine.
100+
options.ListenAnyIP(endPoint.Port, listenOptions =>
101+
{
102+
ConfigureListenOptions(listenOptions, config, endPoint);
103+
});
104+
}
96105

97106
// Other gRPC servers don't include a server header
98107
options.AddServerHeader = false;

perf/benchmarkapps/GrpcClient/ClientOptions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class ClientOptions
2525
public Uri? Url { get; set; }
2626
#if NET5_0_OR_GREATER
2727
public string? UdsFileName { get; set; }
28+
public string? NamedPipeName { get; set; }
2829
#endif
2930
public int Connections { get; set; }
3031
public int Warmup { get; set; }
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#region Copyright notice and license
2+
3+
// Copyright 2019 The gRPC Authors
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
#endregion
18+
19+
using System.IO.Pipes;
20+
using System.Security.Principal;
21+
22+
#if NET5_0_OR_GREATER
23+
24+
namespace GrpcClient;
25+
26+
public class NamedPipeConnectionFactory
27+
{
28+
private readonly string _pipeName;
29+
private readonly TokenImpersonationLevel? _impersonationLevel;
30+
31+
public NamedPipeConnectionFactory(string pipeName, TokenImpersonationLevel? impersonationLevel = null)
32+
{
33+
_pipeName = pipeName;
34+
_impersonationLevel = impersonationLevel;
35+
}
36+
37+
public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _,
38+
CancellationToken cancellationToken = default)
39+
{
40+
var clientStream = new NamedPipeClientStream(
41+
serverName: ".",
42+
pipeName: _pipeName,
43+
direction: PipeDirection.InOut,
44+
options: PipeOptions.WriteThrough | PipeOptions.Asynchronous,
45+
impersonationLevel: _impersonationLevel ?? TokenImpersonationLevel.Anonymous);
46+
47+
try
48+
{
49+
await clientStream.ConnectAsync(cancellationToken).ConfigureAwait(false);
50+
return clientStream;
51+
}
52+
catch
53+
{
54+
clientStream.Dispose();
55+
throw;
56+
}
57+
}
58+
}
59+
60+
#endif

perf/benchmarkapps/GrpcClient/Program.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public static async Task<int> Main(string[] args)
6363
{
6464
var urlOption = new Option<Uri>(new string[] { "-u", "--url" }, "The server url to request") { IsRequired = true };
6565
var udsFileNameOption = new Option<string>(new string[] { "--udsFileName" }, "The Unix Domain Socket file name");
66+
var namedPipeNameOption = new Option<string>(new string[] { "--namedPipeName" }, "The Named Pipe name");
6667
var connectionsOption = new Option<int>(new string[] { "-c", "--connections" }, () => 1, "Total number of connections to keep open");
6768
var warmupOption = new Option<int>(new string[] { "-w", "--warmup" }, () => 5, "Duration of the warmup in seconds");
6869
var durationOption = new Option<int>(new string[] { "-d", "--duration" }, () => 10, "Duration of the test in seconds");
@@ -81,6 +82,7 @@ public static async Task<int> Main(string[] args)
8182
var rootCommand = new RootCommand();
8283
rootCommand.AddOption(urlOption);
8384
rootCommand.AddOption(udsFileNameOption);
85+
rootCommand.AddOption(namedPipeNameOption);
8486
rootCommand.AddOption(connectionsOption);
8587
rootCommand.AddOption(warmupOption);
8688
rootCommand.AddOption(durationOption);
@@ -101,6 +103,7 @@ public static async Task<int> Main(string[] args)
101103
_options = new ClientOptions();
102104
_options.Url = context.ParseResult.GetValueForOption(urlOption);
103105
_options.UdsFileName = context.ParseResult.GetValueForOption(udsFileNameOption);
106+
_options.NamedPipeName = context.ParseResult.GetValueForOption(namedPipeNameOption);
104107
_options.Connections = context.ParseResult.GetValueForOption(connectionsOption);
105108
_options.Warmup = context.ParseResult.GetValueForOption(warmupOption);
106109
_options.Duration = context.ParseResult.GetValueForOption(durationOption);
@@ -485,6 +488,11 @@ private static ChannelBase CreateChannel(string target)
485488
var connectionFactory = new UnixDomainSocketConnectionFactory(new UnixDomainSocketEndPoint(ResolveUdsPath(_options.UdsFileName)));
486489
httpClientHandler.ConnectCallback = connectionFactory.ConnectAsync;
487490
}
491+
else if (!string.IsNullOrEmpty(_options.NamedPipeName))
492+
{
493+
var connectionFactory = new NamedPipeConnectionFactory(_options.NamedPipeName);
494+
httpClientHandler.ConnectCallback = connectionFactory.ConnectAsync;
495+
}
488496
#endif
489497

490498
httpClientHandler.SslOptions.RemoteCertificateValidationCallback =

perf/benchmarkapps/README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,20 @@ View the latest results [here](https://msit.powerbi.com/view?r=eyJrIjoiYTZjMTk3Y
88

99
The benchmark environment runs the tests using `qps_json_driver`. The driver is a C++ app in https://github.com/grpc/grpc repo that is only buildable on Unix based operating systems.
1010

11-
Because the driver is challenging to get setup, the benchmarks can be run locally from the command line for quick testing. Note that there can be some differences in behavior.
11+
Because the driver is challenging to get setup, the benchmarks can be run locally from the command line for quick testing. Note that there can be some differences in behavior.
1212

13-
Example of running client using Grpc.Net.Client against Grpc.AspNetCore server:
13+
Examples of running client using Grpc.Net.Client against Grpc.AspNetCore server
14+
15+
### TCP sockets
1416

1517
1. **Launch server:** dotnet run -c Release --project .\perf\benchmarkapps\GrpcAspNetCoreServer\ --protocol h2c
1618
2. **Launch client:** dotnet run -c Release --project .\perf\benchmarkapps\GrpcClient\ -- -u http://localhost:5000 -c 10 --streams 50 -s unary -p h2c --grpcClientType grpcnetclient
1719

20+
### Named pipes
21+
22+
1. **Launch server:** dotnet run -c Release --project .\perf\benchmarkapps\GrpcAspNetCoreServer\ --protocol h2c --namedPipeName PerfPipe
23+
2. **Launch client:** dotnet run -c Release --project .\perf\benchmarkapps\GrpcClient\ -- -u http://localhost:5000 -c 10 --streams 50 -s unary -p h2c --grpcClientType grpcnetclient --namedPipeName PerfPipe
24+
1825
## QpsWorker
1926

2027
The `QpsWorker` runs in the [gRPC benchmark environment](https://grpc.io/docs/guides/benchmarking/). The worker hosts gRPC services which are used to start a benchmark server or client.

0 commit comments

Comments
 (0)