Como calcular o tempo de execução de um trecho de código em C ++

121

Eu tenho que calcular o tempo de execução de um trecho de código C ++ em segundos. Ele deve estar funcionando em máquinas Windows ou Unix.

Eu uso o código a seguir para fazer isso. (importar antes)

clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;

No entanto, para pequenas entradas ou instruções curtas como a = a + 1, recebo o resultado "0 segundos". Eu acho que deve ser algo como 0,0000001 segundos ou algo assim.

Lembro que System.nanoTime()em Java funciona muito bem nesse caso. No entanto, não consigo obter a mesma funcionalidade exata da clock()função do C ++.

Você tem uma solução?

AhmetB - Google
fonte
29
Lembre-se de que qualquer comparação com base na diferença de horário pode ser imprecisa devido ao fato de que o sistema operacional pode não executar seu encadeamento do início ao fim. Isso pode interrompê-lo e executar outros threads entrelaçados com o seu, o que terá um impacto significativo no tempo real necessário para concluir sua operação. Você pode executar várias vezes e calcular a média dos resultados; você pode minimizar o número de outros processos em execução. Mas nada disso eliminará completamente o efeito de suspensão da linha.
Mordachai
14
Mordachi, por que você quer eliminá-lo? Você deseja ver como sua função se desempenha em um ambiente do mundo real, não em um reino mágico, onde os threads nunca são interrompidos. Contanto que você o execute várias vezes e faça uma média, será muito preciso.
9789 Thomas Bonini
Sim, eu corro algumas vezes e avg resultados.
AhmetB - Google
14
Andreas, o comentário de Mordachai é relevante se o OP quiser comparar o desempenho de seu código com um algoritmo diferente. Por exemplo, se ele executar vários testes de relógio esta tarde e depois testar um algoritmo diferente amanhã de manhã, sua comparação pode não ser confiável, pois ele pode compartilhar recursos com muito mais processos à tarde do que de manhã. Ou talvez um conjunto de códigos faça com que o sistema operacional ofereça menos tempo de processamento. Existem inúmeras razões pelas quais esse tipo de medição de desempenho não é confiável se ele deseja realizar uma comparação com base no tempo.
Weberc2
4
@Mordachai Eu sei que estou respondendo a um comentário antigo, mas para quem se deparar com isso como eu fiz - para cronometrar o desempenho dos algoritmos, você deseja fazer o mínimo de algumas execuções, não a média. Esse foi o que teve menos interrupções no sistema operacional e, portanto, está cronometrando principalmente o seu código.
Baruch

Respostas:

115

Você pode usar esta função que escrevi. Você chama GetTimeMs64()e retorna o número de milissegundos decorridos desde a época do unix usando o relógio do sistema - exatamente como time(NULL), exceto em milissegundos.

Funciona em janelas e linux; é thread-safe.

Observe que a granularidade é de 15 ms no Windows; no linux, é dependente da implementação, mas geralmente 15 ms também.

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif

/* Remove if already defined */
typedef long long int64; typedef unsigned long long uint64;

/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
 * windows and linux. */

uint64 GetTimeMs64()
{
#ifdef _WIN32
 /* Windows */
 FILETIME ft;
 LARGE_INTEGER li;

 /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
  * to a LARGE_INTEGER structure. */
 GetSystemTimeAsFileTime(&ft);
 li.LowPart = ft.dwLowDateTime;
 li.HighPart = ft.dwHighDateTime;

 uint64 ret = li.QuadPart;
 ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
 ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */

 return ret;
#else
 /* Linux */
 struct timeval tv;

 gettimeofday(&tv, NULL);

 uint64 ret = tv.tv_usec;
 /* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
 ret /= 1000;

 /* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
 ret += (tv.tv_sec * 1000);

 return ret;
#endif
}
Thomas Bonini
fonte
1
Para referência futura: eu apenas o jogo em um arquivo de cabeçalho e o uso. Fico feliz em tê-lo.
Daniel Handojo
1
Acredito que o método gettimeofdaypode dar um resultado não intencional se o relógio do sistema for alterado. Se isso for um problema para você, você pode querer dar uma olhada clock_gettime.
Azmisov
Esse método para Windows tem alguma vantagem GetTickCount?
MicroVirus
Não compila usandogcc -std=c99
Assimilater
@MicroVirus: sim, GetTickCounté o tempo decorrido desde que o sistema foi iniciado, enquanto minha função retorna o tempo desde a época do UNIX, o que significa que você pode usá-lo para datas e horas. Se você está interessado apenas no tempo decorrido entre dois eventos, a minha ainda é uma escolha melhor porque é uma int64; GetTickCount é um int32 e transborda a cada 50 dias, o que significa que você pode obter resultados estranhos se os dois eventos registrados estiverem entre o transbordamento.
Thomas Bonini
43

Eu tenho outro exemplo de trabalho que usa microssegundos (UNIX, POSIX, etc).

    #include <sys/time.h>
    typedef unsigned long long timestamp_t;

    static timestamp_t
    get_timestamp ()
    {
      struct timeval now;
      gettimeofday (&now, NULL);
      return  now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
    }

    ...
    timestamp_t t0 = get_timestamp();
    // Process
    timestamp_t t1 = get_timestamp();

    double secs = (t1 - t0) / 1000000.0L;

Aqui está o arquivo em que codificamos isso:

https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c

arhuaco
fonte
5
Você deve adicionar #include <sys/time.h>no início do seu exemplo.
niekas
40

Aqui está uma solução simples no C ++ 11, que oferece uma resolução satisfatória.

#include <iostream>
#include <chrono>

class Timer
{
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const { 
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }

private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

Ou no * nix, para c ++ 03

#include <iostream>
#include <ctime>

class Timer
{
public:
    Timer() { clock_gettime(CLOCK_REALTIME, &beg_); }

    double elapsed() {
        clock_gettime(CLOCK_REALTIME, &end_);
        return end_.tv_sec - beg_.tv_sec +
            (end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
    }

    void reset() { clock_gettime(CLOCK_REALTIME, &beg_); }

private:
    timespec beg_, end_;
};

Aqui está o exemplo de uso:

int main()
{
    Timer tmr;
    double t = tmr.elapsed();
    std::cout << t << std::endl;

    tmr.reset();
    t = tmr.elapsed();
    std::cout << t << std::endl;

    return 0;
}

De https://gist.github.com/gongzhitaao/7062087

gongzhitaao
fonte
Estou recebendo este erro com a sua solução c ++ 11:/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
user9869932
@julianromera que plataforma você está usando? você instalou a biblioteca libstdc ++ eg +?
gongzhitaao 02/09
É uma grade Slurm do Linux ubuntu 12. Acabei de consertar. Adicionei -static-libstdc ++ no final do vinculador. Obrigado por perguntar @gongzhitaao
user9869932
18
#include <boost/progress.hpp>

using namespace boost;

int main (int argc, const char * argv[])
{
  progress_timer timer;

  // do stuff, preferably in a 100x loop to make it take longer.

  return 0;
}

Quando progress_timersair do escopo, imprimirá o tempo decorrido desde a sua criação.

ATUALIZAÇÃO : Aqui está uma versão que funciona sem o Boost (testado no macOS / iOS):

#include <chrono>
#include <string>
#include <iostream>
#include <math.h>
#include <unistd.h>

class NLTimerScoped {
private:
    const std::chrono::steady_clock::time_point start;
    const std::string name;

public:
    NLTimerScoped( const std::string & name ) : name( name ), start( std::chrono::steady_clock::now() ) {
    }


    ~NLTimerScoped() {
        const auto end(std::chrono::steady_clock::now());
        const auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ).count();

        std::cout << name << " duration: " << duration_ms << "ms" << std::endl;
    }

};

int main(int argc, const char * argv[]) {

    {
        NLTimerScoped timer( "sin sum" );

        float a = 0.0f;

        for ( int i=0; i < 1000000; i++ ) {
            a += sin( (float) i / 100 );
        }

        std::cout << "sin sum = " << a << std::endl;
    }



    {
        NLTimerScoped timer( "sleep( 4 )" );

        sleep( 4 );
    }



    return 0;
}

Tomas Andrle
fonte
2
Isso funciona, mas observe que o progress_timer está obsoleto (algum tempo antes do aumento 1.50) - o auto_cpu_timer pode ser mais apropriado.
DavidA
3
@meowsqueak hmm, o auto_cpu_timer parece exigir que a biblioteca do sistema Boost esteja vinculada, portanto, não é mais uma solução apenas de cabeçalho. Que pena ... torna as outras opções mais atraentes de repente.
Tomas Andrle 28/09/12
1
Sim, esse é um bom ponto, se você ainda não vincula o Boost, é mais um problema do que vale a pena. Mas se você já faz, funciona muito bem.
DavidA
@meowsqueak Sim, ou para alguns testes rápidos de benchmark, basta obter a versão mais antiga do Boost.
Tomas Andrle
@TomasAndrle O link não existe mais.
Zheng Qu
5

O Windows fornece a função QueryPerformanceCounter () e o Unix possui gettimeofday (). Ambas as funções podem medir pelo menos 1 diferença de microssegundos.

Captain Comic
fonte
Mas o uso do windows.h é restrito. A mesma fonte compilada deve ser executada no Windows e no Unix. Como lidar com esse problema?
AhmetB - Google
2
Em seguida, procure por uma biblioteca de invólucros stackoverflow.com/questions/1487695/…
Captain Comic
4
a mesma fonte compilada parece que você deseja executar o mesmo binário nos dois sistemas, o que não parece ser o caso. Se você quis dizer a mesma fonte , em seguida, um #ifdefdeve estar ok (e é a julgar pela resposta que você aceita), e então eu não vejo o problema: #ifdef WIN32 #include <windows.h> ... #else ... #endif.
apenas alguém
3

Em alguns programas que escrevi, usei o RDTS para esse fim. RDTSC não é sobre o tempo, mas sobre o número de ciclos desde o início do processador. Você precisa calibrá-lo em seu sistema para obter um resultado em segundo, mas é realmente útil quando você deseja avaliar o desempenho; é ainda melhor usar o número de ciclos diretamente, sem tentar alterá-los para segundos.

(o link acima é para uma página da Wikipedia, mas tem exemplos de código C ++, a versão em inglês está aqui )

kriss
fonte
2

Sugiro usar as funções da biblioteca padrão para obter informações de tempo do sistema.

Se você deseja uma resolução mais precisa, execute mais iterações de execução. Em vez de executar o programa uma vez e obter amostras, execute-o 1000 vezes ou mais.

Thomas Matthews
fonte
2

É melhor executar o loop interno várias vezes com o tempo de desempenho apenas uma vez e média dividindo as repetições do loop interno do que executar a coisa toda (loop + tempo de desempenho) várias vezes e média. Isso reduzirá a sobrecarga do código de tempo do desempenho em relação à sua seção de perfil real.

Envolva as chamadas do timer para o sistema apropriado. Para o Windows, o QueryPerformanceCounter é bastante rápido e "seguro" de usar.

Você também pode usar "rdtsc" em qualquer PC X86 moderno, mas pode haver problemas em algumas máquinas com vários núcleos (o salto de núcleo pode alterar o timer) ou se você tiver algum tipo de velocidade ativada.

Adisak
fonte
2

(solução específica para Windows) A maneira atual (por volta de 2017) de obter horários precisos no Windows é usar "QueryPerformanceCounter". Essa abordagem tem o benefício de fornecer resultados muito precisos e é recomendada pela EM. Basta inserir o blob de código em um novo aplicativo de console para obter uma amostra funcional. Há uma longa discussão aqui: Adquirindo carimbos de data / hora de alta resolução

#include <iostream>
#include <tchar.h>
#include <windows.h>

int main()
{
constexpr int MAX_ITER{ 10000 };
constexpr __int64 us_per_hour{ 3600000000ull }; // 3.6e+09
constexpr __int64 us_per_min{ 60000000ull };
constexpr __int64 us_per_sec{ 1000000ull };
constexpr __int64 us_per_ms{ 1000ull };

// easy to work with
__int64 startTick, endTick, ticksPerSecond, totalTicks = 0ull;

QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond);

for (int iter = 0; iter < MAX_ITER; ++iter) {// start looping
    QueryPerformanceCounter((LARGE_INTEGER *)&startTick); // Get start tick
    // code to be timed
    std::cout << "cur_tick = " << iter << "\n";
    QueryPerformanceCounter((LARGE_INTEGER *)&endTick); // Get end tick
    totalTicks += endTick - startTick; // accumulate time taken
}

// convert to elapsed microseconds
__int64 totalMicroSeconds =  (totalTicks * 1000000ull)/ ticksPerSecond;

__int64 hours = totalMicroSeconds / us_per_hour;
totalMicroSeconds %= us_per_hour;
__int64 minutes = totalMicroSeconds / us_per_min;
totalMicroSeconds %= us_per_min;
__int64 seconds = totalMicroSeconds / us_per_sec;
totalMicroSeconds %= us_per_sec;
__int64 milliseconds = totalMicroSeconds / us_per_ms;
totalMicroSeconds %= us_per_ms;


std::cout << "Total time: " << hours << "h ";
std::cout << minutes << "m " << seconds << "s " << milliseconds << "ms ";
std::cout << totalMicroSeconds << "us\n";

return 0;
}

fonte
2

Uma solução completa e infalível para o agendamento de threads, que deve render exatamente os mesmos tempos para cada teste, é compilar seu programa para ser independente do SO e inicializar o computador para executar o programa em um ambiente sem SO. No entanto, isso é praticamente impraticável e seria difícil na melhor das hipóteses.

Um bom substituto para deixar o sistema operacional livre é apenas definir a afinidade do encadeamento atual como 1 núcleo e a prioridade como mais alta. Essa alternativa deve fornecer resultados consistentes o suficiente.

Além disso, você deve desativar as otimizações que interferem na depuração, o que para g ++ ou gcc significa adicionar -Ogà linha de comando , para impedir que o código que está sendo testado seja otimizado. O -O0sinalizador não deve ser usado porque introduz uma sobrecarga extra desnecessária que seria incluída nos resultados de temporização, assim distorcendo a velocidade programada do código.

Pelo contrário, ambos assumindo que você usa -Ofast(ou pelo menos -O3) na construção da produção final e ignorando o problema da eliminação de código "inoperante", -Ogexecutam muito poucas otimizações em comparação com -Ofast; portanto, -Ogpode deturpar a velocidade real do código no produto final.

Além disso, todos os testes de velocidade (até certo ponto) perduram: no produto final de produção compilado -Ofast, cada trecho / seção / função do código não é isolado; em vez disso, cada trecho de código flui continuamente para o próximo, permitindo que o compilador se junte, mescle e otimize partes de código em potencial de todo o lugar.

Ao mesmo tempo, se você estiver comparando um trecho de código que faz uso pesado realloc(), o trecho de código poderá ser executado mais lentamente em um produto de produção com fragmentação de memória alta o suficiente. Portanto, a expressão "o todo é mais do que a soma de suas partes" se aplica a essa situação porque o código na compilação de produção final pode ser notavelmente mais rápido ou mais lento que o snippet individual que você está testando com rapidez.

Uma solução parcial que pode diminuir a incongruência está sendo usada -Ofastno teste de velocidade COM a adição de asm volatile("" :: "r"(var))variáveis ​​envolvidas no teste para evitar a eliminação do código morto / loop.

Aqui está um exemplo de como comparar funções de raiz quadrada em um computador com Windows.

// set USE_ASM_TO_PREVENT_ELIMINATION  to 0 to prevent `asm volatile("" :: "r"(var))`
// set USE_ASM_TO_PREVENT_ELIMINATION  to 1 to enforce `asm volatile("" :: "r"(var))`
#define USE_ASM_TO_PREVENT_ELIMINATION 1

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <chrono>
#include <cmath>
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(__rdtsc)
#include <cstdint>

class Timer {
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const { 
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }
private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

unsigned int guess_sqrt32(register unsigned int n) {
    register unsigned int g = 0x8000;
    if(g*g > n) {
        g ^= 0x8000;
    }
    g |= 0x4000;
    if(g*g > n) {
        g ^= 0x4000;
    }
    g |= 0x2000;
    if(g*g > n) {
        g ^= 0x2000;
    }
    g |= 0x1000;
    if(g*g > n) {
        g ^= 0x1000;
    }
    g |= 0x0800;
    if(g*g > n) {
        g ^= 0x0800;
    }
    g |= 0x0400;
    if(g*g > n) {
        g ^= 0x0400;
    }
    g |= 0x0200;
    if(g*g > n) {
        g ^= 0x0200;
    }
    g |= 0x0100;
    if(g*g > n) {
        g ^= 0x0100;
    }
    g |= 0x0080;
    if(g*g > n) {
        g ^= 0x0080;
    }
    g |= 0x0040;
    if(g*g > n) {
        g ^= 0x0040;
    }
    g |= 0x0020;
    if(g*g > n) {
        g ^= 0x0020;
    }
    g |= 0x0010;
    if(g*g > n) {
        g ^= 0x0010;
    }
    g |= 0x0008;
    if(g*g > n) {
        g ^= 0x0008;
    }
    g |= 0x0004;
    if(g*g > n) {
        g ^= 0x0004;
    }
    g |= 0x0002;
    if(g*g > n) {
        g ^= 0x0002;
    }
    g |= 0x0001;
    if(g*g > n) {
        g ^= 0x0001;
    }
    return g;
}

unsigned int empty_function( unsigned int _input ) {
    return _input;
}

unsigned long long empty_ticks=0;
double empty_seconds=0;
Timer my_time;

template<unsigned int benchmark_repetitions>
void benchmark( char* function_name, auto (*function_to_do)( auto ) ) {
    register unsigned int i=benchmark_repetitions;
    register unsigned long long start=0;
    my_time.reset();
    start=__rdtsc();
    while ( i-- ) {
        auto result = (*function_to_do)( i << 7 );
        #if USE_ASM_TO_PREVENT_ELIMINATION == 1
            asm volatile("" :: "r"(
                // There is no data type in C++ that is smaller than a char, so it will
                //  not throw a segmentation fault error to reinterpret any arbitrary
                //  data type as a char. Although, the compiler might not like it.
                result
            ));
        #endif
    }
    if ( function_name == nullptr ) {
        empty_ticks = (__rdtsc()-start);
        empty_seconds = my_time.elapsed();
        std::cout<< "Empty:\n" << empty_ticks
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << empty_seconds
                << " seconds\n\n";
    } else {
        std::cout<< function_name<<":\n" << (__rdtsc()-start-empty_ticks)
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << (my_time.elapsed()-empty_seconds)
                << " seconds\n\n";
    }
}


int main( void ) {
    void* Cur_Thread=   GetCurrentThread();
    void* Cur_Process=  GetCurrentProcess();
    unsigned long long  Current_Affinity;
    unsigned long long  System_Affinity;
    unsigned long long furthest_affinity;
    unsigned long long nearest_affinity;

    if( ! SetThreadPriority(Cur_Thread,THREAD_PRIORITY_TIME_CRITICAL) ) {
        SetThreadPriority( Cur_Thread, THREAD_PRIORITY_HIGHEST );
    }
    if( ! SetPriorityClass(Cur_Process,REALTIME_PRIORITY_CLASS) ) {
        SetPriorityClass( Cur_Process, HIGH_PRIORITY_CLASS );
    }
    GetProcessAffinityMask( Cur_Process, &Current_Affinity, &System_Affinity );
    furthest_affinity = 0x8000000000000000ULL>>__builtin_clzll(Current_Affinity);
    nearest_affinity  = 0x0000000000000001ULL<<__builtin_ctzll(Current_Affinity);
    SetProcessAffinityMask( Cur_Process, furthest_affinity );
    SetThreadAffinityMask( Cur_Thread, furthest_affinity );

    const int repetitions=524288;

    benchmark<repetitions>( nullptr, empty_function );
    benchmark<repetitions>( "Standard Square Root", standard_sqrt );
    benchmark<repetitions>( "Original Guess Square Root", original_guess_sqrt32 );
    benchmark<repetitions>( "New Guess Square Root", new_guess_sqrt32 );


    SetThreadPriority( Cur_Thread, THREAD_PRIORITY_IDLE );
    SetPriorityClass( Cur_Process, IDLE_PRIORITY_CLASS );
    SetProcessAffinityMask( Cur_Process, nearest_affinity );
    SetThreadAffinityMask( Cur_Thread, nearest_affinity );
    for (;;) { getchar(); }

    return 0;
}

Além disso, agradeço a Mike Jarvis por seu Timer.

Observe (isso é muito importante) que, se você estiver executando trechos de código maiores, deverá reduzir o número de iterações para evitar que o computador congele.

Jack Giffin
fonte
2
Boa resposta, exceto para desativar a otimização. Aferição -O0código é um grande desperdício de tempo, porque a sobrecarga de -O0 em vez de um normal, -O2ou -O3 -march=nativevaria descontroladamente dependendo do código e a carga de trabalho. por exemplo, tmp vars com nomes extras custa tempo em -O0. Existem outras maneiras de evitar que as coisas sejam otimizadas, como ocultar coisas do otimizador com volatilefunções não embutidas ou instruções asm embutidas vazias. -O0não está nem perto de ser utilizável porque o código tem gargalos diferentes-O0 , não o mesmo, mas pior.
Peter Cordes
1
Ugh, -Ogainda não é muito realista, dependendo do código. Pelo menos -O2, de preferência -O3é mais realista. Use asm volatile("" ::: "+r"(var))ou algo para fazer o compilador materializar um valor em um registro e impedir a propagação constante por meio dele.
27419 Peter Cordes
@PeterCordes Obrigado novamente por suas idéias. Atualizei o conteúdo com -O3e o trecho de código com asm volatile("" ::: "+r"(var)).
Jack Giffin
1
asm volatile("" ::: "+r"( i ));parece desnecessário. No código otimizado, não há razão para forçar o compilador a se materializar i, bem como i<<7dentro do loop. Você está impedindo a otimização para, em tmp -= 128vez de mudar o tempo todo. Usar o resultado de uma chamada de função é bom, se não for void. Like int result = (*function_to_do)( i << 7 );. Você pode usar uma asmdeclaração sobre esse resultado.
Peter Cordes
@ PeterCordes Muito obrigado novamente ou por suas idéias. Agora, minha postagem contém as correções para o valor de retorno function_to_dopara que function_to_dopossam ser incorporadas sem serem eliminadas. Entre em contato se tiver mais sugestões.
Jack Giffin
1

Para casos em que você deseja cronometrar o mesmo trecho de código toda vez que ele é executado (por exemplo, para criar um perfil de código que você acha que pode ser um gargalo), aqui está um invólucro (uma pequena modificação) da função de Andreas Bonini que eu acho útil:

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#endif

/*
 *  A simple timer class to see how long a piece of code takes. 
 *  Usage:
 *
 *  {
 *      static Timer timer("name");
 *
 *      ...
 *
 *      timer.start()
 *      [ The code you want timed ]
 *      timer.stop()
 *
 *      ...
 *  }
 *
 *  At the end of execution, you will get output:
 *
 *  Time for name: XXX seconds
 */
class Timer
{
public:
    Timer(std::string name, bool start_running=false) : 
        _name(name), _accum(0), _running(false)
    {
        if (start_running) start();
    }

    ~Timer() { stop(); report(); }

    void start() {
        if (!_running) {
            _start_time = GetTimeMicroseconds();
            _running = true;
        }
    }
    void stop() {
        if (_running) {
            unsigned long long stop_time = GetTimeMicroseconds();
            _accum += stop_time - _start_time;
            _running = false;
        }
    }
    void report() { 
        std::cout<<"Time for "<<_name<<": " << _accum / 1.e6 << " seconds\n"; 
    }
private:
    // cf. http://stackoverflow.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
    unsigned long long GetTimeMicroseconds()
    {
#ifdef _WIN32
        /* Windows */
        FILETIME ft;
        LARGE_INTEGER li;

        /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
         *   * to a LARGE_INTEGER structure. */
        GetSystemTimeAsFileTime(&ft);
        li.LowPart = ft.dwLowDateTime;
        li.HighPart = ft.dwHighDateTime;

        unsigned long long ret = li.QuadPart;
        ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
        ret /= 10; /* From 100 nano seconds (10^-7) to 1 microsecond (10^-6) intervals */
#else
        /* Linux */
        struct timeval tv;

        gettimeofday(&tv, NULL);

        unsigned long long ret = tv.tv_usec;
        /* Adds the seconds (10^0) after converting them to microseconds (10^-6) */
        ret += (tv.tv_sec * 1000000);
#endif
        return ret;
    }
    std::string _name;
    long long _accum;
    unsigned long long _start_time;
    bool _running;
};
Mike Jarvis
fonte
1

apenas uma classe simples que compara o código de bloqueio:

using namespace std::chrono;

class benchmark {
  public:
  time_point<high_resolution_clock>  t0, t1;
  unsigned int *d;
  benchmark(unsigned int *res) : d(res) { 
                 t0 = high_resolution_clock::now();
  }
  ~benchmark() { t1 = high_resolution_clock::now();
                  milliseconds dur = duration_cast<milliseconds>(t1 - t0);
                  *d = dur.count();
  }
};
// simple usage 
// unsigned int t;
// { // put the code in a block
//  benchmark bench(&t);
//  // ...
//  // code to benchmark
// }
// HERE the t contains time in milliseconds

// one way to use it can be :
#define BENCH(TITLE,CODEBLOCK) \
  unsigned int __time__##__LINE__ = 0;  \
  { benchmark bench(&__time__##__LINE__); \
      CODEBLOCK \
  } \
  printf("%s took %d ms\n",(TITLE),__time__##__LINE__);


int main(void) {
  BENCH("TITLE",{
    for(int n = 0; n < testcount; n++ )
      int a = n % 3;
  });
  return 0;
}
nullqube
fonte
0

O boost :: timer provavelmente fornecerá a precisão necessária. Não é suficientemente preciso para lhe dizer quanto tempo a = a+1;levará, mas eu que razão você teria para cronometrar algo que leva alguns nanossegundos?

Brendan Long
fonte
Ele se baseia na clock()função do cabeçalho padrão C ++.
Petter
0

Eu criei um lambda que chama a chamada de função N vezes e retorna a média.

double c = BENCHMARK_CNT(25, fillVectorDeque(variable));

Você pode encontrar o cabeçalho do c ++ 11 aqui .

queimador
fonte
0

Criei um utilitário simples para medir o desempenho de blocos de código, usando o high_resolution_clock da biblioteca chrono: https://github.com/nfergu/codetimer .

Os tempos podem ser gravados em diferentes teclas, e uma exibição agregada dos tempos de cada tecla pode ser exibida.

O uso é o seguinte:

#include <chrono>
#include <iostream>
#include "codetimer.h"

int main () {
    auto start = std::chrono::high_resolution_clock::now();
    // some code here
    CodeTimer::record("mykey", start);
    CodeTimer::printStats();
    return 0;
}
Neil
fonte
0

Você também pode olhar no [cxx-rtimers][1]GitHub, que fornece algumas rotinas somente de cabeçalho para coletar estatísticas no tempo de execução de qualquer bloco de código onde você pode criar uma variável local. Esses timers têm versões que usam std :: chrono no C ++ 11, ou timers da biblioteca Boost, ou funções padrão do timer POSIX. Esses temporizadores relatam a duração média, máxima e mínima gasta dentro de uma função, bem como o número de vezes que é chamado. Eles podem ser usados ​​da seguinte maneira:

#include <rtimers/cxx11.hpp>

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensive");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}
rwp
fonte
0

É assim que eu faço, não muito código, fácil de entender, se encaixa nas minhas necessidades:

void bench(std::function<void()> fnBench, std::string name, size_t iterations)
{
    if (iterations == 0)
        return;
    if (fnBench == nullptr)
        return;
    std::chrono::high_resolution_clock::time_point start, end;
    if (iterations == 1)
    {
        start = std::chrono::high_resolution_clock::now();
        fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    else
    {
        start = std::chrono::high_resolution_clock::now();
        for (size_t i = 0; i < iterations; ++i)
            fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    printf
    (
        "bench(*, \"%s\", %u) = %4.6lfs\r\n",
        name.c_str(),
        iterations,
        std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count()
    );
}

Uso:

bench
(
    []() -> void // function
    {
        // Put your code here
    },
    "the name of this", // name
    1000000 // iterations
);
cisco211
fonte
0
#include <omp.h>

double start = omp_get_wtime();

// code 

double finish = omp_get_wtime();

double total_time = finish - start;
Nate Frisch
fonte
2
Embora esse código possa resolver a questão, incluindo uma explicação de como e por que isso resolve o problema realmente ajudaria a melhorar a qualidade da sua postagem e provavelmente resultará em mais votos positivos. Lembre-se de que você está respondendo à pergunta dos leitores no futuro, não apenas à pessoa que está perguntando agora. Por favor edite sua resposta para adicionar explicações e dar uma indicação do que limitações e premissas se aplicam.
Dharman 22/07