Reorganize source code in preparation to move into aspnet/AspNetCore

Prior to reorganization, this source code was found in https://github.com/aspnet/Razor/tree/dotnet/aspnetcore-tooling@582f3f867eeb8fca00e6b328faf7665c9a98476c
\n\nCommit migrated from 33b287d4a4
This commit is contained in:
Ryan Nowak 2018-11-29 15:13:03 -08:00
commit 1c99d2ed4a
11 changed files with 4462 additions and 0 deletions

View File

@ -0,0 +1 @@
[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark]

View File

@ -0,0 +1,58 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class CodeGenerationBenchmark
{
public CodeGenerationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "MSN.cshtml")))
{
current = current.Parent;
}
var root = current;
var fileSystem = RazorProjectFileSystem.Create(root.FullName);
ProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, b => RazorExtensions.Register(b)); ;
MSN = fileSystem.GetItem(Path.Combine(root.FullName, "MSN.cshtml"));
}
public RazorProjectEngine ProjectEngine { get; }
public RazorProjectItem MSN { get; }
[Benchmark(Description = "Razor Design Time Code Generation of MSN.com")]
public void CodeGeneration_DesignTime_LargeStaticFile()
{
var codeDocument = ProjectEngine.ProcessDesignTime(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
}
}
[Benchmark(Description = "Razor Runtime Code Generation of MSN.com")]
public void CodeGeneration_Runtime_LargeStaticFile()
{
var codeDocument = ProjectEngine.Process(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
<ServerGarbageCollection>true</ServerGarbageCollection>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
<ProjectReference Include="..\..\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\src\Microsoft.VisualStudio.LanguageServices.Razor\Serialization\*.cs">
<Link>Serialization\%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestServices.cs">
<Link>TestServices\%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestWorkspace.cs">
<Link>TestServices\%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestLanguageServices.cs">
<Link>TestServices\%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestWorkspaceServices.cs">
<Link>TestServices\%(FileName)%(Extension)</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,53 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class BackgroundCodeGenerationBenchmark : ProjectSnapshotManagerBenchmarkBase
{
[IterationSetup]
public void Setup()
{
SnapshotManager = CreateProjectSnapshotManager();
SnapshotManager.HostProjectAdded(HostProject);
SnapshotManager.Changed += SnapshotManager_Changed;
}
[IterationCleanup]
public void Cleanup()
{
SnapshotManager.Changed -= SnapshotManager_Changed;
Tasks.Clear();
}
private List<Task> Tasks { get; } = new List<Task>();
private DefaultProjectSnapshotManager SnapshotManager { get; set; }
[Benchmark(Description = "Generates the code for 100 files", OperationsPerInvoke = 100)]
public async Task BackgroundCodeGeneration_Generate100Files()
{
for (var i = 0; i < Documents.Length; i++)
{
SnapshotManager.DocumentAdded(HostProject, Documents[i], TextLoaders[i % 4]);
}
await Task.WhenAll(Tasks);
}
private void SnapshotManager_Changed(object sender, ProjectChangeEventArgs e)
{
// The real work happens here.
var project = SnapshotManager.GetLoadedProject(e.ProjectFilePath);
var document = project.GetDocument(e.DocumentFilePath);
Tasks.Add(document.GetGeneratedOutputAsync());
}
}
}

View File

@ -0,0 +1,30 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using BenchmarkDotNet.Attributes;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class ProjectLoadBenchmark : ProjectSnapshotManagerBenchmarkBase
{
[IterationSetup]
public void Setup()
{
SnapshotManager = CreateProjectSnapshotManager();
}
private DefaultProjectSnapshotManager SnapshotManager { get; set; }
[Benchmark(Description = "Initializes a project and 100 files", OperationsPerInvoke = 100)]
public void ProjectLoad_AddProjectAnd100Files()
{
SnapshotManager.HostProjectAdded(HostProject);
for (var i= 0; i < Documents.Length; i++)
{
SnapshotManager.DocumentAdded(HostProject, Documents[i], TextLoaders[i % 4]);
}
}
}
}

View File

@ -0,0 +1,154 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServices.Razor.Serialization;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class ProjectSnapshotManagerBenchmarkBase
{
public ProjectSnapshotManagerBenchmarkBase()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "Razor.sln")))
{
current = current.Parent;
}
var root = current;
var projectRoot = Path.Combine(root.FullName, "test", "testapps", "LargeProject");
HostProject = new HostProject(Path.Combine(projectRoot, "LargeProject.csproj"), FallbackRazorConfiguration.MVC_2_1);
TextLoaders = new TextLoader[4];
for (var i = 0; i < 4; i++)
{
var filePath = Path.Combine(projectRoot, "Views", "Home", $"View00{i % 4}.cshtml");
var text = SourceText.From(filePath, encoding: null);
TextLoaders[i] = TextLoader.From(TextAndVersion.Create(text, VersionStamp.Create()));
}
Documents = new HostDocument[100];
for (var i = 0; i < Documents.Length; i++)
{
var filePath = Path.Combine(projectRoot, "Views", "Home", $"View00{i % 4}.cshtml");
Documents[i] = new HostDocument(filePath, $"/Views/Home/View00{i}.cshtml");
}
var tagHelpers = Path.Combine(root.FullName, "benchmarks", "Microsoft.AspNetCore.Razor.Performance", "taghelpers.json");
TagHelperResolver = new StaticTagHelperResolver(ReadTagHelpers(tagHelpers));
}
internal HostProject HostProject { get; }
internal HostDocument[] Documents { get; }
internal TextLoader[] TextLoaders { get; }
internal TagHelperResolver TagHelperResolver { get; }
internal DefaultProjectSnapshotManager CreateProjectSnapshotManager()
{
var services = TestServices.Create(
new IWorkspaceService[]
{
new StaticProjectSnapshotProjectEngineFactory(),
},
new ILanguageService[]
{
TagHelperResolver,
});
return new DefaultProjectSnapshotManager(
new TestForegroundDispatcher(),
new TestErrorReporter(),
Array.Empty<ProjectSnapshotChangeTrigger>(),
new AdhocWorkspace(services));
}
private static IReadOnlyList<TagHelperDescriptor> ReadTagHelpers(string filePath)
{
var serializer = new JsonSerializer();
serializer.Converters.Add(new RazorDiagnosticJsonConverter());
serializer.Converters.Add(new TagHelperDescriptorJsonConverter());
using (var reader = new JsonTextReader(File.OpenText(filePath)))
{
return serializer.Deserialize<IReadOnlyList<TagHelperDescriptor>>(reader);
}
}
private class TestForegroundDispatcher : ForegroundDispatcher
{
public override bool IsForegroundThread => true;
public override TaskScheduler ForegroundScheduler => TaskScheduler.Default;
public override TaskScheduler BackgroundScheduler => TaskScheduler.Default;
}
private class TestErrorReporter : ErrorReporter
{
public override void ReportError(Exception exception)
{
}
public override void ReportError(Exception exception, ProjectSnapshot project)
{
}
public override void ReportError(Exception exception, Project workspaceProject)
{
}
}
private class StaticTagHelperResolver : TagHelperResolver
{
private readonly IReadOnlyList<TagHelperDescriptor> _tagHelpers;
public StaticTagHelperResolver(IReadOnlyList<TagHelperDescriptor> tagHelpers)
{
this._tagHelpers = tagHelpers;
}
public override Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, CancellationToken cancellationToken = default)
{
return Task.FromResult(new TagHelperResolutionResult(_tagHelpers, Array.Empty<RazorDiagnostic>()));
}
}
private class StaticProjectSnapshotProjectEngineFactory : ProjectSnapshotProjectEngineFactory
{
public override IProjectEngineFactory FindFactory(ProjectSnapshot project)
{
throw new NotImplementedException();
}
public override IProjectEngineFactory FindSerializableFactory(ProjectSnapshot project)
{
throw new NotImplementedException();
}
public override RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
{
return RazorProjectEngine.Create(configuration, fileSystem, b =>
{
RazorExtensions.Register(b);
});
}
}
}
}

View File

@ -0,0 +1,77 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class SyntaxTreeGenerationBenchmark
{
public SyntaxTreeGenerationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "MSN.cshtml")))
{
current = current.Parent;
}
var root = current;
var fileSystem = RazorProjectFileSystem.Create(root.FullName);
ProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, b => RazorExtensions.Register(b)); ;
var projectItem = fileSystem.GetItem(Path.Combine(root.FullName, "MSN.cshtml"));
MSN = RazorSourceDocument.ReadFrom(projectItem);
var directiveFeature = ProjectEngine.EngineFeatures.OfType<IRazorDirectiveFeature>().FirstOrDefault();
Directives = directiveFeature?.Directives.ToArray() ?? Array.Empty<DirectiveDescriptor>();
}
public RazorProjectEngine ProjectEngine { get; }
public RazorSourceDocument MSN { get; }
public DirectiveDescriptor[] Directives { get; }
[Benchmark(Description = "Razor Design Time Syntax Tree Generation of MSN.com")]
public void SyntaxTreeGeneration_DesignTime_LargeStaticFile()
{
var options = RazorParserOptions.CreateDesignTime(o =>
{
foreach (var directive in Directives)
{
o.Directives.Add(directive);
}
});
var syntaxTree = RazorSyntaxTree.Parse(MSN, options);
if (syntaxTree.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, syntaxTree.Diagnostics));
}
}
[Benchmark(Description = "Razor Runtime Syntax Tree Generation of MSN.com")]
public void SyntaxTreeGeneration_Runtime_LargeStaticFile()
{
var options = RazorParserOptions.Create(o =>
{
foreach (var directive in Directives)
{
o.Directives.Add(directive);
}
});
var syntaxTree = RazorSyntaxTree.Parse(MSN, options);
if (syntaxTree.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, syntaxTree.Diagnostics));
}
}
}
}

View File

@ -0,0 +1,54 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.VisualStudio.LanguageServices.Razor.Serialization;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class TagHelperSerializationBenchmark
{
private readonly byte[] _tagHelperBuffer;
public TagHelperSerializationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "taghelpers.json")))
{
current = current.Parent;
}
var tagHelperFilePath = Path.Combine(current.FullName, "taghelpers.json");
_tagHelperBuffer = File.ReadAllBytes(tagHelperFilePath);
}
[Benchmark(Description = "Razor TagHelper Serialization")]
public void TagHelper_Serialization_RoundTrip()
{
var serializer = new JsonSerializer();
serializer.Converters.Add(new RazorDiagnosticJsonConverter());
serializer.Converters.Add(new TagHelperDescriptorJsonConverter());
// Deserialize from json file.
IReadOnlyList<TagHelperDescriptor> tagHelpers;
using (var stream = new MemoryStream(_tagHelperBuffer))
using (var reader = new JsonTextReader(new StreamReader(stream)))
{
tagHelpers = serializer.Deserialize<IReadOnlyList<TagHelperDescriptor>>(reader);
}
// Serialize back to json.
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 4096))
{
serializer.Serialize(writer, tagHelpers);
}
}
}
}

View File

@ -0,0 +1,11 @@
Compile the solution in Release mode (so binaries are available in release)
To run a specific benchmark add it as parameter.
```
dotnet run -c Release <benchmark_name>
```
If you run without any parameters, you'll be offered the list of all benchmarks and get to choose.
```
dotnet run -c Release
```

File diff suppressed because one or more lines are too long