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

Use out-of-process disassembler with InProcessEmitToolchain #2397

Closed
wants to merge 2 commits into from
Closed
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
23 changes: 21 additions & 2 deletions src/BenchmarkDotNet/Disassemblers/DisassemblyDiagnoser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
using BenchmarkDotNet.Portability;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Toolchains;
using BenchmarkDotNet.Toolchains.InProcess.Emit;
using BenchmarkDotNet.Toolchains.InProcess.NoEmit;
using BenchmarkDotNet.Validators;

Expand Down Expand Up @@ -71,6 +73,11 @@ public void Handle(HostSignal signal, DiagnoserActionParameters parameters)

switch (signal)
{
case HostSignal.AfterAll when benchmark.GetToolchain().IsInProcess:
if (!IsOutOfProcessDisassemblerSupportedForCurrentPlatform())
throw new PlatformNotSupportedException("The current platform does not support disassembling in-process.");
results.Add(benchmark, windowsDifferentArchitectureDisassembler.Disassemble(parameters));
break;
case HostSignal.AfterAll when ShouldUseSameArchitectureDisassembler(benchmark, parameters):
results.Add(benchmark, sameArchitectureDisassembler.Disassemble(parameters));
break;
Expand Down Expand Up @@ -100,9 +107,16 @@ public IEnumerable<ValidationError> Validate(ValidationParameters validationPara

foreach (var benchmark in validationParameters.Benchmarks)
{
if (benchmark.Job.Infrastructure.TryGetToolchain(out var toolchain) && toolchain is InProcessNoEmitToolchain)
if (benchmark.Job.Infrastructure.TryGetToolchain(out var toolchain) && toolchain.IsInProcess)
{
yield return new ValidationError(true, "InProcessToolchain has no DisassemblyDiagnoser support", benchmark);
if (toolchain is InProcessNoEmitToolchain)
{
yield return new ValidationError(true, "InProcessNoEmitToolchain has no DisassemblyDiagnoser support", benchmark);
}
if (toolchain is InProcessEmitToolchain && !IsOutOfProcessDisassemblerSupportedForCurrentPlatform())
{
yield return new ValidationError(true, "InProcessEmitToolchain has no DisassemblyDiagnoser support on this platform", benchmark);
}
}
else if (benchmark.Job.IsNativeAOT())
{
Expand Down Expand Up @@ -155,6 +169,11 @@ private static bool ShouldUseSameArchitectureDisassembler(BenchmarkCase benchmar
return false;
}

private static bool IsOutOfProcessDisassemblerSupportedForCurrentPlatform()
=> RuntimeInformation.IsWindows()
&& RuntimeInformation.GetCurrentPlatform() is Platform.X64 or Platform.X86
&& !RuntimeInformation.IsMono && !RuntimeInformation.IsWasm && !RuntimeInformation.IsAot;

private static IEnumerable<IExporter> GetExporters(Dictionary<BenchmarkCase, DisassemblyResult> results, DisassemblyDiagnoserConfig config)
{
if (config.ExportGithubMarkdown)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Portability;
using BenchmarkDotNet.Tests.Loggers;
using BenchmarkDotNet.Tests.XUnit;
using BenchmarkDotNet.Toolchains.InProcess.Emit;
using Xunit;
using Xunit.Abstractions;

Expand Down Expand Up @@ -105,6 +107,33 @@ public void CanDisassembleAllMethodCalls(Jit jit, Platform platform, Runtime run
AssertDisassembled(disassemblyDiagnoser, $"{nameof(WithCalls.Recursive)}()");
}

// For some reason the GitHub runner with Core cannot fully disassemble, so we skip it.
[FactEnvSpecific("InProcess disassembly only supported on Windows x86/64.", EnvRequirement.WindowsOnly, EnvRequirement.X86X64Only, EnvRequirement.FullFrameworkOnly)]
[Trait(Constants.Category, Constants.BackwardCompatibilityCategory)]
public void CanDisassembleAllMethodCallsInProcess()
{
var disassemblyDiagnoser = new DisassemblyDiagnoser(
new DisassemblyDiagnoserConfig(printSource: true, maxDepth: 3));

var config = ManualConfig.CreateEmpty()
.AddJob(Job.Dry
.WithStrategy(RunStrategy.ColdStart)
.WithToolchain(InProcessEmitToolchain.Instance)
)
.AddLogger(DefaultConfig.Instance.GetLoggers().ToArray())
.AddColumnProvider(DefaultColumnProviders.Instance)
.AddDiagnoser(disassemblyDiagnoser)
.AddLogger(new OutputLogger(Output));

CanExecute<WithCalls>(config);

AssertDisassembled(disassemblyDiagnoser, $"{nameof(WithCalls.Benchmark)}(Int32)");
AssertDisassembled(disassemblyDiagnoser, $"{nameof(WithCalls.Benchmark)}(Boolean)");
AssertDisassembled(disassemblyDiagnoser, $"{nameof(WithCalls.Static)}()");
AssertDisassembled(disassemblyDiagnoser, $"{nameof(WithCalls.Instance)}()");
AssertDisassembled(disassemblyDiagnoser, $"{nameof(WithCalls.Recursive)}()");
}

[Theory]
[MemberData(nameof(GetAllJits))]
[Trait(Constants.Category, Constants.BackwardCompatibilityCategory)]
Expand Down
3 changes: 2 additions & 1 deletion tests/BenchmarkDotNet.Tests/XUnit/EnvRequirement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public enum EnvRequirement
FullFrameworkOnly,
NonFullFramework,
DotNetCoreOnly,
DotNetCore30Only
DotNetCore30Only,
X86X64Only
}
2 changes: 2 additions & 0 deletions tests/BenchmarkDotNet.Tests/XUnit/EnvRequirementChecker.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using JetBrains.Annotations;
using BdnRuntimeInformation = BenchmarkDotNet.Portability.RuntimeInformation;
Expand All @@ -22,6 +23,7 @@ public static class EnvRequirementChecker
EnvRequirement.NonFullFramework => !BdnRuntimeInformation.IsFullFramework ? null : "Non-Full .NET Framework test",
EnvRequirement.DotNetCoreOnly => BdnRuntimeInformation.IsNetCore ? null : ".NET/.NET Core-only test",
EnvRequirement.DotNetCore30Only => IsRuntime(RuntimeMoniker.NetCoreApp30) ? null : ".NET Core 3.0-only test",
EnvRequirement.X86X64Only => BdnRuntimeInformation.GetCurrentPlatform() is Platform.X64 or Platform.X86 ? null : "x86- or x64-only test",
_ => throw new ArgumentOutOfRangeException(nameof(requirement), requirement, "Unknown value")
};

Expand Down