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

Make wasm-interpreter work like wasm-aot #1769

Merged
merged 5 commits into from Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions samples/BenchmarkDotNet.Samples/IntroWasm.cs
Expand Up @@ -35,10 +35,9 @@ public class IntroWasmFluentConfig
public static void Run()
{
// the Wasm Toolchain requires two mandatory arguments:
const string mainJsPath = @"/home/adam/projects/runtime/src/mono/wasm/runtime-test.js";
const string cliPath = @"/home/adam/projects/runtime/dotnet.sh";

WasmRuntime runtime = new WasmRuntime(mainJs: new FileInfo(mainJsPath), msBuildMoniker: "net5.0");
WasmRuntime runtime = new WasmRuntime(msBuildMoniker: "net5.0");
NetCoreAppSettings netCoreAppSettings = new NetCoreAppSettings(
targetFrameworkMoniker: "net5.0", runtimeFrameworkVersion: null, name: "Wasm",
customDotNetCliPath: cliPath);
Expand Down
3 changes: 0 additions & 3 deletions src/BenchmarkDotNet/ConsoleArguments/CommandLineOptions.cs
Expand Up @@ -175,9 +175,6 @@ public class CommandLineOptions
[Option("wasmEngine", Required = false, HelpText = "Full path to a java script engine used to run the benchmarks, used by Wasm toolchain.")]
public FileInfo WasmJavascriptEngine { get; set; }

[Option("wasmMainJS", Required = false, HelpText = "Path to the main.js file used by Wasm toolchain. Mandatory when using \"--runtimes wasm\"")]
public FileInfo WasmMainJs { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep in mind that once we delete this parameter and you update BDN in dotnet/performance everything that is still using this argument is going to get an error from the BDN config parser

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I am aware. We have made changes in dotnet/performance so nothing is using it.


[Option("wasmArgs", Required = false, Default = "--expose_wasm", HelpText = "Arguments for the javascript engine used by Wasm toolchain.")]
public string WasmJavaScriptEngineArguments { get; set; }

Expand Down
11 changes: 1 addition & 10 deletions src/BenchmarkDotNet/ConsoleArguments/ConfigParser.cs
Expand Up @@ -112,19 +112,11 @@ private static bool Validate(CommandLineOptions options, ILogger logger)
logger.WriteLineError($"The provided runtime \"{runtime}\" is invalid. Available options are: {string.Join(", ", Enum.GetNames(typeof(RuntimeMoniker)).Select(name => name.ToLower()))}.");
return false;
}
else if (runtimeMoniker == RuntimeMoniker.Wasm && options.WasmMainJs == null && options.RuntimeSrcDir == null) {
logger.WriteLine("Either runtimeSrcDir or WasmMainJS must be specified.");
}
else if (runtimeMoniker == RuntimeMoniker.Wasm && options.WasmMainJs.IsNotNullButDoesNotExist())
{
logger.WriteLineError($"The provided {nameof(options.WasmMainJs)} \"{options.WasmMainJs}\" does NOT exist.");
return false;
}
else if (runtimeMoniker == RuntimeMoniker.MonoAOTLLVM && (options.AOTCompilerPath == null || options.AOTCompilerPath.IsNotNullButDoesNotExist()))
{
logger.WriteLineError($"The provided {nameof(options.AOTCompilerPath)} \"{ options.AOTCompilerPath }\" does NOT exist. It MUST be provided.");
}
else if (runtimeMoniker == RuntimeMoniker.Wasm && options.AOTCompilerMode == MonoAotCompilerMode.wasm && (options.RuntimeSrcDir == null || options.RuntimeSrcDir.IsNotNullButDoesNotExist()))
else if (runtimeMoniker == RuntimeMoniker.Wasm && (options.RuntimeSrcDir == null || options.RuntimeSrcDir.IsNotNullButDoesNotExist()))
{
logger.WriteLineError($"The provided {nameof(options.RuntimeSrcDir)} \"{options.RuntimeSrcDir}\" does NOT exist. It MUST be provided for wasm-aot.");
return false;
Expand Down Expand Up @@ -425,7 +417,6 @@ private static Job MakeWasmJob(Job baseJob, CommandLineOptions options, TimeSpan
bool wasmAot = options.AOTCompilerMode == MonoAotCompilerMode.wasm;

var wasmRuntime = new WasmRuntime(
mainJs: options.WasmMainJs ?? new FileInfo(Path.Combine(options.RuntimeSrcDir.FullName, "src", "mono", "wasm", "runtime-test.js")),
msBuildMoniker: msBuildMoniker,
javaScriptEngine: options.WasmJavascriptEngine?.FullName ?? "v8",
javaScriptEngineArguments: options.WasmJavaScriptEngineArguments,
Expand Down
21 changes: 3 additions & 18 deletions src/BenchmarkDotNet/Environments/Runtimes/WasmRuntime.cs
Expand Up @@ -12,8 +12,6 @@ public class WasmRuntime : Runtime, IEquatable<WasmRuntime>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static readonly WasmRuntime Default = new WasmRuntime();

public FileInfo MainJs { get; }

public string JavaScriptEngine { get; }

public string JavaScriptEngineArguments { get; }
Expand All @@ -31,37 +29,24 @@ public class WasmRuntime : Runtime, IEquatable<WasmRuntime>
/// <param name="msBuildMoniker">moniker, default: "net5.0"</param>
/// <param name="displayName">default: "Wasm"</param>
/// <remarks>path to mainJs MUST be provided</remarks>
public WasmRuntime(FileInfo mainJs, string msBuildMoniker = "net5.0", string displayName = "Wasm", string javaScriptEngine = "v8", string javaScriptEngineArguments = "--expose_wasm", bool aot = false, DirectoryInfo runtimeSrcDir = null) : base(RuntimeMoniker.Wasm, msBuildMoniker, displayName)
public WasmRuntime(string msBuildMoniker = "net5.0", string displayName = "Wasm", string javaScriptEngine = "v8", string javaScriptEngineArguments = "--expose_wasm", bool aot = false, DirectoryInfo runtimeSrcDir = null) : base(RuntimeMoniker.Wasm, msBuildMoniker, displayName)
{
if (!aot && mainJs == null)
throw new ArgumentNullException(paramName: nameof(mainJs));
if (!aot && mainJs.IsNotNullButDoesNotExist())
throw new FileNotFoundException($"Provided {nameof(mainJs)} file: \"{mainJs.FullName}\" doest NOT exist");
if (!string.IsNullOrEmpty(javaScriptEngine) && javaScriptEngine != "v8" && !File.Exists(javaScriptEngine))
throw new FileNotFoundException($"Provided {nameof(javaScriptEngine)} file: \"{javaScriptEngine}\" doest NOT exist");

MainJs = mainJs;
JavaScriptEngine = javaScriptEngine;
JavaScriptEngineArguments = javaScriptEngineArguments;
Aot = aot;
RuntimeSrcDir = runtimeSrcDir;
}

// this ctor exists only for the purpose of having .Default property that returns something consumable by RuntimeInformation.GetCurrentRuntime()
private WasmRuntime(string msBuildMoniker = "net5.0", string displayName = "Wasm", string javaScriptEngine = "v8", string javaScriptEngineArguments = "--expose_wasm") : base(RuntimeMoniker.Wasm, msBuildMoniker, displayName)
{
MainJs = new FileInfo("fake");
JavaScriptEngine = javaScriptEngine;
JavaScriptEngineArguments = javaScriptEngineArguments;
}

public override bool Equals(object obj)
=> obj is WasmRuntime other && Equals(other);

public bool Equals(WasmRuntime other)
=> other != null && base.Equals(other) && other.MainJs == MainJs && other.JavaScriptEngine == JavaScriptEngine && other.JavaScriptEngineArguments == JavaScriptEngineArguments && other.Aot == Aot && other.RuntimeSrcDir == RuntimeSrcDir;
=> other != null && base.Equals(other) && other.JavaScriptEngine == JavaScriptEngine && other.JavaScriptEngineArguments == JavaScriptEngineArguments && other.Aot == Aot && other.RuntimeSrcDir == RuntimeSrcDir;

public override int GetHashCode()
=> base.GetHashCode() ^ MainJs.GetHashCode() ^ (JavaScriptEngine?.GetHashCode() ?? 0) ^ (JavaScriptEngineArguments?.GetHashCode() ?? 0 ^ Aot.GetHashCode() ^ (RuntimeSrcDir?.GetHashCode() ?? 0));
=> base.GetHashCode() ^ (JavaScriptEngine?.GetHashCode() ?? 0) ^ (JavaScriptEngineArguments?.GetHashCode() ?? 0 ^ Aot.GetHashCode() ^ (RuntimeSrcDir?.GetHashCode() ?? 0));
}
}
25 changes: 10 additions & 15 deletions src/BenchmarkDotNet/Templates/WasmCsProj.txt
@@ -1,37 +1,32 @@
<Project Sdk="$SDKNAME$" DefaultTargets="$TARGET$">
<Project Sdk="$SDKNAME$" DefaultTargets="publish">
<PropertyGroup>
<OutputType>Exe</OutputType>
<OutputPath>bin</OutputPath>
<RuntimeSrcDir>$RUNTIMESRCDIR$</RuntimeSrcDir>
<RuntimeConfig>Release</RuntimeConfig>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<TargetFramework>$TFM$</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AppDir>$(MSBuildThisFileDirectory)\bin\$TFM$\browser-wasm\publish</AppDir>
<AssemblyName>$PROGRAMNAME$</AssemblyName>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<WasmMainJSPath>$MAINJS$</WasmMainJSPath>
<MicrosoftNetCoreAppRuntimePackDir>$RUNTIMEPACK$</MicrosoftNetCoreAppRuntimePackDir>
<UsingBrowserRuntimeWorkload>false</UsingBrowserRuntimeWorkload>
<PublishTrimmed>false</PublishTrimmed>
<RunAOTCompilation>false</RunAOTCompilation>
<WasmMainJSPath>$(RuntimeSrcDir)\src\mono\wasm\runtime-test.js</WasmMainJSPath>
<WasmGenerateRunV8Script>true</WasmGenerateRunV8Script>
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
<WasmNativeWorkload>false</WasmNativeWorkload>
<UsingBrowserRuntimeWorkload>false</UsingBrowserRuntimeWorkload>
$COPIEDSETTINGS$
</PropertyGroup>

<Import Project="$(RuntimeSrcDir)/src/mono/wasm/build/WasmApp.LocalBuild.props" />
<Import Project="$(RuntimeSrcDir)/src/mono/wasm/build/WasmApp.LocalBuild.targets" />

<ItemGroup>
<Compile Include="$CODEFILENAME$" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>

<Target Name="UpdateRuntimePack"
DependsOnTargets="ResolveFrameworkReferences" Condition="'$(MicrosoftNetCoreAppRuntimePackDir)' != ''">
<ItemGroup>
<ResolvedRuntimePack Update="@(ResolvedRuntimePack)" PackageDirectory="$(MicrosoftNetCoreAppRuntimePackDir)" />
</ItemGroup>
</Target>

<Target Name="PublishWithCustomRuntimePack"
AfterTargets="Build"
DependsOnTargets="UpdateRuntimePack;Publish" />

<ItemGroup>
<ProjectReference Include="$CSPROJPATH$" />
</ItemGroup>
Expand Down
53 changes: 0 additions & 53 deletions src/BenchmarkDotNet/Toolchains/MonoWasm/WasmBuilder.cs
Expand Up @@ -28,61 +28,8 @@ public BuildResult Build(GenerateResult generateResult, BuildPartition buildPart

WasmRuntime runtime = (WasmRuntime)buildPartition.Runtime;

if (buildResult.IsBuildSuccess && !runtime.Aot)
{
BuildApp(buildPartition.ProgramName, generateResult.ArtifactsPaths.BuildArtifactsDirectoryPath, runtime);
}

return buildResult;
}

private void BuildApp(string programName, string projectRoot, WasmRuntime runtime)
{
string appDir = Path.Combine(projectRoot, $"bin", targetFrameworkMoniker, "browser-wasm", "publish");
string outputDir = Path.Combine(appDir, "output");

string mainAssemblyPath = Path.Combine(appDir, $"{programName}.dll");

if (!File.Exists(mainAssemblyPath))
throw new ArgumentException($"File MainAssembly='{mainAssemblyPath}' doesn't exist.");

var assemblies = Directory.GetFiles(appDir, "*.dll");

// Create app
Directory.CreateDirectory(outputDir);
Directory.CreateDirectory(Path.Combine(outputDir, "managed"));
foreach (var assembly in assemblies)
File.Copy(assembly, Path.Combine(outputDir, "managed", Path.GetFileName(assembly)), true);

string timeZoneDat = "dotnet.timezones.blat";
string icutDat = "icudt.dat";

foreach (var f in new string[] { "dotnet.wasm", "dotnet.js", timeZoneDat, icutDat })
File.Copy(Path.Combine(appDir, f), Path.Combine(outputDir, f), true);

File.Copy(runtime.MainJs.FullName, Path.Combine(outputDir, "runtime.js"), true);

using (var sw = File.CreateText(Path.Combine(outputDir, "mono-config.js")))
{
sw.WriteLine("config = {");
sw.WriteLine("\t\"assembly_root\": \"managed\",");
sw.WriteLine("\t\"enable_debugging\": 0,");
sw.WriteLine("\t\"assets\": [");

foreach (var assembly in assemblies)
{
sw.Write($"\t\t{{ \"behavior\": \"assembly\", \"name\": \"{ Path.GetFileName(assembly)}\" }}");
sw.WriteLine(",");
}

sw.WriteLine($"\t\t{{ \"behavior\": \"icu\", \"name\": \"icudt.dat\", \"load_remote\": false}},");
sw.WriteLine($"\t\t{{ \"behavior\": \"vfs\", \"name\": \"{timeZoneDat}\", \"virtual_path\": \"/usr/share/zoneinfo/\" }}");

sw.WriteLine("\t],");
sw.WriteLine("\t\"files_to_map\": []");

sw.WriteLine("};");
}
}
}
}
8 changes: 0 additions & 8 deletions src/BenchmarkDotNet/Toolchains/MonoWasm/WasmGenerator.cs
Expand Up @@ -85,7 +85,6 @@ protected void GenerateProjectInterpreter(BuildPartition buildPartition, Artifac
.Replace("$SDKNAME$", sdkName)
.Replace("$RUNTIMEPACK$", CustomRuntimePack ?? "")
.Replace("$TARGET$", CustomRuntimePack != null ? "PublishWithCustomRuntimePack" : "Publish")
.Replace("$MAINJS$", runtime.MainJs.ToString())
.ToString();

File.WriteAllText(artifactsPaths.ProjectFilePath, content);
Expand All @@ -96,14 +95,7 @@ protected void GenerateProjectInterpreter(BuildPartition buildPartition, Artifac

protected override string GetBinariesDirectoryPath(string buildArtifactsDirectoryPath, string configuration)
{
if (Aot)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this change and I would like to be sure that we are not breaking anything. Have you tested both AOT and non-AOT toolchains?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, before wasm-intepreter mode was using a simplified custom app builder I built into BDN, because that was the best thing that could be done at the time.

Wasm-aot used all the app bundling stuff from the the runtime source directory, which put things in a different place than the one I coded into BDN.

With this change, both wasm-interpreter and wasm-aot will use the app builder from the runtime source dir, so the files will end up in the same place.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested both AOT and interpreter configurations.

{
return Path.Combine(buildArtifactsDirectoryPath, "bin", TargetFrameworkMoniker, "browser-wasm", "AppBundle");
}
else
{
return Path.Combine(buildArtifactsDirectoryPath, "bin", TargetFrameworkMoniker, "browser-wasm", "publish", "output");
}
}
}
}