From 001d60ae2ad0566eaca0cec7edbccb0fe6a38f5a Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Tue, 9 Apr 2024 10:48:32 -0700 Subject: [PATCH] [wasm] use sbrk instead of emscripten mmap or malloc when loading bytes into heap (#100106) Use sbrk to allocate persistent space for large load_bytes_into_heap calls to avoid the startup overhead of emscripten's malloc and memset for the new space --- src/mono/browser/browser.proj | 1 + src/mono/browser/runtime/assets.ts | 4 ++-- src/mono/browser/runtime/dotnet.d.ts | 1 + src/mono/browser/runtime/memory.ts | 19 ++++++++++++++++++- src/mono/browser/runtime/types/emscripten.ts | 1 + 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/mono/browser/browser.proj b/src/mono/browser/browser.proj index 38d6f035e6cf3..09123abe3d19b 100644 --- a/src/mono/browser/browser.proj +++ b/src/mono/browser/browser.proj @@ -200,6 +200,7 @@ + diff --git a/src/mono/browser/runtime/assets.ts b/src/mono/browser/runtime/assets.ts index 7cdff19d8a84c..318750ad67258 100644 --- a/src/mono/browser/runtime/assets.ts +++ b/src/mono/browser/runtime/assets.ts @@ -7,7 +7,7 @@ import cwraps from "./cwraps"; import { mono_wasm_load_icu_data } from "./icu"; import { Module, loaderHelpers, mono_assert, runtimeHelpers } from "./globals"; import { mono_log_info, mono_log_debug, parseSymbolMapFile } from "./logging"; -import { mono_wasm_load_bytes_into_heap } from "./memory"; +import { mono_wasm_load_bytes_into_heap_persistent } from "./memory"; import { endMeasure, MeasuredBlock, startMeasure } from "./profiler"; import { AssetEntry } from "./types"; import { VoidPtr } from "./types/emscripten"; @@ -37,7 +37,7 @@ export function instantiate_asset (asset: AssetEntry, url: string, bytes: Uint8A // falls through case "heap": case "icu": - offset = mono_wasm_load_bytes_into_heap(bytes); + offset = mono_wasm_load_bytes_into_heap_persistent(bytes); break; case "vfs": { diff --git a/src/mono/browser/runtime/dotnet.d.ts b/src/mono/browser/runtime/dotnet.d.ts index 117d6598258a0..16df07663ea7e 100644 --- a/src/mono/browser/runtime/dotnet.d.ts +++ b/src/mono/browser/runtime/dotnet.d.ts @@ -20,6 +20,7 @@ declare interface Int32Ptr extends NativePointer { declare interface EmscriptenModule { _malloc(size: number): VoidPtr; _free(ptr: VoidPtr): void; + _sbrk(size: number): VoidPtr; out(message: string): void; err(message: string): void; ccall(ident: string, returnType?: string | null, argTypes?: string[], args?: any[], opts?: any): T; diff --git a/src/mono/browser/runtime/memory.ts b/src/mono/browser/runtime/memory.ts index 8205e6fd8098f..5a0ac71d3b329 100644 --- a/src/mono/browser/runtime/memory.ts +++ b/src/mono/browser/runtime/memory.ts @@ -325,7 +325,24 @@ export function withStackAlloc (bytesWanted: number, f: (pt // @bytes must be a typed array. space is allocated for it in the native heap // and it is copied to that location. returns the address of the allocation. export function mono_wasm_load_bytes_into_heap (bytes: Uint8Array): VoidPtr { - const memoryOffset = Module._malloc(bytes.length); + // pad sizes by 16 bytes for simd + const memoryOffset = Module._malloc(bytes.length + 16); + const heapBytes = new Uint8Array(localHeapViewU8().buffer, memoryOffset, bytes.length); + heapBytes.set(bytes); + return memoryOffset; +} + +// @bytes must be a typed array. space is allocated for it in memory +// and it is copied to that location. returns the address of the data. +// the result pointer *cannot* be freed because malloc is bypassed for speed. +export function mono_wasm_load_bytes_into_heap_persistent (bytes: Uint8Array): VoidPtr { + // pad sizes by 16 bytes for simd + const desiredSize = bytes.length + 16; + // wasm memory page size is 64kb. allocations smaller than that are probably best + // serviced by malloc + const memoryOffset = (desiredSize < (64 * 1024)) + ? Module._malloc(desiredSize) + : Module._sbrk(desiredSize); const heapBytes = new Uint8Array(localHeapViewU8().buffer, memoryOffset, bytes.length); heapBytes.set(bytes); return memoryOffset; diff --git a/src/mono/browser/runtime/types/emscripten.ts b/src/mono/browser/runtime/types/emscripten.ts index a9691cde49061..e2cc8e7c73ce6 100644 --- a/src/mono/browser/runtime/types/emscripten.ts +++ b/src/mono/browser/runtime/types/emscripten.ts @@ -26,6 +26,7 @@ export declare interface EmscriptenModule { // this should match emcc -s EXPORTED_FUNCTIONS _malloc(size: number): VoidPtr; _free(ptr: VoidPtr): void; + _sbrk(size: number): VoidPtr; // this should match emcc -s EXPORTED_RUNTIME_METHODS out(message: string): void;