зеркало из https://github.com/dotnet/razor.git
Add benchmarks (#7963)
* Add benchmarks: - Add new benchmark project - Add sample app that can be benchmarked - Check ratio and report failures with exit code.
This commit is contained in:
Родитель
b412228ed6
Коммит
13ad9d5c10
11
Razor.sln
11
Razor.sln
|
@ -182,6 +182,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compiler Tests", "Compiler
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Common.Test", "src\Razor\test\Microsoft.AspNetCore.Razor.Common.Test\Microsoft.AspNetCore.Razor.Common.Test.csproj", "{23E48E5E-91FC-421E-B122-C7D084FCE39A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Microbenchmarks.Generator", "src\Compiler\perf\Microsoft.AspNetCore.Razor.Microbenchmarks.Generator\Microsoft.AspNetCore.Razor.Microbenchmarks.Generator.csproj", "{7400A168-2552-49C7-93E3-D4DAA90C216F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -766,6 +768,14 @@ Global
|
|||
{23E48E5E-91FC-421E-B122-C7D084FCE39A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{23E48E5E-91FC-421E-B122-C7D084FCE39A}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{23E48E5E-91FC-421E-B122-C7D084FCE39A}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{7400A168-2552-49C7-93E3-D4DAA90C216F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7400A168-2552-49C7-93E3-D4DAA90C216F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7400A168-2552-49C7-93E3-D4DAA90C216F}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7400A168-2552-49C7-93E3-D4DAA90C216F}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7400A168-2552-49C7-93E3-D4DAA90C216F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7400A168-2552-49C7-93E3-D4DAA90C216F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7400A168-2552-49C7-93E3-D4DAA90C216F}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7400A168-2552-49C7-93E3-D4DAA90C216F}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -850,6 +860,7 @@ Global
|
|||
{97DE8703-467C-49A7-BCE4-42FF1FEC8AC2} = {FB7C870E-A173-4F75-BE63-4EF39C79A759}
|
||||
{A9F9B5E5-C5C2-4860-BE56-038C70ADBAC9} = {FB7C870E-A173-4F75-BE63-4EF39C79A759}
|
||||
{23E48E5E-91FC-421E-B122-C7D084FCE39A} = {92463391-81BE-462B-AC3C-78C6C760741F}
|
||||
{7400A168-2552-49C7-93E3-D4DAA90C216F} = {C2C98051-0F39-47F2-80B6-E72B29159F2C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0035341D-175A-4D05-95E6-F1C2785A1E26}
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
|
||||
Versions below this comment are not managed by automation and can be changed as needed.
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<PropertyGroup Label="Manual">
|
||||
<!-- Several packages from the editor are used for testing HTML support, and share the following version. -->
|
||||
<Tooling_HtmlEditorPackageVersion>17.5.101-preview-0002</Tooling_HtmlEditorPackageVersion>
|
||||
<!-- Several packages share the MS.CA.Testing version -->
|
||||
|
@ -81,8 +81,6 @@
|
|||
<VisualStudioLanguageServerProtocolVersion>17.4.1008-preview</VisualStudioLanguageServerProtocolVersion>
|
||||
<MicrosoftNetCompilersToolsetVersion>4.4.0</MicrosoftNetCompilersToolsetVersion>
|
||||
<MicrosoftCommonLanguageServerProtocolFrameworkPackageVersion>$(RoslynPackageVersion)</MicrosoftCommonLanguageServerProtocolFrameworkPackageVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Manual">
|
||||
<!-- dotnet/runtime packages -->
|
||||
<MicrosoftExtensionsPackageVersion>6.0.0</MicrosoftExtensionsPackageVersion>
|
||||
<SystemCollectionsImmutablePackageVersion>6.0.0</SystemCollectionsImmutablePackageVersion>
|
||||
|
@ -164,12 +162,14 @@
|
|||
<BenchmarkDotNetVersion>0.13.0.1555</BenchmarkDotNetVersion>
|
||||
<DiffPlexVersion>1.5.0</DiffPlexVersion>
|
||||
<FluentAssertionsVersion>6.7.0</FluentAssertionsVersion>
|
||||
<MicrosoftBuildLocatorVersion>1.4.1</MicrosoftBuildLocatorVersion>
|
||||
<MicrosoftBuildVersion>17.3.0-preview-22364-05</MicrosoftBuildVersion>
|
||||
<MicrosoftBuildFrameworkVersion>$(MicrosoftBuildVersion)</MicrosoftBuildFrameworkVersion>
|
||||
<MicrosoftBuildUtilitiesCoreVersion>$(MicrosoftBuildVersion)</MicrosoftBuildUtilitiesCoreVersion>
|
||||
<MicrosoftCodeAnalysisCommonVersion>4.0.0-4.final</MicrosoftCodeAnalysisCommonVersion>
|
||||
<MicrosoftCodeAnalysisCSharpVersion>4.0.0-4.final</MicrosoftCodeAnalysisCSharpVersion>
|
||||
<MicrosoftCodeAnalysisCSharpWorkspacesVersion>4.3.0-2.final</MicrosoftCodeAnalysisCSharpWorkspacesVersion>
|
||||
<MicrosoftCodeAnalysisWorkspacesMSBuildVersion>4.3.0-2.final</MicrosoftCodeAnalysisWorkspacesMSBuildVersion>
|
||||
<MicrosoftCSharpVersion>4.7.0</MicrosoftCSharpVersion>
|
||||
<MicrosoftCssParserVersion>1.0.0-20200708.1</MicrosoftCssParserVersion>
|
||||
<MicrosoftExtensionsDependencyModelVersion>6.0.0</MicrosoftExtensionsDependencyModelVersion>
|
||||
|
@ -182,5 +182,7 @@
|
|||
<SystemTextJsonVersion>6.0.0</SystemTextJsonVersion>
|
||||
<XunitAssertVersion>$(XunitVersion)</XunitAssertVersion>
|
||||
<XunitExtensibilityExecutionVersion>$(XunitVersion)</XunitExtensibilityExecutionVersion>
|
||||
<!-- Benchmarks -->
|
||||
<Benchmarks_BaselineSourceGeneratorsVersion>7.0.0-preview.5.22528.1</Benchmarks_BaselineSourceGeneratorsVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
|
@ -4,14 +4,17 @@
|
|||
<PackageVersion Include="DiffPlex" Version="$(DiffPlexVersion)" />
|
||||
<PackageVersion Include="FluentAssertions" Version="$(FluentAssertionsVersion)" />
|
||||
<PackageVersion Include="Microsoft.Build.Framework" Version="$(MicrosoftBuildFrameworkVersion)" />
|
||||
<PackageVersion Include="Microsoft.Build.Locator" Version="$(MicrosoftBuildLocatorVersion)" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildUtilitiesCoreVersion)" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="$(MicrosoftCodeAnalysisCommonVersion)" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftCodeAnalysisCSharpVersion)" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(MicrosoftCodeAnalysisCSharpWorkspacesVersion)" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="$(MicrosoftCodeAnalysisWorkspacesMSBuildVersion)" />
|
||||
<PackageVersion Include="Microsoft.CSharp" Version="$(MicrosoftCSharpVersion)" />
|
||||
<PackageVersion Include="Microsoft.Css.Parser" Version="$(MicrosoftCssParserVersion)" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelVersion)" />
|
||||
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="$(MicrosoftExtensionsFileSystemGlobbingVersion)" />
|
||||
<PackageVersion Include="Microsoft.NET.Sdk.Razor.SourceGenerators.Transport" Version="$(Benchmarks_BaselineSourceGeneratorsVersion)" />
|
||||
<PackageVersion Include="Moq" Version="$(MoqVersion)" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="$(NewtonsoftJsonVersion)" />
|
||||
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="$(SystemDiagnosticsDiagnosticSourceVersion)" />
|
||||
|
@ -20,7 +23,6 @@
|
|||
<PackageVersion Include="System.Text.Json" Version="$(SystemTextJsonVersion)" />
|
||||
<PackageVersion Include="xunit.assert" Version="$(XunitAssertVersion)" />
|
||||
<PackageVersion Include="xunit.extensibility.execution" Version="$(XunitExtensibilityExecutionVersion)" />
|
||||
|
||||
<!-- Temporarily force analyzers to match compiler version https://github.com/dotnet/razor-tooling/issues/6758 -->
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="$(Tooling_MicrosoftCodeAnalysisAnalyzersPackageVersion)" NoWarn="NU1608" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="$(Tooling_MicrosoftCodeAnalysisNetAnalyzersPackageVersion)" NoWarn="NU1608" />
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Microsoft.Build.Locator;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Microbenchmarks.Generator;
|
||||
|
||||
public class Benchmarks
|
||||
{
|
||||
ProjectSetup.RazorProject? _project;
|
||||
|
||||
public enum ChangeKind { Independent, DependentIgnorable, Dependent };
|
||||
[ParamsAllUnlessDebug(ChangeKind.Independent)]
|
||||
public ChangeKind Change { get; set; }
|
||||
|
||||
public enum StartupKind { Warm, Cold };
|
||||
[ParamsAllUnlessDebug(StartupKind.Warm)]
|
||||
public StartupKind Startup { get; set; }
|
||||
|
||||
[ModuleInitializer]
|
||||
public static void LoadMSBuild() => MSBuildLocator.RegisterDefaults();
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
_project = ProjectSetup.GetRazorProject(cold: Startup == StartupKind.Cold);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void RunBenchmark()
|
||||
{
|
||||
var compilation = _project!.Compilation;
|
||||
var driver = _project!.GeneratorDriver;
|
||||
driver = RazorChange();
|
||||
|
||||
driver = driver.RunGenerators(compilation);
|
||||
var result = driver.GetRunResult();
|
||||
|
||||
Debug.Assert(result.Diagnostics.IsDefaultOrEmpty);
|
||||
}
|
||||
|
||||
private GeneratorDriver RazorChange()
|
||||
{
|
||||
var driver = _project!.GeneratorDriver;
|
||||
var newRazorFile = GetNewRazorFile();
|
||||
var existingRazorFile = GetExistingRazorFile();
|
||||
|
||||
if (newRazorFile is not null && existingRazorFile is not null)
|
||||
{
|
||||
driver = driver.ReplaceAdditionalText(existingRazorFile, newRazorFile);
|
||||
}
|
||||
else if (newRazorFile is not null)
|
||||
{
|
||||
driver = driver.AddAdditionalTexts(ImmutableArray.Create(newRazorFile));
|
||||
}
|
||||
else if (existingRazorFile is not null)
|
||||
{
|
||||
driver = driver.RemoveAdditionalTexts(ImmutableArray.Create(existingRazorFile));
|
||||
}
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
private AdditionalText? GetNewRazorFile()
|
||||
{
|
||||
if (Change == ChangeKind.Independent)
|
||||
{
|
||||
return new ProjectSetup.InMemoryAdditionalText(IndependentRazorFile, "Pages/Generated/0.razor");
|
||||
}
|
||||
else if (Change == ChangeKind.DependentIgnorable)
|
||||
{
|
||||
return new ProjectSetup.InMemoryAdditionalText(DependentIgnorableRazorFile, "Pages/Counter.razor");
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ProjectSetup.InMemoryAdditionalText(DependentRazorFile, "Pages/Counter.razor");
|
||||
}
|
||||
}
|
||||
|
||||
private AdditionalText? GetExistingRazorFile()
|
||||
{
|
||||
if (Change == ChangeKind.Independent)
|
||||
{
|
||||
return _project!.AdditionalTexts.Single(a => a.Path.EndsWith("\\0.razor", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
return _project!.AdditionalTexts.Single(a => a.Path.EndsWith("Counter.razor", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
private const string IndependentRazorFile = "<h1>Independent File</h1>";
|
||||
|
||||
private const string DependentIgnorableRazorFile = """
|
||||
@page "/counter"
|
||||
|
||||
<PageTitle>Counter edited</PageTitle>
|
||||
|
||||
<h1>Counter</h1>
|
||||
|
||||
<p role="status">Current count: @currentCount</p>
|
||||
|
||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public int IncrementAmount { get; set; } = 1;
|
||||
|
||||
private int currentCount = 0;
|
||||
|
||||
private void IncrementCount()
|
||||
{
|
||||
currentCount += IncrementAmount;
|
||||
}
|
||||
}
|
||||
|
||||
""";
|
||||
|
||||
private const string DependentRazorFile = """
|
||||
@page "/counter"
|
||||
|
||||
<PageTitle>Counter edited</PageTitle>
|
||||
|
||||
<h1>Counter</h1>
|
||||
|
||||
<p role="status">Current count: @currentCount</p>
|
||||
|
||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
||||
|
||||
@code {
|
||||
|
||||
private int currentCount = 0;
|
||||
|
||||
private void IncrementCount()
|
||||
{
|
||||
currentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
""";
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="SampleApp\**" />
|
||||
<EmbeddedResource Remove="SampleApp\**" />
|
||||
<None Remove="SampleApp\**" />
|
||||
<Content Include="SampleApp\**" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" />
|
||||
<PackageReference Include="Microsoft.Build.Locator" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Reference the local source generator when building in regular configurations -->
|
||||
<ItemGroup Condition="'$(Configuration)' != 'Release_Nuget'">
|
||||
<ProjectReference Include="..\..\Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Grab the nuget package and reference its generator when building in Release_Nuget -->
|
||||
<ItemGroup Condition="'$(Configuration)' == 'Release_Nuget'">
|
||||
<PackageReference Include="Microsoft.NET.Sdk.Razor.SourceGenerators.Transport" GeneratePathProperty="true" />
|
||||
<Reference Include="$(PkgMicrosoft_NET_Sdk_Razor_SourceGenerators_Transport)\source-generators\*.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,24 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Microbenchmarks.Generator;
|
||||
internal class ParamsAllUnlessDebugAttribute
|
||||
#if DEBUG
|
||||
: ParamsAttribute
|
||||
#else
|
||||
: ParamsAllValuesAttribute
|
||||
#endif
|
||||
|
||||
{
|
||||
internal ParamsAllUnlessDebugAttribute(params object[] args)
|
||||
#if DEBUG
|
||||
: base(args[0])
|
||||
#else
|
||||
: base()
|
||||
#endif
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Exporters.Csv;
|
||||
using BenchmarkDotNet.Running;
|
||||
|
||||
Job baseJob = Job.Default;
|
||||
#if DEBUG
|
||||
baseJob = baseJob
|
||||
.WithIterationCount(1)
|
||||
.RunOncePerIteration()
|
||||
.WithToolchain(new BenchmarkDotNet.Toolchains.InProcess.Emit.InProcessEmitToolchain(TimeSpan.FromHours(1.0), logOutput: true));
|
||||
#endif
|
||||
|
||||
var config = ManualConfig.CreateMinimumViable()
|
||||
.AddJob(baseJob.WithCustomBuildConfiguration("Release").WithId("Current"))
|
||||
.AddJob(baseJob.WithCustomBuildConfiguration("Release_Nuget").WithId("Baseline").WithBaseline(true))
|
||||
.StopOnFirstError(true)
|
||||
.AddExporter(CsvExporter.Default);
|
||||
|
||||
var results = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
|
||||
|
||||
var reports =
|
||||
from summary in results
|
||||
from report in summary.Reports
|
||||
where !summary.IsBaseline(report.BenchmarkCase)
|
||||
let baselineCase = summary.GetBaseline(summary.GetLogicalGroupKey(report.BenchmarkCase))
|
||||
let baseline = summary.Reports.Single(r => r.BenchmarkCase == baselineCase)
|
||||
select (report, baseline);
|
||||
|
||||
int exitCode = 0;
|
||||
foreach ((var benchmark, var baseline) in reports)
|
||||
{
|
||||
// Note: there are actual statistical tests we could do here, but this should suffice.
|
||||
// We can invest more if we see consistent false positives
|
||||
|
||||
var ratio = benchmark.ResultStatistics.Mean / baseline.ResultStatistics.Mean;
|
||||
|
||||
if (ratio > 1.1)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Benchmark may have regressed!");
|
||||
Console.WriteLine(benchmark.BenchmarkCase.DisplayInfo);
|
||||
exitCode--;
|
||||
}
|
||||
}
|
||||
|
||||
return exitCode;
|
|
@ -0,0 +1,138 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
using Microsoft.CodeAnalysis.MSBuild;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.NET.Sdk.Razor.SourceGenerators;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Microbenchmarks.Generator;
|
||||
internal static class ProjectSetup
|
||||
{
|
||||
internal static async Task<RazorProject> GetRazorProjectAsync(bool cold = true)
|
||||
{
|
||||
var workspace = MSBuildWorkspace.Create();
|
||||
var project = await workspace.OpenProjectAsync("SampleApp/SampleApp.csproj");
|
||||
|
||||
// remove any generators from the project as we don't want generated files in our initial compilation
|
||||
foreach (var analyzerRef in project.AnalyzerReferences)
|
||||
{
|
||||
project = project.RemoveAnalyzerReference(analyzerRef);
|
||||
}
|
||||
|
||||
// get the constituent parts
|
||||
var compilation = await project.GetCompilationAndCheckSuccess();
|
||||
|
||||
List<AdditionalText> additionalTexts = new List<AdditionalText>();
|
||||
foreach (var additionalDocument in project.AdditionalDocuments)
|
||||
{
|
||||
var text = await additionalDocument.GetTextAsync();
|
||||
additionalTexts.Add(new InMemoryAdditionalText(text, additionalDocument.FilePath!));
|
||||
}
|
||||
|
||||
var parseOptions = (CSharpParseOptions)project.ParseOptions!;
|
||||
|
||||
var optionsProvider = new TargetPathAnalyzerConfigOptionsProvider(project.AnalyzerOptions.AnalyzerConfigOptionsProvider);
|
||||
|
||||
// create the generator driver we'll use for the tests
|
||||
// the generator we use will be dependent on the build configuration the benchmark is built in
|
||||
GeneratorDriver driver = CSharpGeneratorDriver.Create(generators: new[] { new RazorSourceGenerator().AsSourceGenerator() },
|
||||
additionalTexts: additionalTexts,
|
||||
parseOptions: parseOptions,
|
||||
optionsProvider: optionsProvider);
|
||||
|
||||
// if we request a warm project, run the driver once through to start with, priming the caches
|
||||
if (!cold)
|
||||
{
|
||||
driver = driver.RunGenerators(compilation);
|
||||
}
|
||||
|
||||
return new(driver, compilation, additionalTexts.ToImmutableArray(), parseOptions, optionsProvider);
|
||||
}
|
||||
|
||||
internal static RazorProject GetRazorProject(bool cold = true) => Task.Run(() => GetRazorProjectAsync(cold)).GetAwaiter().GetResult();
|
||||
|
||||
public static async Task<Compilation> GetCompilationAndCheckSuccess(this Project project)
|
||||
{
|
||||
var comp = await project.GetCompilationAsync();
|
||||
var diagnostics = comp!.GetDiagnostics();
|
||||
if (diagnostics.Any(d => d.Severity != DiagnosticSeverity.Hidden))
|
||||
{
|
||||
//Debug.Fail("Compilation contained non-hidden diagnostics");
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
internal record RazorProject(GeneratorDriver GeneratorDriver, Compilation Compilation, ImmutableArray<AdditionalText> AdditionalTexts, CSharpParseOptions ParseOptions, AnalyzerConfigOptionsProvider OptionsProvider);
|
||||
|
||||
internal sealed class InMemoryAdditionalText : AdditionalText
|
||||
{
|
||||
private readonly SourceText _text;
|
||||
|
||||
public InMemoryAdditionalText(SourceText text, string path)
|
||||
{
|
||||
_text = text;
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public InMemoryAdditionalText(string text, string path)
|
||||
{
|
||||
_text = SourceText.From(text, Encoding.UTF8);
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public override string Path { get; }
|
||||
|
||||
public override SourceText? GetText(CancellationToken cancellationToken = default) => _text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An options provider that will add the required razor metadata if it's missing.
|
||||
/// </summary>
|
||||
internal sealed class TargetPathAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider
|
||||
{
|
||||
private readonly AnalyzerConfigOptionsProvider _provider;
|
||||
|
||||
public TargetPathAnalyzerConfigOptionsProvider(AnalyzerConfigOptionsProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
public override AnalyzerConfigOptions GlobalOptions { get => _provider.GlobalOptions; }
|
||||
|
||||
public override AnalyzerConfigOptions GetOptions(SyntaxTree tree) => _provider.GetOptions(tree);
|
||||
|
||||
public override AnalyzerConfigOptions GetOptions(AdditionalText textFile)
|
||||
{
|
||||
return new TargetPathAnalyzerOptions(textFile.Path, _provider.GetOptions(textFile));
|
||||
}
|
||||
|
||||
internal class TargetPathAnalyzerOptions : AnalyzerConfigOptions
|
||||
{
|
||||
private readonly string _targetPath;
|
||||
|
||||
private readonly AnalyzerConfigOptions _baseOptions;
|
||||
|
||||
public TargetPathAnalyzerOptions(string name, AnalyzerConfigOptions baseOptions)
|
||||
{
|
||||
_targetPath = Convert.ToBase64String(Encoding.UTF8.GetBytes(name));
|
||||
_baseOptions = baseOptions;
|
||||
}
|
||||
|
||||
public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value)
|
||||
{
|
||||
if (!_baseOptions.TryGetValue(key, out value))
|
||||
{
|
||||
value = key == "build_metadata.AdditionalFiles.TargetPath" ? _targetPath : string.Empty;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
root = true
|
|
@ -0,0 +1,12 @@
|
|||
<Router AppAssembly="@typeof(App).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
|
||||
</Found>
|
||||
<NotFound>
|
||||
<PageTitle>Not found</PageTitle>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<p role="alert">Sorry, there's nothing at this address.</p>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
|
@ -0,0 +1,12 @@
|
|||
namespace SampleApp.Data;
|
||||
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string? Summary { get; set; }
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
namespace SampleApp.Data;
|
||||
|
||||
public class WeatherForecastService
|
||||
{
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
public Task<WeatherForecast[]> GetForecastAsync(DateOnly startDate)
|
||||
{
|
||||
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = startDate.AddDays(index),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
|
||||
}).ToArray());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
@page "/counter"
|
||||
|
||||
<PageTitle>Counter</PageTitle>
|
||||
|
||||
<h1>Counter</h1>
|
||||
|
||||
<p role="status">Current count: @currentCount</p>
|
||||
|
||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public int IncrementAmount { get; set; } = 1;
|
||||
|
||||
private int currentCount = 0;
|
||||
|
||||
private void IncrementCount()
|
||||
{
|
||||
currentCount += IncrementAmount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
@page
|
||||
@model SampleApp.Pages.ErrorModel
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>Error</title>
|
||||
<link href="~/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
|
||||
<link href="~/css/site.css" rel="stylesheet" asp-append-version="true" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main">
|
||||
<div class="content px-4">
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (Model.ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,26 @@
|
|||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace SampleApp.Pages;
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
[IgnoreAntiforgeryToken]
|
||||
public class ErrorModel : PageModel
|
||||
{
|
||||
public string? RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
private readonly ILogger<ErrorModel> _logger;
|
||||
|
||||
public ErrorModel(ILogger<ErrorModel> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
@page "/fetchdata"
|
||||
@using SampleApp.Data
|
||||
@inject WeatherForecastService ForecastService
|
||||
|
||||
<PageTitle>Weather forecast</PageTitle>
|
||||
|
||||
<h1>Weather forecast</h1>
|
||||
|
||||
<p>This component demonstrates fetching data from a service.</p>
|
||||
|
||||
@if (forecasts == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var forecast in forecasts)
|
||||
{
|
||||
<tr>
|
||||
<td>@forecast.Date.ToShortDateString()</td>
|
||||
<td>@forecast.TemperatureC</td>
|
||||
<td>@forecast.TemperatureF</td>
|
||||
<td>@forecast.Summary</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
private WeatherForecast[]? forecasts;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
forecasts = await ForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
@page "/0"
|
||||
<h1>Page 0 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/1"
|
||||
<h1>Page 1 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/10"
|
||||
<h1>Page 10 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/11"
|
||||
<h1>Page 11 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/12"
|
||||
<h1>Page 12 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/13"
|
||||
<h1>Page 13 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/14"
|
||||
<h1>Page 14 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/15"
|
||||
<h1>Page 15 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/16"
|
||||
<h1>Page 16 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/17"
|
||||
<h1>Page 17 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/18"
|
||||
<h1>Page 18 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/19"
|
||||
<h1>Page 19 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/2"
|
||||
<h1>Page 2 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/20"
|
||||
<h1>Page 20 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/21"
|
||||
<h1>Page 21 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/22"
|
||||
<h1>Page 22 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/23"
|
||||
<h1>Page 23 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/24"
|
||||
<h1>Page 24 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/25"
|
||||
<h1>Page 25 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/26"
|
||||
<h1>Page 26 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/27"
|
||||
<h1>Page 27 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/28"
|
||||
<h1>Page 28 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/29"
|
||||
<h1>Page 29 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/3"
|
||||
<h1>Page 3 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/30"
|
||||
<h1>Page 30 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/31"
|
||||
<h1>Page 31 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/32"
|
||||
<h1>Page 32 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/33"
|
||||
<h1>Page 33 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/34"
|
||||
<h1>Page 34 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/35"
|
||||
<h1>Page 35 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/36"
|
||||
<h1>Page 36 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/37"
|
||||
<h1>Page 37 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/38"
|
||||
<h1>Page 38 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/39"
|
||||
<h1>Page 39 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/4"
|
||||
<h1>Page 4 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/40"
|
||||
<h1>Page 40 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/41"
|
||||
<h1>Page 41 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/42"
|
||||
<h1>Page 42 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/43"
|
||||
<h1>Page 43 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/44"
|
||||
<h1>Page 44 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/45"
|
||||
<h1>Page 45 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/46"
|
||||
<h1>Page 46 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/47"
|
||||
<h1>Page 47 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/48"
|
||||
<h1>Page 48 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/49"
|
||||
<h1>Page 49 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/5"
|
||||
<h1>Page 5 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/50"
|
||||
<h1>Page 50 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/51"
|
||||
<h1>Page 51 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/52"
|
||||
<h1>Page 52 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/53"
|
||||
<h1>Page 53 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/54"
|
||||
<h1>Page 54 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/55"
|
||||
<h1>Page 55 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/56"
|
||||
<h1>Page 56 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/57"
|
||||
<h1>Page 57 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/58"
|
||||
<h1>Page 58 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/59"
|
||||
<h1>Page 59 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/6"
|
||||
<h1>Page 6 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/60"
|
||||
<h1>Page 60 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/61"
|
||||
<h1>Page 61 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/62"
|
||||
<h1>Page 62 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/63"
|
||||
<h1>Page 63 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/64"
|
||||
<h1>Page 64 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/65"
|
||||
<h1>Page 65 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/66"
|
||||
<h1>Page 66 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/67"
|
||||
<h1>Page 67 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/68"
|
||||
<h1>Page 68 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/69"
|
||||
<h1>Page 69 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/7"
|
||||
<h1>Page 7 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/70"
|
||||
<h1>Page 70 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/71"
|
||||
<h1>Page 71 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/72"
|
||||
<h1>Page 72 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/73"
|
||||
<h1>Page 73 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/74"
|
||||
<h1>Page 74 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/75"
|
||||
<h1>Page 75 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/76"
|
||||
<h1>Page 76 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/77"
|
||||
<h1>Page 77 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/78"
|
||||
<h1>Page 78 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/79"
|
||||
<h1>Page 79 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/8"
|
||||
<h1>Page 8 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/80"
|
||||
<h1>Page 80 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/81"
|
||||
<h1>Page 81 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/82"
|
||||
<h1>Page 82 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/83"
|
||||
<h1>Page 83 </h1>
|
|
@ -0,0 +1,2 @@
|
|||
@page "/84"
|
||||
<h1>Page 84 </h1>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче