2010-02-19 3 views

ответ

4

Я реализовал таймер для подобных ситуаций раньше: на самом деле у меня был класс с двумя различными реализациями: один для Windows и один для POSIX.

Причина в том, что Windows имеет функцию QueryPerformanceCounter(), которая дает вам доступ к очень точным часам, которые идеально подходят для таких таймингов.

В POSIX, однако, это недоступно, поэтому я просто использовал классы boost.datetime для хранения начального и конечного времени, а затем рассчитал продолжительность от них. Он предлагает таймер с высоким разрешением, но разрешение не определено и варьируется от платформы к платформе.

1

Высокоточные таймеры конкретной платформы и поэтому не определены в стандарте C++, но есть библиотеки доступны. См. this question для обсуждения.

0

Это может быть проблема, зависящая от ОС, а не проблема языка.

Если вы на Windows, то вы можете получить доступ к миллисекунды 10- до 16-миллисекунды таймер через GetTickCount() или GetTickCount64(). Просто назовите его один раз в начале и один раз в конце и вычтите.

Это было то, что я использовал раньше, если я правильно помню. На связанной странице есть и другие варианты.

+0

ли GetTickCount() использовать QueryPerformanceCounter() под капотом или? – Mithrax

+0

Этого я не знаю. Я добавил ссылку на страницу GetTickCount(), и похоже, что у вас есть другие, возможно лучшие варианты, основанные на том, что там есть. – John

+0

№ GetTickCount() неточно. Если вам нужен точный счет, вы должны использовать QueryPerformanceCounter() (EDIT: неточно я имею в виду +/- 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

Это будет работать, но резолюция будет плохой. –

+0

Это фактически не работает для измерения абсолютного времени, так как 'clock()' возвращает только время процессора, которое ** ваш ** код взял. Поэтому, если вы замените '\\ Do stuff'' usleep (1000000) 'printf вернет 0.0000 секунд вместо 1 секунды. – CodingAway

3

Я использую свою собственную версию функции time_it Python. Преимущество этой функции заключается в том, что она повторяет вычисление столько раз, сколько необходимо для получения значимых результатов. Если вычисление происходит очень быстро, оно будет повторяться много раз. В итоге вы получаете среднее время всех повторений. Он не использует нестандартную функциональность:

#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); 
} 

Следующий пример использует функцию time_it для измерения производительности различных контейнеров 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"; 
    }  
} 

В случае кому-то интересно вот я вывожу получить (скомпилирован с VS2008 в режиме выпуска):

вектор: 8,7168

список: 27,776

Deque: 91,52

набор: 103,04

unordered_set: 29.76

+0

Очень интересно. Как для функции синхронизации, так и для проницательности в отношении разных сдерживающих устройств! Спасибо. – Morlock

+0

@Morlock - Спасибо! Я бы взял тайминги с щепоткой солида, 'std :: deque' ведет себя ужасно в этом тесте, но я уверен, что в общем случае это не так уж плохо. – Manuel

3

Я использовал boost::timer для измерения продолжительности операции. Он обеспечивает очень простой способ измерения и в то же время независимый от платформы. Вот пример:

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

P.S. Чтобы преодолеть прецизионные ошибки, было бы здорово измерить операции, которые занимают несколько секунд. Особенно, когда вы пытаетесь сравнить несколько альтернатив. Если вы хотите измерить что-то, что занимает очень мало времени, попробуйте поместить его в цикл. Например, запустите операцию 1000 раз, а затем разделите общее время на 1000.

0

Вы можете найти полезный this класс.

Используя идиом RAII, он печатает текст, указанный в конструкции, когда вызывается деструктор, заполняя заполненную временную метку надлежащим значением.

Пример использования:

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

Выход:

Elapsed time: 1.00509s. 
1

я смиренно представить свой собственный micro-benchmarking mini-library (on Github). Это очень просто - единственное преимущество, которое у него есть, сводится к тому, что у него уже есть высокопроизводительный таймер, реализованный для Windows и Linux, и абстрагирует от раздражающего шаблона.

Просто передайте функцию (или лямбда), количество раз, которое должно быть вызвано для каждого тестового прогона (по умолчанию: 1), и количество тестовых прогонов (по умолчанию: 100). Самый быстрый испытательный пробег (измеряется в дробных миллисекундах) возвращается:

// 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; 
} 
Смежные вопросы