Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/BenchmarkDotNet/ConsoleArguments/CommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ public bool UseDisassemblyDiagnoser
[Option("wasmDataDir", Required = false, HelpText = "Wasm data directory")]
public DirectoryInfo? WasmDataDirectory { get; set; }

[Option("wasmCoreCLR", Required = false, Default = false, HelpText = "Use CoreCLR runtime pack (Microsoft.NETCore.App.Runtime.browser-wasm) instead of the Mono runtime pack for WASM benchmarks.")]
public bool WasmCoreCLR { get; set; }

[Option("noForcedGCs", Required = false, HelpText = "Specifying would not forcefully induce any GCs.")]
public bool NoForcedGCs { get; set; }

Expand Down
3 changes: 2 additions & 1 deletion src/BenchmarkDotNet/ConsoleArguments/ConfigParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,8 @@ private static Job MakeWasmJob(Job baseJob, CommandLineOptions options, string m
javaScriptEngineArguments: options.WasmJavaScriptEngineArguments ?? "",
aot: wasmAot,
wasmDataDir: options.WasmDataDirectory?.FullName ?? "",
moniker: moniker);
moniker: moniker,
isMonoRuntime: !options.WasmCoreCLR);

var toolChain = WasmToolchain.From(new NetCoreAppSettings(
targetFrameworkMoniker: wasmRuntime.MsBuildMoniker,
Expand Down
15 changes: 12 additions & 3 deletions src/BenchmarkDotNet/Environments/Runtimes/WasmRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ public class WasmRuntime : Runtime, IEquatable<WasmRuntime>

public string WasmDataDir { get; }

/// <summary>
/// When true (default), the generated project uses Microsoft.NET.Sdk.WebAssembly which sets UseMonoRuntime=true
/// and resolves the Mono runtime pack (Microsoft.NETCore.App.Runtime.Mono.browser-wasm). When false, the generated
/// project uses Microsoft.NET.Sdk which resolves the CoreCLR runtime pack (Microsoft.NETCore.App.Runtime.browser-wasm).
/// </summary>
public bool IsMonoRuntime { get; }

/// <summary>
/// creates new instance of WasmRuntime
/// </summary>
Expand All @@ -31,7 +38,8 @@ public class WasmRuntime : Runtime, IEquatable<WasmRuntime>
/// <param name="aot">Specifies whether AOT or Interpreter (default) project should be generated.</param>
/// <param name="wasmDataDir">Specifies a wasm data directory surfaced as $(WasmDataDir) for the project</param>
/// <param name="moniker">Runtime moniker</param>
public WasmRuntime(string msBuildMoniker = "net5.0", string displayName = "Wasm", string javaScriptEngine = "v8", string javaScriptEngineArguments = "--expose_wasm", bool aot = false, string wasmDataDir = "", RuntimeMoniker moniker = RuntimeMoniker.Wasm) : base(moniker, msBuildMoniker, displayName)
/// <param name="isMonoRuntime">When true (default), use Mono runtime pack; when false, use CoreCLR runtime pack.</param>
public WasmRuntime(string msBuildMoniker = "net5.0", string displayName = "Wasm", string javaScriptEngine = "v8", string javaScriptEngineArguments = "--expose_wasm", bool aot = false, string wasmDataDir = "", RuntimeMoniker moniker = RuntimeMoniker.Wasm, bool isMonoRuntime = true) : base(moniker, msBuildMoniker, displayName)
{
if (javaScriptEngine.IsNotBlank() && javaScriptEngine != "v8" && !File.Exists(javaScriptEngine))
throw new FileNotFoundException($"Provided {nameof(javaScriptEngine)} file: \"{javaScriptEngine}\" doest NOT exist");
Expand All @@ -40,15 +48,16 @@ public WasmRuntime(string msBuildMoniker = "net5.0", string displayName = "Wasm"
JavaScriptEngineArguments = javaScriptEngineArguments;
Aot = aot;
WasmDataDir = wasmDataDir;
IsMonoRuntime = isMonoRuntime;
}

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

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

public override int GetHashCode()
=> HashCode.Combine(base.GetHashCode(), JavaScriptEngine, JavaScriptEngineArguments, Aot);
=> HashCode.Combine(base.GetHashCode(), JavaScriptEngine, JavaScriptEngineArguments, Aot, IsMonoRuntime);
}
}
3 changes: 1 addition & 2 deletions src/BenchmarkDotNet/Templates/WasmCsProj.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
<RunAOTCompilation>$RUN_AOT$</RunAOTCompilation>
<PublishTrimmed>$(RunAOTCompilation)</PublishTrimmed>
<WasmGenerateRunV8Script>true</WasmGenerateRunV8Script>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
<EnableDefaultWasmAssembliesToBundle>false</EnableDefaultWasmAssembliesToBundle>
Expand All @@ -32,8 +31,8 @@

<ItemGroup>
<Compile Include="$CODEFILENAME$" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
<!-- move this too? -->
<TrimmerRootDescriptor Include="WasmLinkerDescription.xml" Condition="'$(RunAOTCompilation)' == 'true'" />
<Content Update="wwwroot\**" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

<ItemGroup>
Expand Down
5 changes: 3 additions & 2 deletions src/BenchmarkDotNet/Toolchains/DotNetCli/DotNetCliCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ internal static string GetRestoreCommand(ArtifactsPaths artifactsPaths, BuildPar
.AppendArgument($"\"{filePath}\"")
// restore doesn't support -f argument.
.AppendArgument(artifactsPaths.PackagesDirectoryName.IsBlank() ? string.Empty : $"--packages \"{artifactsPaths.PackagesDirectoryName}\"")
.AppendArgument(buildPartition?.Runtime is WasmRuntime ? "-r browser-wasm" : string.Empty)
.AppendArgument(GetCustomMsBuildArguments(buildPartition.RepresentativeBenchmarkCase, buildPartition.Resolver))
.AppendArgument(extraArguments)
.AppendArgument(GetMandatoryMsBuildSettings(buildPartition.BuildConfiguration))
Expand Down Expand Up @@ -221,7 +220,9 @@ internal static StringBuilder MaybeAppendOutputPaths(this StringBuilder stringBu
? stringBuilder
: stringBuilder
// Use AltDirectorySeparatorChar so it's not interpreted as an escaped quote `\"`.
.AppendArgument($"/p:ArtifactsPath=\"{artifactsPaths.BuildArtifactsDirectoryPath}{Path.AltDirectorySeparatorChar}\"")
// Use a subdirectory for ArtifactsPath so that DefaultItemExcludes (which the SDK
// sets to $(ArtifactsPath)/**) doesn't cover project-level files like wwwroot/.
.AppendArgument($"/p:ArtifactsPath=\"{artifactsPaths.BuildArtifactsDirectoryPath}{Path.AltDirectorySeparatorChar}.artifacts{Path.AltDirectorySeparatorChar}\"")
.AppendArgument($"/p:OutDir=\"{artifactsPaths.BinariesDirectoryPath}{Path.AltDirectorySeparatorChar}\"")
// OutputPath is legacy, per-project version of OutDir. We set both just in case. https://github.com/dotnet/msbuild/issues/87
.AppendArgument($"/p:OutputPath=\"{artifactsPaths.BinariesDirectoryPath}{Path.AltDirectorySeparatorChar}\"")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace BenchmarkDotNet.Toolchains.DotNetCli;

public class DotNetCliPublisher(string tfm, string? customDotNetCliPath = null, string? extraArguments = null, IReadOnlyList<EnvironmentVariable>? environmentVariables = null) : IBuilder
public class DotNetCliPublisher(string tfm, string? customDotNetCliPath = null, string? extraArguments = null, IReadOnlyList<EnvironmentVariable>? environmentVariables = null, bool logOutput = false) : IBuilder
{
public string TargetFrameworkMoniker { get; } = tfm;
public string CustomDotNetCliPath { get; } = customDotNetCliPath;
Expand All @@ -21,6 +21,7 @@ public virtual BuildResult Build(GenerateResult generateResult, BuildPartition b
logger,
buildPartition,
environmentVariables,
buildPartition.Timeout
buildPartition.Timeout,
logOutput: logOutput
).RestoreThenBuildThenPublish();
}
4 changes: 2 additions & 2 deletions src/BenchmarkDotNet/Toolchains/MonoWasm/WasmExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ private static ExecuteResult Execute(BenchmarkCase benchmarkCase, BenchmarkId be
private static Process CreateProcess(BenchmarkCase benchmarkCase, ArtifactsPaths artifactsPaths, string args, IResolver resolver)
{
WasmRuntime runtime = (WasmRuntime)benchmarkCase.GetRuntime();
string mainJs = runtime.RuntimeMoniker < RuntimeMoniker.WasmNet70 ? "main.js" : "test-main.js";
const string mainJs = "benchmark-main.mjs";

var start = new ProcessStartInfo
{
FileName = runtime.JavaScriptEngine,
Arguments = $"{runtime.JavaScriptEngineArguments} {mainJs} -- --run {artifactsPaths.ProgramName}.dll {args} ",
WorkingDirectory = Path.Combine(artifactsPaths.BinariesDirectoryPath, "AppBundle"),
WorkingDirectory = Path.Combine(artifactsPaths.BinariesDirectoryPath, "wwwroot"),
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = false, // not supported by WASM!
Expand Down
14 changes: 10 additions & 4 deletions src/BenchmarkDotNet/Toolchains/MonoWasm/WasmGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ namespace BenchmarkDotNet.Toolchains.MonoWasm
public class WasmGenerator : CsProjGenerator
{
private readonly string CustomRuntimePack;
private readonly string MainJS;
private const string MainJS = "benchmark-main.mjs";

public WasmGenerator(string targetFrameworkMoniker, string cliPath, string packagesPath, string customRuntimePack, bool aot)
: base(targetFrameworkMoniker, cliPath, packagesPath, runtimeFrameworkVersion: null)
{
CustomRuntimePack = customRuntimePack;
MainJS = (targetFrameworkMoniker == "net5.0" || targetFrameworkMoniker == "net6.0") ? "main.js" : "test-main.js";
BenchmarkRunCallType = aot ? Code.CodeGenBenchmarkRunCallType.Direct : Code.CodeGenBenchmarkRunCallType.Reflection;
}

Expand All @@ -46,7 +45,9 @@ protected void GenerateProjectFile(BuildPartition buildPartition, ArtifactsPaths

var xmlDoc = new XmlDocument();
xmlDoc.Load(projectFile.FullName);
var (customProperties, sdkName) = GetSettingsThatNeedToBeCopied(xmlDoc, projectFile);
var (customProperties, _) = GetSettingsThatNeedToBeCopied(xmlDoc, projectFile);
// Microsoft.NET.Sdk.WebAssembly auto-defaults UseMonoRuntime=true.
string sdkName = runtime.IsMonoRuntime ? "Microsoft.NET.Sdk.WebAssembly" : "Microsoft.NET.Sdk";

string content = new StringBuilder(ResourceHelper.LoadTemplate("WasmCsProj.txt"))
.Replace("$PLATFORM$", buildPartition.Platform.ToConfig())
Expand All @@ -63,10 +64,15 @@ protected void GenerateProjectFile(BuildPartition buildPartition, ArtifactsPaths

File.WriteAllText(artifactsPaths.ProjectFilePath, content);

// Place benchmark-main.mjs in wwwroot/ next to the generated csproj.
string projectWwwroot = Path.Combine(Path.GetDirectoryName(artifactsPaths.ProjectFilePath)!, "wwwroot");
Directory.CreateDirectory(projectWwwroot);
File.WriteAllText(Path.Combine(projectWwwroot, MainJS), ResourceHelper.LoadTemplate(MainJS));

GatherReferences(buildPartition, artifactsPaths, logger);
}

protected override string GetExecutablePath(string binariesDirectoryPath, string programName) => Path.Combine(binariesDirectoryPath, "AppBundle", MainJS);
protected override string GetExecutablePath(string binariesDirectoryPath, string programName) => Path.Combine(binariesDirectoryPath, "wwwroot", MainJS);

protected override string GetBinariesDirectoryPath(string buildArtifactsDirectoryPath, string configuration)
=> Path.Combine(buildArtifactsDirectoryPath, "bin", configuration, TargetFrameworkMoniker, "browser-wasm");
Expand Down
2 changes: 1 addition & 1 deletion src/BenchmarkDotNet/Toolchains/MonoWasm/WasmToolchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static IToolchain From(NetCoreAppSettings netCoreAppSettings)
netCoreAppSettings.PackagesPath,
netCoreAppSettings.CustomRuntimePack,
netCoreAppSettings.AOTCompilerMode == MonoAotLLVM.MonoAotCompilerMode.wasm),
new DotNetCliBuilder(netCoreAppSettings.TargetFrameworkMoniker,
new DotNetCliPublisher(netCoreAppSettings.TargetFrameworkMoniker,
netCoreAppSettings.CustomDotNetCliPath,
// aot builds can be very slow
logOutput: netCoreAppSettings.AOTCompilerMode == MonoAotLLVM.MonoAotCompilerMode.wasm),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="AppBundle\**" CopyToOutputDirectory="Always" />
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
Expand Down
3 changes: 0 additions & 3 deletions tests/BenchmarkDotNet.IntegrationTests/WasmTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.IO;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
Expand Down Expand Up @@ -33,12 +32,10 @@ private ManualConfig GetConfig(MonoAotCompilerMode aotCompilerMode)
var dotnetVersion = "net8.0";
var logger = new OutputLogger(Output);
var netCoreAppSettings = new NetCoreAppSettings(dotnetVersion, null, "Wasm", aotCompilerMode: aotCompilerMode);
var mainJsPath = Path.Combine(AppContext.BaseDirectory, "AppBundle", "test-main.js");

return ManualConfig.CreateEmpty()
.AddLogger(logger)
.AddJob(Job.Dry
.WithArguments([new MsBuildArgument($"/p:WasmMainJSPath={mainJsPath}")])
.WithRuntime(new WasmRuntime(dotnetVersion, moniker: RuntimeMoniker.WasmNet80, javaScriptEngineArguments: "--expose_wasm --module"))
.WithToolchain(WasmToolchain.From(netCoreAppSettings)))
.WithBuildTimeout(TimeSpan.FromSeconds(240))
Expand Down