Skip to content

Commit 7b56497

Browse files
author
John Luo
committed
Merge branch 'master' of ..\aspnetcore-tooling2\
2 parents 07bab03 + 4bdf89b commit 7b56497

25 files changed

+7493
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark]
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.IO;
6+
using BenchmarkDotNet.Attributes;
7+
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
8+
using Microsoft.AspNetCore.Razor.Language;
9+
10+
namespace Microsoft.AspNetCore.Razor.Performance
11+
{
12+
public class CodeGenerationBenchmark
13+
{
14+
public CodeGenerationBenchmark()
15+
{
16+
var current = new DirectoryInfo(AppContext.BaseDirectory);
17+
while (current != null && !File.Exists(Path.Combine(current.FullName, "MSN.cshtml")))
18+
{
19+
current = current.Parent;
20+
}
21+
22+
var root = current;
23+
var fileSystem = RazorProjectFileSystem.Create(root.FullName);
24+
25+
ProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, b => RazorExtensions.Register(b)); ;
26+
27+
MSN = fileSystem.GetItem(Path.Combine(root.FullName, "MSN.cshtml"), FileKinds.Legacy);
28+
}
29+
30+
public RazorProjectEngine ProjectEngine { get; }
31+
32+
public RazorProjectItem MSN { get; }
33+
34+
[Benchmark(Description = "Razor Design Time Code Generation of MSN.com")]
35+
public void CodeGeneration_DesignTime_LargeStaticFile()
36+
{
37+
var codeDocument = ProjectEngine.ProcessDesignTime(MSN);
38+
var generated = codeDocument.GetCSharpDocument();
39+
40+
if (generated.Diagnostics.Count != 0)
41+
{
42+
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
43+
}
44+
}
45+
46+
[Benchmark(Description = "Razor Runtime Code Generation of MSN.com")]
47+
public void CodeGeneration_Runtime_LargeStaticFile()
48+
{
49+
var codeDocument = ProjectEngine.Process(MSN);
50+
var generated = codeDocument.GetCSharpDocument();
51+
52+
if (generated.Diagnostics.Count != 0)
53+
{
54+
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
55+
}
56+
}
57+
}
58+
}

src/Razor/perf/Microsoft.AspNetCore.Razor.Performance/MSN.cshtml

Lines changed: 3983 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.1</TargetFramework>
5+
<OutputType>Exe</OutputType>
6+
<ServerGarbageCollection>true</ServerGarbageCollection>
7+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
8+
<IsPackable>false</IsPackable>
9+
<ExcludeFromSourceBuild>true</ExcludeFromSourceBuild>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
14+
<ProjectReference Include="..\..\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<Compile Include="..\..\src\Microsoft.VisualStudio.LanguageServices.Razor\Serialization\*.cs">
19+
<Link>Serialization\%(FileName)%(Extension)</Link>
20+
</Compile>
21+
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestServices.cs">
22+
<Link>TestServices\%(FileName)%(Extension)</Link>
23+
</Compile>
24+
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestWorkspace.cs">
25+
<Link>TestServices\%(FileName)%(Extension)</Link>
26+
</Compile>
27+
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestLanguageServices.cs">
28+
<Link>TestServices\%(FileName)%(Extension)</Link>
29+
</Compile>
30+
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestWorkspaceServices.cs">
31+
<Link>TestServices\%(FileName)%(Extension)</Link>
32+
</Compile>
33+
</ItemGroup>
34+
35+
<ItemGroup>
36+
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
37+
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
38+
<PackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />
39+
</ItemGroup>
40+
41+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using System.Threading.Tasks;
6+
using BenchmarkDotNet.Attributes;
7+
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
8+
9+
namespace Microsoft.AspNetCore.Razor.Performance
10+
{
11+
public class BackgroundCodeGenerationBenchmark : ProjectSnapshotManagerBenchmarkBase
12+
{
13+
[IterationSetup]
14+
public void Setup()
15+
{
16+
SnapshotManager = CreateProjectSnapshotManager();
17+
SnapshotManager.ProjectAdded(HostProject);
18+
SnapshotManager.Changed += SnapshotManager_Changed;
19+
}
20+
21+
[IterationCleanup]
22+
public void Cleanup()
23+
{
24+
SnapshotManager.Changed -= SnapshotManager_Changed;
25+
26+
Tasks.Clear();
27+
}
28+
29+
private List<Task> Tasks { get; } = new List<Task>();
30+
31+
private DefaultProjectSnapshotManager SnapshotManager { get; set; }
32+
33+
[Benchmark(Description = "Generates the code for 100 files", OperationsPerInvoke = 100)]
34+
public async Task BackgroundCodeGeneration_Generate100Files()
35+
{
36+
for (var i = 0; i < Documents.Length; i++)
37+
{
38+
SnapshotManager.DocumentAdded(HostProject, Documents[i], TextLoaders[i % 4]);
39+
}
40+
41+
await Task.WhenAll(Tasks);
42+
}
43+
44+
private void SnapshotManager_Changed(object sender, ProjectChangeEventArgs e)
45+
{
46+
// The real work happens here.
47+
var project = SnapshotManager.GetLoadedProject(e.ProjectFilePath);
48+
var document = project.GetDocument(e.DocumentFilePath);
49+
50+
Tasks.Add(document.GetGeneratedOutputAsync());
51+
}
52+
}
53+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using BenchmarkDotNet.Attributes;
5+
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
6+
7+
namespace Microsoft.AspNetCore.Razor.Performance
8+
{
9+
public class ProjectLoadBenchmark : ProjectSnapshotManagerBenchmarkBase
10+
{
11+
[IterationSetup]
12+
public void Setup()
13+
{
14+
SnapshotManager = CreateProjectSnapshotManager();
15+
}
16+
17+
private DefaultProjectSnapshotManager SnapshotManager { get; set; }
18+
19+
[Benchmark(Description = "Initializes a project and 100 files", OperationsPerInvoke = 100)]
20+
public void ProjectLoad_AddProjectAnd100Files()
21+
{
22+
SnapshotManager.ProjectAdded(HostProject);
23+
24+
for (var i= 0; i < Documents.Length; i++)
25+
{
26+
SnapshotManager.DocumentAdded(HostProject, Documents[i], TextLoaders[i % 4]);
27+
}
28+
}
29+
}
30+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
10+
using Microsoft.AspNetCore.Razor.Language;
11+
using Microsoft.CodeAnalysis;
12+
using Microsoft.CodeAnalysis.Host;
13+
using Microsoft.CodeAnalysis.Razor;
14+
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
15+
using Microsoft.CodeAnalysis.Razor.Serialization;
16+
using Microsoft.CodeAnalysis.Text;
17+
using Microsoft.VisualStudio.LanguageServices.Razor.Serialization;
18+
using Newtonsoft.Json;
19+
20+
namespace Microsoft.AspNetCore.Razor.Performance
21+
{
22+
public class ProjectSnapshotManagerBenchmarkBase
23+
{
24+
public ProjectSnapshotManagerBenchmarkBase()
25+
{
26+
var current = new DirectoryInfo(AppContext.BaseDirectory);
27+
while (current != null && !File.Exists(Path.Combine(current.FullName, "Razor.sln")))
28+
{
29+
current = current.Parent;
30+
}
31+
32+
var root = current;
33+
var projectRoot = Path.Combine(root.FullName, "test", "testapps", "LargeProject");
34+
35+
HostProject = new HostProject(Path.Combine(projectRoot, "LargeProject.csproj"), FallbackRazorConfiguration.MVC_2_1, rootNamespace: null);
36+
37+
TextLoaders = new TextLoader[4];
38+
for (var i = 0; i < 4; i++)
39+
{
40+
var filePath = Path.Combine(projectRoot, "Views", "Home", $"View00{i % 4}.cshtml");
41+
var text = SourceText.From(filePath, encoding: null);
42+
TextLoaders[i] = TextLoader.From(TextAndVersion.Create(text, VersionStamp.Create()));
43+
}
44+
45+
Documents = new HostDocument[100];
46+
for (var i = 0; i < Documents.Length; i++)
47+
{
48+
var filePath = Path.Combine(projectRoot, "Views", "Home", $"View00{i % 4}.cshtml");
49+
Documents[i] = new HostDocument(filePath, $"/Views/Home/View00{i}.cshtml", FileKinds.Legacy);
50+
}
51+
52+
var tagHelpers = Path.Combine(root.FullName, "benchmarks", "Microsoft.AspNetCore.Razor.Performance", "taghelpers.json");
53+
TagHelperResolver = new StaticTagHelperResolver(ReadTagHelpers(tagHelpers));
54+
}
55+
56+
internal HostProject HostProject { get; }
57+
58+
internal HostDocument[] Documents { get; }
59+
60+
internal TextLoader[] TextLoaders { get; }
61+
62+
internal TagHelperResolver TagHelperResolver { get; }
63+
64+
internal DefaultProjectSnapshotManager CreateProjectSnapshotManager()
65+
{
66+
var services = TestServices.Create(
67+
new IWorkspaceService[]
68+
{
69+
TagHelperResolver,
70+
new StaticProjectSnapshotProjectEngineFactory(),
71+
},
72+
new ILanguageService[]
73+
{
74+
});
75+
76+
return new DefaultProjectSnapshotManager(
77+
new TestForegroundDispatcher(),
78+
new TestErrorReporter(),
79+
Array.Empty<ProjectSnapshotChangeTrigger>(),
80+
new AdhocWorkspace(services));
81+
}
82+
83+
private static IReadOnlyList<TagHelperDescriptor> ReadTagHelpers(string filePath)
84+
{
85+
var serializer = new JsonSerializer();
86+
serializer.Converters.Add(new RazorDiagnosticJsonConverter());
87+
serializer.Converters.Add(new TagHelperDescriptorJsonConverter());
88+
89+
using (var reader = new JsonTextReader(File.OpenText(filePath)))
90+
{
91+
return serializer.Deserialize<IReadOnlyList<TagHelperDescriptor>>(reader);
92+
}
93+
}
94+
95+
private class TestForegroundDispatcher : ForegroundDispatcher
96+
{
97+
public override bool IsForegroundThread => true;
98+
99+
public override TaskScheduler ForegroundScheduler => TaskScheduler.Default;
100+
101+
public override TaskScheduler BackgroundScheduler => TaskScheduler.Default;
102+
}
103+
104+
private class TestErrorReporter : ErrorReporter
105+
{
106+
public override void ReportError(Exception exception)
107+
{
108+
}
109+
110+
public override void ReportError(Exception exception, ProjectSnapshot project)
111+
{
112+
}
113+
114+
public override void ReportError(Exception exception, Project workspaceProject)
115+
{
116+
}
117+
}
118+
119+
private class StaticTagHelperResolver : TagHelperResolver
120+
{
121+
private readonly IReadOnlyList<TagHelperDescriptor> _tagHelpers;
122+
123+
public StaticTagHelperResolver(IReadOnlyList<TagHelperDescriptor> tagHelpers)
124+
{
125+
this._tagHelpers = tagHelpers;
126+
}
127+
128+
public override Task<TagHelperResolutionResult> GetTagHelpersAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken = default)
129+
{
130+
return Task.FromResult(new TagHelperResolutionResult(_tagHelpers, Array.Empty<RazorDiagnostic>()));
131+
}
132+
}
133+
134+
private class StaticProjectSnapshotProjectEngineFactory : ProjectSnapshotProjectEngineFactory
135+
{
136+
public override IProjectEngineFactory FindFactory(ProjectSnapshot project)
137+
{
138+
throw new NotImplementedException();
139+
}
140+
141+
public override IProjectEngineFactory FindSerializableFactory(ProjectSnapshot project)
142+
{
143+
throw new NotImplementedException();
144+
}
145+
146+
public override RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
147+
{
148+
return RazorProjectEngine.Create(configuration, fileSystem, b =>
149+
{
150+
RazorExtensions.Register(b);
151+
});
152+
}
153+
}
154+
}
155+
}

0 commit comments

Comments
 (0)