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 Maui Blazor Desktop #2526

Merged
merged 38 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6cda3b4
Add `mauiblazordesktop` scenario
TanayParikh Jun 28, 2022
80650cf
Update pre.py
TanayParikh Jun 28, 2022
b1930a9
First working iteration of MauiBlazor WinUI startup with inner startu…
LoopedBard3 Jul 5, 2022
7d41b15
Update pre.py
TanayParikh Jul 5, 2022
a09528b
Only take the first frame stop, hopefully will fix pipeline issue.
LoopedBard3 Jul 7, 2022
55754f3
Make sure the traces get uploaded.
LoopedBard3 Jul 7, 2022
9e056be
Scenarios is not found as a module, stub out the methods that would h…
LoopedBard3 Jul 8, 2022
726084c
Try figuring out if the file is actually moved correctly.
LoopedBard3 Jul 8, 2022
b2ccc6f
Move to powershell commands instead of linux commands.
LoopedBard3 Jul 8, 2022
a72c145
Try just getting the file.
LoopedBard3 Jul 11, 2022
fff0b5a
Try uploading the whole app to run locally.
LoopedBard3 Jul 11, 2022
87c1413
zip up the app before uploading for easier downloading.
LoopedBard3 Jul 11, 2022
f6e5faa
Change log level to always log first render.
LoopedBard3 Jul 11, 2022
8fad321
Add logging for the providers being enabled to see if there is someth…
LoopedBard3 Jul 11, 2022
1d1f478
Switch to using the already built perflabstartup... event.
LoopedBard3 Jul 12, 2022
db5e6a2
Fix file name that gets the render added.
LoopedBard3 Jul 12, 2022
75b6a29
Add back in staticwinformstemplate.
LoopedBard3 Jul 12, 2022
d390669
Further debugging why the events are not being traced.
LoopedBard3 Jul 14, 2022
6de4739
Exit early to show that we are in the if statement around the event s…
LoopedBard3 Jul 15, 2022
1c8ea55
Remove the first render boolean to see if it is the if or the whole c…
LoopedBard3 Jul 15, 2022
95cce29
Set src dir instead of using just src.
LoopedBard3 Jul 15, 2022
6e56683
Get a binlog to see if the index.razor.cs file is being included prop…
LoopedBard3 Jul 18, 2022
f6f0055
Scenarios was not found.
LoopedBard3 Jul 18, 2022
41f665a
Put the binlog generation as a part of the incorrect test.
LoopedBard3 Jul 19, 2022
d942037
Try to fix error about windows TFM not being found.
LoopedBard3 Jul 19, 2022
a94768b
Try installing webview2 at the start of run.
LoopedBard3 Jul 21, 2022
a0fc49e
Add webview installation attempt before running. This will ensure we …
LoopedBard3 Jul 22, 2022
d80b7c6
Remove unneeded testing/logging things since we are using PerfLabGene…
LoopedBard3 Jul 22, 2022
ea44390
Update channel map to the new 6.0 version.
LoopedBard3 Jul 22, 2022
a0f9840
Update the default version for release/6.0.
LoopedBard3 Jul 22, 2022
a473b00
Add quality to the channels so the version download works properly.
LoopedBard3 Jul 22, 2022
e0f534c
Redisable Static Winforms Template.
LoopedBard3 Jul 22, 2022
8b4ea25
Cleanup testing artifacts.
LoopedBard3 Jul 22, 2022
78b08b9
Add newline to end of file.
LoopedBard3 Jul 22, 2022
895ff92
Rename WinUICustomParser to WinUIBlazorParser.
LoopedBard3 Aug 2, 2022
19b5b50
Update src/scenarios/mauiblazordesktop/src/Replacement.Index.razor.cs
LoopedBard3 Aug 4, 2022
b921927
Double check that WebView is properly installed, and exit if the inst…
LoopedBard3 Aug 5, 2022
d006471
Changed debug print statements to logger info, warning, and error sta…
LoopedBard3 Aug 5, 2022
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
8 changes: 5 additions & 3 deletions scripts/channel_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ class ChannelMap():
channel_map = {
'release/6.0': {
'tfm': 'net6.0',
'branch': 'release/6.0',
'branch': '6.0.4xx',
'quality': 'daily'
},'6.0': {
'tfm': 'net6.0',
'branch': 'release/6.0',
'branch': '6.0.4xx',
'quality': 'daily'
},
'main': {
'tfm': 'net6.0',
'branch': 'main',
'branch': '6.0',
'quality': 'daily'
},
'master': {
Expand Down
2 changes: 1 addition & 1 deletion scripts/dotnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,7 @@ def install(
# run, we will be testing the "wrong" version, ie, not the version we specified.
if (not versions) and channels:
for channel in channels:
cmdline_args = common_cmdline_args + ['-Channel', channel if channel != "release/6.0" else "6.0"]
cmdline_args = common_cmdline_args + ['-Channel', channel if channel != "release/6.0" else "6.0.4xx"]
if ChannelMap.get_quality_from_channel(channel) is not None:
cmdline_args += ['-Quality', ChannelMap.get_quality_from_channel(channel)]
RunCommand(cmdline_args, verbose=verbose, retry=1).run(
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')
66 changes: 66 additions & 0 deletions src/scenarios/mauiblazordesktop/pre.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'''
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.codefixes import insert_after
from shared.precommands import PreCommands
from shared import const
from test import EXENAME
import requests
import winreg

setup_loggers(True)
NugetURL = 'https://raw.githubusercontent.com/dotnet/maui/main/NuGet.config'
WebViewURL = 'https://go.microsoft.com/fwlink/p/?LinkId=2124703' # Obtained from https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section
WebViewInstalled = False
NugetFile = requests.get(NugetURL)
open('./Nuget.config', 'wb').write(NugetFile.content)

lmkey = r"SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"
cukey = r"Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as hklm_hive:
try:
with winreg.OpenKey(hklm_hive, lmkey) as openkey:
pvvalue = winreg.QueryValueEx(openkey, 'pv')[0]
if pvvalue and pvvalue != '' and pvvalue != '0.0.0.0':
WebViewInstalled = True
print(f"pvvalue found {pvvalue}")
except:
print("WebView not verified in Local_Machine Registry")
if not WebViewInstalled:
try:
with winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) as hkcu_hive:
with winreg.OpenKey(hkcu_hive, cukey) as openkey:
pvvalue = winreg.QueryValueEx(openkey, 'pv')[0]
if pvvalue and pvvalue != '' and pvvalue != '0.0.0.0':
WebViewInstalled = True
print(f"pvvalue found {pvvalue}")
except:
print("WebView not verified in Current_Machine Registry")
if not WebViewInstalled:
WebViewInstallFile = requests.get(WebViewURL)
open('./MicrosoftEdgeWebview2Setup.exe', 'wb').write(WebViewInstallFile.content)
subprocess.run(['powershell', '-Command', r'Start-Process "./MicrosoftEdgeWebview2Setup.exe" -Wait'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
print("Installed WebView2")
WebViewInstalled = True
LoopedBard3 marked this conversation as resolved.
Show resolved Hide resolved
else:
print("WebViewAlreadyInstalled")


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.copy2(os.path.join(const.SRCDIR, 'Replacement.Index.razor.cs'), os.path.join(const.APPDIR, 'Pages', 'Index.razor.cs'))
precommands.add_startup_logging(os.path.join('Pages', 'Index.razor.cs'), "if (firstRender) {")
LoopedBard3 marked this conversation as resolved.
Show resolved Hide resolved
precommands.execute(['/p:Platform=x64','/p:WindowsAppSDKSelfContained=True','/p:WindowsPackageType=None','/p:WinUISDKReferences=False','/p:PublishReadyToRun=true'])
14 changes: 14 additions & 0 deletions src/scenarios/mauiblazordesktop/src/Replacement.Index.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Components;
using System.Diagnostics.Tracing;
namespace MauiBlazorDesktopTesting.Pages
{
public partial class Index
{
protected override void OnAfterRender(bool firstRender)
{
if (firstRender) {

LoopedBard3 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
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='WinUIBlazor',
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,
WinUIBlazor
}

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.WinUIBlazor:
parser = new WinUIBlazorParser();
break;
}

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

namespace ScenarioMeasurement
{
public class WinUIBlazorParser : IParser
{
const String WinUIProvider = "Microsoft-Windows-XAML";
const String PerfProvider = "PerfLabGenericEventSource";

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;
bool frameStopCaught = false;
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 (!frameStopCaught && pid.HasValue && evt.ProcessID == pid && evt.ProcessName.Equals(processName, StringComparison.OrdinalIgnoreCase))
{
baseStartup.Add(evt.TimeStampRelativeMSec - start);
frameStopCaught = true;
}
});

source.Dynamic.AddCallbackForProviderEvent(PerfProvider, "Startup", 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;
frameStopCaught = false;
}
});

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() }
};
}
}
}