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; } } }