Comme les autres ont dit, Stopwatch
devrait être le bon outil pour cela. Il peut y avoir quelques améliorations apportées à ce que, voir ce fil en particulier: l'analyse comparative des petits exemples de code en C#, cette mise en œuvre peut-elle être améliorée?.
J'ai vu quelques conseils utiles par Thomas Maierhofer ici
Fondamentalement, son code ressemble à ceci:
//prevent the JIT Compiler from optimizing Fkt calls away
long seed = Environment.TickCount;
//use the second Core/Processor for the test
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
//prevent "Normal" Processes from interrupting Threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
//prevent "Normal" Threads from interrupting this thread
Thread.CurrentThread.Priority = ThreadPriority.Highest;
//warm up
method();
var stopwatch = new Stopwatch()
for (int i = 0; i < repetitions; i++)
{
stopwatch.Reset();
stopwatch.Start();
for (int j = 0; j < iterations; j++)
method();
stopwatch.Stop();
print stopwatch.Elapsed.TotalMilliseconds;
}
Une autre approche consiste à s'appuyer sur Process.TotalProcessTime
pour mesurer combien de temps la CPU a été occupé à l'exécution de la très code/processus, comme le montre ici, Cela peut refléter plus de réel scénario étant donné qu'aucun autre processus affecte la mesure. Il fait quelque chose comme:
var start = Process.GetCurrentProcess().TotalProcessorTime;
method();
var stop = Process.GetCurrentProcess().TotalProcessorTime;
print (end - begin).TotalMilliseconds;
Un nu de la mise en œuvre détaillée de la samething peuvent être trouvés ici.
J'ai écrit une classe d'assistance pour effectuer à la fois dans un format facile à utiliser:
public class Clock
{
interface IStopwatch
{
bool IsRunning { get; }
TimeSpan Elapsed { get; }
void Start();
void Stop();
void Reset();
}
class TimeWatch : IStopwatch
{
Stopwatch stopwatch = new Stopwatch();
public TimeSpan Elapsed
{
get { return stopwatch.Elapsed; }
}
public bool IsRunning
{
get { return stopwatch.IsRunning; }
}
public TimeWatch()
{
if (!Stopwatch.IsHighResolution)
throw new NotSupportedException("Your hardware doesn't support high resolution counter");
//prevent the JIT Compiler from optimizing Fkt calls away
long seed = Environment.TickCount;
//use the second Core/Processor for the test
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
//prevent "Normal" Processes from interrupting Threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
//prevent "Normal" Threads from interrupting this thread
Thread.CurrentThread.Priority = ThreadPriority.Highest;
}
public void Start()
{
stopwatch.Start();
}
public void Stop()
{
stopwatch.Stop();
}
public void Reset()
{
stopwatch.Reset();
}
}
class CpuWatch : IStopwatch
{
TimeSpan startTime;
TimeSpan endTime;
bool isRunning;
public TimeSpan Elapsed
{
get
{
if (IsRunning)
throw new NotImplementedException("Getting elapsed span while watch is running is not implemented");
return endTime - startTime;
}
}
public bool IsRunning
{
get { return isRunning; }
}
public void Start()
{
startTime = Process.GetCurrentProcess().TotalProcessorTime;
isRunning = true;
}
public void Stop()
{
endTime = Process.GetCurrentProcess().TotalProcessorTime;
isRunning = false;
}
public void Reset()
{
startTime = TimeSpan.Zero;
endTime = TimeSpan.Zero;
}
}
public static void BenchmarkTime(Action action, int iterations = 10000)
{
Benchmark<TimeWatch>(action, iterations);
}
static void Benchmark<T>(Action action, int iterations) where T : IStopwatch, new()
{
//clean Garbage
GC.Collect();
//wait for the finalizer queue to empty
GC.WaitForPendingFinalizers();
//clean Garbage
GC.Collect();
//warm up
action();
var stopwatch = new T();
var timings = new double[5];
for (int i = 0; i < timings.Length; i++)
{
stopwatch.Reset();
stopwatch.Start();
for (int j = 0; j < iterations; j++)
action();
stopwatch.Stop();
timings[i] = stopwatch.Elapsed.TotalMilliseconds;
print timings[i];
}
print "normalized mean: " + timings.NormalizedMean().ToString();
}
public static void BenchmarkCpu(Action action, int iterations = 10000)
{
Benchmark<CpuWatch>(action, iterations);
}
}
Appelez simplement
Clock.BenchmarkTime(() =>
{
//code
}, 10000000);
ou
Clock.BenchmarkCpu(() =>
{
//code
}, 10000000);
La dernière partie de l' Clock
est la partie la plus délicate. Si vous souhaitez afficher l'échéance finale, c'est à vous de choisir quelle sorte de calendrier que vous souhaitez. J'ai écrit une méthode d'extension NormalizedMean
qui vous donne le moyen de le lire timings à rejeter le bruit. Je veux dire que je calculer la déviation de chaque calendrier à partir de la moyenne réelle, et puis j'ai jeter les valeurs qui a été plus loin (seulement les plus lents) à partir de la moyenne de l'écart (appelé écart absolu; à noter que ce n'est pas souvent entendu écart-type), et enfin de retour à la moyenne des valeurs restantes. Cela signifie, par exemple, si chronométré valeurs sont { 1, 2, 3, 2, 100 }
(en ms ou quoi que ce soit), il ignore 100
, et renvoie la moyenne des { 1, 2, 3, 2 }
qui 2
. Ou si les timings sont { 240, 220, 200, 220, 220, 270 }
, il ignore 270
, et renvoie la moyenne des { 240, 220, 200, 220, 220 }
qui 220
.
public static double NormalizedMean(this ICollection<double> values)
{
if (values.Count == 0)
return double.NaN;
var deviations = values.Deviations().ToArray();
var meanDeviation = deviations.Sum(t => Math.Abs(t.Item2)) / values.Count;
return deviations.Where(t => t.Item2 > 0 || Math.Abs(t.Item2) <= meanDeviation).Average(t => t.Item1);
}
public static IEnumerable<Tuple<double, double>> Deviations(this ICollection<double> values)
{
if (values.Count == 0)
yield break;
var avg = values.Average();
foreach (var d in values)
yield return Tuple.Create(d, avg - d);
}