2010-02-19 22 views

Respuesta

4

Implementé un temporizador para situaciones como esta antes: en realidad terminé con una clase con dos implementaciones diferentes, una para Windows y otra para POSIX.

La razón es que Windows tiene la función QueryPerformanceCounter() que le da acceso a un reloj muy preciso que es ideal para tales tiempos.

En POSIX, sin embargo, esto no está disponible, así que acabo de utilizar las clases boost.datetime para almacenar las horas de inicio y finalización, y luego calculé la duración de esas. Ofrece un temporizador de "alta resolución", pero la resolución no está definida y varía de una plataforma a otra.

1

temporizadores de alta precisión dependen de la plataforma y por tanto no son especificados por el estándar de C++, pero hay bibliotecas disponibles. Ver this question para una discusión.

0

Esto podría ser un problema dependiente del sistema operativo en lugar de un problema de idioma.

Si estás en Windows, entonces puede acceder a un temporizador milisegundos de 10 a 16 milisegundos a través GetTickCount() o GetTickCount64(). Solo llámalo una vez al comienzo y una vez al final, y reste.

Eso era lo que usaba antes si recuerdo correctamente. La página enlazada también tiene otras opciones.

+0

¿El GetTickCount() utiliza QueryPerformanceCounter() debajo de la campana o? – Mithrax

+0

Eso no lo sé. Agregué un enlace a la página GetTickCount() y parece que tiene otras opciones, probablemente mejores, basadas en lo que hay allí. – John

+0

No. GetTickCount() es inexacto. Si quiere un recuento preciso, debe usar QueryPerformanceCounter() (EDITAR: por inexacto quiero decir +/- 10ms) –

0
#include <time.h> 

clock_t start, end; 
start = clock(); 
//Do stuff 
end = clock(); 

printf("Took: %f\n", (float)((end - start)/(float)CLOCKS_PER_SEC)); 
+0

Esto funcionaría pero la resolución será pobre. –

+0

Esto no funcionaría realmente para medir el tiempo absoluto, ya que 'clock()' solo devuelve el tiempo de CPU que ** tomó su código **. Por lo tanto, si reemplaza '\\ Do stuff' con' usleep (1000000) ', el printf devolverá 0.0000 segundos en lugar de 1 segundo. – CodingAway

3

uso mi propia versión de la función de Python time_it. La ventaja de esta función es que repite un cálculo tantas veces como sea necesario para obtener resultados significativos. Si el cálculo es muy rápido, se repetirá muchas veces. Al final, obtienes el tiempo promedio de todas las repeticiones. No utiliza ninguna funcionalidad no estándar:

#include <ctime> 

double clock_diff_to_sec(long clock_diff) 
{ 
    return double(clock_diff)/CLOCKS_PER_SEC; 
} 

template<class Proc> 
double time_it(Proc proc, int N=1) // returns time in microseconds 
{ 
    std::clock_t const start = std::clock(); 
    for(int i = 0; i < N; ++i) 
     proc(); 
    std::clock_t const end = std::clock(); 
    if(clock_diff_to_sec(end - start) < .2) 
     return time_it(proc, N * 5); 
    return clock_diff_to_sec(end - start) * (1e6/N); 
} 

el siguiente ejemplo se utiliza la función time_it para medir el desempeño de los diferentes contenedores STL:

void dummy_op(int i) 
{ 
    if(i == -1) 
     std::cout << i << "\n"; 
} 

template<class Container> 
void test(Container const & c) 
{ 
    std::for_each(c.begin(), c.end(), &dummy_op); 
} 

template<class OutIt> 
void init(OutIt it) 
{ 
    for(int i = 0; i < 1000; ++i) 
     *it = i; 
} 

int main(int argc, char ** argv) 
{ 
    { 
     std::vector<int> c; 
     init(std::back_inserter(c)); 
     std::cout << "vector: " 
        << time_it(boost::bind(&test<std::vector<int> >, c)) << "\n"; 
    }  
    { 
     std::list<int> c; 
     init(std::back_inserter(c)); 
     std::cout << "list: " 
        << time_it(boost::bind(&test<std::list<int> >, c)) << "\n"; 
    } 
    { 
     std::deque<int> c; 
     init(std::back_inserter(c)); 
     std::cout << "deque: " 
        << time_it(boost::bind(&test<std::deque<int> >, c)) << "\n"; 
    } 
    { 
     std::set<int> c; 
     init(std::inserter(c, c.begin())); 
     std::cout << "set: " 
        << time_it(boost::bind(&test<std::set<int> >, c)) << "\n"; 
    } 
    { 
     std::tr1::unordered_set<int> c; 
     init(std::inserter(c, c.begin())); 
     std::cout << "unordered_set: " 
      << time_it(boost::bind(&test<std::tr1::unordered_set<int> >, c)) << "\n"; 
    }  
} 

En caso de que alguien es curioso aquí es la salida I Get (compilado con VS2008 en modo de lanzamiento):

vectorial: 8,7168

lista: 27,776

deque: 91,52

conjunto: 103,04

unordered_set: 29.76

+0

Muy interesante. ¡Tanto para la función de sincronización como para la información sobre el containter diferente! Gracias. – Morlock

+0

@Morlock - ¡Gracias! Tomaría los tiempos con un poco de sal, 'std :: deque' se comporta terriblemente en esta prueba, pero estoy seguro de que, en general, no es tan malo. – Manuel

3

Utilicé boost::timer para medir la duración de una operación. Proporciona una manera muy fácil de hacer la medición y, al mismo tiempo, ser independiente de la plataforma. Aquí hay un ejemplo:

boost::timer myTimer; 
doOperation(); 
std::cout << myTimer.elapsed(); 

P.S. Para superar los errores de precisión, sería genial medir las operaciones que toman unos segundos. Especialmente cuando intentas comparar varias alternativas. Si quiere medir algo que lleva muy poco tiempo, intente ponerlo en un bucle. Por ejemplo, ejecute la operación 1000 veces y luego divida el tiempo total entre 1000.

0

Puede encontrar la clase útil this.

Utilizando la expresión RAII, imprime el texto dado en la construcción cuando se llama al destructor, rellenando el marcador de posición del tiempo transcurrido con el valor adecuado.

Ejemplo de uso:

int main() 
{ 
    trace_elapsed_time t("Elapsed time: %ts.\n"); 
    usleep(1.005 * 1e6); 
} 

Salida:

Elapsed time: 1.00509s. 
1

Humildemente presento mi propia micro-benchmarking mini-library (on Github). Es súper simple: la única ventaja que tiene sobre su propio rendimiento es que ya tiene el código de temporizador de alto rendimiento implementado para Windows y Linux, y abstrae el texto repetitivo molesto.

Simplemente pase en una función (o lambda), el número de veces que debe llamarse por ejecución de prueba (predeterminado: 1), y el número de ejecuciones de prueba (predeterminado: 100). La prueba de funcionamiento más rápido (medido en milisegundos fraccionarios) se devuelve:

// Example that times the compare-and-swap atomic operation from C++11 
// Sample GCC command: g++ -std=c++11 -DNDEBUG -O3 -lrt main.cpp microbench/systemtime.cpp -o bench 
#include "microbench/microbench.h" 

#include <cstdio> 
#include <atomic> 

int main() 
{ 
    std::atomic<int> x(0); 
    int y = 0; 

    printf("CAS takes %.4fms to execute 100000 iterations\n", 
     moodycamel::microbench(
      [&]() { x.compare_exchange_strong(y, 0); }, /* function to benchmark */ 
      100000, /* iterations per test run */ 
      100 /* test runs */ 
     ) 
    ); 

    // Result: Clocks in at 1.2ms (12ns per CAS operation) in my environment 

    return 0; 
} 
Cuestiones relacionadas