É DateTime.Agora a melhor forma de medir uma função de desempenho?
-
09-06-2019 - |
Pergunta
Eu preciso encontrar um gargalo e precisa com a maior precisão possível medir o tempo.
É o seguinte fragmento de código a melhor maneira de medir o desempenho?
DateTime startTime = DateTime.Now;
// Some execution process
DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);
Solução
Não, não.Use o Cronómetro (em System.Diagnostics
)
Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();
Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);
Cronómetro verifica automaticamente a existência de alta precisão temporizadores.
Vale ressaltar que DateTime.Now
muitas vezes, é um pouco mais lento do que DateTime.UtcNow
devido ao trabalho que tem de ser feito com fusos horários, DST e tal.
Data / hora.UtcNow normalmente tem uma resolução de 15 ms.Ver John Chapman post do blog sobre DateTime.Now
precisão para um grande resumo.
Curiosidades interessantes:O cronômetro volta no DateTime.UtcNow
se o seu hardware não oferece suporte a uma alta freqüência de contador.Você pode verificar para ver se o Cronômetro usa hardware para alcançar alta precisão, observando o campo estático Cronómetro.IsHighResolution.
Outras dicas
Se você quer algo rápido e sujo gostaria de sugerir o uso do Cronômetro, em vez de um maior grau de precisão.
Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();
Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);
Como alternativa, se você precisa de algo um pouco mais sofisticado, você provavelmente deve considerar o uso de uma festa de 3 profiler, tais como FORMIGAS.
Este artigo diz que primeiro de tudo você precisa para comparar três alternativas, Stopwatch
, DateTime.Now
E DateTime.UtcNow
.
Ele também mostra que, em alguns casos (quando o contador de desempenho não existe) o Cronômetro estiver usando data e hora.UtcNow + algum processamento extra.Por isso é óbvio que, neste caso DateTime.UtcNow é a melhor opção (porque outros usá-lo + de processamento)
No entanto, como se vê, o contador quase sempre existe - ver Explicação sobre a alta resolução do contador de desempenho e sua existência relacionados .NET Cronômetro?.
Aqui está um gráfico de desempenho.Observe como o baixo custo de desempenho UtcNow tem em comparação com as alternativas:
O eixo X é exemplo de tamanho de dados, e o eixo Y é o tempo relativo de exemplo.
Uma coisa Stopwatch
é melhor é que ele fornece maior tempo de resolução de medições.Outro é a sua mais OO natureza.No entanto, a criação de um wrapper em torno de OO UtcNow
não pode ser rígido.
É útil para enviar sua benchmarking código em uma classe de utilitário/método.O StopWatch
classe não precisa ser Disposed
ou Stopped
no erro.Assim, o código mais simples para horário alguns ação é
public partial class With
{
public static long Benchmark(Action action)
{
var stopwatch = Stopwatch.StartNew();
action();
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
}
Exemplo de código de chamada
public void Execute(Action action)
{
var time = With.Benchmark(action);
log.DebugFormat(“Did action in {0} ms.”, time);
}
Aqui é o método de extensão de versão
public static class Extensions
{
public static long Benchmark(this Action action)
{
return With.Benchmark(action);
}
}
E chamada de exemplo de código
public void Execute(Action action)
{
var time = action.Benchmark()
log.DebugFormat(“Did action in {0} ms.”, time);
}
O cronómetro a funcionalidade seria melhor (maior precisão).Eu também recomendo apenas o download de um dos criadores de perfil popular, embora (DotTrace e FORMIGAS são as que eu usei mais...a versão de avaliação gratuita para DotTrace é totalmente funcional e não nag, como alguns dos outros).
Usar o Sistema.O diagnóstico.Cronómetro de classe.
Stopwatch sw = new Stopwatch();
sw.Start();
// Do some code.
sw.Stop();
// sw.ElapsedMilliseconds = the time your "do some code" took.
Idem para o Cronômetro, ele é muito melhor.
Em relação ao desempenho de medição, você também deve verificar se o seu "// Algumas Processo de Execução" é um processo curto.
Também tenha em mente que a primeira execução de suas "// Algumas Processo de Execução" pode ser a forma mais lenta do que as execuções subsequentes.
Eu normalmente testar um método executado 1000 vezes ou 1000000 vezes em um loop e eu fico muito precisa de mais dados do que de executar uma vez.
Estas são todas ótimas maneiras de medir o tempo, mas que é apenas uma forma indirecta para encontrar gargalo(s).
A maneira mais direta para encontrar um bottneck em um thread é para que ele comece a funcionar, e enquanto ele está fazendo o que faz você esperar, parar com uma pausa ou quebra de chave.Fazer isso várias vezes.Se o seu gargalo tem X% de hora, X% é a probabilidade de que você vai pegá-lo no ato em cada instantâneo.
Aqui está uma explicação mais detalhada de como e por que funciona
FYI, o .NET classe Timer não é para diagnósticos, gera eventos em um intervalo pré-definido, como este (a partir de MSDN):
System.Timers.Timer aTimer;
public static void Main()
{
// Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
Isso realmente não ajuda a saber quanto tempo algo tomou, só que de uma certa quantidade de tempo decorrido.
O temporizador é também exposto como um controle no Sistema.O Windows.Formas de...você pode encontrá-lo em sua ferramenta de designer de caixa em VS05/VS08
Esta é a forma correta:
using System;
using System.Diagnostics;
class Program
{
public static void Main()
{
Stopwatch stopWatch = Stopwatch.StartNew();
// some other code
stopWatch.Stop();
// this not correct to get full timer resolution
Console.WriteLine("{0} ms", stopWatch.ElapsedMilliseconds);
// Correct way to get accurate high precision timing
Console.WriteLine("{0} ms", stopWatch.Elapsed.TotalMilliseconds);
}
}
Para mais informações, acesse através Usar o Cronômetro em vez de Datahora para obter precisas de contador de desempenho.
O Visual Studio Team System tem algumas características que podem ajudar com este problema.Essencialmente, você pode escrever testes de unidade e misturá-los em diferentes cenários de execução contra o software como parte de um esforço ou teste de carga.Isso pode ajudar a identificar áreas de código que o impacto de seu desempenho de aplicações mais.
Microsoft' grupo de Padrões e Práticas tem alguma orientação em O Visual Studio Team System De Teste De Desempenho De Orientação.
Eu só encontrei um post em Vance Morrison blog sobre um CodeTimer classe ele escreveu o que torna o uso de StopWatch
mais fácil e faz algumas coisas legais sobre o lado.
Eu tenho feito muito pouco para este tipo de desempenho (verificação de eu tendem a pensar apenas "esta é lenta, torná-lo mais rápido") então, eu tenho muito bonito ido sempre com isso.
Google revela um monte de recursos/artigos de desempenho de verificação.
Falar de muitos usando pinvoke para obter informações de desempenho.Um monte de materiais de estudo realmente só mencionar usando o perfmon..
Editar:
Visto que a fala do Cronômetro..Bom!Eu aprendi algo :)
A maneira que eu uso dentro de meus programas é usando o Cronómetro de classe, como mostrado aqui.
Stopwatch sw = new Stopwatch();
sw.Start();
// Critical lines of code
long elapsedMs = sw.Elapsed.TotalMilliseconds;
Isso não é profissional o suficiente:
Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();
Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);
Mais confiável versão é:
PerformWork();
int repeat = 1000;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < repeat; i++)
{
PerformWork();
}
sw.Stop();
Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds / repeat);
No meu código real, vou adicionar o GC.Chamada a cobrar para alterar heap gerenciado para um estado conhecido, e adicionar chamada de Suspensão, de modo que diferentes intervalos de código pode ser facilmente separados em ETW perfil.