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);
Foi útil?

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:

Enter image description here

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

@Sean Câmaras

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 :)

Este parece ser um bom artigo

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top