diff --git a/src/BenchmarkDotNet/Detectors/AppHostDetector.cs b/src/BenchmarkDotNet/Detectors/AppHostDetector.cs new file mode 100644 index 0000000000..033174808c --- /dev/null +++ b/src/BenchmarkDotNet/Detectors/AppHostDetector.cs @@ -0,0 +1,35 @@ +using BenchmarkDotNet.Extensions; +using System.Diagnostics; +using System.Reflection; + +namespace BenchmarkDotNet.Detectors; + +internal static class AppHostDetector +{ + public static bool HasAppHost() + { + var entryAssembly = Assembly.GetEntryAssembly(); + + // Check NativeAOT + if (entryAssembly == null) + return false; + + using var process = Process.GetCurrentProcess(); + var processName = process.ProcessName; + + // Check executed with `dotnet run` + if (processName.Equals("dotnet", StringComparison.OrdinalIgnoreCase)) + return false; + + // Check Single-file executable (AppHost is bundled) + if (entryAssembly.Location.IsBlank()) + return true; + + // Check entry assembly extension. + if (entryAssembly.Location.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + return true; + + // Return false for unknown environment + return false; + } +} diff --git a/src/BenchmarkDotNet/Disassemblers/DisassemblyDiagnoser.cs b/src/BenchmarkDotNet/Disassemblers/DisassemblyDiagnoser.cs index fd3dcbcded..074729876c 100644 --- a/src/BenchmarkDotNet/Disassemblers/DisassemblyDiagnoser.cs +++ b/src/BenchmarkDotNet/Disassemblers/DisassemblyDiagnoser.cs @@ -1,4 +1,4 @@ -using BenchmarkDotNet.Analysers; +using BenchmarkDotNet.Analysers; using BenchmarkDotNet.Columns; using BenchmarkDotNet.Detectors; using BenchmarkDotNet.Disassemblers; @@ -100,7 +100,7 @@ public async ValueTask HandleAsync(HostSignal signal, DiagnoserActionParameters ); break; case HostSignal.SeparateLogic when ShouldUseMonoDisassembler(benchmark): - var result = await monoDisassembler.Disassemble(benchmark, (MonoRuntime) benchmark.Job.Environment.Runtime!, cancellationToken).ConfigureAwait(false); + var result = await monoDisassembler.Disassemble(benchmark, (MonoRuntime)benchmark.Job.Environment.Runtime!, cancellationToken).ConfigureAwait(false); results.Add(benchmark, result); break; } @@ -174,6 +174,16 @@ public async IAsyncEnumerable ValidateAsync(ValidationParameter { yield return new ValidationError(true, $"Only Windows and Linux are supported in DisassemblyDiagnoser without Mono. Current OS is {System.Runtime.InteropServices.RuntimeInformation.OSDescription}"); } + + var isInProcess = benchmark.Job.Infrastructure.TryGetToolchain(out toolchain) && toolchain.IsInProcess; + if (isInProcess && OsDetector.IsMacOS() && AppHostDetector.HasAppHost()) + { + // On macos environment, WriteDump API is used and it cause freeze when using AppHost with InProcessToolchain. + // https://github.com/dotnet/BenchmarkDotNet/issues/3076 + var errorMessage = "DisassemblyDiagnoser is not supported on macos environment that using AppHost and InProcessToolchain. " + + "Disable AppHost with 'false' or use another toolchain"; + yield return new ValidationError(true, errorMessage); + } } }