-
-
Notifications
You must be signed in to change notification settings - Fork 983
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Implemented power-management, add docs (#68) * Power Management review changes (#68) * Comparing power plans (#68) Cosmetic fixes (#68)
- Loading branch information
1 parent
e1d4d2f
commit 8aa6ade
Showing
12 changed files
with
327 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
--- | ||
uid: docs.powerplans | ||
name: Power Plans | ||
--- | ||
|
||
# Power Plans | ||
|
||
BenchmarkDotNet forces Windows OS to execute on the High-Performance power plan. You can disable this feature by modify PowerPlanMode property. You can see it in the @BenchmarkDotNet.Samples.IntroPowerPlan. | ||
|
||
Please note. During an execution, BenchmarkDotNet saves the current power plan and applies it according to the PowerPlanMode property. When all of the benchmarks finish, a previous power plan comes back. However, if someone killed process or energy was plugged off, we could stay with the High-Performance power plan. In this situation, we should return it manually in Windows Control Panel or by powercfg command. | ||
|
||
### Links | ||
|
||
* Power policy settings: https://docs.microsoft.com/en-us/windows/desktop/power/power-policy-settings | ||
* Powercfg command: https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/powercfg-command-line-options | ||
* @BenchmarkDotNet.Samples.IntroPowerPlan | ||
|
||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
--- | ||
uid: BenchmarkDotNet.Samples.IntroPowerPlan | ||
--- | ||
|
||
## Sample: IntroPowerPlan | ||
|
||
This sample shows how we can turn off changing power plans. | ||
|
||
### Source code | ||
|
||
[!code-csharp[IntroPowerPlan.cs](../../../samples/BenchmarkDotNet.Samples/IntroPowerPlan.cs)] | ||
|
||
### Links | ||
|
||
* @docs.powerplans | ||
* The permanent link to this sample: @BenchmarkDotNet.Samples.IntroPowerPlan | ||
|
||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using BenchmarkDotNet.Attributes; | ||
using BenchmarkDotNet.Configs; | ||
using BenchmarkDotNet.Environments; | ||
using BenchmarkDotNet.Jobs; | ||
|
||
namespace BenchmarkDotNet.Samples | ||
{ | ||
[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 IterationTest() | ||
{ | ||
int j = 0; | ||
for (int i = 0; i < short.MaxValue; ++i) | ||
{ | ||
j = i; | ||
} | ||
|
||
return j; | ||
} | ||
|
||
[Benchmark] | ||
public int SplitJoin() | ||
=> string.Join(",", new string[1000]).Split(',').Length; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace BenchmarkDotNet.Environments | ||
{ | ||
public enum PowerPlan | ||
{ | ||
HighPerformance, | ||
UserPowerPlan, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
using System; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
|
||
namespace BenchmarkDotNet.Helpers | ||
{ | ||
internal class PowerManagementHelper | ||
{ | ||
private const uint ErrorMoreData = 234; | ||
private const uint SuccessCode = 0; | ||
|
||
internal static Guid? CurrentPlan | ||
{ | ||
get | ||
{ | ||
IntPtr activeGuidPtr = IntPtr.Zero; | ||
uint res = PowerGetActiveScheme(IntPtr.Zero, ref activeGuidPtr); | ||
if (res != SuccessCode) | ||
return null; | ||
|
||
return (Guid)Marshal.PtrToStructure(activeGuidPtr, typeof(Guid)); | ||
} | ||
} | ||
|
||
internal static string CurrentPlanFriendlyName | ||
{ | ||
get | ||
{ | ||
uint buffSize = 0; | ||
StringBuilder buffer = new StringBuilder(); | ||
IntPtr activeGuidPtr = IntPtr.Zero; | ||
uint res = PowerGetActiveScheme(IntPtr.Zero, ref activeGuidPtr); | ||
if (res != SuccessCode) | ||
return null; | ||
res = PowerReadFriendlyName(IntPtr.Zero, activeGuidPtr, IntPtr.Zero, IntPtr.Zero, buffer, ref buffSize); | ||
if (res == ErrorMoreData) | ||
{ | ||
buffer.Capacity = (int)buffSize; | ||
res = PowerReadFriendlyName(IntPtr.Zero, activeGuidPtr, | ||
IntPtr.Zero, IntPtr.Zero, buffer, ref buffSize); | ||
} | ||
if (res != SuccessCode) | ||
return null; | ||
|
||
return buffer.ToString(); | ||
} | ||
} | ||
|
||
internal static bool Set(Guid newPolicy) | ||
{ | ||
return PowerSetActiveScheme(IntPtr.Zero, ref newPolicy) == 0; | ||
} | ||
|
||
[DllImport("powrprof.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] | ||
private static extern uint PowerReadFriendlyName(IntPtr RootPowerKey, IntPtr SchemeGuid, IntPtr SubGroupOfPowerSettingGuid, IntPtr PowerSettingGuid, StringBuilder Buffer, ref uint BufferSize); | ||
|
||
[DllImport("powrprof.dll", ExactSpelling = true)] | ||
private static extern int PowerSetActiveScheme(IntPtr ReservedZero, ref Guid policyGuid); | ||
|
||
[DllImport("powrprof.dll", ExactSpelling = true)] | ||
private static extern uint PowerGetActiveScheme(IntPtr UserRootPowerKey, ref IntPtr ActivePolicyGuid); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using BenchmarkDotNet.Environments; | ||
using BenchmarkDotNet.Helpers; | ||
using BenchmarkDotNet.Loggers; | ||
using BenchmarkDotNet.Portability; | ||
|
||
namespace BenchmarkDotNet.Running | ||
{ | ||
internal class PowerManagementApplier | ||
{ | ||
private readonly ILogger logger; | ||
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(PowerPlan powerPlan) | ||
{ | ||
var guid = powerPlansDict[powerPlan]; | ||
ApplyPerformancePlan(guid); | ||
} | ||
|
||
internal void ApplyPerformancePlan(string guid) | ||
{ | ||
if (RuntimeInformation.IsWindows()) | ||
{ | ||
if (string.IsNullOrEmpty(guid) == false && powerPlanChanged == false) | ||
ApplyPlanByGuid(guid); | ||
else if (string.IsNullOrEmpty(guid)) | ||
ApplyUserPowerPlan(); | ||
} | ||
} | ||
|
||
internal void ApplyUserPowerPlan() | ||
{ | ||
if (powerPlanChanged && RuntimeInformation.IsWindows()) | ||
{ | ||
try | ||
{ | ||
if (userCurrentPowerPlan != null && PowerManagementHelper.Set(userCurrentPowerPlan.Value)) | ||
{ | ||
powerPlanChanged = false; | ||
var powerPlanFriendlyName = PowerManagementHelper.CurrentPlanFriendlyName; | ||
logger.WriteInfo($"Succesfully reverted power plan (GUID: {userCurrentPowerPlan.Value} FriendlyName: {powerPlanFriendlyName})"); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
logger.WriteLineError($"Cannot revert power plan (error message: {ex.Message})"); | ||
} | ||
} | ||
} | ||
|
||
private void ApplyPlanByGuid(string guid) | ||
{ | ||
try | ||
{ | ||
if (isInitialized == false) | ||
{ | ||
userCurrentPowerPlan = PowerManagementHelper.CurrentPlan; | ||
isInitialized = true; | ||
} | ||
|
||
if (PowerManagementHelper.Set(new Guid(guid))) | ||
{ | ||
powerPlanChanged = true; | ||
var powerPlanFriendlyName = PowerManagementHelper.CurrentPlanFriendlyName; | ||
logger.WriteInfo($"Setup power plan (GUID: {guid} FriendlyName: {powerPlanFriendlyName})"); | ||
} | ||
else | ||
logger.WriteLineError($"Cannot setup power plan (GUID: {guid})"); | ||
} | ||
catch (Exception ex) | ||
{ | ||
logger.WriteLineError($"Cannot setup power plan (GUID: {guid}, error message: {ex.Message})"); | ||
} | ||
} | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
tests/BenchmarkDotNet.IntegrationTests/PowerManagementApplierTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using BenchmarkDotNet.Attributes; | ||
using BenchmarkDotNet.Configs; | ||
using BenchmarkDotNet.Environments; | ||
using BenchmarkDotNet.Helpers; | ||
using BenchmarkDotNet.Portability; | ||
using BenchmarkDotNet.Running; | ||
using BenchmarkDotNet.Tests.Loggers; | ||
using BenchmarkDotNet.Tests.XUnit; | ||
using System.Threading; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace BenchmarkDotNet.IntegrationTests | ||
{ | ||
public class PowerManagementApplierTests : BenchmarkTestExecutor | ||
{ | ||
public const string HighPerformancePlanGuid = "8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c"; | ||
|
||
public PowerManagementApplierTests(ITestOutputHelper output) : base(output) { } | ||
|
||
[FactWindowsOnly("Setting high-performance plan is suitable only on Windows")] | ||
public void TestSettingAndRevertingBackGuid() | ||
{ | ||
var userPlan = PowerManagementHelper.CurrentPlan; | ||
var logger = new OutputLogger(Output); | ||
var powerManagementApplier = new PowerManagementApplier(logger); | ||
var config = DefaultConfig.Instance.With(logger); | ||
powerManagementApplier.ApplyPerformancePlan(PowerPlan.HighPerformance); | ||
Assert.Equal(HighPerformancePlanGuid, PowerManagementHelper.CurrentPlan.ToString()); | ||
Assert.Equal("High performance", PowerManagementHelper.CurrentPlanFriendlyName); | ||
powerManagementApplier.ApplyUserPowerPlan(); | ||
Assert.Equal(userPlan, PowerManagementHelper.CurrentPlan); | ||
} | ||
|
||
[FactWindowsOnly("Setting high-performance plan is suitable only on Windows")] | ||
public void TestPowerPlanShouldNotChange() | ||
{ | ||
var userPlan = PowerManagementHelper.CurrentPlan; | ||
var logger = new OutputLogger(Output); | ||
var powerManagementApplier = new PowerManagementApplier(logger); | ||
var config = DefaultConfig.Instance.With(logger); | ||
powerManagementApplier.ApplyPerformancePlan(PowerPlan.UserPowerPlan); | ||
Assert.Equal(userPlan.ToString(), PowerManagementHelper.CurrentPlan.ToString()); | ||
powerManagementApplier.ApplyUserPowerPlan(); | ||
Assert.Equal(userPlan, PowerManagementHelper.CurrentPlan); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters