diff --git a/Directory.Packages.props b/Directory.Packages.props index c4410a3..f7d103d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,13 +13,13 @@ - - - - - - - + + + + + + + diff --git a/source/Nice3point.BenchmarkDotNet.Revit/Hosting/BenchmarkHostProcess.cs b/source/Nice3point.BenchmarkDotNet.Revit/Hosting/BenchmarkHostProcess.cs new file mode 100644 index 0000000..4f97c2a --- /dev/null +++ b/source/Nice3point.BenchmarkDotNet.Revit/Hosting/BenchmarkHostProcess.cs @@ -0,0 +1,19 @@ +using System.Reflection; + +namespace Nice3point.BenchmarkDotNet.Revit.Hosting; + +/// +/// Provides the facts about the BenchmarkDotNet host process. +/// +internal static class BenchmarkHostProcess +{ + private const string GeneratedProgramTypeName = "BenchmarkDotNet.Autogenerated.UniqueProgramName"; + + /// + /// Gets a value indicating whether the current process is the BenchmarkDotNet host process. + /// + /// + /// in a benchmark process that runs a generated program, and inside Revit. + /// + public static bool IsCurrent { get; } = Assembly.GetEntryAssembly() is { } entryAssembly && entryAssembly.GetType(GeneratedProgramTypeName) is null; +} diff --git a/source/Nice3point.BenchmarkDotNet.Revit/Hosting/ProfilerAttachThread.cs b/source/Nice3point.BenchmarkDotNet.Revit/Hosting/ProfilerAttachThread.cs new file mode 100644 index 0000000..b10884e --- /dev/null +++ b/source/Nice3point.BenchmarkDotNet.Revit/Hosting/ProfilerAttachThread.cs @@ -0,0 +1,28 @@ +namespace Nice3point.BenchmarkDotNet.Revit.Hosting; + +/// +/// Starts the profiler attach thread of the .NET Framework runtime in every benchmark process. +/// +/// +/// A .NET Framework benchmark process with Revit answers a profiler attach request only on the attach thread. +/// The runtime reads the setting when it starts. +/// A benchmark process inherits the setting from the BenchmarkDotNet host process. +/// +internal static class ProfilerAttachThread +{ + /// + /// Enables the profiler attach thread for the benchmark processes the host process starts. + /// + /// + /// The call has no effect outside the BenchmarkDotNet host process and on .NET. + /// + public static void Enable() + { +#if NETFRAMEWORK + if (BenchmarkHostProcess.IsCurrent) + { + Environment.SetEnvironmentVariable("COMPlus_AttachThreadAlwaysOn", "1"); + } +#endif + } +} diff --git a/source/Nice3point.BenchmarkDotNet.Revit/Hosting/RevitUiMetadataResolver.cs b/source/Nice3point.BenchmarkDotNet.Revit/Hosting/RevitUiMetadataResolver.cs index 17cbb4c..b0be316 100644 --- a/source/Nice3point.BenchmarkDotNet.Revit/Hosting/RevitUiMetadataResolver.cs +++ b/source/Nice3point.BenchmarkDotNet.Revit/Hosting/RevitUiMetadataResolver.cs @@ -19,7 +19,6 @@ namespace Nice3point.BenchmarkDotNet.Revit.Hosting; internal static class RevitUiMetadataResolver { private const string AssemblyName = "RevitAPIUI"; - private const string GeneratedProgramTypeName = "BenchmarkDotNet.Autogenerated.UniqueProgramName"; // IMAGE_COR20_HEADER offsets. private const int CorFlagsOffset = 16; @@ -57,7 +56,7 @@ internal static class RevitUiMetadataResolver /// public static void Register() { - if (Assembly.GetEntryAssembly() is not { } entryAssembly || entryAssembly.GetType(GeneratedProgramTypeName) is not null) + if (!BenchmarkHostProcess.IsCurrent) { return; } diff --git a/source/Nice3point.BenchmarkDotNet.Revit/RevitApplicationBenchmark.cs b/source/Nice3point.BenchmarkDotNet.Revit/RevitApplicationBenchmark.cs index 3cdc48e..1122dd7 100644 --- a/source/Nice3point.BenchmarkDotNet.Revit/RevitApplicationBenchmark.cs +++ b/source/Nice3point.BenchmarkDotNet.Revit/RevitApplicationBenchmark.cs @@ -32,6 +32,7 @@ public abstract class RevitApplicationBenchmark /// The runtime calls the method once per process, when the module loads. /// The method sets the STA apartment state of the current thread and initializes the injector. /// In the BenchmarkDotNet host process, the method registers the resolver of the RevitAPIUI metadata. + /// On .NET Framework, the host process enables the profiler attach thread of the benchmark processes. /// Inside Revit, the method has no effect. /// #pragma warning disable CA2255 @@ -49,6 +50,7 @@ public static void Initialize() Thread.CurrentThread.SetApartmentState(ApartmentState.STA); RevitUiMetadataResolver.Register(); + ProfilerAttachThread.Enable(); InjectorInitializer.InitializeModule(); }