Skip to content

Commit

Permalink
Comparing power plans (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarekM25 committed Jan 13, 2019
1 parent 2dd626c commit 684e99d
Show file tree
Hide file tree
Showing 16 changed files with 113 additions and 69 deletions.
34 changes: 24 additions & 10 deletions samples/BenchmarkDotNet.Samples/IntroPowerPlan.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;

namespace BenchmarkDotNet.Samples
{
[HighPerformancePowerPlan(false)]
public class IntroPowerPlanDisabled
[Config(typeof(Config))]
public class IntroPowerPlan
{
private class Config : ManualConfig
{
public Config()
{
Add(Job.MediumRun.WithPowerPlan(PowerPlan.HighPerformance));
Add(Job.MediumRun.WithPowerPlan(PowerPlan.UserPowerPlan));
}
}

[Benchmark]
public int SplitJoin()
=> string.Join(",", new string[1000]).Split(',').Length;
}
public int IterationTest()
{
int j = 0;
for (int i = 0; i < short.MaxValue; ++i)
{
j = i;
}

return j;
}

// By default benchmark.net uses high-performance power plan.
// There is no need to set it to true explicitly
[HighPerformancePowerPlan(true)]
public class IntroPowerPlanEnabled
{
[Benchmark]
public int SplitJoin()
=> string.Join(",", new string[1000]).Split(',').Length;
Expand Down

This file was deleted.

1 change: 0 additions & 1 deletion src/BenchmarkDotNet/Configs/ConfigExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public static IDiagnoser GetCompositeDiagnoser(this IConfig config, BenchmarkCas
/// determines if all auto-generated files should be kept or removed after running the benchmarks
/// </summary>
///
[PublicAPI] public static IConfig WithHighPerformancePowerPlan(this IConfig config, bool highPerformancePowerPlan = true) => config.With(c => c.HighPerformancePowerPlan = highPerformancePowerPlan);
[PublicAPI] public static IConfig KeepBenchmarkFiles(this IConfig config, bool value = true) => config.With(m => m.KeepBenchmarkFiles = value);
[PublicAPI] public static IConfig RemoveBenchmarkFiles(this IConfig config) => config.KeepBenchmarkFiles(false);
[PublicAPI] public static IConfig WithArtifactsPath(this IConfig config, string artifactsPath) => config.With(m => m.ArtifactsPath = artifactsPath);
Expand Down
2 changes: 0 additions & 2 deletions src/BenchmarkDotNet/Configs/DefaultConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ public IEnumerable<IValidator> GetValidators()

public Encoding Encoding => Encoding.ASCII;

public bool HighPerformancePowerPlan => true;

public IEnumerable<BenchmarkLogicalGroupRule> GetLogicalGroupRules() => Array.Empty<BenchmarkLogicalGroupRule>();

public bool StopOnFirstError => false;
Expand Down
5 changes: 0 additions & 5 deletions src/BenchmarkDotNet/Configs/IConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@ public interface IConfig
/// </summary>
Encoding Encoding { get; }

/// <summary>
/// the default value is true
/// </summary>
bool HighPerformancePowerPlan { get; }

IEnumerable<BenchmarkLogicalGroupRule> GetLogicalGroupRules();

bool StopOnFirstError { get; }
Expand Down
2 changes: 0 additions & 2 deletions src/BenchmarkDotNet/Configs/ManualConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ public class ManualConfig : IConfig
[PublicAPI] public bool SummaryPerType { get; set; } = true;
[PublicAPI] public string ArtifactsPath { get; set; }
[PublicAPI] public Encoding Encoding { get; set; }
[PublicAPI] public bool HighPerformancePowerPlan { get; set; } = true;

public void Add(params IColumn[] newColumns) => columnProviders.AddRange(newColumns.Select(c => c.ToProvider()));
public void Add(params IColumnProvider[] newColumnProviders) => columnProviders.AddRange(newColumnProviders);
Expand Down Expand Up @@ -83,7 +82,6 @@ public void Add(IConfig config)
SummaryPerType &= config.SummaryPerType;
ArtifactsPath = config.ArtifactsPath ?? ArtifactsPath;
Encoding = config.Encoding ?? Encoding;
HighPerformancePowerPlan &= config.HighPerformancePowerPlan;
summaryStyle = summaryStyle ?? config.GetSummaryStyle();
logicalGroupRules.AddRange(config.GetLogicalGroupRules());
StopOnFirstError |= config.StopOnFirstError;
Expand Down
2 changes: 0 additions & 2 deletions src/BenchmarkDotNet/Configs/ReadOnlyConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ public ReadOnlyConfig([NotNull] IConfig config)

public Encoding Encoding => config.Encoding;

public bool HighPerformancePowerPlan => config.HighPerformancePowerPlan;

public IEnumerable<BenchmarkLogicalGroupRule> GetLogicalGroupRules() => config.GetLogicalGroupRules();

public bool StopOnFirstError => config.StopOnFirstError;
Expand Down
8 changes: 8 additions & 0 deletions src/BenchmarkDotNet/Environments/PowerPlan.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace BenchmarkDotNet.Environments
{
public enum PowerPlan
{
HighPerformance,
UserPowerPlan,
}
}
1 change: 0 additions & 1 deletion src/BenchmarkDotNet/Helpers/PowerManagementHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ namespace BenchmarkDotNet.Helpers
{
internal class PowerManagementHelper
{
internal const string HighPerformanceGuid = "8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c";
private const uint ErrorMoreData = 234;
private const uint SuccessCode = 0;

Expand Down
9 changes: 9 additions & 0 deletions src/BenchmarkDotNet/Jobs/EnvironmentMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public sealed class EnvironmentMode : JobMode<EnvironmentMode>
public static readonly Characteristic<IntPtr> AffinityCharacteristic = CreateCharacteristic<IntPtr>(nameof(Affinity));
public static readonly Characteristic<GcMode> GcCharacteristic = CreateCharacteristic<GcMode>(nameof(Gc));
public static readonly Characteristic<IReadOnlyList<EnvironmentVariable>> EnvironmentVariablesCharacteristic = CreateCharacteristic<IReadOnlyList<EnvironmentVariable>>(nameof(EnvironmentVariables));
public static readonly Characteristic<PowerPlanMode> PowerPlanModeCharacteristic = CreateCharacteristic<PowerPlanMode>(nameof(PowerPlanMode));

public static readonly EnvironmentMode Clr = new EnvironmentMode(Runtime.Clr).Freeze();
public static readonly EnvironmentMode Core = new EnvironmentMode(Runtime.Core).Freeze();
Expand Down Expand Up @@ -42,6 +43,7 @@ [PublicAPI] public EnvironmentMode(string id, Jit jit, Platform platform) : this
[PublicAPI] public EnvironmentMode(string id) : base(id)
{
GcCharacteristic[this] = new GcMode();
PowerPlanModeCharacteristic[this] = new PowerPlanMode();
}

/// <summary>
Expand Down Expand Up @@ -92,5 +94,12 @@ public IReadOnlyList<EnvironmentVariable> EnvironmentVariables
set => EnvironmentVariablesCharacteristic[this] = value;
}


public PowerPlanMode PowerPlanMode
{
get => PowerPlanModeCharacteristic[this];
set => PowerPlanModeCharacteristic[this] = value;
}

}
}
7 changes: 7 additions & 0 deletions src/BenchmarkDotNet/Jobs/JobExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@ public static Job WithHeapAffinitizeMask(this Job job, int heapAffinitizeMask) =
/// </summary>
public static Job WithMaxIterationCount(this Job job, int count) => job.WithCore(j => j.Run.MaxIterationCount = count);

/// <summary>
/// Power plan for benchmarks.
/// The default value is HighPerformance.
/// <remarks>Only available for Windows.</remarks>
/// </summary>
public static Job WithPowerPlan(this Job job, PowerPlan powerPlan) => job.WithCore(j => j.Environment.PowerPlanMode.PowerPlan = powerPlan);

// Infrastructure
public static Job With(this Job job, IToolchain toolchain) => job.WithCore(j => j.Infrastructure.Toolchain = toolchain);
[PublicAPI] public static Job With(this Job job, IClock clock) => job.WithCore(j => j.Infrastructure.Clock = clock);
Expand Down
28 changes: 28 additions & 0 deletions src/BenchmarkDotNet/Jobs/PowerPlanMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using BenchmarkDotNet.Characteristics;
using BenchmarkDotNet.Environments;

namespace BenchmarkDotNet.Jobs
{
public sealed class PowerPlanMode : JobMode<PowerPlanMode>
{
public static readonly Characteristic<PowerPlan> PowerPlanCharacteristic = CreateCharacteristic<PowerPlan>(nameof(PowerPlan));

public PowerPlanMode() : this(null)
{
}

private PowerPlanMode(string id) : base(id)
{
}

public PowerPlan PowerPlan
{
get { return PowerPlanCharacteristic[this]; }
set { PowerPlanCharacteristic[this] = value; }
}

public bool Equals(PowerPlanMode other)
=> other != null
&& other.PowerPlan == PowerPlan;
}
}
6 changes: 3 additions & 3 deletions src/BenchmarkDotNet/Running/BenchmarkRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ [PublicAPI] public static Summary[] Run(BenchmarkRunInfo[] benchmarkRunInfos, [C
using (var logStreamWriter = StreamWriter.FromPath(Path.Combine(rootArtifactsFolderPath, title + ".log")))
{
var logger = new CompositeLogger(commonSettingsConfig.GetCompositeLogger(), new StreamLogger(logStreamWriter));
var powerManagementApplier = new PowerManagementApplier(logger);

var supportedBenchmarks = GetSupportedBenchmarks(benchmarkRunInfos, logger, resolver);

Expand Down Expand Up @@ -109,7 +108,6 @@ [PublicAPI] public static Summary[] Run(BenchmarkRunInfo[] benchmarkRunInfos, [C

foreach (var benchmarkRunInfo in supportedBenchmarks) // we run them in the old order now using the new build artifacts
{
powerManagementApplier.ApplyPerformancePlan(benchmarkRunInfo.Config.HighPerformancePowerPlan);
var runChronometer = Chronometer.Start();

var summary = Run(benchmarkRunInfo, benchmarkToBuildResult, resolver, logger, artifactsToCleanup, rootArtifactsFolderPath, ref runChronometer);
Expand Down Expand Up @@ -137,7 +135,6 @@ [PublicAPI] public static Summary[] Run(BenchmarkRunInfo[] benchmarkRunInfos, [C
}
finally
{
powerManagementApplier.ApplyUserPowerPlan(logger);
logger.WriteLineHeader("// * Artifacts cleanup *");
Cleanup(new HashSet<string>(artifactsToCleanup.Distinct()));
}
Expand Down Expand Up @@ -170,13 +167,15 @@ private static Summary Run(BenchmarkRunInfo benchmarkRunInfo,
var config = benchmarkRunInfo.Config;
var reports = new List<BenchmarkReport>();
string title = GetTitle(new[] { benchmarkRunInfo });
var powerManagementApplier = new PowerManagementApplier(logger);

logger.WriteLineInfo("// Found benchmarks:");
foreach (var benchmark in benchmarks)
logger.WriteLineInfo($"// {benchmark.DisplayInfo}");
logger.WriteLine();
foreach (var benchmark in benchmarks)
{
powerManagementApplier.ApplyPerformancePlan(benchmark.Job.Environment.PowerPlanMode.PowerPlan);
var info = buildResults[benchmark];
var buildResult = info.buildResult;

Expand Down Expand Up @@ -217,6 +216,7 @@ private static Summary Run(BenchmarkRunInfo benchmarkRunInfo,

var clockSpan = runChronometer.GetElapsed();

powerManagementApplier.ApplyUserPowerPlan();
return new Summary(title,
reports,
HostEnvironmentInfo.GetCurrent(),
Expand Down
37 changes: 25 additions & 12 deletions src/BenchmarkDotNet/Running/PowerManagementApplier.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Helpers;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Portability;
Expand All @@ -11,26 +13,37 @@ internal class PowerManagementApplier
private Guid? userCurrentPowerPlan;
private bool powerPlanChanged = false;
private bool isInitialized = false;
private static readonly Dictionary<PowerPlan, string> powerPlansDict = new Dictionary<PowerPlan, string>()
{
{ PowerPlan.UserPowerPlan, null },
{ PowerPlan.HighPerformance, "8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c" }
};

internal PowerManagementApplier(ILogger logger)
{
this.logger = logger;
}

internal void ApplyPerformancePlan(bool highPerformancePowerPlan)
internal void ApplyPerformancePlan(PowerPlan powerPlan)
{
var guid = powerPlansDict[powerPlan];
ApplyPerformancePlan(guid);
}

internal void ApplyPerformancePlan(string guid)
{
if (RuntimeInformation.IsWindows())
{
if (highPerformancePowerPlan && powerPlanChanged == false)
ApplyHighPerformancePlan(logger);
else if (highPerformancePowerPlan == false)
ApplyUserPowerPlan(logger);
if (string.IsNullOrEmpty(guid) == false && powerPlanChanged == false)
ApplyPlanByGuid(guid);
else if (string.IsNullOrEmpty(guid))
ApplyUserPowerPlan();
}
}

internal void ApplyUserPowerPlan(ILogger logger)
internal void ApplyUserPowerPlan()
{
if (powerPlanChanged && userCurrentPowerPlan != null && RuntimeInformation.IsWindows())
if (powerPlanChanged && RuntimeInformation.IsWindows())
{
try
{
Expand All @@ -48,7 +61,7 @@ internal void ApplyUserPowerPlan(ILogger logger)
}
}

private void ApplyHighPerformancePlan(ILogger logger)
private void ApplyPlanByGuid(string guid)
{
try
{
Expand All @@ -58,18 +71,18 @@ private void ApplyHighPerformancePlan(ILogger logger)
isInitialized = true;
}

if (PowerManagementHelper.Set(new Guid(PowerManagementHelper.HighPerformanceGuid)))
if (PowerManagementHelper.Set(new Guid(guid)))
{
powerPlanChanged = true;
var powerPlanFriendlyName = PowerManagementHelper.CurrentPlanFriendlyName;
logger.WriteInfo($"Setup power plan (GUID: {PowerManagementHelper.HighPerformanceGuid} FriendlyName: {powerPlanFriendlyName})");
logger.WriteInfo($"Setup power plan (GUID: {guid} FriendlyName: {powerPlanFriendlyName})");
}
else
logger.WriteLineError($"Cannot setup power plan (GUID: {PowerManagementHelper.HighPerformanceGuid})");
logger.WriteLineError($"Cannot setup power plan (GUID: {guid})");
}
catch (Exception ex)
{
logger.WriteLineError($"Cannot setup power plan (GUID: {PowerManagementHelper.HighPerformanceGuid}, error message: {ex.Message})");
logger.WriteLineError($"Cannot setup power plan (GUID: {guid}, error message: {ex.Message})");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Helpers;
using BenchmarkDotNet.Portability;
using BenchmarkDotNet.Running;
Expand All @@ -14,6 +15,7 @@ namespace BenchmarkDotNet.IntegrationTests
public class PowerManagementApplierTests : BenchmarkTestExecutor
{
public const string PowerSaverGuid = "e22fd527-0c09-43ad-83d6-ba300affc27d";
public const string HighPerformancePlanGuid = "8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c";

public PowerManagementApplierTests(ITestOutputHelper output) : base(output) { }

Expand All @@ -24,10 +26,10 @@ public void TestSettingAndRevertingBackGuid()
var logger = new OutputLogger(Output);
var powerManagementApplier = new PowerManagementApplier(logger);
var config = DefaultConfig.Instance.With(logger);
powerManagementApplier.ApplyPerformancePlan(config.HighPerformancePowerPlan);
Assert.Equal(PowerManagementHelper.HighPerformanceGuid, PowerManagementHelper.CurrentPlan.ToString());
powerManagementApplier.ApplyPerformancePlan(PowerPlan.HighPerformance);
Assert.Equal(HighPerformancePlanGuid, PowerManagementHelper.CurrentPlan.ToString());
Assert.Equal("High performance", PowerManagementHelper.CurrentPlanFriendlyName);
powerManagementApplier.ApplyUserPowerPlan(logger);
powerManagementApplier.ApplyUserPowerPlan();
Assert.Equal(userPlan, PowerManagementHelper.CurrentPlan);
}

Expand All @@ -37,10 +39,10 @@ public void TestPowerPlanShouldNotChange()
var userPlan = PowerManagementHelper.CurrentPlan;
var logger = new OutputLogger(Output);
var powerManagementApplier = new PowerManagementApplier(logger);
var config = DefaultConfig.Instance.With(logger).WithHighPerformancePowerPlan(false);
powerManagementApplier.ApplyPerformancePlan(config.HighPerformancePowerPlan);
var config = DefaultConfig.Instance.With(logger);
powerManagementApplier.ApplyPerformancePlan(PowerPlan.UserPowerPlan);
Assert.Equal(userPlan.ToString(), PowerManagementHelper.CurrentPlan.ToString());
powerManagementApplier.ApplyUserPowerPlan(logger);
powerManagementApplier.ApplyUserPowerPlan();
Assert.Equal(userPlan, PowerManagementHelper.CurrentPlan);
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/BenchmarkDotNet.Tests/JobTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ public static void Test07GetCharacteristics()
Assert.Equal("Id;Accuracy;AnalyzeLaunchVariance;EvaluateOverhead;" +
"MaxAbsoluteError;MaxRelativeError;MinInvokeCount;MinIterationTime;OutlierMode;Environment;Affinity;EnvironmentVariables;" +
"Jit;Platform;Runtime;Gc;AllowVeryLargeObjects;Concurrent;CpuGroups;Force;HeapAffinitizeMask;HeapCount;NoAffinitize;" +
"RetainVm;Server;Infrastructure;Arguments;BuildConfiguration;Clock;EngineFactory;NuGetReferences;Toolchain;Meta;Baseline;IsDefault;IsMutator;Run;InvocationCount;IterationCount;IterationTime;" +
"RetainVm;Server;PowerPlanMode;PowerPlan;Infrastructure;Arguments;BuildConfiguration;Clock;EngineFactory;NuGetReferences;Toolchain;Meta;Baseline;IsDefault;IsMutator;Run;InvocationCount;IterationCount;IterationTime;" +
"LaunchCount;MaxIterationCount;MaxWarmupIterationCount;MinIterationCount;MinWarmupIterationCount;RunStrategy;UnrollFactor;WarmupCount", string.Join(";", a));
}

Expand Down

0 comments on commit 684e99d

Please sign in to comment.