diff --git a/src/BenchmarkDotNet/Extensions/ProcessExtensions.cs b/src/BenchmarkDotNet/Extensions/ProcessExtensions.cs
index 2bdc94d730..7ea7cbb0b7 100644
--- a/src/BenchmarkDotNet/Extensions/ProcessExtensions.cs
+++ b/src/BenchmarkDotNet/Extensions/ProcessExtensions.cs
@@ -124,7 +124,7 @@ internal static void SetEnvironmentVariables(this ProcessStartInfo start, Benchm
// we have to set "COMPlus_GC*" environment variables as documented in
// https://docs.microsoft.com/en-us/dotnet/core/run-time-config/garbage-collector
if (benchmarkCase.Job.Infrastructure.Toolchain is CoreRunToolchain _)
- start.SetCoreRunEnvironmentVariables(benchmarkCase);
+ start.SetCoreRunEnvironmentVariables(benchmarkCase, resolver);
if (!benchmarkCase.Job.HasValue(EnvironmentMode.EnvironmentVariablesCharacteristic))
return;
@@ -229,19 +229,21 @@ private static int RunProcessAndIgnoreOutput(string fileName, string arguments,
}
}
- private static void SetCoreRunEnvironmentVariables(this ProcessStartInfo start, BenchmarkCase benchmarkCase)
+ private static void SetCoreRunEnvironmentVariables(this ProcessStartInfo start, BenchmarkCase benchmarkCase, IResolver resolver)
{
var gcMode = benchmarkCase.Job.Environment.Gc;
- if (!gcMode.HasChanges)
- return; // do nothing for the default settings
-
- start.EnvironmentVariables["COMPlus_gcServer"] = gcMode.Server ? "1" : "0";
- start.EnvironmentVariables["COMPlus_gcConcurrent"] = gcMode.Concurrent ? "1" : "0";
- start.EnvironmentVariables["COMPlus_GCCpuGroup"] = gcMode.CpuGroups ? "1" : "0";
- start.EnvironmentVariables["COMPlus_gcAllowVeryLargeObjects"] = gcMode.AllowVeryLargeObjects ? "1" : "0";
- start.EnvironmentVariables["COMPlus_GCRetainVM"] = gcMode.RetainVm ? "1" : "0";
- start.EnvironmentVariables["COMPlus_GCNoAffinitize"] = gcMode.NoAffinitize ? "1" : "0";
+ start.EnvironmentVariables["COMPlus_gcServer"] = gcMode.ResolveValue(GcMode.ServerCharacteristic, resolver) ? "1" : "0";
+ start.EnvironmentVariables["COMPlus_gcConcurrent"] = gcMode.ResolveValue(GcMode.ConcurrentCharacteristic, resolver) ? "1" : "0";
+
+ if (gcMode.HasValue(GcMode.CpuGroupsCharacteristic))
+ start.EnvironmentVariables["COMPlus_GCCpuGroup"] = gcMode.ResolveValue(GcMode.CpuGroupsCharacteristic, resolver) ? "1" : "0";
+ if (gcMode.HasValue(GcMode.AllowVeryLargeObjectsCharacteristic))
+ start.EnvironmentVariables["COMPlus_gcAllowVeryLargeObjects"] = gcMode.ResolveValue(GcMode.AllowVeryLargeObjectsCharacteristic, resolver) ? "1" : "0";
+ if (gcMode.HasValue(GcMode.RetainVmCharacteristic))
+ start.EnvironmentVariables["COMPlus_GCRetainVM"] = gcMode.ResolveValue(GcMode.RetainVmCharacteristic, resolver) ? "1" : "0";
+ if (gcMode.HasValue(GcMode.NoAffinitizeCharacteristic))
+ start.EnvironmentVariables["COMPlus_GCNoAffinitize"] = gcMode.ResolveValue(GcMode.NoAffinitizeCharacteristic, resolver) ? "1" : "0";
if (gcMode.HasValue(GcMode.HeapAffinitizeMaskCharacteristic))
start.EnvironmentVariables["COMPlus_GCHeapAffinitizeMask"] = gcMode.HeapAffinitizeMask.ToString("X");
if (gcMode.HasValue(GcMode.HeapCountCharacteristic))
diff --git a/src/BenchmarkDotNet/Toolchains/AppConfigGenerator.cs b/src/BenchmarkDotNet/Toolchains/AppConfigGenerator.cs
index aa35f039f6..c1db452d2b 100644
--- a/src/BenchmarkDotNet/Toolchains/AppConfigGenerator.cs
+++ b/src/BenchmarkDotNet/Toolchains/AppConfigGenerator.cs
@@ -100,15 +100,15 @@ private static void GenerateJitSettings(XmlDocument xmlDocument, XmlNode runtime
private static void GenerateGCSettings(XmlDocument xmlDocument, XmlNode runtimeElement, GcMode gcMode, IResolver resolver)
{
- if (!gcMode.HasChanges)
- return;
-
CreateNodeWithAttribute(xmlDocument, runtimeElement, "gcConcurrent", "enabled", gcMode.ResolveValue(GcMode.ConcurrentCharacteristic, resolver).ToLowerCase());
CreateNodeWithAttribute(xmlDocument, runtimeElement, "gcServer", "enabled", gcMode.ResolveValue(GcMode.ServerCharacteristic, resolver).ToLowerCase());
- CreateNodeWithAttribute(xmlDocument, runtimeElement, "GCCpuGroup", "enabled", gcMode.ResolveValue(GcMode.CpuGroupsCharacteristic, resolver).ToLowerCase());
- CreateNodeWithAttribute(xmlDocument, runtimeElement, "gcAllowVeryLargeObjects", "enabled", gcMode.ResolveValue(GcMode.AllowVeryLargeObjectsCharacteristic, resolver).ToLowerCase());
- CreateNodeWithAttribute(xmlDocument, runtimeElement, "GCNoAffinitize", "enabled", gcMode.ResolveValue(GcMode.NoAffinitizeCharacteristic, resolver).ToLowerCase());
+ if (gcMode.HasValue(GcMode.CpuGroupsCharacteristic))
+ CreateNodeWithAttribute(xmlDocument, runtimeElement, "GCCpuGroup", "enabled", gcMode.ResolveValue(GcMode.CpuGroupsCharacteristic, resolver).ToLowerCase());
+ if (gcMode.HasValue(GcMode.AllowVeryLargeObjectsCharacteristic))
+ CreateNodeWithAttribute(xmlDocument, runtimeElement, "gcAllowVeryLargeObjects", "enabled", gcMode.ResolveValue(GcMode.AllowVeryLargeObjectsCharacteristic, resolver).ToLowerCase());
+ if (gcMode.HasValue(GcMode.NoAffinitizeCharacteristic))
+ CreateNodeWithAttribute(xmlDocument, runtimeElement, "GCNoAffinitize", "enabled", gcMode.ResolveValue(GcMode.NoAffinitizeCharacteristic, resolver).ToLowerCase());
if (gcMode.HasValue(GcMode.HeapAffinitizeMaskCharacteristic))
CreateNodeWithAttribute(xmlDocument, runtimeElement, "GCHeapAffinitizeMask", "enabled", gcMode.ResolveValue(GcMode.HeapAffinitizeMaskCharacteristic, resolver).ToString());
if (gcMode.HasValue(GcMode.HeapCountCharacteristic))
diff --git a/src/BenchmarkDotNet/Toolchains/CsProj/CsProjGenerator.cs b/src/BenchmarkDotNet/Toolchains/CsProj/CsProjGenerator.cs
index 1b490bd4df..821faf574f 100644
--- a/src/BenchmarkDotNet/Toolchains/CsProj/CsProjGenerator.cs
+++ b/src/BenchmarkDotNet/Toolchains/CsProj/CsProjGenerator.cs
@@ -83,16 +83,15 @@ protected override void GenerateProject(BuildPartition buildPartition, Artifacts
[PublicAPI]
protected virtual string GetRuntimeSettings(GcMode gcMode, IResolver resolver)
{
- if (!gcMode.HasChanges)
- return string.Empty;
-
- return new StringBuilder(80)
+ var builder = new StringBuilder(80)
.AppendLine("")
- .AppendLine($"{gcMode.ResolveValue(GcMode.ServerCharacteristic, resolver).ToLowerCase()}")
- .AppendLine($"{gcMode.ResolveValue(GcMode.ConcurrentCharacteristic, resolver).ToLowerCase()}")
- .AppendLine($"{gcMode.ResolveValue(GcMode.RetainVmCharacteristic, resolver).ToLowerCase()}")
- .AppendLine("")
- .ToString();
+ .AppendLine($"{gcMode.ResolveValue(GcMode.ServerCharacteristic, resolver).ToLowerCase()}")
+ .AppendLine($"{gcMode.ResolveValue(GcMode.ConcurrentCharacteristic, resolver).ToLowerCase()}");
+
+ if (gcMode.HasValue(GcMode.RetainVmCharacteristic))
+ builder.AppendLine($"{gcMode.ResolveValue(GcMode.RetainVmCharacteristic, resolver).ToLowerCase()}");
+
+ return builder.AppendLine("").ToString();
}
// the host project or one of the .props file that it imports might contain some custom settings that needs to be copied, sth like
diff --git a/tests/BenchmarkDotNet.IntegrationTests/BenchmarkDotNet.IntegrationTests.csproj b/tests/BenchmarkDotNet.IntegrationTests/BenchmarkDotNet.IntegrationTests.csproj
index 5afd242d86..e213a47f05 100755
--- a/tests/BenchmarkDotNet.IntegrationTests/BenchmarkDotNet.IntegrationTests.csproj
+++ b/tests/BenchmarkDotNet.IntegrationTests/BenchmarkDotNet.IntegrationTests.csproj
@@ -12,6 +12,7 @@
pdbonly
true
$(NoWarn);CA2007
+ true
diff --git a/tests/BenchmarkDotNet.IntegrationTests/GcModeTests.cs b/tests/BenchmarkDotNet.IntegrationTests/GcModeTests.cs
index 75769e8b77..123218d7ff 100644
--- a/tests/BenchmarkDotNet.IntegrationTests/GcModeTests.cs
+++ b/tests/BenchmarkDotNet.IntegrationTests/GcModeTests.cs
@@ -18,10 +18,14 @@ public GcModeTests(ITestOutputHelper outputHelper) : base(outputHelper) { }
private IConfig CreateConfig(GcMode gc) => ManualConfig.CreateEmpty().AddJob(new Job(Job.Dry, gc));
[Fact]
- public void CanHostGcMode()
+ public void HostProcessSettingsAreCopiedByDefault()
{
var config = CreateConfig(GcMode.Default);
- CanExecute(config);
+
+ if (GCSettings.IsServerGC)
+ CanExecute(config);
+ else
+ CanExecute(config);
}
[Fact]
diff --git a/tests/BenchmarkDotNet.Tests/AppConfigGeneratorTests.cs b/tests/BenchmarkDotNet.Tests/AppConfigGeneratorTests.cs
index baa1b2ab43..227fd85c9b 100644
--- a/tests/BenchmarkDotNet.Tests/AppConfigGeneratorTests.cs
+++ b/tests/BenchmarkDotNet.Tests/AppConfigGeneratorTests.cs
@@ -5,9 +5,11 @@
using System.Text;
using BenchmarkDotNet.Characteristics;
using BenchmarkDotNet.Environments;
+using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Running;
using Xunit;
using BenchmarkDotNet.Tests.XUnit;
+using System.Runtime;
namespace BenchmarkDotNet.Tests
{
@@ -20,10 +22,10 @@ public void GeneratesMinimalRequiredAppConfigForEmptySource()
{
using (var destination = new Utf8StringWriter())
{
- const string expectedMinimal =
+ string expectedMinimal =
"" +
"" +
- "" +
+ $"{GcSettings}" +
"";
AppConfigGenerator.Generate(Job.Default, TextReader.Null, destination, Resolver);
@@ -38,10 +40,10 @@ public void GeneratesMinimalRequiredAppConfigForAlmostEmptySource()
using (var source = new StringReader(""))
using (var destination = new Utf8StringWriter())
{
- const string expectedMinimal =
+ string expectedMinimal =
"" +
"" +
- "" +
+ $"{GcSettings}" +
"";
AppConfigGenerator.Generate(Job.Default, source, destination, Resolver);
@@ -53,50 +55,69 @@ public void GeneratesMinimalRequiredAppConfigForAlmostEmptySource()
[Fact]
public void RewritesCustomSettings()
{
- const string customSettings =
+ string customSettingsWithoutRuntimeNode =
"" +
"" +
"" +
"withItsValue" +
- "" +
"";
- using (var source = new StringReader(customSettings))
+ string customSettingsWithRuntimeNode =
+ "" +
+ "" +
+ "" +
+ "withItsValue" +
+ $"{GcSettings}" +
+ "";
+
+ using (var source = new StringReader(customSettingsWithoutRuntimeNode))
using (var destination = new Utf8StringWriter())
{
AppConfigGenerator.Generate(Job.Default, source, destination, Resolver);
- AssertAreEqualIgnoringWhitespacesAndCase(customSettings, destination.ToString());
+ AssertAreEqualIgnoringWhitespacesAndCase(customSettingsWithRuntimeNode, destination.ToString());
}
}
[Fact]
public void RewritesCustomRuntimeSettings()
{
- const string customSettings =
+ string customSettingsBefore =
"" +
"" +
"" +
"withItsValue" +
- "" +
+ $"" +
"";
- using (var source = new StringReader(customSettings))
+ string customSettingsAfter =
+ "" +
+ "" +
+ "" +
+ "withItsValue" +
+ $"{GcSettings}" +
+ "";
+
+ using (var source = new StringReader(customSettingsBefore))
using (var destination = new Utf8StringWriter())
{
AppConfigGenerator.Generate(Job.Default, source, destination, Resolver);
- AssertAreEqualIgnoringWhitespacesAndCase(customSettings, destination.ToString());
+ AssertAreEqualIgnoringWhitespacesAndCase(customSettingsAfter, destination.ToString());
}
}
[Theory]
- [InlineData(Jit.LegacyJit, "")]
- [InlineData(Jit.RyuJit, "")]
+ [InlineData(Jit.LegacyJit, "")]
+ [InlineData(Jit.RyuJit, "")]
public void GeneratesRightJitSettings(Jit jit, string expectedRuntimeNode)
{
const string customSettings =
@@ -109,7 +130,7 @@ public void GeneratesRightJitSettings(Jit jit, string expectedRuntimeNode)
"" +
"" +
"withItsValue" +
- expectedRuntimeNode +
+ $"{expectedRuntimeNode}{GcSettings}" +
"" + Environment.NewLine;
using (var source = new StringReader(customSettings))
@@ -133,7 +154,7 @@ public void RemovesStartupSettingsForPrivateBuildsOfClr()
string withoutStartup =
"" +
"" +
- "" +
+ $"{GcSettings}" +
"" + Environment.NewLine;
using (var source = new StringReader(input))
@@ -158,7 +179,7 @@ public void LeavsStartupSettingsIntactForNonPrivateBuildsOfClr()
"" +
"" +
"" +
- "" +
+ $"{GcSettings}" +
"" + Environment.NewLine;
using (var source = new StringReader(input))
@@ -186,7 +207,7 @@ public void RewritesCustomAssemblyBindingRedirects()
"" +
"";
- const string settingsWithBindingsAndJit =
+ string settingsWithBindingsAndJit =
"" +
"" +
"" +
@@ -197,6 +218,7 @@ public void RewritesCustomAssemblyBindingRedirects()
"" +
"" +
"" +
+ GcSettings +
"" +
"";
@@ -234,6 +256,8 @@ private static string RemoveWhiteSpaces(string input)
}
return buffer.ToString();
}
+
+ private static readonly string GcSettings = $"";
}
internal class Utf8StringWriter : StringWriter