Skip to content

Commit 1607ab2

Browse files
pavelsavararadical
andauthored
[browser] improve default initial memory size (#80507)
make EmccInitialHeapSize dynamic based on size of the assemblies and AOT DATA segments Co-authored-by: Ankit Jain <radical@gmail.com>
1 parent d793586 commit 1607ab2

File tree

5 files changed

+97
-9
lines changed

5 files changed

+97
-9
lines changed

src/mono/sample/wasm/browser-bench/Wasm.Browser.Bench.Sample.csproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@
99
<EnableAggressiveTrimming Condition="'$(EnableAOTAndTrimming)' != ''">$(EnableAOTAndTrimming)</EnableAggressiveTrimming>
1010
<PublishTrimmed Condition="'$(EnableAOTAndTrimming)' != ''">$(EnableAOTAndTrimming)</PublishTrimmed>
1111
<RunAOTCompilation Condition="'$(EnableAOTAndTrimming)' != ''">$(EnableAOTAndTrimming)</RunAOTCompilation>
12-
<!-- the default heap size is ~512MB, which is too much because AppStart loads more copies
13-
of the wasm runtime and can leak a few of them. the result is that browser-bench's memory
14-
usage can climb as high as 3GB or more and then fail -->
15-
<EmccInitialHeapSize>83886080</EmccInitialHeapSize>
1612
</PropertyGroup>
1713

1814
<ItemGroup>

src/mono/wasm/build/WasmApp.Native.targets

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@
188188
<_EmccLinkRsp>$(_WasmIntermediateOutputPath)emcc-link.rsp</_EmccLinkRsp>
189189

190190
<EmccInitialHeapSize Condition="'$(EmccInitialHeapSize)' == ''">$(EmccTotalMemory)</EmccInitialHeapSize>
191-
<EmccInitialHeapSize Condition="'$(EmccInitialHeapSize)' == ''">536870912</EmccInitialHeapSize>
192191
</PropertyGroup>
193192

194193
<ItemGroup>
@@ -231,7 +230,6 @@
231230
<_EmccLDFlags Include="-s ASSERTIONS=$(_EmccAssertionLevelDefault)" Condition="'$(_WasmDevel)' == 'true'" />
232231
<_EmccLDFlags Include="@(_EmccCommonFlags)" />
233232
<_EmccLDSFlags Include="-Wl,--allow-undefined" />
234-
<_EmccLDSFlags Include="-s INITIAL_MEMORY=$(EmccInitialHeapSize)" />
235233

236234
<!-- ILLinker should have removed unused imports, so error for Publish -->
237235
<_EmccLDSFlags Include="-s ERROR_ON_UNDEFINED_SYMBOLS=0" Condition="'$(WasmBuildingForNestedPublish)' != 'true'" />
@@ -372,7 +370,39 @@
372370
</ItemGroup>
373371
</Target>
374372

375-
<Target Name="_WasmWriteRspFilesForLinking" DependsOnTargets="_CheckEmccIsExpectedVersion">
373+
<Target Name="_WasmCalculateInitialHeapSize"
374+
Condition="'$(EmccInitialHeapSize)' == ''"
375+
DependsOnTargets="_CheckEmccIsExpectedVersion">
376+
<ItemGroup>
377+
<_AOTObjectFile Include="%(_BitcodeFile.ObjectFile)" />
378+
</ItemGroup>
379+
380+
<!-- for AOT builds we use llvm-size tool to collect size of the DATA segment in each object file -->
381+
<Exec Command="llvm-size$(_ExeExt) -d --format=sysv @(_AOTObjectFile, ' ')"
382+
Condition="'$(_WasmShouldAOT)' == 'true'"
383+
IgnoreStandardErrorWarningFormat="true"
384+
ConsoleToMsBuild="true"
385+
StandardOutputImportance="low" StandardErrorImportance="low"
386+
EnvironmentVariables="@(EmscriptenEnvVars)" >
387+
<Output TaskParameter="ConsoleOutput" ItemName="LlvmAotSizeOutput" />
388+
</Exec>
389+
<ItemGroup Condition="'$(_WasmShouldAOT)' == 'true'">
390+
<_AOTDataSegmentSize Condition="$([System.String]::Copy('%(LlvmAotSizeOutput.Identity)').StartsWith('DATA '))"
391+
Include="$([System.String]::Copy('%(LlvmAotSizeOutput.Identity)').Replace(&quot;DATA &quot;, &quot;&quot;).Replace(&quot; 0&quot;, &quot;&quot;).Trim())" />
392+
</ItemGroup>
393+
394+
<WasmCalculateInitialHeapSize
395+
Assemblies="@(WasmAssembliesToBundle)"
396+
AOTDataSegmentSizes="@(_AOTDataSegmentSize)">
397+
<Output TaskParameter="InitialHeapSize" PropertyName="_WasmCalculatedInitialHeapSize" />
398+
</WasmCalculateInitialHeapSize>
399+
<PropertyGroup>
400+
<EmccInitialHeapSize Condition="'$(EmccInitialHeapSize)' == '' and '$(_WasmCalculatedInitialHeapSize)' != '' and $(_WasmCalculatedInitialHeapSize) > 16777216">$(_WasmCalculatedInitialHeapSize)</EmccInitialHeapSize>
401+
<EmccInitialHeapSize Condition="'$(EmccInitialHeapSize)' == ''">16777216</EmccInitialHeapSize>
402+
</PropertyGroup>
403+
</Target>
404+
405+
<Target Name="_WasmWriteRspFilesForLinking" DependsOnTargets="_CheckEmccIsExpectedVersion;_WasmCalculateInitialHeapSize">
376406
<PropertyGroup>
377407
<_WasmEHLib Condition="'$(WasmEnableExceptionHandling)' == 'true'">libmono-wasm-eh-wasm.a</_WasmEHLib>
378408
<_WasmEHLib Condition="'$(WasmEnableExceptionHandling)' != 'true'">libmono-wasm-eh-js.a</_WasmEHLib>
@@ -383,6 +413,8 @@
383413
</PropertyGroup>
384414
<ItemGroup>
385415
<!-- order matters -->
416+
<_EmccLDSFlags Include="-s INITIAL_MEMORY=$(EmccInitialHeapSize)" />
417+
386418
<_WasmNativeFileForLinking Include="%(_BitcodeFile.ObjectFile)" />
387419
<_WasmNativeFileForLinking Include="%(_WasmSourceFileToCompile.ObjectFile)" />
388420

src/mono/wasm/build/WasmApp.targets

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project>
22
<UsingTask TaskName="WasmAppBuilder" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
33
<UsingTask TaskName="WasmLoadAssembliesAndReferences" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
4+
<UsingTask TaskName="WasmCalculateInitialHeapSize" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
45

56
<!--
67
Required public items/properties:
@@ -51,7 +52,7 @@
5152
- $(EmccFlags) - Emcc flags used for both compiling native files, and linking
5253
- $(EmccExtraLDFlags) - Extra emcc flags for linking
5354
- $(EmccExtraCFlags) - Extra emcc flags for compiling native files
54-
- $(EmccInitialHeapSize) - Initial heap size specified with `emcc`. Default value: 536870912
55+
- $(EmccInitialHeapSize) - Initial heap size specified with `emcc`. Default value: 16777216 or size of the DLLs, whichever is larger.
5556
Corresponds to `INITIAL_MEMORY` arg for emcc.
5657
(previously named EmccTotalMemory, which is still kept as an alias)
5758

src/mono/wasm/wasm.proj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@
158158
<PropertyGroup>
159159
<_EmccExportedRuntimeMethods>&quot;[@(EmccExportedRuntimeMethod -> '%27%(Identity)%27', ',')]&quot;</_EmccExportedRuntimeMethods>
160160
<_EmccExportedFunctions>@(EmccExportedFunction -> '%(Identity)',',')</_EmccExportedFunctions>
161-
<EmccInitialHeapSize>536870912</EmccInitialHeapSize>
161+
<EmccInitialHeapSize>16777216</EmccInitialHeapSize>
162162
</PropertyGroup>
163163
<ItemGroup>
164164
<_EmccLinkFlags Include="-s INITIAL_MEMORY=$(EmccInitialHeapSize)" />
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.IO;
6+
using Microsoft.Build.Framework;
7+
using Microsoft.Build.Utilities;
8+
9+
namespace Microsoft.WebAssembly.Build.Tasks;
10+
11+
/// <summary>estimate the total memory needed for the assemblies and AOT data segments.</summary>
12+
public class WasmCalculateInitialHeapSize : Task
13+
{
14+
[Required]
15+
public string[] Assemblies { get; set; } = Array.Empty<string>();
16+
17+
public string[] AOTDataSegmentSizes { get; set; } = Array.Empty<string>();
18+
19+
[Output]
20+
public long InitialHeapSize { get; private set; }
21+
22+
public override bool Execute()
23+
{
24+
long totalDllSize = 0;
25+
long totalDataSize = 0;
26+
27+
foreach (string asm in Assemblies)
28+
{
29+
var info = new FileInfo(asm);
30+
if (!info.Exists)
31+
{
32+
Log.LogError($"Could not find assembly '{asm}'");
33+
return false;
34+
}
35+
totalDllSize += info.Length;
36+
}
37+
38+
// during non-AOT builds, AOTDataSegmentSizes is empty
39+
foreach (string segment in AOTDataSegmentSizes)
40+
{
41+
if (!long.TryParse(segment, out long segmentSize))
42+
{
43+
Log.LogError($"Could not parse AOT Data segment size '{segment}");
44+
return false;
45+
}
46+
totalDataSize += segmentSize;
47+
}
48+
49+
// this is arbitrary guess about memory overhead of the runtime, after the assemblies are loaded
50+
const double extraMemoryRatio = 1.2;
51+
// plus size of data segments generated by AOT
52+
long memorySize = totalDataSize + (long)(totalDllSize * extraMemoryRatio);
53+
54+
// round it up to 64KB page size for wasm
55+
InitialHeapSize = (memorySize + 0x10000) & 0xFFFF0000;
56+
57+
return true;
58+
}
59+
}

0 commit comments

Comments
 (0)