Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mauiblazordesktop scenario #2515

Closed
Closed
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
15 changes: 15 additions & 0 deletions eng/performance/scenarios.proj
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
</HelixWorkItem>
</ItemGroup>

<!-- SOD & Device Startup for Windows Desktop MAUI -->
<ItemGroup>
<HelixWorkItem Include="SOD - Desktop Maui Unpackaged" Condition="'$(TargetsWindows)' == 'true'">
<PayloadDirectory>$(ScenariosDir)mauidesktop</PayloadDirectory>
Expand All @@ -89,6 +90,20 @@
</HelixWorkItem>
</ItemGroup>

<!-- SOD & Device Startup for Windows Desktop MAUI Blazor -->
<ItemGroup>
<HelixWorkItem Include="SOD - Desktop Maui Blazor Unpackaged" Condition="'$(TargetsWindows)' == 'true'">
<PayloadDirectory>$(ScenariosDir)mauiblazordesktop</PayloadDirectory>
<PreCommands>$(Python) pre.py publish -c Release -f $(_Framework)-windows10.0.19041.0</PreCommands>
<Command>$(Python) test.py sod --scenario-name &quot;%(Identity)&quot;</Command>
</HelixWorkItem>
<HelixWorkItem Include="Device Startup - Desktop Maui Blazor Default" Condition="'$(TargetsWindows)' == 'true'">
<PayloadDirectory>$(ScenariosDir)mauiblazordesktop</PayloadDirectory>
<PreCommands>$(Python) pre.py publish -c Release -f $(_Framework)-windows10.0.19041.0</PreCommands>
<Command>$(Python) test.py startup --scenario-name &quot;%(Identity)&quot;</Command>
</HelixWorkItem>
</ItemGroup>

<!--
This is useful for local testing to print the produced helix items
To use this when you are changing how items are produced, uncomment the target
Expand Down
9 changes: 9 additions & 0 deletions src/scenarios/mauiblazordesktop/post.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'''
post cleanup script
'''

from shared.postcommands import PostCommands, clean_directories

postcommands = PostCommands()
clean_directories()
postcommands.uninstall_workload('maui')
31 changes: 31 additions & 0 deletions src/scenarios/mauiblazordesktop/pre.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'''
pre-command: Example call 'python .\pre.py publish -f net6.0-windows10.0.19041.0 -c Release'
'''
import shutil
import subprocess
import sys
import os
from performance.logger import setup_loggers
from shared.precommands import PreCommands
from shared import const
from test import EXENAME
import requests

setup_loggers(True)
NugetURL = 'https://raw.githubusercontent.com/dotnet/maui/main/NuGet.config'
NugetFile = requests.get(NugetURL)
open('./Nuget.config', 'wb').write(NugetFile.content)

precommands = PreCommands()
precommands.install_workload('maui', ['--from-rollback-file', 'https://aka.ms/dotnet/maui/net6.0.json', '--configfile', './Nuget.config'])
precommands.new(template='maui-blazor',
output_dir=const.APPDIR,
bin_dir=const.BINDIR,
exename=EXENAME,
working_directory=sys.path[0],
no_restore=False)

subprocess.run(["dotnet", "add", "./app", "package", "Microsoft.WindowsAppSDK"]) # Add the package reference for the Microsoft.WindowsAppSDK for self-contained running
shutil.copy(os.path.join('src', 'Replacement.Index.razor.cs'), os.path.join(const.APPDIR, 'Pages', 'Index.razor.cs'))

precommands.execute(['/p:Platform=x64','/p:WindowsAppSDKSelfContained=True','/p:WindowsPackageType=None','/p:WinUISDKReferences=False','/p:PublishReadyToRun=true'])
18 changes: 18 additions & 0 deletions src/scenarios/mauiblazordesktop/src/Replacement.Index.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Components;
using System.Diagnostics.Tracing;
namespace MauiBlazorDesktopTesting.Pages
{
public partial class Index
{
private static EventSource log = new EventSource(
"Perf-Custom-Event",
EventSourceSettings.EtwSelfDescribingEventFormat);
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
log.Write("FirstRender", new EventSourceOptions {Level=EventLevel.Verbose, Opcode=EventOpcode.Info });
}
}
}
}
26 changes: 26 additions & 0 deletions src/scenarios/mauiblazordesktop/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os
import subprocess
from shared.runner import TestTraits, Runner

EXENAME = 'MauiBlazorDesktopTesting'

def main():
traits = TestTraits(exename=EXENAME,
guiapp='true',
startupmetric='WinUICustom',
timeout=30,
measurementdelay='6',
runwithoutexit='false',
processwillexit="false",
)
runner = Runner(traits)
runner.run()


if __name__ == "__main__":
result = subprocess.run(['powershell', '-Command', r'Get-ChildItem .\pub\Microsoft.Maui.dll | Select-Object -ExpandProperty VersionInfo | Select-Object ProductVersion | Select-Object -ExpandProperty ProductVersion'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
os.environ["MAUI_VERSION"] = result.stdout.decode('utf-8').strip()
print(f'Env: MAUI_VERSION: {os.environ["MAUI_VERSION"]}')
if("sha" not in os.environ["MAUI_VERSION"] and "azdo" not in os.environ["MAUI_VERSION"]):
raise ValueError(f"MAUI_VERSION does not contain sha and azdo indicating failure to retrieve or set the value. MAUI_VERSION: {os.environ['MAUI_VERSION']}")
main()
6 changes: 5 additions & 1 deletion src/tools/ScenarioMeasurement/Startup/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ enum MetricType
InnerLoopMsBuild,
DotnetWatch,
DeviceTimeToMain,
WinUI
WinUI,
WinUICustom
}

public class InnerLoopMarkerEventSource : EventSource
Expand Down Expand Up @@ -277,6 +278,9 @@ static void checkArg(string arg, string name)
case MetricType.WinUI:
parser = new WinUIParser();
break;
case MetricType.WinUICustom:
parser = new WinUICustomParser();
break;
}

var pids = new List<int>();
Expand Down
100 changes: 100 additions & 0 deletions src/tools/ScenarioMeasurement/Startup/WinUICustomParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using Microsoft.Diagnostics.Tracing;
using Reporting;
using System;
using System.Collections.Generic;

namespace ScenarioMeasurement
{
public class WinUICustomParser : IParser
{
const String WinUIProvider = "Microsoft-Windows-XAML";
const String PerfProvider = "Perf-Custom-Event";

public void EnableKernelProvider(ITraceSession kernel)
{
kernel.EnableKernelProvider(TraceSessionManager.KernelKeyword.Process, TraceSessionManager.KernelKeyword.Thread, TraceSessionManager.KernelKeyword.ContextSwitch);
}

public void EnableUserProviders(ITraceSession user)
{
user.EnableUserProvider(WinUIProvider, TraceEventLevel.Verbose);
user.EnableUserProvider(PerfProvider, TraceEventLevel.Verbose);
}

public IEnumerable<Counter> Parse(string mergeTraceFile, string processName, IList<int> pids, string commandLine)
{
var baseStartup = new List<double>();
var delayedStartup = new List<double>();
var threadTimes = new List<double>();
double threadTime = 0;
var ins = new Dictionary<int, double>();
double start = -1;
int? pid = null;
using (var source = new ETWTraceEventSource(mergeTraceFile))
{
source.Kernel.ProcessStart += evt =>
{
if (processName.Equals(evt.ProcessName, StringComparison.OrdinalIgnoreCase) && pids.Contains(evt.ProcessID) && evt.CommandLine.Trim() == commandLine.Trim())
{
if (pid.HasValue)
{
// Processes might be reentrant. For now this traces the first (outermost) process of a given name.
return;
}
pid = evt.ProcessID;
start = evt.TimeStampRelativeMSec;
}
};

source.Kernel.ThreadCSwitch += evt =>
{
if (!pid.HasValue) // we're currently in a measurement interval
return;

if (evt.NewProcessID != pid && evt.OldProcessID != pid)
return; // but this isn't our process

if (evt.OldProcessID == pid) // this is a switch out from our process
{
if (ins.TryGetValue(evt.OldThreadID, out var value)) // had we ever recorded a switch in for this thread?
{
threadTime += evt.TimeStampRelativeMSec - value;
ins.Remove(evt.OldThreadID);
}
}
else // this is a switch in to our process
{
ins[evt.NewThreadID] = evt.TimeStampRelativeMSec;
}
};

source.Dynamic.AddCallbackForProviderEvent(WinUIProvider, "Frame/Stop", evt =>
{
if (pid.HasValue && evt.ProcessID == pid && evt.ProcessName.Equals(processName, StringComparison.OrdinalIgnoreCase))
{
baseStartup.Add(evt.TimeStampRelativeMSec - start);
}
});

source.Dynamic.AddCallbackForProviderEvent(PerfProvider, "FirstRender", evt =>
{
if (pid.HasValue && evt.ProcessID == pid && evt.ProcessName.Equals(processName, StringComparison.OrdinalIgnoreCase))
{
delayedStartup.Add(evt.TimeStampRelativeMSec - start);
threadTimes.Add(threadTime);
pid = null;
threadTime = 0;
start = 0;
}
});

source.Process();
}
return new[] {
new Counter() { Name = "WinUI Inner Blazor Startup", MetricName = "ms", DefaultCounter=true, TopCounter=true, Results = delayedStartup.ToArray() },
new Counter() { Name = "WinUI Startup", MetricName = "ms", DefaultCounter=false, TopCounter=true, Results = baseStartup.ToArray() },
new Counter() { Name = "Time on Thread", MetricName = "ms", TopCounter=true, Results = threadTimes.ToArray() }
};
}
}
}