From 6a72e2632a1fcc2621fb6351f0e970cc298378f5 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Thu, 21 Mar 2024 14:08:03 -0700 Subject: [PATCH 1/4] Add new persistent version of load_bytes_into_heap that uses sbrk to avoid the overhead of emscripten's mmap HACK: Use sbrk instead of mmap to allocate wasm pages, to skip memset. Disable vfree. Fix build Revert mmap experiment --- 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 | 11 +++++++++++ src/mono/browser/runtime/types/emscripten.ts | 1 + 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/mono/browser/browser.proj b/src/mono/browser/browser.proj index 38d6f035e6cf36..09123abe3d19b5 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 7cdff19d8a84c9..318750ad672589 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 e0d644558b46b8..07a21e06dc7f00 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 8205e6fd8098f4..af6227471873d5 100644 --- a/src/mono/browser/runtime/memory.ts +++ b/src/mono/browser/runtime/memory.ts @@ -331,6 +331,17 @@ export function mono_wasm_load_bytes_into_heap (bytes: Uint8Array): VoidPtr { 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 memoryOffset = Module._sbrk(bytes.length + 16); + const heapBytes = new Uint8Array(localHeapViewU8().buffer, memoryOffset, bytes.length); + heapBytes.set(bytes); + return memoryOffset; +} + export function getEnv (name: string): string | null { let charPtr: CharPtr = 0; try { diff --git a/src/mono/browser/runtime/types/emscripten.ts b/src/mono/browser/runtime/types/emscripten.ts index a9691cde490611..e2cc8e7c73ce67 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; From 44fc4581bc79a05fc150339a8b1b84cb9c8e1d2d Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Tue, 26 Mar 2024 10:33:51 -0700 Subject: [PATCH 2/4] Don't use sbrk to load small files into the heap --- src/mono/browser/runtime/memory.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/mono/browser/runtime/memory.ts b/src/mono/browser/runtime/memory.ts index af6227471873d5..5a0ac71d3b3295 100644 --- a/src/mono/browser/runtime/memory.ts +++ b/src/mono/browser/runtime/memory.ts @@ -325,7 +325,8 @@ 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; @@ -336,7 +337,12 @@ export function mono_wasm_load_bytes_into_heap (bytes: Uint8Array): VoidPtr { // 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 memoryOffset = Module._sbrk(bytes.length + 16); + 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; From 6911d378a4718af1c5546074516ea284583dbdf1 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Tue, 26 Mar 2024 18:00:26 -0700 Subject: [PATCH 3/4] Use sbrk instead of mmap for dlmalloc on wasm Fix build --- src/mono/mono/utils/dlmalloc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mono/mono/utils/dlmalloc.c b/src/mono/mono/utils/dlmalloc.c index 53fbd2adf2bf85..5ff079f4e4e5e6 100644 --- a/src/mono/mono/utils/dlmalloc.c +++ b/src/mono/mono/utils/dlmalloc.c @@ -19,13 +19,24 @@ * - the defines below */ +#include #include "mono-mmap.h" #define USE_DL_PREFIX 1 #define USE_LOCKS 1 + +#ifdef HOST_WASM +#pragma clang diagnostic ignored "-Wunused-variable" +/* Use sbrk to allocate memory, and never release pages since emscripten mmap is fake */ +#define HAVE_MORECORE 1 +#define NO_MALLINFO 1 +#undef HAVE_MMAP +#define HAVE_MMAP 0 +#else /* Use mmap for allocating memory */ #define HAVE_MORECORE 0 #define NO_MALLINFO 1 +#endif // HOST_WASM #include /* From 7bd8b465807e22d239a21047daeb9739b41de62d Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Wed, 27 Mar 2024 10:05:38 -0700 Subject: [PATCH 4/4] Revert "Use sbrk instead of mmap for dlmalloc on wasm" This reverts commit 0024b82862c67b6baeae63020a743cf42d7c6c20. --- src/mono/mono/utils/dlmalloc.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/mono/mono/utils/dlmalloc.c b/src/mono/mono/utils/dlmalloc.c index 5ff079f4e4e5e6..53fbd2adf2bf85 100644 --- a/src/mono/mono/utils/dlmalloc.c +++ b/src/mono/mono/utils/dlmalloc.c @@ -19,24 +19,13 @@ * - the defines below */ -#include #include "mono-mmap.h" #define USE_DL_PREFIX 1 #define USE_LOCKS 1 - -#ifdef HOST_WASM -#pragma clang diagnostic ignored "-Wunused-variable" -/* Use sbrk to allocate memory, and never release pages since emscripten mmap is fake */ -#define HAVE_MORECORE 1 -#define NO_MALLINFO 1 -#undef HAVE_MMAP -#define HAVE_MMAP 0 -#else /* Use mmap for allocating memory */ #define HAVE_MORECORE 0 #define NO_MALLINFO 1 -#endif // HOST_WASM #include /*