From b608846c097f8d0c9c7fc409ea96b783e1f0071a Mon Sep 17 00:00:00 2001 From: James Tayler Date: Wed, 12 Apr 2023 18:25:27 +1200 Subject: [PATCH] Add benchmark dotnet and comprehensive set of end to end benchmarks (#1175) * add BenchmarkDotNet and comprehensive set of end to end benchmarks * http content does indeed throw * cleanup unused variables * fix benchmark that was complaining about IEnumerable return type and test against only 3 orders of magnitue * fix memory leak in benchmarks * allow controlling benchmarks from command line * run all end to end benchmarks if no args supplied, else run benchmarks for the args supplied * cut down number of benchmarks * mock http was the wrong tool for the job here - fixed the benchmarks by returning static payloads instead as no state hangs around between runs * add scripts to run benchmarks for each return type * add multi-targeting support to benchmarks --- .gitignore | 1 + .../net5.0/Benchmark_AllReturnTypes.bat | 1 + ...enchmark_ObservableHttpResponseMessage.bat | 1 + .../Benchmarks/net5.0/Benchmark_Task.bat | 1 + .../net5.0/Benchmark_TaskApiResponseT.bat | 1 + .../net5.0/Benchmark_TaskHttpContent.bat | 1 + .../Benchmark_TaskHttpResponseMessage.bat | 1 + .../net5.0/Benchmark_TaskStream.bat | 1 + .../net5.0/Benchmark_TaskString.bat | 1 + .../Benchmarks/net5.0/Benchmark_TaskT.bat | 1 + .../net6.0/Benchmark_AllReturnTypes.bat | 1 + ...enchmark_ObservableHttpResponseMessage.bat | 1 + .../Benchmarks/net6.0/Benchmark_Task.bat | 1 + .../net6.0/Benchmark_TaskApiResponseT.bat | 1 + .../net6.0/Benchmark_TaskHttpContent.bat | 1 + .../Benchmark_TaskHttpResponseMessage.bat | 1 + .../net6.0/Benchmark_TaskStream.bat | 1 + .../net6.0/Benchmark_TaskString.bat | 1 + .../Benchmarks/net6.0/Benchmark_TaskT.bat | 1 + .../Benchmark_AllReturnTypes.bat | 1 + ...enchmark_ObservableHttpResponseMessage.bat | 1 + .../netcoreapp3.1/Benchmark_Task.bat | 1 + .../Benchmark_TaskApiResponseT.bat | 1 + .../Benchmark_TaskHttpContent.bat | 1 + .../Benchmark_TaskHttpResponseMessage.bat | 1 + .../netcoreapp3.1/Benchmark_TaskStream.bat | 1 + .../netcoreapp3.1/Benchmark_TaskString.bat | 1 + .../netcoreapp3.1/Benchmark_TaskT.bat | 1 + Refit.Benchmarks/EndToEndBenchmark.cs | 247 ++++++++++++++++++ Refit.Benchmarks/IGitHubService.cs | 73 ++++++ Refit.Benchmarks/Program.cs | 21 ++ Refit.Benchmarks/Refit.Benchmarks.csproj | 35 +++ .../StaticFileHttpResponseHandler.cs | 34 +++ .../newtonsoft-json-10-users.json | 82 ++++++ .../system-text-json-10-users.json | 82 ++++++ Refit.sln | 19 ++ 36 files changed, 621 insertions(+) create mode 100644 Refit.Benchmarks/Benchmarks/net5.0/Benchmark_AllReturnTypes.bat create mode 100644 Refit.Benchmarks/Benchmarks/net5.0/Benchmark_ObservableHttpResponseMessage.bat create mode 100644 Refit.Benchmarks/Benchmarks/net5.0/Benchmark_Task.bat create mode 100644 Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskApiResponseT.bat create mode 100644 Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskHttpContent.bat create mode 100644 Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskHttpResponseMessage.bat create mode 100644 Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskStream.bat create mode 100644 Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskString.bat create mode 100644 Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskT.bat create mode 100644 Refit.Benchmarks/Benchmarks/net6.0/Benchmark_AllReturnTypes.bat create mode 100644 Refit.Benchmarks/Benchmarks/net6.0/Benchmark_ObservableHttpResponseMessage.bat create mode 100644 Refit.Benchmarks/Benchmarks/net6.0/Benchmark_Task.bat create mode 100644 Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskApiResponseT.bat create mode 100644 Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskHttpContent.bat create mode 100644 Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskHttpResponseMessage.bat create mode 100644 Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskStream.bat create mode 100644 Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskString.bat create mode 100644 Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskT.bat create mode 100644 Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_AllReturnTypes.bat create mode 100644 Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_ObservableHttpResponseMessage.bat create mode 100644 Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_Task.bat create mode 100644 Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskApiResponseT.bat create mode 100644 Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskHttpContent.bat create mode 100644 Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskHttpResponseMessage.bat create mode 100644 Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskStream.bat create mode 100644 Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskString.bat create mode 100644 Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskT.bat create mode 100644 Refit.Benchmarks/EndToEndBenchmark.cs create mode 100644 Refit.Benchmarks/IGitHubService.cs create mode 100644 Refit.Benchmarks/Program.cs create mode 100644 Refit.Benchmarks/Refit.Benchmarks.csproj create mode 100644 Refit.Benchmarks/StaticFileHttpResponseHandler.cs create mode 100644 Refit.Benchmarks/newtonsoft-json-10-users.json create mode 100644 Refit.Benchmarks/system-text-json-10-users.json diff --git a/.gitignore b/.gitignore index 9950e7471..c27e24da2 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,4 @@ Refit-Tests/test-results *.binlog /InterfaceStubGenerator.Core/Properties/launchSettings.json *.svclog +**/BenchmarkDotNet.Artifacts diff --git a/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_AllReturnTypes.bat b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_AllReturnTypes.bat new file mode 100644 index 000000000..7a549f60e --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_AllReturnTypes.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --framework=net5.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_ObservableHttpResponseMessage.bat b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_ObservableHttpResponseMessage.bat new file mode 100644 index 000000000..6b73e961f --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_ObservableHttpResponseMessage.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *ObservableHttpResponseMessage* --framework=net5.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_Task.bat b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_Task.bat new file mode 100644 index 000000000..1a3288e8a --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_Task.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *Task_Async* --framework=net5.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskApiResponseT.bat b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskApiResponseT.bat new file mode 100644 index 000000000..c731fc1de --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskApiResponseT.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskApiResponseT_Async* --framework=net5.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskHttpContent.bat b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskHttpContent.bat new file mode 100644 index 000000000..71e37c49d --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskHttpContent.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskHttpContent_Async* --framework=net5.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskHttpResponseMessage.bat b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskHttpResponseMessage.bat new file mode 100644 index 000000000..70fa04234 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskHttpResponseMessage.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskHttpResponseMessage_Async* --framework=net5.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskStream.bat b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskStream.bat new file mode 100644 index 000000000..b3064b6c4 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskStream.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskStream_Async* --framework=net5.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskString.bat b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskString.bat new file mode 100644 index 000000000..57f952afe --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskString.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskString_Async* --framework=net5.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskT.bat b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskT.bat new file mode 100644 index 000000000..a41e2a39a --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net5.0/Benchmark_TaskT.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskT_Async* --framework=net5.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_AllReturnTypes.bat b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_AllReturnTypes.bat new file mode 100644 index 000000000..7be02aaa8 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_AllReturnTypes.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --framework=net6.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_ObservableHttpResponseMessage.bat b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_ObservableHttpResponseMessage.bat new file mode 100644 index 000000000..0d9d0b10b --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_ObservableHttpResponseMessage.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *ObservableHttpResponseMessage* --framework=net6.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_Task.bat b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_Task.bat new file mode 100644 index 000000000..4449b8c08 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_Task.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *Task_Async* --framework=net6.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskApiResponseT.bat b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskApiResponseT.bat new file mode 100644 index 000000000..62701066d --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskApiResponseT.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskApiResponseT_Async* --framework=net6.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskHttpContent.bat b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskHttpContent.bat new file mode 100644 index 000000000..6c13f932b --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskHttpContent.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskHttpContent_Async* --framework=net6.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskHttpResponseMessage.bat b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskHttpResponseMessage.bat new file mode 100644 index 000000000..d8f1cdf1a --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskHttpResponseMessage.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskHttpResponseMessage_Async* --framework=net6.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskStream.bat b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskStream.bat new file mode 100644 index 000000000..4196d1f20 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskStream.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskStream_Async* --framework=net6.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskString.bat b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskString.bat new file mode 100644 index 000000000..b786ad057 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskString.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskString_Async* --framework=net6.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskT.bat b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskT.bat new file mode 100644 index 000000000..facc3522b --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/net6.0/Benchmark_TaskT.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskT_Async* --framework=net6.0 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_AllReturnTypes.bat b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_AllReturnTypes.bat new file mode 100644 index 000000000..29ba6d353 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_AllReturnTypes.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --framework=netcoreapp3.1 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_ObservableHttpResponseMessage.bat b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_ObservableHttpResponseMessage.bat new file mode 100644 index 000000000..682bd0f51 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_ObservableHttpResponseMessage.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *ObservableHttpResponseMessage* --framework=netcoreapp3.1 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_Task.bat b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_Task.bat new file mode 100644 index 000000000..739ea5950 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_Task.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *Task_Async* --framework=netcoreapp3.1 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskApiResponseT.bat b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskApiResponseT.bat new file mode 100644 index 000000000..3c8a29f0f --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskApiResponseT.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskApiResponseT_Async* --framework=netcoreapp3.1 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskHttpContent.bat b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskHttpContent.bat new file mode 100644 index 000000000..5b730517a --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskHttpContent.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskHttpContent_Async* --framework=netcoreapp3.1 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskHttpResponseMessage.bat b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskHttpResponseMessage.bat new file mode 100644 index 000000000..f30ef8865 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskHttpResponseMessage.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskHttpResponseMessage_Async* --framework=netcoreapp3.1 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskStream.bat b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskStream.bat new file mode 100644 index 000000000..79de481b9 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskStream.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskStream_Async* --framework=netcoreapp3.1 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskString.bat b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskString.bat new file mode 100644 index 000000000..48c9ccc50 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskString.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskString_Async* --framework=netcoreapp3.1 \ No newline at end of file diff --git a/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskT.bat b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskT.bat new file mode 100644 index 000000000..9496c7e43 --- /dev/null +++ b/Refit.Benchmarks/Benchmarks/netcoreapp3.1/Benchmark_TaskT.bat @@ -0,0 +1 @@ +dotnet run --project ../../Refit.Benchmarks.csproj -c Release --filter *TaskT_Async* --framework=netcoreapp3.1 \ No newline at end of file diff --git a/Refit.Benchmarks/EndToEndBenchmark.cs b/Refit.Benchmarks/EndToEndBenchmark.cs new file mode 100644 index 000000000..355e17cb7 --- /dev/null +++ b/Refit.Benchmarks/EndToEndBenchmark.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using AutoFixture; +using BenchmarkDotNet.Attributes; + +namespace Refit.Benchmarks +{ + [MemoryDiagnoser] + public class EndToEndBenchmark + { + private readonly Fixture autoFixture = new(); + private const string Host = "https://github.com"; + private SystemTextJsonContentSerializer systemTextJsonContentSerializer; + private NewtonsoftJsonContentSerializer newtonsoftJsonContentSerializer; + private readonly IDictionary> users = new Dictionary>(); + private readonly IDictionary> refitClient = new Dictionary> + { + {SerializationStrategy.SystemTextJson, new Dictionary()}, + {SerializationStrategy.NewtonsoftJson, new Dictionary()} + }; + + private readonly IDictionary httpMethod = new Dictionary + { + {HttpVerb.Get, HttpMethod.Get}, {HttpVerb.Post, HttpMethod.Post} + }; + + private const int TenUsers = 10; + + public enum SerializationStrategy + { + SystemTextJson, + NewtonsoftJson + } + + public enum HttpVerb + { + Get, + Post + } + + [GlobalSetup] + public Task SetupAsync() + { + + systemTextJsonContentSerializer = new SystemTextJsonContentSerializer(); + refitClient[SerializationStrategy.SystemTextJson][HttpStatusCode.OK] = RestService.For(Host, new RefitSettings(systemTextJsonContentSerializer) + { + HttpMessageHandlerFactory = () => new StaticFileHttpResponseHandler("system-text-json-10-users.json", HttpStatusCode.OK) + }); + refitClient[SerializationStrategy.SystemTextJson][HttpStatusCode.InternalServerError] = RestService.For(Host, new RefitSettings(systemTextJsonContentSerializer) + { + HttpMessageHandlerFactory = () => new StaticFileHttpResponseHandler("system-text-json-10-users.json", HttpStatusCode.InternalServerError) + }); + + newtonsoftJsonContentSerializer = new NewtonsoftJsonContentSerializer(); + refitClient[SerializationStrategy.NewtonsoftJson][HttpStatusCode.OK] = RestService.For(Host, new RefitSettings(newtonsoftJsonContentSerializer) + { + HttpMessageHandlerFactory = () => new StaticFileHttpResponseHandler("newtonsoft-json-10-users.json", System.Net.HttpStatusCode.OK) + }); + refitClient[SerializationStrategy.NewtonsoftJson][HttpStatusCode.InternalServerError] = RestService.For(Host, new RefitSettings(newtonsoftJsonContentSerializer) + { + HttpMessageHandlerFactory = () => new StaticFileHttpResponseHandler("newtonsoft-json-10-users.json", System.Net.HttpStatusCode.InternalServerError) + }); + + users[TenUsers] = autoFixture.CreateMany(TenUsers); + + return Task.CompletedTask; + } + + /* + * Each [Benchmark] tests one return type that Refit allows and is parameterized to test different, serializers, and http methods, and status codes + */ + + [Params(HttpStatusCode.OK, HttpStatusCode.InternalServerError)] + public HttpStatusCode HttpStatusCode { get; set; } + + [Params(TenUsers)] + public int ModelCount { get; set; } + + [ParamsAllValues] + public HttpVerb Verb { get; set; } + + [ParamsAllValues] + public SerializationStrategy Serializer { get; set; } + + [Benchmark] + public async Task Task_Async() + { + try + { + switch (Verb) + { + case HttpVerb.Get: + await refitClient[Serializer][HttpStatusCode].GetUsersTaskAsync(); + break; + case HttpVerb.Post: + await refitClient[Serializer][HttpStatusCode].PostUsersTaskAsync(users[ModelCount]); + break; + default: + throw new ArgumentOutOfRangeException(nameof(Verb)); + } + } + catch + { + //swallow + } + } + + [Benchmark] + public async Task TaskString_Async() + { + try + { + switch (Verb) + { + case HttpVerb.Get: + return await refitClient[Serializer][HttpStatusCode].GetUsersTaskStringAsync(); + case HttpVerb.Post: + return await refitClient[Serializer][HttpStatusCode].PostUsersTaskStringAsync(users[ModelCount]); + default: + throw new ArgumentOutOfRangeException(nameof(Verb)); + } + } + catch + { + //swallow + } + + return default; + } + + [Benchmark] + public async Task TaskStream_Async() + { + try + { + switch (Verb) + { + case HttpVerb.Get: + return await refitClient[Serializer][HttpStatusCode].GetUsersTaskStreamAsync(); + case HttpVerb.Post: + return await refitClient[Serializer][HttpStatusCode].PostUsersTaskStreamAsync(users[ModelCount]); + default: + throw new ArgumentOutOfRangeException(nameof(Verb)); + } + } + catch + { + //swallow + } + + return default; + } + + [Benchmark] + public async Task TaskHttpContent_Async() + { + try + { + switch (Verb) + { + case HttpVerb.Get: + return await refitClient[Serializer][HttpStatusCode].GetUsersTaskHttpContentAsync(); + case HttpVerb.Post: + return await refitClient[Serializer][HttpStatusCode].PostUsersTaskHttpContentAsync(users[ModelCount]); + default: + throw new ArgumentOutOfRangeException(nameof(Verb)); + } + } + catch + { + //swallow + } + + return default; + } + + [Benchmark] + public async Task TaskHttpResponseMessage_Async() + { + switch (Verb) + { + case HttpVerb.Get: + return await refitClient[Serializer][HttpStatusCode].GetUsersTaskHttpResponseMessageAsync(); + case HttpVerb.Post: + return await refitClient[Serializer][HttpStatusCode].PostUsersTaskHttpResponseMessageAsync(users[ModelCount]); + default: + throw new ArgumentOutOfRangeException(nameof(Verb)); + } + } + + [Benchmark] + public IObservable ObservableHttpResponseMessage() + { + switch (Verb) + { + case HttpVerb.Get: + return refitClient[Serializer][HttpStatusCode].GetUsersObservableHttpResponseMessage(); + case HttpVerb.Post: + return refitClient[Serializer][HttpStatusCode].PostUsersObservableHttpResponseMessage(users[ModelCount]); + default: + throw new ArgumentOutOfRangeException(nameof(Verb)); + } + } + + [Benchmark] + public async Task> TaskT_Async() + { + try + { + switch (Verb) + { + case HttpVerb.Get: + return await refitClient[Serializer][HttpStatusCode].GetUsersTaskTAsync(); + case HttpVerb.Post: + return await refitClient[Serializer][HttpStatusCode].PostUsersTaskTAsync(users[ModelCount]); + default: + throw new ArgumentOutOfRangeException(nameof(Verb)); + } + } + catch + { + //swallow + } + + return default; + } + + [Benchmark] + public async Task>> TaskApiResponseT_Async() + { + switch (Verb) + { + case HttpVerb.Get: + return await refitClient[Serializer][HttpStatusCode].GetUsersTaskApiResponseTAsync(); + case HttpVerb.Post: + return await refitClient[Serializer][HttpStatusCode].PostUsersTaskApiResponseTAsync(users[ModelCount]); + default: + throw new ArgumentOutOfRangeException(nameof(Verb)); + } + } + } +} diff --git a/Refit.Benchmarks/IGitHubService.cs b/Refit.Benchmarks/IGitHubService.cs new file mode 100644 index 000000000..db00557e6 --- /dev/null +++ b/Refit.Benchmarks/IGitHubService.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; + +using Refit; +using System.Threading.Tasks; + +namespace Refit.Benchmarks +{ + public interface IGitHubService + { + //Task - throws + [Get("/users")] + public Task GetUsersTaskAsync(); + [Post("/users")] + public Task PostUsersTaskAsync([Body] IEnumerable users); + + //Task - throws + [Get("/users")] + public Task GetUsersTaskStringAsync(); + [Post("/users")] + public Task PostUsersTaskStringAsync([Body] IEnumerable users); + + //Task - throws + [Get("/users")] + public Task GetUsersTaskStreamAsync(); + [Post("/users")] + public Task PostUsersTaskStreamAsync([Body] IEnumerable users); + + //Task - throws + [Get("/users")] + public Task GetUsersTaskHttpContentAsync(); + [Post("/users")] + public Task PostUsersTaskHttpContentAsync([Body] IEnumerable users); + + //Task + [Get("/users")] + public Task GetUsersTaskHttpResponseMessageAsync(); + [Post("/users")] + public Task PostUsersTaskHttpResponseMessageAsync([Body] IEnumerable users); + + //IObservable + [Get("/users")] + public IObservable GetUsersObservableHttpResponseMessage(); + [Post("/users")] + public IObservable PostUsersObservableHttpResponseMessage([Body] IEnumerable users); + + //Task<> - throws + [Get("/users")] + public Task> GetUsersTaskTAsync(); + [Post("/users")] + public Task> PostUsersTaskTAsync([Body] IEnumerable users); + + //Task> + [Get("/users")] + public Task>> GetUsersTaskApiResponseTAsync(); + [Post("/users")] + public Task>> PostUsersTaskApiResponseTAsync([Body] IEnumerable users); + } + + public class User + { + public int Id { get; set; } + public string Name { get; set; } + public string Bio { get; set; } + public int Followers { get; set; } + public int Following { get; set; } + public string Url { get; set; } + } +} + + diff --git a/Refit.Benchmarks/Program.cs b/Refit.Benchmarks/Program.cs new file mode 100644 index 000000000..c2a4993ea --- /dev/null +++ b/Refit.Benchmarks/Program.cs @@ -0,0 +1,21 @@ +using System; + +using BenchmarkDotNet.Running; + +namespace Refit.Benchmarks +{ + class Program + { + static void Main(string[] args) + { + if (args != null && args.Length > 0) + { + BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); + } + else + { + BenchmarkRunner.Run(); + } + } + } +} diff --git a/Refit.Benchmarks/Refit.Benchmarks.csproj b/Refit.Benchmarks/Refit.Benchmarks.csproj new file mode 100644 index 000000000..887f9fc41 --- /dev/null +++ b/Refit.Benchmarks/Refit.Benchmarks.csproj @@ -0,0 +1,35 @@ + + + + + + Exe + net6.0;net5.0;netcoreapp3.1 + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + PreserveNewest + + + + + diff --git a/Refit.Benchmarks/StaticFileHttpResponseHandler.cs b/Refit.Benchmarks/StaticFileHttpResponseHandler.cs new file mode 100644 index 000000000..ba6978988 --- /dev/null +++ b/Refit.Benchmarks/StaticFileHttpResponseHandler.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Refit.Benchmarks +{ + public class StaticFileHttpResponseHandler : HttpMessageHandler + { + private readonly HttpStatusCode responseCode; + private readonly string responsePayload; + + public StaticFileHttpResponseHandler(string fileName, HttpStatusCode responseCode) + { + if (string.IsNullOrEmpty(fileName)) + throw new ArgumentNullException(nameof(fileName)); + + responsePayload = File.ReadAllText(fileName); +; this.responseCode = responseCode; + } + + protected override Task SendAsync(HttpRequestMessage request, + CancellationToken cancellationToken) + { + return Task.FromResult(new HttpResponseMessage(responseCode) + { + RequestMessage = request, + Content = new StringContent(responsePayload) + }); + } + } +} diff --git a/Refit.Benchmarks/newtonsoft-json-10-users.json b/Refit.Benchmarks/newtonsoft-json-10-users.json new file mode 100644 index 000000000..67b6ed3fd --- /dev/null +++ b/Refit.Benchmarks/newtonsoft-json-10-users.json @@ -0,0 +1,82 @@ +[ + { + "Id": 253, + "Name": "Namee3a23814-bfe9-4d4b-96db-8fc95d209ea8", + "Bio": "Biof413d158-7ca7-4b1b-9073-565b3621bb83", + "Followers": 154, + "Following": 136, + "Url": "Url70f46596-f86f-4e82-900d-0f07d7dc468c" + }, + { + "Id": 122, + "Name": "Namef5407028-0d39-41bf-86a3-94890dabff6c", + "Bio": "Bioed5c52a9-37ed-4bc3-94fc-ab2de047ad31", + "Followers": 48, + "Following": 188, + "Url": "Url7d04e0a5-63d8-42e9-996a-af1efeee6b3d" + }, + { + "Id": 78, + "Name": "Name3176c49e-d65d-44f6-89af-14a79aa6103e", + "Bio": "Bioc901bb07-874a-449e-8cc7-892ea008de32", + "Followers": 218, + "Following": 229, + "Url": "Urlf2a24e82-c01e-4ca5-86c7-4360dbffd955" + }, + { + "Id": 169, + "Name": "Namebf433061-810b-4e0e-b9a4-33690ba557a7", + "Bio": "Bioe43d91cd-a399-401e-b126-a94f4f35ac97", + "Followers": 167, + "Following": 142, + "Url": "Urlea793c4a-436f-4ba8-8f3b-e48d88f8ff16" + }, + { + "Id": 173, + "Name": "Name2ff320b0-4c21-4799-825f-2da0b00eecb7", + "Bio": "Bio4d33933d-484c-468b-a433-7cbf5801795a", + "Followers": 255, + "Following": 198, + "Url": "Url84860aea-c2d1-4b0d-8be3-9c961b06d08a" + }, + { + "Id": 100, + "Name": "Name13c3cb21-4a84-4c02-8fc5-30b2287c203d", + "Bio": "Bio90233954-82e4-4e36-9152-3bc8e1ca37ab", + "Followers": 128, + "Following": 84, + "Url": "Url126ac70f-429a-458e-8138-957883491938" + }, + { + "Id": 172, + "Name": "Name97594a03-d0a8-4711-8d9f-af2067da734c", + "Bio": "Bio9feb6a20-49ae-480c-a819-a2655ef44a9b", + "Followers": 41, + "Following": 146, + "Url": "Urldaa25203-cf3a-4744-b5b0-58505a602980" + }, + { + "Id": 243, + "Name": "Name74b11b10-f465-4217-9de4-d8d9884a4c99", + "Bio": "Bio4733a1be-9b5f-44bc-ada1-2154265e3dec", + "Followers": 120, + "Following": 45, + "Url": "Urleb4bb38d-ae61-4cc4-b9f7-111f2d6e06b8" + }, + { + "Id": 106, + "Name": "Name4c1a2b16-ebaf-4d5b-b262-a0b33562fc6b", + "Bio": "Bioa9ff296d-921b-4f8f-95bb-5a569e0cb176", + "Followers": 79, + "Following": 133, + "Url": "Url732335eb-f081-4842-940e-e130bb8a475b" + }, + { + "Id": 245, + "Name": "Name0c42a076-95d3-49b8-a2ea-711fc1569c19", + "Bio": "Bio78b6cbf1-7595-4ed1-b530-f438ea6320ce", + "Followers": 5, + "Following": 212, + "Url": "Urlc2a5296a-ea03-4b6a-bbc9-92e1e1e56d21" + } +] \ No newline at end of file diff --git a/Refit.Benchmarks/system-text-json-10-users.json b/Refit.Benchmarks/system-text-json-10-users.json new file mode 100644 index 000000000..61e98369e --- /dev/null +++ b/Refit.Benchmarks/system-text-json-10-users.json @@ -0,0 +1,82 @@ +[ + { + "id": 253, + "name": "Namee3a23814-bfe9-4d4b-96db-8fc95d209ea8", + "bio": "Biof413d158-7ca7-4b1b-9073-565b3621bb83", + "followers": 154, + "following": 136, + "url": "Url70f46596-f86f-4e82-900d-0f07d7dc468c" + }, + { + "id": 122, + "name": "Namef5407028-0d39-41bf-86a3-94890dabff6c", + "bio": "Bioed5c52a9-37ed-4bc3-94fc-ab2de047ad31", + "followers": 48, + "following": 188, + "url": "Url7d04e0a5-63d8-42e9-996a-af1efeee6b3d" + }, + { + "id": 78, + "name": "Name3176c49e-d65d-44f6-89af-14a79aa6103e", + "bio": "Bioc901bb07-874a-449e-8cc7-892ea008de32", + "followers": 218, + "following": 229, + "url": "Urlf2a24e82-c01e-4ca5-86c7-4360dbffd955" + }, + { + "id": 169, + "name": "Namebf433061-810b-4e0e-b9a4-33690ba557a7", + "bio": "Bioe43d91cd-a399-401e-b126-a94f4f35ac97", + "followers": 167, + "following": 142, + "url": "Urlea793c4a-436f-4ba8-8f3b-e48d88f8ff16" + }, + { + "id": 173, + "name": "Name2ff320b0-4c21-4799-825f-2da0b00eecb7", + "bio": "Bio4d33933d-484c-468b-a433-7cbf5801795a", + "followers": 255, + "following": 198, + "url": "Url84860aea-c2d1-4b0d-8be3-9c961b06d08a" + }, + { + "id": 100, + "name": "Name13c3cb21-4a84-4c02-8fc5-30b2287c203d", + "bio": "Bio90233954-82e4-4e36-9152-3bc8e1ca37ab", + "followers": 128, + "following": 84, + "url": "Url126ac70f-429a-458e-8138-957883491938" + }, + { + "id": 172, + "name": "Name97594a03-d0a8-4711-8d9f-af2067da734c", + "bio": "Bio9feb6a20-49ae-480c-a819-a2655ef44a9b", + "followers": 41, + "following": 146, + "url": "Urldaa25203-cf3a-4744-b5b0-58505a602980" + }, + { + "id": 243, + "name": "Name74b11b10-f465-4217-9de4-d8d9884a4c99", + "bio": "Bio4733a1be-9b5f-44bc-ada1-2154265e3dec", + "followers": 120, + "following": 45, + "url": "Urleb4bb38d-ae61-4cc4-b9f7-111f2d6e06b8" + }, + { + "id": 106, + "name": "Name4c1a2b16-ebaf-4d5b-b262-a0b33562fc6b", + "bio": "Bioa9ff296d-921b-4f8f-95bb-5a569e0cb176", + "followers": 79, + "following": 133, + "url": "Url732335eb-f081-4842-940e-e130bb8a475b" + }, + { + "id": 245, + "name": "Name0c42a076-95d3-49b8-a2ea-711fc1569c19", + "bio": "Bio78b6cbf1-7595-4ed1-b530-f438ea6320ce", + "followers": 5, + "following": 212, + "url": "Urlc2a5296a-ea03-4b6a-bbc9-92e1e1e56d21" + } +] \ No newline at end of file diff --git a/Refit.sln b/Refit.sln index 5973b1e3c..e2c673a32 100644 --- a/Refit.sln +++ b/Refit.sln @@ -31,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InterfaceStubGenerator.Rosl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Refit.Xml", "Refit.Xml\Refit.Xml.csproj", "{C4E38B33-3D17-47A7-A47F-8F3900F07499}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Refit.Benchmarks", "Refit.Benchmarks\Refit.Benchmarks.csproj", "{ABD72A27-9C30-481A-8303-D8F825A8FD47}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution InterfaceStubGenerator.Shared\InterfaceStubGenerator.Shared.projitems*{72869789-0310-4916-9a41-20d16a01c1b8}*SharedItemsImports = 5 @@ -160,12 +162,29 @@ Global {C4E38B33-3D17-47A7-A47F-8F3900F07499}.Release|x64.Build.0 = Release|Any CPU {C4E38B33-3D17-47A7-A47F-8F3900F07499}.Release|x86.ActiveCfg = Release|Any CPU {C4E38B33-3D17-47A7-A47F-8F3900F07499}.Release|x86.Build.0 = Release|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Debug|ARM.ActiveCfg = Debug|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Debug|ARM.Build.0 = Debug|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Debug|x64.ActiveCfg = Debug|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Debug|x64.Build.0 = Debug|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Debug|x86.ActiveCfg = Debug|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Debug|x86.Build.0 = Debug|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Release|Any CPU.Build.0 = Release|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Release|ARM.ActiveCfg = Release|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Release|ARM.Build.0 = Release|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Release|x64.ActiveCfg = Release|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Release|x64.Build.0 = Release|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Release|x86.ActiveCfg = Release|Any CPU + {ABD72A27-9C30-481A-8303-D8F825A8FD47}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {EB833B36-D3CA-4308-A776-8D574F2ADF64} = {0E99249A-FB80-4C60-8FD3-13820E853FF7} + {ABD72A27-9C30-481A-8303-D8F825A8FD47} = {0E99249A-FB80-4C60-8FD3-13820E853FF7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6E9C2873-AFF9-4D32-A784-1BA094814054}