Skip to content

Commit

Permalink
feat: add startup and performance benchmarks (#1731)
Browse files Browse the repository at this point in the history
* chore: use file scoped namespaces

* feat: add performance and startup benchmarks

* feat: add first call benchmarks
  • Loading branch information
TimothyMakkison committed Jun 24, 2024
1 parent b75734a commit 8a40692
Show file tree
Hide file tree
Showing 8 changed files with 480 additions and 344 deletions.
479 changes: 239 additions & 240 deletions Refit.Benchmarks/EndToEndBenchmark.cs

Large diffs are not rendered by default.

149 changes: 74 additions & 75 deletions Refit.Benchmarks/IGitHubService.cs
Original file line number Diff line number Diff line change
@@ -1,77 +1,76 @@
namespace Refit.Benchmarks
namespace Refit.Benchmarks;

public interface IGitHubService
{
public interface IGitHubService
{
//Task - throws
[Get("/users")]
public Task GetUsersTaskAsync();

[Post("/users")]
public Task PostUsersTaskAsync([Body] IEnumerable<User> users);

//Task<string> - throws
[Get("/users")]
public Task<string> GetUsersTaskStringAsync();

[Post("/users")]
public Task<string> PostUsersTaskStringAsync([Body] IEnumerable<User> users);

//Task<Stream> - throws
[Get("/users")]
public Task<Stream> GetUsersTaskStreamAsync();

[Post("/users")]
public Task<Stream> PostUsersTaskStreamAsync([Body] IEnumerable<User> users);

//Task<HttpContent> - throws
[Get("/users")]
public Task<HttpContent> GetUsersTaskHttpContentAsync();

[Post("/users")]
public Task<HttpContent> PostUsersTaskHttpContentAsync([Body] IEnumerable<User> users);

//Task<HttpResponseMessage>
[Get("/users")]
public Task<HttpResponseMessage> GetUsersTaskHttpResponseMessageAsync();

[Post("/users")]
public Task<HttpResponseMessage> PostUsersTaskHttpResponseMessageAsync(
[Body] IEnumerable<User> users
);

//IObservable<HttpResponseMessage>
[Get("/users")]
public IObservable<HttpResponseMessage> GetUsersObservableHttpResponseMessage();

[Post("/users")]
public IObservable<HttpResponseMessage> PostUsersObservableHttpResponseMessage(
[Body] IEnumerable<User> users
);

//Task<<T>> - throws
[Get("/users")]
public Task<List<User>> GetUsersTaskTAsync();

[Post("/users")]
public Task<List<User>> PostUsersTaskTAsync([Body] IEnumerable<User> users);

//Task<ApiResponse<T>>
[Get("/users")]
public Task<ApiResponse<List<User>>> GetUsersTaskApiResponseTAsync();

[Post("/users")]
public Task<ApiResponse<List<User>>> PostUsersTaskApiResponseTAsync(
[Body] IEnumerable<User> 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; }
}
//Task - throws
[Get("/users")]
public Task GetUsersTaskAsync();

[Post("/users")]
public Task PostUsersTaskAsync([Body] IEnumerable<User> users);

//Task<string> - throws
[Get("/users")]
public Task<string> GetUsersTaskStringAsync();

[Post("/users")]
public Task<string> PostUsersTaskStringAsync([Body] IEnumerable<User> users);

//Task<Stream> - throws
[Get("/users")]
public Task<Stream> GetUsersTaskStreamAsync();

[Post("/users")]
public Task<Stream> PostUsersTaskStreamAsync([Body] IEnumerable<User> users);

//Task<HttpContent> - throws
[Get("/users")]
public Task<HttpContent> GetUsersTaskHttpContentAsync();

[Post("/users")]
public Task<HttpContent> PostUsersTaskHttpContentAsync([Body] IEnumerable<User> users);

//Task<HttpResponseMessage>
[Get("/users")]
public Task<HttpResponseMessage> GetUsersTaskHttpResponseMessageAsync();

[Post("/users")]
public Task<HttpResponseMessage> PostUsersTaskHttpResponseMessageAsync(
[Body] IEnumerable<User> users
);

//IObservable<HttpResponseMessage>
[Get("/users")]
public IObservable<HttpResponseMessage> GetUsersObservableHttpResponseMessage();

[Post("/users")]
public IObservable<HttpResponseMessage> PostUsersObservableHttpResponseMessage(
[Body] IEnumerable<User> users
);

//Task<<T>> - throws
[Get("/users")]
public Task<List<User>> GetUsersTaskTAsync();

[Post("/users")]
public Task<List<User>> PostUsersTaskTAsync([Body] IEnumerable<User> users);

//Task<ApiResponse<T>>
[Get("/users")]
public Task<ApiResponse<List<User>>> GetUsersTaskApiResponseTAsync();

[Post("/users")]
public Task<ApiResponse<List<User>>> PostUsersTaskApiResponseTAsync(
[Body] IEnumerable<User> 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; }
}
28 changes: 28 additions & 0 deletions Refit.Benchmarks/IPerformanceService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace Refit.Benchmarks;

public interface IPerformanceService
{
[Get("/users")]
public Task<string> ConstantRoute();

[Get("/users/{id}")]
public Task<string> DynamicRoute(int id);

[Get("/users/{id}/{user}/{status}")]
public Task<string> ComplexDynamicRoute(int id, string user, string status);

[Get("/users/{request.someProperty}")]
public Task<string> ObjectRequest(PathBoundObject request);

[Post("/users/{id}/{request.someProperty}")]
[Headers("User-Agent: Awesome Octocat App", "X-Emoji: :smile_cat:")]
public Task<string> ComplexRequest(int id, PathBoundObject request, [Query(CollectionFormat.Multi)]int[] queries);
}

public class PathBoundObject
{
public string SomeProperty { get; set; }

[Query]
public string SomeQuery { get; set; }
}
48 changes: 48 additions & 0 deletions Refit.Benchmarks/PerformanceBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Net;
using BenchmarkDotNet.Attributes;

namespace Refit.Benchmarks;

[MemoryDiagnoser]
public class PerformanceBenchmark
{
private IPerformanceService? service;

private const string Host = "https://github.com";
private SystemTextJsonContentSerializer systemTextJsonContentSerializer;

[GlobalSetup]
public Task SetupAsync()
{
systemTextJsonContentSerializer = new SystemTextJsonContentSerializer();
service =
RestService.For<IPerformanceService>(
Host,
new RefitSettings(systemTextJsonContentSerializer)
{
HttpMessageHandlerFactory = () =>
new StaticValueHttpResponseHandler(
"Ok",
HttpStatusCode.OK
)
}
);

return Task.CompletedTask;
}

[Benchmark]
public async Task<string> ConstantRouteAsync() => await service.ConstantRoute();

[Benchmark]
public async Task<string> DynamicRouteAsync() => await service.DynamicRoute(101);

[Benchmark]
public async Task<string> ComplexDynamicRouteAsync() => await service.ComplexDynamicRoute(101, "tom", "yCxv");

[Benchmark]
public async Task<string> ObjectRequestAsync() => await service.ObjectRequest(new PathBoundObject(){SomeProperty = "myProperty", SomeQuery = "myQuery"});

[Benchmark]
public async Task<string> ComplexRequestAsync() => await service.ComplexRequest(101, new PathBoundObject(){SomeProperty = "myProperty", SomeQuery = "myQuery"}, [1,2,3,4,5,6]);
}
24 changes: 9 additions & 15 deletions Refit.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
using BenchmarkDotNet.Running;
using Refit.Benchmarks;

namespace Refit.Benchmarks
if (args is { Length: > 0 })
{
class Program
{
static void Main(string[] args)
{
if (args != null && args.Length > 0)
{
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
else
{
BenchmarkRunner.Run<EndToEndBenchmark>();
}
}
}
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
else
{
BenchmarkRunner.Run<EndToEndBenchmark>();
// BenchmarkRunner.Run<StartupBenchmark>();
// BenchmarkRunner.Run<PerformanceBenchmarks>();
}
49 changes: 49 additions & 0 deletions Refit.Benchmarks/StartupBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Net;
using BenchmarkDotNet.Attributes;

namespace Refit.Benchmarks;

[MemoryDiagnoser]
public class StartupBenchmark
{
private IPerformanceService initialisedService;
private const string Host = "https://github.com";
private readonly RefitSettings settings = new RefitSettings()
{
HttpMessageHandlerFactory = () =>
new StaticValueHttpResponseHandler(
"Ok",
HttpStatusCode.OK
)
};


[IterationSetup(Targets = [nameof(FirstCallConstantRouteAsync), nameof(FirstCallComplexRequestAsync)])]
public void Setup()
{
initialisedService = RestService.For<IPerformanceService>(Host, settings);
}

[Benchmark]
public IPerformanceService CreateService() => RestService.For<IPerformanceService>(Host, settings);

[Benchmark]
public async Task<string> FirstCallConstantRouteAsync() => await initialisedService.ConstantRoute();

[Benchmark]
public async Task<string> ConstantRouteAsync()
{
var service = RestService.For<IPerformanceService>(Host, settings);
return await service.ConstantRoute();
}

[Benchmark]
public async Task<string> FirstCallComplexRequestAsync() => await initialisedService.ObjectRequest(new PathBoundObject(){SomeProperty = "myProperty", SomeQuery = "myQuery"});

[Benchmark]
public async Task<string> ComplexRequestAsync()
{
var service = RestService.For<IPerformanceService>(Host, settings);
return await service.ObjectRequest(new PathBoundObject(){SomeProperty = "myProperty", SomeQuery = "myQuery"});
}
}
27 changes: 13 additions & 14 deletions Refit.Benchmarks/StaticFileHttpResponseHandler.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using System.Net;

namespace Refit.Benchmarks
namespace Refit.Benchmarks;

public class StaticFileHttpResponseHandler : HttpMessageHandler
{
public class StaticFileHttpResponseHandler : HttpMessageHandler
{
private readonly HttpStatusCode responseCode;
private readonly string responsePayload;
private readonly HttpStatusCode responseCode;
private readonly string responsePayload;

public StaticFileHttpResponseHandler(string fileName, HttpStatusCode responseCode)
{
public StaticFileHttpResponseHandler(string fileName, HttpStatusCode responseCode)
{
if (string.IsNullOrEmpty(fileName))
throw new ArgumentNullException(nameof(fileName));

Expand All @@ -17,11 +17,11 @@ public StaticFileHttpResponseHandler(string fileName, HttpStatusCode responseCod
this.responseCode = responseCode;
}

protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken
)
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken
)
{
return Task.FromResult(
new HttpResponseMessage(responseCode)
{
Expand All @@ -30,5 +30,4 @@ CancellationToken cancellationToken
}
);
}
}
}
}
20 changes: 20 additions & 0 deletions Refit.Benchmarks/StaticValueHttpResponseHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Net;

namespace Refit.Benchmarks;

public class StaticValueHttpResponseHandler (string response, HttpStatusCode code) : HttpMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken
)
{
return Task.FromResult(
new HttpResponseMessage(code)
{
RequestMessage = request,
Content = new StringContent(response)
}
);
}
}

0 comments on commit 8a40692

Please sign in to comment.