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

[browser] app start benchmark fix, loadBootResource fix #89857

Merged
merged 19 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from 17 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
Expand Up @@ -21,6 +21,7 @@
</PropertyGroup>
<ItemGroup>
<WasmExtraFilesToDeploy Include="main.js" />
<WasmExtraFilesToDeploy Include="advanced-sample.lib.module.js" />
<!-- add export GL object from Module -->
<EmccExportedRuntimeMethod Include="GL" />
<NativeFileReference Include="fibonacci.c" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

export function onRuntimeConfigLoaded(config) {
console.log("advanced-sample onRuntimeConfigLoaded")
}

export async function onRuntimeReady({ getAssemblyExports, getConfig }) {
console.log("advanced-sample onRuntimeReady")
}
6 changes: 3 additions & 3 deletions src/mono/sample/wasm/browser-advanced/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'wasm-unsafe-eval';" />
<script type='module' src="./main.js"></script>
<script type='module' src="./_framework/dotnet.js"></script>
<link rel="preload" href="./_framework/blazor.boot.json" as="fetch" crossorigin="anonymous">
<script type='module' src="./dotnet.js"></script>
<link rel="preload" href="./blazor.boot.json" as="fetch" crossorigin="use-credentials">
<link rel="prefetch" href="./dotnet.native.js" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./dotnet.runtime.js" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./dotnet.native.wasm" as="fetch" crossorigin="anonymous">
<!-- users should consider if they optimize for the first load or subsequent load from memory snapshot -->
<link rel="prefetch" href="./icudt.dat" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./managed/System.Private.CoreLib.wasm" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./System.Private.CoreLib.wasm" as="fetch" crossorigin="anonymous">
</head>

<body>
Expand Down
3 changes: 3 additions & 0 deletions src/mono/sample/wasm/browser-advanced/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ try {
// config is loaded and could be tweaked before the rest of the runtime startup sequence
config.environmentVariables["MONO_LOG_LEVEL"] = "debug";
config.browserProfilerOptions = {};
config.resources.modulesAfterConfigLoaded = {
"advanced-sample.lib.module.js": ""
}
},
preInit: () => { console.log('user code Module.preInit'); },
preRun: () => { console.log('user code Module.preRun'); },
Expand Down
10 changes: 5 additions & 5 deletions src/mono/sample/wasm/browser-bench/appstart-frame.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="module" src="./frame-main.js"></script>
<script type='module' src="./_framework/dotnet.js"></script>
<link rel="preload" href="./_framework/blazor.boot.json" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./dotnet.native.js" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./dotnet.runtime.js" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./dotnet.native.wasm" as="fetch" crossorigin="anonymous">
<link rel="preload" href="./_framework/blazor.boot.json" as="fetch" crossorigin="use-credentials">
<link rel="prefetch" href="./_framework/dotnet.native.js" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./_framework/dotnet.runtime.js" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./_framework/dotnet.native.wasm" as="fetch" crossorigin="anonymous">
<!-- users should consider if they optimize for the first load or subsequent load from memory snapshot -->
<link rel="prefetch" href="./managed/System.Private.CoreLib.dll" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./_framework/System.Private.CoreLib.dll" as="fetch" crossorigin="anonymous">
</head>

<body>
Expand Down
58 changes: 42 additions & 16 deletions src/mono/sample/wasm/simple-server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System;
using System.Security.Cryptography;

namespace HttpServer
{
Expand All @@ -16,11 +17,13 @@ public sealed class Session
public int Finished { get; set; } = 0;
}

public sealed record FileContent(byte[] buffer, string hash);

public sealed class Program
{
private bool Verbose = false;
private ConcurrentDictionary<string, Session> Sessions = new ConcurrentDictionary<string, Session>();
private Dictionary<string, byte[]> cache = new Dictionary<string, byte[]>(StringComparer.OrdinalIgnoreCase);
private Dictionary<string, FileContent> cache = new(StringComparer.OrdinalIgnoreCase);

public static int Main()
{
Expand Down Expand Up @@ -104,7 +107,7 @@ private void HandleRequest(HttpListener listener)
ReceivePostAsync(context);
}

private async Task<byte[]?> GetFileContent(string path)
private async Task<FileContent?> GetFileContent(string path)
{
if (Verbose)
await Console.Out.WriteLineAsync($"get content for: {path}");
Expand All @@ -124,9 +127,13 @@ private void HandleRequest(HttpListener listener)
if (Verbose)
await Console.Out.WriteLineAsync($"adding content to cache for: {path}");

cache[path] = content;
using HashAlgorithm hashAlgorithm = SHA256.Create();
byte[] hash = hashAlgorithm.ComputeHash(content);
var fc = new FileContent(content, "sha256-" + Convert.ToBase64String(hash));

cache[path] = fc;

return content;
return fc;
}

private async void ReceivePostAsync(HttpListenerContext context)
Expand Down Expand Up @@ -189,14 +196,14 @@ private async void ServeAsync(HttpListenerContext context)
else if (path.StartsWith("/"))
path = path.Substring(1);

byte[]? buffer;
FileContent? fc;
try
{
buffer = await GetFileContent(path);
fc = await GetFileContent(path);

if (buffer != null && throttleMbps > 0)
if (fc != null && throttleMbps > 0)
{
double delaySeconds = (buffer.Length * 8) / (throttleMbps * 1024 * 1024);
double delaySeconds = (fc.buffer.Length * 8) / (throttleMbps * 1024 * 1024);
int delayMs = (int)(delaySeconds * 1000);
if (session != null)
{
Expand Down Expand Up @@ -246,12 +253,20 @@ private async void ServeAsync(HttpListenerContext context)
}
}
}
catch (Exception)
catch (System.IO.DirectoryNotFoundException)
{
if (Verbose)
Console.WriteLine($"Not found: {path}");
fc = null;
}
catch (Exception ex)
{
buffer = null;
if (Verbose)
Console.WriteLine($"Exception: {ex}");
fc = null;
}

if (buffer != null)
if (fc != null)
{
string? contentType = null;
if (path.EndsWith(".wasm"))
Expand All @@ -270,7 +285,7 @@ private async void ServeAsync(HttpListenerContext context)
{
Console.WriteLine("Faking 500 " + url);
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
await stream.WriteAsync(buffer, 0, 0).ConfigureAwait(false);
await stream.WriteAsync(fc.buffer, 0, 0).ConfigureAwait(false);
await stream.FlushAsync();
context.Response.Close();
return;
Expand All @@ -279,25 +294,36 @@ private async void ServeAsync(HttpListenerContext context)
if (contentType != null)
context.Response.ContentType = contentType;

context.Response.ContentLength64 = buffer.Length;
context.Response.AppendHeader("cache-control", "public, max-age=31536000");
// context.Response.AppendHeader("cache-control", "public, max-age=31536000");
context.Response.AppendHeader("Cross-Origin-Embedder-Policy", "require-corp");
context.Response.AppendHeader("Cross-Origin-Opener-Policy", "same-origin");
context.Response.AppendHeader("ETag", fc.hash);

// test download re-try
if (url.Query.Contains("testAbort"))
{
Console.WriteLine("Faking abort " + url);
await stream.WriteAsync(buffer, 0, 10).ConfigureAwait(false);
context.Response.ContentLength64 = fc.buffer.Length;
await stream.WriteAsync(fc.buffer, 0, 10).ConfigureAwait(false);
await stream.FlushAsync();
await Task.Delay(100);
context.Response.Abort();
return;
}
var ifNoneMatch = context.Request.Headers.Get("If-None-Match");
if (ifNoneMatch == fc.hash)
{
context.Response.StatusCode = 304;
await stream.FlushAsync();
stream.Close();
context.Response.Close();
return;
}

try
{
await stream.WriteAsync(buffer).ConfigureAwait(false);
context.Response.ContentLength64 = fc.buffer.Length;
await stream.WriteAsync(fc.buffer).ConfigureAwait(false);
}
catch (Exception e)
{
Expand Down
2 changes: 1 addition & 1 deletion src/mono/wasm/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ See also [fetch integrity on MDN](https://developer.mozilla.org/en-US/docs/Web/A
In order to start downloading application resources as soon as possible you can add HTML elements to `<head>` of your page similar to:

```html
<link rel="preload" href="./_framework/blazor.boot.json" as="fetch" crossorigin="anonymous">
<link rel="preload" href="./_framework/blazor.boot.json" as="fetch" crossorigin="use-credentials">
<link rel="prefetch" href="./_framework/dotnet.native.js" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./_framework/dotnet.runtime.js" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./_framework/dotnet.native.wasm" as="fetch" crossorigin="anonymous">
Expand Down
34 changes: 26 additions & 8 deletions src/mono/wasm/runtime/dotnet.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ type MonoConfig = {
* Gets a value that determines whether to enable caching of the 'resources' inside a CacheStorage instance within the browser.
*/
cacheBootResources?: boolean;
/**
* Configures use of the `integrity` directive for fetching assets
*/
disableIntegrityCheck?: boolean;
/**
* Configures use of the `no-cache` directive for fetching assets
*/
disableNoCacheFetch?: boolean;
/**
* Enables diagnostic log messages during startup
*/
Expand Down Expand Up @@ -212,18 +220,28 @@ type ResourceList = {
* When returned string is not qualified with `./` or absolute URL, it will be resolved against the application base URI.
*/
type LoadBootResourceCallback = (type: WebAssemblyBootResourceType, name: string, defaultUri: string, integrity: string, behavior: AssetBehaviors) => string | Promise<Response> | null | undefined;
interface ResourceRequest {
name: string;
behavior: AssetBehaviors;
resolvedUrl?: string;
hash?: string | null | "";
}
interface LoadingResource {
name: string;
url: string;
response: Promise<Response>;
}
interface AssetEntry extends ResourceRequest {
interface AssetEntry {
/**
* the name of the asset, including extension.
*/
name: string;
/**
* determines how the asset will be handled once loaded
*/
behavior: AssetBehaviors;
/**
* this should be absolute url to the asset
*/
resolvedUrl?: string;
/**
* the integrity hash of the asset (if any)
*/
hash?: string | null | "";
/**
* If specified, overrides the path of the asset in the virtual filesystem and similar data structures once downloaded.
*/
Expand Down Expand Up @@ -442,4 +460,4 @@ declare global {
}
declare const createDotnetRuntime: CreateDotnetRuntimeType;

export { AssetBehaviors, AssetEntry, CreateDotnetRuntimeType, DotnetHostBuilder, DotnetModuleConfig, EmscriptenModule, GlobalizationMode, IMemoryView, ModuleAPI, MonoConfig, ResourceRequest, RuntimeAPI, createDotnetRuntime as default, dotnet, exit };
export { AssetBehaviors, AssetEntry, CreateDotnetRuntimeType, DotnetHostBuilder, DotnetModuleConfig, EmscriptenModule, GlobalizationMode, IMemoryView, ModuleAPI, MonoConfig, RuntimeAPI, createDotnetRuntime as default, dotnet, exit };
Loading
Loading