diff --git a/build/httpclient-scenarios.yml b/build/httpclient-scenarios.yml index d1d63f8d9..0af17a5fd 100644 --- a/build/httpclient-scenarios.yml +++ b/build/httpclient-scenarios.yml @@ -19,13 +19,13 @@ parameters: type: string default: '--client.framework net9.0 --server.framework net8.0' # net8.0 for server is a temporary workaround -- name: getScenarios +- name: getScenarios type: object default: - displayName: "GET" arguments: --scenario httpclient-kestrel-get --variable useHttpMessageInvoker=true --property server=kestrel --property client=dotnetinvoker --property method=get --client.options.collectCounters true -- name: postScenarios +- name: postScenarios type: object default: - displayName: "POST" @@ -41,7 +41,9 @@ parameters: - displayName: "HTTP/2.0 (mult conn)" arguments: --variable httpVersion=2.0 --variable useHttps=true --variable http20EnableMultipleConnections=true --property httpversion=h2multconn - displayName: "HTTP/3.0" - arguments: --variable httpVersion=3.0 --variable useHttps=true --property httpversion=h3 + arguments: --variable httpVersion=3.0 --variable useHttps=true --variable http30EnableMultipleConnections=false --property httpversion=h3 + - displayName: "HTTP/3.0 (mult conn)" + arguments: --variable httpVersion=3.0 --variable useHttps=true --variable http30EnableMultipleConnections=true --property httpversion=h3multconn - name: clientsxThreads type: object diff --git a/scenarios/README.md b/scenarios/README.md index 0b8b5cda8..ec16fe482 100644 --- a/scenarios/README.md +++ b/scenarios/README.md @@ -8,7 +8,7 @@ Continuous benchmarking results are available on [this PowerBI dashboard](https: ## Requirements -These jobs can be executed using the .NET Crank global tool. +These jobs can be executed using the .NET Crank global tool. [.NET Core]() is required to install the global tool. Install `crank` with the following command: @@ -62,7 +62,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario ### Available scenarios -- `plaintext`: Middleware implementation +- `plaintext`: Middleware implementation - `https`: Middleware implementation, using HTTPS - `endpoint`: Middleware implementation with Endpoint routing - `mvc`: Controller implementation @@ -85,7 +85,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario ### Available scenarios -- `json`: Middleware implementation +- `json`: Middleware implementation - `https`: Middleware implementation, using HTTPS - `mvc`: Controller implementation - `mapaction`: Endpoint routing implementation @@ -125,8 +125,8 @@ The following scenarios are using ASP.NET CORE MVC - `fortunes_ef_mvc_https` The suffixes represent different database access strategies: - -- No suffix: Raw ADO.NET + +- No suffix: Raw ADO.NET - "ef" suffix: Entity Framework Core - "dapper" suffix: Dapper @@ -159,7 +159,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario These scenarios are running several web proxies, including [YARP](https://github.com/microsoft/reverse-proxy). -The downstream service returns a variable size content. By default the result is 10 bytes. +The downstream service returns a variable size content. By default the result is 10 bytes. ### Sample @@ -261,7 +261,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario These scenarios measure the performance of different Grpc server and clients implementations. - Go -- Native (C) +- Native (C) - ASP.NET ### Sample @@ -287,13 +287,13 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario #### Arguments -- Number of streams: +- Number of streams: - `--variable streams=1` - `--variable streams=70` -- Number of connections: +- Number of connections: - `--variable connections=1` - `--variable connections=28` -- Protocol: +- Protocol: - `--variable protocol=h2` - `--variable protocol=h3` - `--variable protocol=h2c` @@ -345,15 +345,15 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario #### Arguments -- Scenario: +- Scenario: - `--variable scenario=broadcast` - `--variable scenario=echo` - `--variable scenario=echoAll` -- Transport: +- Transport: - `--variable transport=websockets` - `--variable transport=serversentevents` - `--variable transport=longpolling` -- Protocol: +- Protocol: - `--variable protocol=json` - `--variable protocol=messagepack` @@ -397,7 +397,7 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario These scenarios are running various distributed cache benchmarks. -For all the scenarios, the store is initialized with `CacheCount` cache entries. Each request will issue a read or a write based on the `WriteRatio` +For all the scenarios, the store is initialized with `CacheCount` cache entries. Each request will issue a read or a write based on the `WriteRatio` argument choosing a key randomly. The HTTP response won't contain the cache entry data so that it doesn't impact the raw store perf measurement. ### Sample @@ -512,6 +512,9 @@ crank --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenario - Enable multiple HTTP/2.0 connections: - `--variable http20EnableMultipleConnections=true` (default) - `--variable http20EnableMultipleConnections=false` +- Enable multiple HTTP/3.0 connections (from .NET 9.0): + - `--variable http30EnableMultipleConnections=true` (default) + - `--variable http30EnableMultipleConnections=false` - Whether to use WinHttpHandler instead of SocketsHttpHandler: - `--variable useWinHttpHandler=false` (default) - `--variable useWinHttpHandler=true` -- *requires Windows* @@ -538,7 +541,7 @@ These scenarios provide benchmarks to help improve the performance of the .NET G ### Sample ``` -crank --config https://raw.githubusercontent.com/dotnet/performance/main/src/benchmarks/gc/scenarios/CrankConfiguration.yaml --scenario 2gb-pinning --profile aspnet-citrine-win --application.framework net9.0 +crank --config https://raw.githubusercontent.com/dotnet/performance/main/src/benchmarks/gc/scenarios/CrankConfiguration.yaml --scenario 2gb-pinning --profile aspnet-citrine-win --application.framework net9.0 ``` ### Available scenarios diff --git a/scenarios/httpclient.benchmarks.yml b/scenarios/httpclient.benchmarks.yml index eef4d8742..666fdc303 100644 --- a/scenarios/httpclient.benchmarks.yml +++ b/scenarios/httpclient.benchmarks.yml @@ -25,6 +25,7 @@ variables: # HttpClient-specific parameters: http11MaxConnectionsPerServer: 0 #unlimited http20EnableMultipleConnections: true + http30EnableMultipleConnections: true useWinHttpHandler: false useHttpMessageInvoker: false useDefaultRequestHeaders: false @@ -102,6 +103,7 @@ scenarios: numberOfHttpClients: 1 concurrencyPerHttpClient: '{% if cores > 0 %}{{cores}}{% else %}1{% endif %}' http20EnableMultipleConnections: false + http30EnableMultipleConnections: false useHttpMessageInvoker: true host: '{{secondaryAddress}}' @@ -168,7 +170,7 @@ jobs: isConsoleApp: true waitForExit: true timeout: 1200 #seconds - arguments: '--address {{host}} --port {{serverPort}} --useHttps {{useHttps}} --path /{{scenario}} --scenario {{scenario}} --httpVersion {{httpVersion}} --numberOfHttpClients {{numberOfHttpClients}} --concurrencyPerHttpClient {{concurrencyPerHttpClient}} --http11MaxConnectionsPerServer {{http11MaxConnectionsPerServer}} --http20EnableMultipleConnections {{http20EnableMultipleConnections}} --useWinHttpHandler {{useWinHttpHandler}} --useHttpMessageInvoker {{useHttpMessageInvoker}} --collectRequestTimings {{collectRequestTimings}} --contentSize {{requestContentSize}} --contentWriteSize {{requestContentWriteSize}} --contentFlushAfterWrite {{requestContentFlushAfterWrite}} --contentUnknownLength {{requestContentUnknownLength}} {{headersDictionary[requestHeaders]}} --generatedStaticHeadersCount {{generatedStaticRequestHeadersCount}} --generatedDynamicHeadersCount {{generatedDynamicRequestHeadersCount}} --useDefaultRequestHeaders {{useDefaultRequestHeaders}} --warmup {{warmup}} --duration {{duration}}' + arguments: '--address {{host}} --port {{serverPort}} --useHttps {{useHttps}} --path /{{scenario}} --scenario {{scenario}} --httpVersion {{httpVersion}} --numberOfHttpClients {{numberOfHttpClients}} --concurrencyPerHttpClient {{concurrencyPerHttpClient}} --http11MaxConnectionsPerServer {{http11MaxConnectionsPerServer}} --http20EnableMultipleConnections {{http20EnableMultipleConnections}} --http30EnableMultipleConnections {{http30EnableMultipleConnections}} --useWinHttpHandler {{useWinHttpHandler}} --useHttpMessageInvoker {{useHttpMessageInvoker}} --collectRequestTimings {{collectRequestTimings}} --contentSize {{requestContentSize}} --contentWriteSize {{requestContentWriteSize}} --contentFlushAfterWrite {{requestContentFlushAfterWrite}} --contentUnknownLength {{requestContentUnknownLength}} {{headersDictionary[requestHeaders]}} --generatedStaticHeadersCount {{generatedStaticRequestHeadersCount}} --generatedDynamicHeadersCount {{generatedDynamicRequestHeadersCount}} --useDefaultRequestHeaders {{useDefaultRequestHeaders}} --warmup {{warmup}} --duration {{duration}}' wrk: source: diff --git a/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptions.cs b/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptions.cs index 6d56617b0..60f7f5062 100644 --- a/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptions.cs +++ b/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptions.cs @@ -18,6 +18,7 @@ public class ClientOptions public int ConcurrencyPerHttpClient { get; set; } public int Http11MaxConnectionsPerServer { get; set; } public bool Http20EnableMultipleConnections { get; set; } + public bool Http30EnableMultipleConnections { get; set; } public bool UseWinHttpHandler { get; set; } public bool UseHttpMessageInvoker { get; set; } public bool CollectRequestTimings { get; set; } @@ -37,9 +38,9 @@ public override string ToString() { return $"Address={Address}; Port={Port}; UseHttps={UseHttps}; Path={Path}; HttpVersion={HttpVersion}; NumberOfHttpClients={NumberOfHttpClients}; " + $"ConcurrencyPerHttpClient={ConcurrencyPerHttpClient}; Http11MaxConnectionsPerServer={Http11MaxConnectionsPerServer}; " + - $"Http20EnableMultipleConnections={Http20EnableMultipleConnections}; UseWinHttpHandler={UseWinHttpHandler}; " + - $"UseHttpMessageInvoker={UseHttpMessageInvoker}; CollectRequestTimings={CollectRequestTimings}; Scenario={Scenario}; " + - $"ContentSize={ContentSize}; ContentWriteSize={ContentWriteSize}; ContentFlushAfterWrite={ContentFlushAfterWrite}; " + + $"Http20EnableMultipleConnections={Http20EnableMultipleConnections}; Http30EnableMultipleConnections={Http30EnableMultipleConnections}; " + + $"UseWinHttpHandler={UseWinHttpHandler}; UseHttpMessageInvoker={UseHttpMessageInvoker}; CollectRequestTimings={CollectRequestTimings}; " + + $"Scenario={Scenario}; ContentSize={ContentSize}; ContentWriteSize={ContentWriteSize}; ContentFlushAfterWrite={ContentFlushAfterWrite}; " + $"ContentUnknownLength={ContentUnknownLength}; Headers=[{string.Join(", ", Headers.Select(h => $"\"{h.Name}: {h.Value}\""))}]; " + $"GeneratedStaticHeadersCount={GeneratedStaticHeadersCount}; GeneratedDynamicHeadersCount={GeneratedDynamicHeadersCount}; " + $"UseDefaultRequestHeaders={UseDefaultRequestHeaders}; Warmup={Warmup}; Duration={Duration}"; diff --git a/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptionsBinder.cs b/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptionsBinder.cs index b40715078..a1e78bc7e 100644 --- a/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptionsBinder.cs +++ b/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/ClientOptionsBinder.cs @@ -15,6 +15,7 @@ public class ClientOptionsBinder : BinderBase public static Option ConcurrencyPerHttpClientOption { get; } = new Option("--concurrencyPerHttpClient", () => 1, "Number of concurrect requests per one HttpClient"); public static Option Http11MaxConnectionsPerServerOption { get; } = new Option("--http11MaxConnectionsPerServer", () => 0, "Max number of HTTP/1.1 connections per server, 0 for unlimited"); public static Option Http20EnableMultipleConnectionsOption { get; } = new Option("--http20EnableMultipleConnections", () => true, "Enable multiple HTTP/2.0 connections"); + public static Option Http30EnableMultipleConnectionsOption { get; } = new Option("--http30EnableMultipleConnections", () => true, "Enable multiple HTTP/3.0 connections"); public static Option UseWinHttpHandlerOption { get; } = new Option("--useWinHttpHandler", () => false, "Use WinHttpHandler instead of SocketsHttpHandler"); public static Option UseHttpMessageInvokerOption { get; } = new Option("--useHttpMessageInvoker", () => false, "Use HttpMessageInvoker instead of HttpClient"); public static Option CollectRequestTimingsOption { get; } = new Option("--collectRequestTimings", () => false, "Collect percentiled metrics of request timings"); @@ -41,6 +42,7 @@ public static void AddOptionsToCommand(RootCommand command) command.AddOption(ConcurrencyPerHttpClientOption); command.AddOption(Http11MaxConnectionsPerServerOption); command.AddOption(Http20EnableMultipleConnectionsOption); + command.AddOption(Http30EnableMultipleConnectionsOption); command.AddOption(UseWinHttpHandlerOption); command.AddOption(UseHttpMessageInvokerOption); command.AddOption(CollectRequestTimingsOption); @@ -72,6 +74,7 @@ protected override ClientOptions GetBoundValue(BindingContext bindingContext) ConcurrencyPerHttpClient = parsed.GetValueForOption(ConcurrencyPerHttpClientOption), Http11MaxConnectionsPerServer = parsed.GetValueForOption(Http11MaxConnectionsPerServerOption), Http20EnableMultipleConnections = parsed.GetValueForOption(Http20EnableMultipleConnectionsOption), + Http30EnableMultipleConnections = parsed.GetValueForOption(Http30EnableMultipleConnectionsOption), UseWinHttpHandler = parsed.GetValueForOption(UseWinHttpHandlerOption), UseHttpMessageInvoker = parsed.GetValueForOption(UseHttpMessageInvokerOption), CollectRequestTimings = parsed.GetValueForOption(CollectRequestTimingsOption), diff --git a/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/Program.cs b/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/Program.cs index 28b3eac68..cc4a254cd 100644 --- a/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/Program.cs +++ b/src/BenchmarksApps/HttpClientBenchmarks/Clients/HttpClient/Program.cs @@ -129,6 +129,9 @@ private static async Task Setup() SslOptions = new SslClientAuthenticationOptions { RemoteCertificateValidationCallback = delegate { return true; } }, MaxConnectionsPerServer = max11ConnectionsPerServer, EnableMultipleHttp2Connections = s_options.Http20EnableMultipleConnections, + #if NET9_0_OR_GREATER + EnableMultipleHttp3Connections = s_options.Http30EnableMultipleConnections, + #endif ConnectTimeout = Timeout.InfiniteTimeSpan, }; } @@ -396,7 +399,7 @@ private static void CreateRequestContentData() } private static HttpRequestMessage CreateRequest(HttpMethod method, Uri uri) => - new HttpRequestMessage(method, uri) { + new HttpRequestMessage(method, uri) { Version = s_options.HttpVersion!, VersionPolicy = HttpVersionPolicy.RequestVersionExact };