using System;
using System.Diagnostics;
using System.Reflection;
namespace Clave.PerformanceTests
{
///
/// Times how long Clave takes to build a ChordArbiter, taking a control through every row.
///
public static class Program
{
public const string QuickOption = "--quick";
public const string Usage = "Usage: Clave.PerformanceTests [--quick] [text in the row names to run]";
public static bool IsJitOptimizerDisabled(Assembly assembly)
{
var debuggable = assembly.GetCustomAttribute();
return debuggable != null && debuggable.IsJITOptimizerDisabled;
}
///
/// Why timings taken in this process wouldn't mean anything, or null when they would.
///
public static string ReasonTimingsAreMeaningless()
{
if (Debugger.IsAttached)
{
return "a debugger is attached";
}
foreach (Assembly assembly in new[] { typeof(Program).Assembly, typeof(ChordSetBuilder).Assembly })
{
if (IsJitOptimizerDisabled(assembly))
{
return assembly.GetName().Name + " is a Debug build";
}
}
return null;
}
///
/// One core at high priority, so the scheduler neither migrates the timing loop nor preempts it for background
/// work.
///
public static void ClaimOneCore()
{
Process self = Process.GetCurrentProcess();
self.PriorityClass = ProcessPriorityClass.High;
self.ProcessorAffinity = (IntPtr)(1L << (Environment.ProcessorCount - 1));
}
public static int Main(string[] args)
{
bool quick = false;
string filter = "";
foreach (string arg in args)
{
if (arg == QuickOption)
{
quick = true;
}
else if (arg.StartsWith("--", StringComparison.Ordinal) || filter != "")
{
Console.WriteLine(Usage);
return 2;
}
else
{
filter = arg;
}
}
string meaningless = ReasonTimingsAreMeaningless();
if (meaningless != null)
{
Console.WriteLine("Timings here would mean nothing, because " + meaningless + ".");
return 1;
}
ClaimOneCore();
Console.WriteLine($".NET {Environment.Version}, {IntPtr.Size * 8}-bit, {Environment.ProcessorCount} " +
"logical processors, pinned to the last processor at high priority.");
Console.WriteLine();
int rounds = quick ? Measurement.QuickRounds : Measurement.Rounds;
ChordSetBuilding.Run(filter, rounds);
ChordSetBuilding.Run("ChordArbiter changes and chord construction", ArbiterOperations.Scenarios, filter,
rounds);
return 0;
}
}
}