Skip to content

Add benchmarks for RDG #50266

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

<ItemGroup>
<InternalsVisibleTo Include="Microsoft.AspNetCore.Http.Extensions.Tests" />
<InternalsVisibleTo Include="Microsoft.AspNetCore.Http.Microbenchmarks" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious: which internal types do we need this for? I had assumed that RunGenerator should just work by passing it a source and the generator.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RequestDelegateCreationTestBase class that I'm source-sharing between our integration tests and our benchmarks dependencies on some types that are internal to the generator (e.g. the Endpoint type which represents the info we've derived vai Roslyn about a method invocation that maps to a minimal API).

I could've done work work to factor out the RequestDelegateCreationTestBase class here but I figured there was no harm in doing IVT between our benchmarks and generator.

Also, it'll help in the future if we decide to profile specific parts of the generator implementation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks for the explanation. I know other repos like dotnet/runtime try to avoid IVT for these cases and prefer source sharing instead but I think both approaches are fine 😃

</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions src/Http/Http/perf/Microbenchmarks/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
global using Xunit;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need this because the shared RequestDelegateCreationTestBase has some asserts. I'm just importing Xunit into the context instead of adding if-defs to the shared code to avoid calling Assert all the time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Can we add this explanation as a comment to this line 🙂

Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,34 @@
<ServerGarbageCollection>true</ServerGarbageCollection>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RootNamespace>Microsoft.AspNetCore.Http</RootNamespace>
<PreserveCompilationContext>true</PreserveCompilationContext>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to enable this to support passing assembly info to the Roslyn compilation instance at runtime.

</PropertyGroup>

<ItemGroup>
<Reference Include="BenchmarkDotNet" />
<Reference Include="Microsoft.AspNetCore" />
<Reference Include="Microsoft.AspNetCore.Testing" />
<Reference Include="Microsoft.AspNetCore.Http" />
<Reference Include="Microsoft.AspNetCore.Http.Results" />
<Reference Include="Microsoft.AspNetCore.Http.Extensions" />
<Compile Include="$(SharedSourceRoot)BenchmarkRunner\*.cs" />
<Reference Include="Microsoft.AspNetCore.Mvc.Core" />
<Reference Include="Microsoft.Extensions.DependencyInjection" />
<Reference Include="Microsoft.Extensions.DependencyModel" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" IsImplicitlyDefined="true" Version="$(MicrosoftCodeAnalysisVersion_LatestVS)" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" IsImplicitlyDefined="true" Version="$(MicrosoftCodeAnalysisVersion_LatestVS)" />
</ItemGroup>

<ItemGroup>
<Compile Include="$(RepoRoot)src\Http\Http.Extensions\test\RequestDelegateGenerator\RequestDelegateCreationTestBase.cs" LinkBase="Shared" />
<Compile Include="$(RepoRoot)src\Http\Http.Extensions\test\RequestDelegateGenerator\SharedTypes.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)BenchmarkRunner\*.cs" LinkBase="Shared" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\Http\Http.Extensions\gen\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http.Generators.Tests;

namespace Microsoft.AspNetCore.Http.Microbenchmarks;

public class RequestDelegateGeneratorBenchmarks : RequestDelegateCreationTestBase
{
protected override bool IsGeneratorEnabled => true;

[Params(10, 100, 1000, 10000)]
public int EndpointCount { get; set; }

private string _source;

[GlobalSetup]
public void Setup()
{
_source = "";
for (var i = 0; i < EndpointCount; i++)
{
_source += $"""app.MapGet("/route{i}", (int? id) => "Hello World!");""";
}
}

[Benchmark]
public async Task CreateRequestDelegate()
{
await RunGeneratorAsync(_source);
}
}