Skip to content
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
@@ -0,0 +1,43 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.IO;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectEngineHost.Serialization;

namespace Microsoft.AspNetCore.Razor.Microbenchmarks;

internal static class CommonResources
{
public static readonly byte[] LegacyTagHelperBytes = Resources.GetResourceBytes("taghelpers.json");
public static readonly IReadOnlyList<TagHelperDescriptor> LegacyTagHelpers = LoadTagHelpers(LegacyTagHelperBytes);

public static readonly byte[] LegacyProjectRazorJsonBytes = Resources.GetResourceBytes("project.razor.json");
public static readonly ProjectRazorJson LegacyProjectRazorJson = LoadProjectRazorJson(LegacyProjectRazorJsonBytes);

public static readonly byte[] TelerikTagHelperBytes = Resources.GetResourceBytes("Kendo.Mvc.Examples.taghelpers.json", folder: "Telerik");
public static readonly IReadOnlyList<TagHelperDescriptor> TelerikTagHelpers = LoadTagHelpers(TelerikTagHelperBytes);

public static readonly byte[] TelerikProjectRazorJsonBytes = Resources.GetResourceBytes("Kendo.Mvc.Examples.project.razor.json", folder: "Telerik");
public static readonly ProjectRazorJson TelerikProjectRazorJson = LoadProjectRazorJson(TelerikProjectRazorJsonBytes);

private static IReadOnlyList<TagHelperDescriptor> LoadTagHelpers(byte[] bytes)
{
using var stream = new MemoryStream(bytes);
using var reader = new StreamReader(stream);

return JsonDataConvert.DeserializeData(reader,
static r => r.ReadArrayOrEmpty(
static r => ObjectReaders.ReadTagHelper(r, useCache: false)));
}

private static ProjectRazorJson LoadProjectRazorJson(byte[] bytes)
{
using var stream = new MemoryStream(bytes);
using var reader = new StreamReader(stream);

return JsonDataConvert.DeserializeData(reader,
static r => r.ReadNonNullObject(ObjectReaders.ReadProjectRazorJsonFromProperties));
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

#nullable disable

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Remote.Razor;

namespace Microsoft.AspNetCore.Razor.Microbenchmarks;

public class RemoteTagHelperDeltaProviderBenchmark : TagHelperBenchmarkBase
public class RemoteTagHelperDeltaProviderBenchmark
{
public RemoteTagHelperDeltaProviderBenchmark()
{
DefaultTagHelperSet = DefaultTagHelpers.ToHashSet();
DefaultTagHelperSet = CommonResources.LegacyTagHelpers.ToHashSet();

Added50PercentMoreDefaultTagHelpers = DefaultTagHelperSet
.Take(DefaultTagHelperSet.Count / 2)
Expand All @@ -25,7 +24,7 @@ public RemoteTagHelperDeltaProviderBenchmark()
.ToHashSet();

RemovedHalfOfDefaultTagHelpers = DefaultTagHelperSet
.Take(DefaultTagHelpers.Count / 2)
.Take(CommonResources.LegacyTagHelpers.Count / 2)
.ToHashSet();

var tagHelpersToMutate = DefaultTagHelperSet
Expand All @@ -47,6 +46,7 @@ public RemoteTagHelperDeltaProviderBenchmark()

private string ProjectFilePath { get; } = "C:/path/to/project.csproj";

[AllowNull]
private RemoteTagHelperDeltaProvider Provider { get; set; }

private int LastResultId { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

namespace Microsoft.AspNetCore.Razor.Microbenchmarks;

public enum ResourceSet
{
Legacy,
Telerik
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

namespace Microsoft.AspNetCore.Razor.Microbenchmarks.Serialization;

public class CompletionListSerializationBenchmark : TagHelperBenchmarkBase
public class CompletionListSerializationBenchmark
{
private readonly byte[] _completionListBuffer;

Expand Down Expand Up @@ -78,7 +78,7 @@ private CompletionList GenerateCompletionList(string documentContent, int queryI
{
var sourceDocument = RazorSourceDocument.Create(documentContent, RazorSourceDocumentProperties.Default);
var syntaxTree = RazorSyntaxTree.Parse(sourceDocument);
var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: string.Empty, DefaultTagHelpers);
var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: string.Empty, CommonResources.LegacyTagHelpers);

var queryableChange = new SourceChange(queryIndex, length: 0, newText: string.Empty);
var owner = syntaxTree.Root.LocateOwner(queryableChange);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,85 @@
// Licensed under the MIT license. See License.txt in the project root for license information.

using System.IO;
using System.Text;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Razor.ProjectEngineHost.Serialization;
using Newtonsoft.Json;

namespace Microsoft.AspNetCore.Razor.Microbenchmarks.Serialization;

public class ProjectRazorJsonSerializationBenchmark
{
// Hardcoded expectations from `Resources\project.razor.json`
private const string ExpectedFilePath = @"C:\Users\admin\location\blazorserver\blazorserver.csproj";
private const int ExpectedTagHelperCount = 228;
[ParamsAllValues]
public ResourceSet ResourceSet { get; set; }

private byte[]? _projectRazorJsonBytes;
private ProjectRazorJson ProjectRazorJson
=> ResourceSet switch
{
ResourceSet.Telerik => CommonResources.TelerikProjectRazorJson,
_ => CommonResources.LegacyProjectRazorJson
};

private byte[] ProjectRazorJsonBytes
=> ResourceSet switch
{
ResourceSet.Telerik => CommonResources.TelerikProjectRazorJsonBytes,
_ => CommonResources.LegacyProjectRazorJsonBytes
};

private byte[] ProjectRazorJsonBytes => _projectRazorJsonBytes.AssumeNotNull();
private static ProjectRazorJson DeserializeProjectRazorJson(TextReader reader)
{
return JsonDataConvert.DeserializeData(reader,
static r => r.ReadNonNullObject(ObjectReaders.ReadProjectRazorJsonFromProperties));
}

[GlobalSetup]
public void Setup()
private static void SerializeProjectRazorJson(TextWriter writer, ProjectRazorJson projectRazorJson)
{
_projectRazorJsonBytes = Resources.GetResourceBytes("project.razor.json");
JsonDataConvert.SerializeObject(writer, projectRazorJson, ObjectWriters.WriteProperties);
}

[Benchmark(Description = "Serialize ProjectRazorJson")]
public void Serialize()
{
using var stream = new MemoryStream();
using var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 4096);

SerializeProjectRazorJson(writer, ProjectRazorJson);
}

[Benchmark(Description = "Razor ProjectRazorJson Roundtrip JsonConverter Serialization")]
public void ProjectRazorJson_Serialization_RoundTrip()
[Benchmark(Description = "Deserialize ProjectRazorJson")]
public void Deserialize()
{
using var stream = new MemoryStream(ProjectRazorJsonBytes);
using var jsonReader = new JsonTextReader(new StreamReader(stream));
using var reader = new StreamReader(stream);

jsonReader.Read();
var projectRazorJson = DeserializeProjectRazorJson(reader);

var dataReader = JsonDataReader.Get(jsonReader);
try
if (projectRazorJson.ProjectWorkspaceState is null ||
projectRazorJson.ProjectWorkspaceState.TagHelpers.Count != ProjectRazorJson.ProjectWorkspaceState?.TagHelpers.Count)
{
var result = dataReader.ReadObject(ObjectReaders.ReadProjectRazorJsonFromProperties);

if (result is null ||
result.FilePath != ExpectedFilePath ||
result.ProjectWorkspaceState?.TagHelpers.Count != ExpectedTagHelperCount)
{
throw new InvalidDataException();
}
throw new InvalidDataException();
}
finally
}

[Benchmark(Description = "RoundTrip ProjectRazorJson")]
public void RoundTrip()
{
using var stream = new MemoryStream();
using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 4096, leaveOpen: true))
{
SerializeProjectRazorJson(writer, ProjectRazorJson);
}

stream.Seek(0, SeekOrigin.Begin);

using var reader = new StreamReader(stream);

var projectRazorJson = DeserializeProjectRazorJson(reader);

if (projectRazorJson.ProjectWorkspaceState is null ||
projectRazorJson.ProjectWorkspaceState.TagHelpers.Count != ProjectRazorJson.ProjectWorkspaceState?.TagHelpers.Count)
{
JsonDataReader.Return(dataReader);
jsonReader.Close();
stream.Close();
throw new InvalidDataException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,45 +14,55 @@ namespace Microsoft.AspNetCore.Razor.Microbenchmarks.Serialization;

public class TagHelperResolutionResultSerializationBenchmark
{
[ParamsAllValues]
public ResourceSet ResourceSet { get; set; }

private IReadOnlyList<TagHelperDescriptor> TagHelpers
=> ResourceSet switch
{
ResourceSet.Telerik => CommonResources.TelerikTagHelpers,
_ => CommonResources.LegacyTagHelpers
};

private JsonSerializer? _serializer;
private TagHelperResolutionResult? _tagHelperResolutionResult;

private JsonSerializer Serializer => _serializer.AssumeNotNull();
private TagHelperResolutionResult TagHelperResolutionResult => _tagHelperResolutionResult.AssumeNotNull();

[GlobalSetup]
public void Setup()
public void GlobalSetup()
{
var tagHelperBuffer = Resources.GetResourceBytes("taghelpers.json");

// Deserialize from json file.
_serializer = new JsonSerializer();
_serializer.Converters.Add(TagHelperDescriptorJsonConverter.Instance);
_serializer.Converters.Add(TagHelperResolutionResultJsonConverter.Instance);
}

using var stream = new MemoryStream(tagHelperBuffer);
using var reader = new JsonTextReader(new StreamReader(stream));

var tagHelpers = Serializer.Deserialize<IReadOnlyList<TagHelperDescriptor>>(reader);
_tagHelperResolutionResult = new TagHelperResolutionResult(tagHelpers, Array.Empty<RazorDiagnostic>());
[IterationSetup]
public void IterationSetup()
{
_tagHelperResolutionResult = new TagHelperResolutionResult(TagHelpers, Array.Empty<RazorDiagnostic>());
}

[Benchmark(Description = "Razor TagHelperResolutionResult Roundtrip JsonConverter Serialization")]
public void TagHelper_JsonConvert_Serialization_RoundTrip()
[Benchmark(Description = "RoundTrip TagHelperDescriptorResult")]
public void RoundTrip()
{
MemoryStream originalStream;
using (originalStream = new MemoryStream())
using (var writer = new StreamWriter(originalStream, Encoding.UTF8, bufferSize: 4096))
using var stream = new MemoryStream();
using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 4096, leaveOpen: true))
{
Serializer.Serialize(writer, TagHelperResolutionResult);
}

TagHelperResolutionResult deserializedResult;
var stream = new MemoryStream(originalStream.GetBuffer());
using (stream)
using (var reader = new JsonTextReader(new StreamReader(stream)))
stream.Seek(0, SeekOrigin.Begin);

using var reader = new StreamReader(stream);
using var jsonReader = new JsonTextReader(reader);

var result = Serializer.Deserialize<TagHelperResolutionResult>(jsonReader);

if (result is null ||
result.Descriptors.Count != TagHelpers.Count)
{
deserializedResult = Serializer.Deserialize<TagHelperResolutionResult>(reader).AssumeNotNull();
throw new InvalidDataException();
}
}
}
Loading