//-----------------------------------------------------------------------
//
// Copyright (c) Outercurve Foundation. All rights reserved.
//
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.Test.Performance {
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using DotNetOpenAuth.Logging;
using NUnit.Framework;
///
/// Suppresses logging and forces the CPU into a high performance mode.
///
internal class HighPerformance : IDisposable {
private readonly PowerManagment.PowerSetting powerSetting;
private readonly ProcessPriorityClass originalProcessPriority;
#pragma warning disable 0618
///
/// Initializes a new instance of the class.
///
internal HighPerformance() {
////if (!WaitForQuietCpu()) {
//// Assert.Inconclusive("Timed out waiting for a quiet CPU in which to perform perf tests.");
////}
this.powerSetting = new PowerManagment.PowerSetting(PowerManagment.PowerProfiles.HighPerformance);
this.originalProcessPriority = Process.GetCurrentProcess().PriorityClass;
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
SpinCpu();
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose() {
Thread.CurrentThread.Priority = ThreadPriority.Normal;
Process.GetCurrentProcess().PriorityClass = this.originalProcessPriority;
this.powerSetting.Dispose(); // restores original power setting.
}
#pragma warning restore 0618
///
/// Runs the CPU in a tight loop to get it out of any low power state.
///
private static void SpinCpu() {
int dummy;
new MultiSampleCodeTimer(10, 1000).Measure(
"Loop 1K times",
1,
delegate {
int k = 0;
while (k < 1000) {
k++; // still in danger of being optimized.
}
dummy = k; // avoid optimization.
});
}
private static bool WaitForQuietCpu(float maxCpuSpike = 25, int minSecondsOfQuiet = 2, int maxSecondsBeforeGiveUp = 30) {
using (var pc = new System.Diagnostics.PerformanceCounter()) {
pc.CategoryName = "Processor";
pc.CounterName = "% Processor Time";
pc.InstanceName = "_Total";
TimeSpan samplingInterval = TimeSpan.FromMilliseconds(1000);
TimeSpan minimumQuietTime = TimeSpan.FromSeconds(minSecondsOfQuiet);
TimeSpan maximumTimeBeforeBail = TimeSpan.FromSeconds(maxSecondsBeforeGiveUp);
DateTime startTryingStamp = DateTime.Now;
int hitsRequired = (int)(minimumQuietTime.TotalMilliseconds / samplingInterval.TotalMilliseconds);
while (DateTime.Now - startTryingStamp < maximumTimeBeforeBail) {
int hits;
for (hits = 0; hits < hitsRequired; hits++) {
float currentCpuUtilization = pc.NextValue();
if (currentCpuUtilization > maxCpuSpike) {
////Console.WriteLine("Miss: CPU at {0}% utilization", currentCpuUtilization);
break;
}
////Console.WriteLine("Hit: CPU at {0}% utilization", currentCpuUtilization);
Thread.Sleep(samplingInterval);
}
if (hits == hitsRequired) {
return true;
}
Thread.Sleep(samplingInterval);
}
return false;
}
}
///
/// PowerManagement allows you to access the funtionality of the Control Panel -> Power Options
/// dialog in windows. (Currently we only use VISTA APIs).
///
private static class PowerManagment {
internal static unsafe Guid CurrentPolicy {
get {
Guid* retPolicy = null;
Guid ret = Guid.Empty;
try {
int callRet = PowerGetActiveScheme(IntPtr.Zero, ref retPolicy);
if (callRet == 0) {
ret = *retPolicy;
Marshal.FreeHGlobal((IntPtr)retPolicy);
}
} catch (Exception) {
}
return ret;
}
set {
Guid newPolicy = value;
int result = PowerSetActiveScheme(IntPtr.Zero, ref newPolicy);
if (result != 0) {
TestUtilities.TestLogger.ErrorFormat("Unable to set power management policy. Error code: {0}", result);
////throw new Win32Exception(result);
}
}
}
[DllImport("powrprof.dll")]
private static unsafe extern int PowerGetActiveScheme(IntPtr reservedZero, ref Guid* policyGuidRet);
[DllImport("powrprof.dll")]
private static extern int PowerSetActiveScheme(IntPtr reservedZero, ref Guid policyGuid);
internal static class PowerProfiles {
internal static Guid HighPerformance = new Guid(0x8c5e7fda, 0xe8bf, 0x4a96, 0x9a, 0x85, 0xa6, 0xe2, 0x3a, 0x8c, 0x63, 0x5c);
internal static Guid Balanced = new Guid(0x381b4222, 0xf694, 0x41f0, 0x96, 0x85, 0xff, 0x5b, 0xb2, 0x60, 0xdf, 0x2e);
internal static Guid PowerSaver = new Guid(0xa1841308, 0x3541, 0x4fab, 0xbc, 0x81, 0xf7, 0x15, 0x56, 0xf2, 0x0b, 0x4a);
}
internal class PowerSetting : IDisposable {
///
/// The power policy in effect when this instance was constructed.
///
private Guid previousPolicy;
///
/// Initializes a new instance of the class.
///
/// The power profile.
internal PowerSetting(Guid powerProfile) {
this.previousPolicy = PowerManagment.CurrentPolicy;
if (this.previousPolicy != powerProfile) {
PowerManagment.CurrentPolicy = powerProfile;
}
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose() {
if (this.previousPolicy != PowerManagment.CurrentPolicy) {
PowerManagment.CurrentPolicy = this.previousPolicy;
}
}
}
}
}
}