Мне нужно вычислить время выполнения фрагмента кода C ++ в секундах. Он должен работать либо на машинах Windows, либо на Unix.
Для этого я использую следующий код. (импорт раньше)
clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;
Однако для небольших вводов или коротких операторов, таких как a = a + 1, я получаю результат «0 секунд». Я думаю, это должно быть что-то вроде 0,0000001 секунды или что-то в этом роде.
Я помню, что System.nanoTime()
на Java в этом случае неплохо работает. Однако я не могу получить такую же точную функциональность от clock()
функции C ++.
У тебя есть решение?
c++
benchmarking
AhmetB - Google
источник
источник
Ответы:
Вы можете использовать эту функцию, которую я написал. Вы вызываете
GetTimeMs64()
, и он возвращает количество миллисекунд, прошедших с эпохи unix, используя системные часы - точно так жеtime(NULL)
, за исключением миллисекунд.Он работает как в Windows, так и в Linux; это потокобезопасный.
Обратите внимание, что степень детализации для окон составляет 15 мс; в Linux это зависит от реализации, но обычно это также 15 мс.
источник
gettimeofday
может дать непредвиденный результат при изменении системных часов. Если это будет проблемой для вас, вы можетеclock_gettime
вместо этого взглянуть .GetTickCount
?gcc -std=c99
GetTickCount
это время, прошедшее с момента запуска системы, а моя функция возвращает время с эпохи UNIX, что означает, что вы можете использовать ее для даты и времени. Если вас интересует только время, прошедшее между двумя событиями, мой вариант все равно будет лучшим выбором, потому что это int64; GetTickCount - это тип int32, который переполняется каждые 50 дней, что означает, что вы можете получить странные результаты, если два зарегистрированных вами события находятся между переполнением.У меня есть еще один рабочий пример, в котором используются микросекунды (UNIX, POSIX и т. Д.).
Вот файл, в котором мы это закодировали:
https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c
источник
#include <sys/time.h>
в начале вашего примера.Вот простое решение на C ++ 11, которое дает удовлетворительное разрешение.
Или на * nix, для c ++ 03
Вот пример использования:
С https://gist.github.com/gongzhitaao/7062087
источник
/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
Когда он
progress_timer
выходит за пределы области видимости, он распечатывает время, прошедшее с момента его создания.ОБНОВЛЕНИЕ : вот версия, которая работает без Boost (проверена на macOS / iOS):
источник
Windows предоставляет функцию QueryPerformanceCounter (), а Unix имеет gettimeofday (). Обе функции могут измерять разницу минимум в 1 микросекунду.
источник
#ifdef
должен быть в порядке (и это , судя по ответу вы приняли), и тогда я не вижу проблемы:#ifdef WIN32 #include <windows.h> ... #else ... #endif
.В некоторых программах, которые я написал, я использовал для этой цели RDTS . RDTSC - это не время, а количество циклов от запуска процессора. Вы должны откалибровать его в своей системе, чтобы получить результат за секунду, но это действительно удобно, когда вы хотите оценить производительность, даже лучше использовать количество циклов напрямую, не пытаясь вернуть их к секундам.
(ссылка выше - на страницу французской Википедии, но в ней есть примеры кода C ++, английская версия здесь )
источник
Я предлагаю использовать стандартные библиотечные функции для получения информации о времени из системы.
Если вам нужно более точное разрешение, выполните больше итераций выполнения. Вместо того чтобы запускать программу один раз и получать образцы, запустите ее 1000 или более раз.
источник
Лучше запустить внутренний цикл несколько раз с синхронизацией производительности только один раз и усреднить, разделив повторения внутреннего цикла, чем запускать все это (цикл + время производительности) несколько раз и в среднем. Это уменьшит накладные расходы на код времени производительности по сравнению с вашим фактическим профилированным разделом.
Оберните вызовы таймера для соответствующей системы. Для Windows QueryPerformanceCounter довольно быстр и «безопасен» в использовании.
Вы также можете использовать «rdtsc» на любом современном ПК с X86, но могут возникнуть проблемы на некоторых многоядерных машинах (переключение ядра может изменить таймер) или если у вас включен какой-либо шаг скорости.
источник
(решение для Windows) Текущий (около 2017 г.) способ получить точные тайминги под окнами - использовать «QueryPerformanceCounter». Этот подход дает очень точные результаты и рекомендуется MS. Просто вставьте большой двоичный код в новое консольное приложение, чтобы получить рабочий образец. Здесь идет продолжительное обсуждение: Получение меток времени с высоким разрешением
источник
Полное безошибочное решение для планирования потоков, которое должно давать одинаковое время для каждого теста, - это скомпилировать вашу программу так, чтобы она не зависела от ОС, и загрузила компьютер, чтобы запустить программу в среде, свободной от ОС. Тем не менее, это в значительной степени непрактично и в лучшем случае будет затруднительно.
Хорошая замена отказу от ОС - просто установить привязку текущего потока к 1 ядру, а приоритет - к наивысшему. Эта альтернатива должна обеспечивать достаточно последовательные результаты.
Также вам следует отключить оптимизацию, которая может мешать отладке, что для g ++ или gcc означает добавление
-Og
в командную строку , чтобы предотвратить оптимизацию тестируемого кода.-O0
Флаг не следует использовать , поскольку он вводит дополнительные ненужные накладные расходы , которые будут включены в результатах синхронизации, тем самым искажая таймерную скорость кода.Напротив, оба предположения, что вы используете
-Ofast
(или, по крайней мере,-O3
) в окончательной производственной сборке, и игнорирование проблемы удаления «мертвого» кода,-Og
выполняют очень мало оптимизаций по сравнению с-Ofast
; таким образом-Og
может искажать реальную скорость кода в конечном продукте.Кроме того, все тесты скорости (до некоторой степени) лжесвидетельствуют: в конечном продукте, скомпилированном с помощью
-Ofast
, каждый фрагмент / раздел / функция кода не изолирован; скорее, каждый фрагмент кода непрерывно перетекает в следующий, что позволяет компилятору потенциально объединять, объединять и оптимизировать фрагменты кода из любого места.В то же время, если вы тестируете фрагмент кода, который интенсивно использует
realloc()
, то этот фрагмент кода может работать медленнее в производственном продукте с достаточно высокой фрагментацией памяти. Следовательно, выражение «целое - это больше, чем сумма его частей» применимо к этой ситуации, потому что код в окончательной производственной сборке может работать заметно быстрее или медленнее, чем отдельный фрагмент, который вы тестируете на скорость.Частичное решение, которое может уменьшить несоответствие, - это использование
-Ofast
для тестирования скорости с добавлениемasm volatile("" :: "r"(var))
к переменным, участвующим в тесте, для предотвращения мертвого кода / устранения цикла.Вот пример того, как протестировать функции квадратного корня на компьютере с Windows.
Также благодарю Майка Джарвиса за его таймер.
Обратите внимание (это очень важно), что если вы собираетесь запускать большие фрагменты кода, вам действительно необходимо уменьшить количество итераций, чтобы ваш компьютер не завис.
источник
-O0
кода является большой тратой времени , так как накладные расходы ,-O0
а не нормальным-O2
или-O3 -march=native
изменяется дико в зависимости от кода и нагрузки. например, дополнительные именованные переменные tmp требуют времени-O0
. Есть и другие способы избежать оптимизации, например, скрытие чего-либо от оптимизатора с помощьюvolatile
не встроенных функций или пустых встроенных операторов asm.-O0
даже близко не к пригодному для использования, потому что у кода есть другие узкие места-O0
, не такие же, а хуже.-Og
все равно не очень реально, в зависимости от кода. По крайней мере-O2
, желательно-O3
более реалистично. Используйтеasm volatile("" ::: "+r"(var))
или что-то еще, чтобы компилятор материализовал значение в регистре и предотвратил распространение констант через него.-O3
и фрагмент кода с помощьюasm volatile("" ::: "+r"(var))
.asm volatile("" ::: "+r"( i ));
кажется ненужным. В оптимизированном коде нет причин заставлять компилятор материализоватьсяi
так же хорошо, какi<<7
внутри цикла. Вы останавливаете его оптимизацию,tmp -= 128
вместо того, чтобы каждый раз переключаться. Однако использование результата вызова функции хорошо, если это не такvoid
. Нравитсяint result = (*function_to_do)( i << 7 );
. Вы можете использоватьasm
заявление об этом результате.function_to_do
чтобы егоfunction_to_do
можно было встроить без удаления. Пожалуйста, дайте мне знать, если у вас есть дополнительные предложения.Для случаев, когда вы хотите синхронизировать один и тот же участок кода каждый раз, когда он запускается (например, для кода профилирования, который, по вашему мнению, может быть узким местом), вот оболочка (небольшая модификация) функции Андреаса Бонини, которую я считаю полезной:
источник
просто простой класс, который тестирует кодовый блок:
источник
boost :: timer , вероятно, даст вам столько точности, сколько вам нужно. Он далеко не настолько точен, чтобы сказать вам, сколько времени
a = a+1;
займет время, но почему вы должны рассчитывать время для того, что занимает пару наносекунд?источник
clock()
функцию из стандартного заголовка C ++.Я создал лямбду, которая вызывает вызов функции N раз и возвращает среднее значение.
Вы можете найти C ++ 11 заголовка здесь .
источник
Я создал простую утилиту для измерения производительности блоков кода, используя high_resolution_clock библиотеки chrono: https://github.com/nfergu/codetimer .
Тайминги могут быть записаны для разных клавиш, и может быть отображен агрегированный вид таймингов для каждой клавиши.
Использование следующее:
источник
Вы также можете посмотреть
[cxx-rtimers][1]
на GitHub, который предоставляет некоторые подпрограммы только для заголовков для сбора статистики во время выполнения любого блока кода, где вы можете создать локальную переменную. У этих таймеров есть версии, которые используют std :: chrono на C ++ 11, или таймеры из библиотеки Boost, или стандартные функции таймера POSIX. Эти таймеры сообщают о средней, максимальной и минимальной продолжительности, затраченной на функцию, а также о количестве ее вызовов. Их можно использовать следующим образом:источник
Вот как я это делаю, мало кода, легко понять, соответствует моим потребностям:
Использование:
источник
источник