В C# я бы запустил класс Секундомер, чтобы сделать некоторые быстро и грязно, как долго некоторые методы берут.Каков наилучший способ узнать, как долго длится функция на C++?
Что эквивалентно этому в C++? Есть ли встроенный таймер высокой точности?
В C# я бы запустил класс Секундомер, чтобы сделать некоторые быстро и грязно, как долго некоторые методы берут.Каков наилучший способ узнать, как долго длится функция на C++?
Что эквивалентно этому в C++? Есть ли встроенный таймер высокой точности?
Я реализовал таймер для подобных ситуаций раньше: на самом деле у меня был класс с двумя различными реализациями: один для Windows и один для POSIX.
Причина в том, что Windows имеет функцию QueryPerformanceCounter()
, которая дает вам доступ к очень точным часам, которые идеально подходят для таких таймингов.
В POSIX, однако, это недоступно, поэтому я просто использовал классы boost.datetime для хранения начального и конечного времени, а затем рассчитал продолжительность от них. Он предлагает таймер с высоким разрешением, но разрешение не определено и варьируется от платформы к платформе.
Вы можете использовать ctime library, чтобы получить время в секундах. Получение времени в миллисекундах зависит от реализации. Here is a discussion Изучение некоторых способов сделать это.
Смотрите также: How to measure time in milliseconds using ANSI C?
Высокоточные таймеры конкретной платформы и поэтому не определены в стандарте C++, но есть библиотеки доступны. См. this question для обсуждения.
Это может быть проблема, зависящая от ОС, а не проблема языка.
Если вы на Windows, то вы можете получить доступ к
миллисекунды
10- до 16-миллисекунды таймер через GetTickCount() или GetTickCount64(). Просто назовите его один раз в начале и один раз в конце и вычтите.
Это было то, что я использовал раньше, если я правильно помню. На связанной странице есть и другие варианты.
#include <time.h>
clock_t start, end;
start = clock();
//Do stuff
end = clock();
printf("Took: %f\n", (float)((end - start)/(float)CLOCKS_PER_SEC));
Это будет работать, но резолюция будет плохой. –
Это фактически не работает для измерения абсолютного времени, так как 'clock()' возвращает только время процессора, которое ** ваш ** код взял. Поэтому, если вы замените '\\ Do stuff'' usleep (1000000) 'printf вернет 0.0000 секунд вместо 1 секунды. – CodingAway
Я использую свою собственную версию функции 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
Очень интересно. Как для функции синхронизации, так и для проницательности в отношении разных сдерживающих устройств! Спасибо. – Morlock
@Morlock - Спасибо! Я бы взял тайминги с щепоткой солида, 'std :: deque' ведет себя ужасно в этом тесте, но я уверен, что в общем случае это не так уж плохо. – Manuel
Я использовал boost::timer для измерения продолжительности операции. Он обеспечивает очень простой способ измерения и в то же время независимый от платформы. Вот пример:
boost::timer myTimer;
doOperation();
std::cout << myTimer.elapsed();
P.S. Чтобы преодолеть прецизионные ошибки, было бы здорово измерить операции, которые занимают несколько секунд. Особенно, когда вы пытаетесь сравнить несколько альтернатив. Если вы хотите измерить что-то, что занимает очень мало времени, попробуйте поместить его в цикл. Например, запустите операцию 1000 раз, а затем разделите общее время на 1000.
Вы можете найти полезный this класс.
Используя идиом RAII, он печатает текст, указанный в конструкции, когда вызывается деструктор, заполняя заполненную временную метку надлежащим значением.
Пример использования:
int main()
{
trace_elapsed_time t("Elapsed time: %ts.\n");
usleep(1.005 * 1e6);
}
Выход:
Elapsed time: 1.00509s.
я смиренно представить свой собственный 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;
}
ли GetTickCount() использовать QueryPerformanceCounter() под капотом или? – Mithrax
Этого я не знаю. Я добавил ссылку на страницу GetTickCount(), и похоже, что у вас есть другие, возможно лучшие варианты, основанные на том, что там есть. – John
№ GetTickCount() неточно. Если вам нужен точный счет, вы должны использовать QueryPerformanceCounter() (EDIT: неточно я имею в виду +/- 10ms) –