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 10 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
10 changes: 5 additions & 5 deletions src/mono/sample/wasm/browser-advanced/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
<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">
<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="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="./icudt.dat" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./managed/System.Private.CoreLib.wasm" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./_framework/icudt.dat" as="fetch" crossorigin="anonymous">
<link rel="prefetch" href="./_framework/System.Private.CoreLib.wasm" as="fetch" crossorigin="anonymous">
</head>

<body>
Expand Down
8 changes: 4 additions & 4 deletions src/mono/sample/wasm/browser-bench/appstart-frame.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
<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="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
48 changes: 33 additions & 15 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);
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -248,10 +255,10 @@ private async void ServeAsync(HttpListenerContext context)
}
catch (Exception)
{
buffer = null;
fc = null;
}

if (buffer != null)
if (fc != null)
{
string? contentType = null;
if (path.EndsWith(".wasm"))
Expand All @@ -270,7 +277,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 +286,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);
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved

// 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
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 hash for integrity checks while fetching assets
*/
disableIntegrityCheck?: boolean;
/**
* Configures use of the hash for integrity checks while fetching assets
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved
*/
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