From 53009b26dd2e8b75fba8b44849e1d323ddb2a31f Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Sun, 22 Jun 2025 15:40:02 -0400 Subject: runtime: use a smaller arena size on Wasm On Wasm, some programs have very small heap. Currently, we use 4 MB arena size (like all other 32-bit platforms). For a very small program, it needs to allocate one heap arena, 4 MB size at a 4 MB aligned address. So we'll need 8 MB of linear memory, whereas only a smaller portion is actually used by the program. On Wasm, samll programs are not uncommon (e.g. WASI plugins), and users are concerned about the memory usage. This CL switches to a smaller arena size, as well as a smaller page allocator chunk size (both are now 512 KB). So the heap will be grown in 512 KB granularity. For a helloworld program, it now uses less than 3 MB of linear memory, instead of 8 MB. Change-Id: Ibd66c1fa6e794a12c00906cbacc8f2e410f196c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/683296 Reviewed-by: David Chase Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/runtime/mpagealloc_test.go | 217 +++++++++++++++++++++-------------------- 1 file changed, 112 insertions(+), 105 deletions(-) (limited to 'src/runtime/mpagealloc_test.go') diff --git a/src/runtime/mpagealloc_test.go b/src/runtime/mpagealloc_test.go index f2b82e3f50..ded7a79922 100644 --- a/src/runtime/mpagealloc_test.go +++ b/src/runtime/mpagealloc_test.go @@ -343,38 +343,6 @@ func TestPageAllocAlloc(t *testing.T) { BaseChunkIdx: {{0, 25}}, }, }, - "AllFree64": { - before: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {}, - }, - scav: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{21, 1}, {63, 65}}, - }, - hits: []hit{ - {64, PageBase(BaseChunkIdx, 0), 2 * PageSize}, - {64, PageBase(BaseChunkIdx, 64), 64 * PageSize}, - {64, PageBase(BaseChunkIdx, 128), 0}, - }, - after: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{0, 192}}, - }, - }, - "AllFree65": { - before: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {}, - }, - scav: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{129, 1}}, - }, - hits: []hit{ - {65, PageBase(BaseChunkIdx, 0), 0}, - {65, PageBase(BaseChunkIdx, 65), PageSize}, - {65, PageBase(BaseChunkIdx, 130), 0}, - }, - after: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{0, 195}}, - }, - }, "ExhaustPallocChunkPages-3": { before: map[ChunkIdx][]BitRange{ BaseChunkIdx: {}, @@ -410,25 +378,6 @@ func TestPageAllocAlloc(t *testing.T) { BaseChunkIdx: {{0, PallocChunkPages}}, }, }, - "StraddlePallocChunkPages": { - before: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{0, PallocChunkPages / 2}}, - BaseChunkIdx + 1: {{PallocChunkPages / 2, PallocChunkPages / 2}}, - }, - scav: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {}, - BaseChunkIdx + 1: {{3, 100}}, - }, - hits: []hit{ - {PallocChunkPages, PageBase(BaseChunkIdx, PallocChunkPages/2), 100 * PageSize}, - {PallocChunkPages, 0, 0}, - {1, 0, 0}, - }, - after: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{0, PallocChunkPages}}, - BaseChunkIdx + 1: {{0, PallocChunkPages}}, - }, - }, "StraddlePallocChunkPages+1": { before: map[ChunkIdx][]BitRange{ BaseChunkIdx: {{0, PallocChunkPages / 2}}, @@ -489,28 +438,6 @@ func TestPageAllocAlloc(t *testing.T) { BaseChunkIdx + 0x41: {{0, PallocChunkPages}}, }, }, - "StraddlePallocChunkPages*2": { - before: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{0, PallocChunkPages / 2}}, - BaseChunkIdx + 1: {}, - BaseChunkIdx + 2: {{PallocChunkPages / 2, PallocChunkPages / 2}}, - }, - scav: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{0, 7}}, - BaseChunkIdx + 1: {{3, 5}, {121, 10}}, - BaseChunkIdx + 2: {{PallocChunkPages/2 + 12, 2}}, - }, - hits: []hit{ - {PallocChunkPages * 2, PageBase(BaseChunkIdx, PallocChunkPages/2), 15 * PageSize}, - {PallocChunkPages * 2, 0, 0}, - {1, 0, 0}, - }, - after: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{0, PallocChunkPages}}, - BaseChunkIdx + 1: {{0, PallocChunkPages}}, - BaseChunkIdx + 2: {{0, PallocChunkPages}}, - }, - }, "StraddlePallocChunkPages*5/4": { before: map[ChunkIdx][]BitRange{ BaseChunkIdx: {{0, PallocChunkPages}}, @@ -536,7 +463,60 @@ func TestPageAllocAlloc(t *testing.T) { BaseChunkIdx + 3: {{0, PallocChunkPages}}, }, }, - "AllFreePallocChunkPages*7+5": { + } + if PallocChunkPages >= 512 { + tests["AllFree64"] = test{ + before: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {}, + }, + scav: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{21, 1}, {63, 65}}, + }, + hits: []hit{ + {64, PageBase(BaseChunkIdx, 0), 2 * PageSize}, + {64, PageBase(BaseChunkIdx, 64), 64 * PageSize}, + {64, PageBase(BaseChunkIdx, 128), 0}, + }, + after: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{0, 192}}, + }, + } + tests["AllFree65"] = test{ + before: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {}, + }, + scav: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{129, 1}}, + }, + hits: []hit{ + {65, PageBase(BaseChunkIdx, 0), 0}, + {65, PageBase(BaseChunkIdx, 65), PageSize}, + {65, PageBase(BaseChunkIdx, 130), 0}, + }, + after: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{0, 195}}, + }, + } + tests["StraddlePallocChunkPages"] = test{ + before: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{0, PallocChunkPages / 2}}, + BaseChunkIdx + 1: {{PallocChunkPages / 2, PallocChunkPages / 2}}, + }, + scav: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {}, + BaseChunkIdx + 1: {{3, 100}}, + }, + hits: []hit{ + {PallocChunkPages, PageBase(BaseChunkIdx, PallocChunkPages/2), 100 * PageSize}, + {PallocChunkPages, 0, 0}, + {1, 0, 0}, + }, + after: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{0, PallocChunkPages}}, + BaseChunkIdx + 1: {{0, PallocChunkPages}}, + }, + } + tests["AllFreePallocChunkPages*7+5"] = test{ before: map[ChunkIdx][]BitRange{ BaseChunkIdx: {}, BaseChunkIdx + 1: {}, @@ -572,7 +552,29 @@ func TestPageAllocAlloc(t *testing.T) { BaseChunkIdx + 6: {{0, PallocChunkPages}}, BaseChunkIdx + 7: {{0, 6}}, }, - }, + } + tests["StraddlePallocChunkPages*2"] = test{ + before: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{0, PallocChunkPages / 2}}, + BaseChunkIdx + 1: {}, + BaseChunkIdx + 2: {{PallocChunkPages / 2, PallocChunkPages / 2}}, + }, + scav: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{0, 7}}, + BaseChunkIdx + 1: {{3, 5}, {121, 10}}, + BaseChunkIdx + 2: {{PallocChunkPages/2 + 12, 2}}, + }, + hits: []hit{ + {PallocChunkPages * 2, PageBase(BaseChunkIdx, PallocChunkPages/2), 15 * PageSize}, + {PallocChunkPages * 2, 0, 0}, + {1, 0, 0}, + }, + after: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{0, PallocChunkPages}}, + BaseChunkIdx + 1: {{0, PallocChunkPages}}, + BaseChunkIdx + 2: {{0, PallocChunkPages}}, + }, + } } // Disable these tests on iOS since we have a small address space. // See #46860. @@ -754,12 +756,13 @@ func TestPageAllocFree(t *testing.T) { if GOOS == "openbsd" && testing.Short() { t.Skip("skipping because virtual memory is limited; see #36210") } - tests := map[string]struct { + type test struct { before map[ChunkIdx][]BitRange after map[ChunkIdx][]BitRange npages uintptr frees []uintptr - }{ + } + tests := map[string]test{ "Free1": { npages: 1, before: map[ChunkIdx][]BitRange{ @@ -840,34 +843,6 @@ func TestPageAllocFree(t *testing.T) { BaseChunkIdx: {{25, PallocChunkPages - 25}}, }, }, - "Free64": { - npages: 64, - before: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{0, PallocChunkPages}}, - }, - frees: []uintptr{ - PageBase(BaseChunkIdx, 0), - PageBase(BaseChunkIdx, 64), - PageBase(BaseChunkIdx, 128), - }, - after: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{192, PallocChunkPages - 192}}, - }, - }, - "Free65": { - npages: 65, - before: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{0, PallocChunkPages}}, - }, - frees: []uintptr{ - PageBase(BaseChunkIdx, 0), - PageBase(BaseChunkIdx, 65), - PageBase(BaseChunkIdx, 130), - }, - after: map[ChunkIdx][]BitRange{ - BaseChunkIdx: {{195, PallocChunkPages - 195}}, - }, - }, "FreePallocChunkPages": { npages: PallocChunkPages, before: map[ChunkIdx][]BitRange{ @@ -965,6 +940,38 @@ func TestPageAllocFree(t *testing.T) { }, }, } + if PallocChunkPages >= 512 { + // avoid constant overflow when PallocChunkPages is small + var PallocChunkPages uint = PallocChunkPages + tests["Free64"] = test{ + npages: 64, + before: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{0, PallocChunkPages}}, + }, + frees: []uintptr{ + PageBase(BaseChunkIdx, 0), + PageBase(BaseChunkIdx, 64), + PageBase(BaseChunkIdx, 128), + }, + after: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{192, PallocChunkPages - 192}}, + }, + } + tests["Free65"] = test{ + npages: 65, + before: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{0, PallocChunkPages}}, + }, + frees: []uintptr{ + PageBase(BaseChunkIdx, 0), + PageBase(BaseChunkIdx, 65), + PageBase(BaseChunkIdx, 130), + }, + after: map[ChunkIdx][]BitRange{ + BaseChunkIdx: {{195, PallocChunkPages - 195}}, + }, + } + } for name, v := range tests { v := v t.Run(name, func(t *testing.T) { -- cgit v1.3