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();
}