Add console runner for measuring Blazor perf on desktop interpreter (#24469)
This commit is contained in:
parent
0335ac60a6
commit
1885af9634
|
|
@ -1455,6 +1455,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropClient", "src\Grpc\t
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropWebsite", "src\Grpc\test\testassets\InteropWebsite\InteropWebsite.csproj", "{19189670-E206-471D-94F8-7D3D545E5020}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wasm.Performance.ConsoleHost", "src\Components\benchmarkapps\Wasm.Performance\ConsoleHost\Wasm.Performance.ConsoleHost.csproj", "{E9408723-E6A9-4715-B906-3B25B0238ABA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -6889,6 +6891,18 @@ Global
|
|||
{19189670-E206-471D-94F8-7D3D545E5020}.Release|x64.Build.0 = Release|Any CPU
|
||||
{19189670-E206-471D-94F8-7D3D545E5020}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{19189670-E206-471D-94F8-7D3D545E5020}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -7618,6 +7632,7 @@ Global
|
|||
{00B2DD87-7E2A-4460-BE1B-5E18B1062B7F} = {E763DA15-8F4E-446C-99B8-309053C75598}
|
||||
{C3A0F425-669F-46A8-893F-CF449A6DAE56} = {00B2DD87-7E2A-4460-BE1B-5E18B1062B7F}
|
||||
{19189670-E206-471D-94F8-7D3D545E5020} = {00B2DD87-7E2A-4460-BE1B-5E18B1062B7F}
|
||||
{E9408723-E6A9-4715-B906-3B25B0238ABA} = {6276A9A0-791B-49C1-AD8F-50AC47CDC196}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
"src\\Components\\WebAssembly\\Sdk\\integrationtests\\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj",
|
||||
"src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj",
|
||||
"src\\Components\\Web\\test\\Microsoft.AspNetCore.Components.Web.Tests.csproj",
|
||||
"src\\Components\\benchmarkapps\\Wasm.Performance\\ConsoleHost\\Wasm.Performance.ConsoleHost.csproj",
|
||||
"src\\Components\\benchmarkapps\\Wasm.Performance\\Driver\\Wasm.Performance.Driver.csproj",
|
||||
"src\\Components\\benchmarkapps\\Wasm.Performance\\TestApp\\Wasm.Performance.TestApp.csproj",
|
||||
"src\\Components\\test\\E2ETest\\Microsoft.AspNetCore.Components.E2ETests.csproj",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
// 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.Runtime.ExceptionServices;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.RenderTree;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Wasm.Performance.ConsoleHost
|
||||
{
|
||||
internal class ConsoleHostRenderer : Renderer
|
||||
{
|
||||
public ConsoleHostRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory)
|
||||
: base(serviceProvider, loggerFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public override Dispatcher Dispatcher { get; } = new NullDispatcher();
|
||||
|
||||
protected override void HandleException(Exception exception)
|
||||
{
|
||||
ExceptionDispatchInfo.Capture(exception).Throw();
|
||||
}
|
||||
|
||||
protected override Task UpdateDisplayAsync(in RenderBatch renderBatch)
|
||||
{
|
||||
// ConsoleHost is only for profiling the .NET side of execution.
|
||||
// There isn't a real display to update.
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Expose some protected APIs publicly
|
||||
public new int AssignRootComponentId(IComponent component)
|
||||
=> base.AssignRootComponentId(component);
|
||||
|
||||
public new Task RenderRootComponentAsync(int componentId)
|
||||
=> base.RenderRootComponentAsync(componentId);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Wasm.Performance.ConsoleHost
|
||||
{
|
||||
internal class NullDispatcher : Dispatcher
|
||||
{
|
||||
public override bool CheckAccess()
|
||||
=> true;
|
||||
|
||||
public override Task InvokeAsync(Action workItem)
|
||||
{
|
||||
workItem();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task InvokeAsync(Func<Task> workItem)
|
||||
=> workItem();
|
||||
|
||||
public override Task<TResult> InvokeAsync<TResult>(Func<TResult> workItem)
|
||||
=> Task.FromResult(workItem());
|
||||
|
||||
public override Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> workItem)
|
||||
=> workItem();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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 Microsoft.Extensions.CommandLineUtils;
|
||||
using Wasm.Performance.ConsoleHost.Scenarios;
|
||||
|
||||
namespace Wasm.Performance.ConsoleHost
|
||||
{
|
||||
internal class Program : CommandLineApplication
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
new Program().Execute(args);
|
||||
}
|
||||
|
||||
public Program()
|
||||
{
|
||||
OnExecute(() =>
|
||||
{
|
||||
ShowHelp();
|
||||
return 1;
|
||||
});
|
||||
|
||||
Commands.Add(new GridScenario());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Wasm.Performance.ConsoleHost.Scenarios
|
||||
{
|
||||
internal abstract class ComponentRenderingScenarioBase : CommandLineApplication
|
||||
{
|
||||
protected ComponentRenderingScenarioBase(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
var cyclesOption = new CommandOption("--cycles", CommandOptionType.SingleValue);
|
||||
Options.Add(cyclesOption);
|
||||
|
||||
OnExecute(() =>
|
||||
{
|
||||
var numCycles = cyclesOption.HasValue() ? int.Parse(cyclesOption.Value()) : 1;
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
PopulateServiceCollection(serviceCollection);
|
||||
var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||
|
||||
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
|
||||
var renderer = new ConsoleHostRenderer(serviceProvider, loggerFactory);
|
||||
|
||||
var startTime = DateTime.Now;
|
||||
ExecuteAsync(renderer, numCycles).Wait();
|
||||
|
||||
var duration = DateTime.Now - startTime;
|
||||
var durationPerCycle = (duration / numCycles).TotalMilliseconds;
|
||||
Console.WriteLine($"{Name}: {durationPerCycle:F1}ms per cycle (cycles tested: {numCycles})");
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void PopulateServiceCollection(IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddLogging();
|
||||
}
|
||||
|
||||
protected abstract Task ExecuteAsync(ConsoleHostRenderer renderer, int numCycles);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Wasm.Performance.TestApp.Pages;
|
||||
|
||||
namespace Wasm.Performance.ConsoleHost.Scenarios
|
||||
{
|
||||
internal class GridScenario : ComponentRenderingScenarioBase
|
||||
{
|
||||
readonly CommandOption _gridTypeOption = new CommandOption("--gridtype", CommandOptionType.SingleValue);
|
||||
|
||||
public GridScenario() : base("grid")
|
||||
{
|
||||
Options.Add(_gridTypeOption);
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(ConsoleHostRenderer renderer, int numCycles)
|
||||
{
|
||||
var gridType = _gridTypeOption.HasValue()
|
||||
? (GridRendering.RenderMode)Enum.Parse(typeof(GridRendering.RenderMode), _gridTypeOption.Value(), true)
|
||||
: GridRendering.RenderMode.FastGrid;
|
||||
|
||||
for (var i = 0; i < numCycles; i++)
|
||||
{
|
||||
var hostPage = new GridRendering { SelectedRenderMode = gridType };
|
||||
hostPage.Show();
|
||||
|
||||
var componentId = renderer.AssignRootComponentId(hostPage);
|
||||
await renderer.RenderRootComponentAsync(componentId);
|
||||
|
||||
hostPage.ChangePage();
|
||||
await renderer.RenderRootComponentAsync(componentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsShipping>false</IsShipping>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\TestApp\Wasm.Performance.TestApp.csproj" />
|
||||
<Compile Include="$(SharedSourceRoot)CommandLineUtils\**\*.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -9,7 +9,9 @@ namespace Wasm.Performance.TestApp
|
|||
{
|
||||
public static void Send(IJSRuntime jsRuntime, string name)
|
||||
{
|
||||
((IJSInProcessRuntime)jsRuntime).Invoke<object>(
|
||||
// jsRuntime will be null if we're in an environment without any
|
||||
// JS runtime, e.g., the console runner
|
||||
((IJSInProcessRuntime)jsRuntime)?.Invoke<object>(
|
||||
"receiveBenchmarkEvent",
|
||||
name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
@page "/gridrendering"
|
||||
@page "/gridrendering"
|
||||
@inject IJSRuntime JSRuntime
|
||||
@using Wasm.Performance.TestApp.Shared.FastGrid
|
||||
|
||||
<h1>20 x 200 Grid</h1>
|
||||
|
||||
<fieldset>
|
||||
<select id="render-mode" @bind="selectedRenderMode">
|
||||
<select id="render-mode" @bind="SelectedRenderMode">
|
||||
<option>@RenderMode.FastGrid</option>
|
||||
<option>@RenderMode.PlainTable</option>
|
||||
<option>@RenderMode.ComplexTable</option>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
{
|
||||
<p><em>(No data assigned)</em></p>
|
||||
}
|
||||
else if (selectedRenderMode == RenderMode.FastGrid)
|
||||
else if (SelectedRenderMode == RenderMode.FastGrid)
|
||||
{
|
||||
<p>FastGrid represents a minimal, optimized implementation of a grid.</p>
|
||||
|
||||
|
|
@ -50,13 +50,13 @@ else if (selectedRenderMode == RenderMode.FastGrid)
|
|||
<GridColumn TRowData="WeatherForecast" Title="Summary">@context.Summary</GridColumn>
|
||||
</Grid>
|
||||
}
|
||||
else if (selectedRenderMode == RenderMode.PlainTable)
|
||||
else if (SelectedRenderMode == RenderMode.PlainTable)
|
||||
{
|
||||
<p>PlainTable represents a minimal but not optimized implementation of a grid.</p>
|
||||
|
||||
<Wasm.Performance.TestApp.Shared.PlainTable.TableComponent Data="@forecasts" Columns="@Columns" />
|
||||
}
|
||||
else if (selectedRenderMode == RenderMode.ComplexTable)
|
||||
else if (SelectedRenderMode == RenderMode.ComplexTable)
|
||||
{
|
||||
<p>ComplexTable represents a maximal, not optimized implementation of a grid, using a wide range of Blazor features at once.</p>
|
||||
|
||||
|
|
@ -64,9 +64,9 @@ else if (selectedRenderMode == RenderMode.ComplexTable)
|
|||
}
|
||||
|
||||
@code {
|
||||
enum RenderMode { PlainTable, ComplexTable, FastGrid }
|
||||
public enum RenderMode { PlainTable, ComplexTable, FastGrid }
|
||||
|
||||
private RenderMode selectedRenderMode = RenderMode.FastGrid;
|
||||
public RenderMode SelectedRenderMode { get; set; } = RenderMode.FastGrid;
|
||||
|
||||
private WeatherForecast[] forecasts;
|
||||
public List<string> Columns { get; set; } = new List<string>
|
||||
|
|
@ -89,17 +89,17 @@ else if (selectedRenderMode == RenderMode.ComplexTable)
|
|||
TemperatureC = index,
|
||||
};
|
||||
|
||||
void Show()
|
||||
public void Show()
|
||||
{
|
||||
forecasts = staticSampleDataPage1;
|
||||
}
|
||||
|
||||
void Hide()
|
||||
public void Hide()
|
||||
{
|
||||
forecasts = null;
|
||||
}
|
||||
|
||||
void ChangePage()
|
||||
public void ChangePage()
|
||||
{
|
||||
forecasts = (forecasts == staticSampleDataPage1) ? staticSampleDataPage2 : staticSampleDataPage1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
@using WeatherForecast = Pages.GridRendering.WeatherForecast
|
||||
@using WeatherForecast = Pages.GridRendering.WeatherForecast
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
<CascadingValue Value="@this">
|
||||
<RowCollection Data="@Data"
|
||||
Columns="@Columns"
|
||||
OnClick="@RefreshComponent"></RowCollection>
|
||||
OnClick="@HandleClickEvent"></RowCollection>
|
||||
</CascadingValue>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -26,21 +26,8 @@
|
|||
[Parameter]
|
||||
public List<string> Columns { get; set; }
|
||||
|
||||
DateTime t1;
|
||||
DateTime t2;
|
||||
Task RefreshComponent(int index)
|
||||
Task HandleClickEvent(int index)
|
||||
{
|
||||
t1 = DateTime.Now;
|
||||
StateHasChanged();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
protected override Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender)
|
||||
{
|
||||
t2 = DateTime.Now;
|
||||
Console.WriteLine("Refresh Time " + (t2 - t1).TotalMilliseconds);
|
||||
}
|
||||
return base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
@using WeatherForecast = Pages.GridRendering.WeatherForecast
|
||||
@using WeatherForecast = Pages.GridRendering.WeatherForecast
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
<tbody>
|
||||
<RowCollection Data="@Data"
|
||||
Columns="@Columns"
|
||||
OnClick="@RefreshComponent"></RowCollection>
|
||||
OnClick="@HandleClickEvent"></RowCollection>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
|
@ -24,21 +24,8 @@
|
|||
[Parameter]
|
||||
public List<string> Columns { get; set; }
|
||||
|
||||
DateTime t1;
|
||||
DateTime t2;
|
||||
Task RefreshComponent(int index)
|
||||
Task HandleClickEvent(int index)
|
||||
{
|
||||
t1 = DateTime.Now;
|
||||
StateHasChanged();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
protected override Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender)
|
||||
{
|
||||
t2 = DateTime.Now;
|
||||
Console.WriteLine("Refresh Time " + (t2 - t1).TotalMilliseconds);
|
||||
}
|
||||
return base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue