Я хочу рассчитать время, необходимое API для возврата значения. Время, необходимое для такого действия, составляет наносекунды. Поскольку API - это класс / функция C ++, я использую timer.h, чтобы вычислить то же самое:
#include <ctime>
#include <cstdio>
using namespace std;
int main(int argc, char** argv) {
clock_t start;
double diff;
start = clock();
diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
cout<<"printf: "<< diff <<'\n';
return 0;
}
Приведенный выше код показывает время в секундах. Как добиться того же за наносекунды и с большей точностью?
clock()
это не так быстро, как я думал.Ответы:
То, что другие писали о многократном запуске функции в цикле, является правильным.
Для Linux (и BSD) вы хотите использовать clock_gettime () .
Для окон вы хотите использовать QueryPerformanceCounter . А вот еще о QPC
По-видимому, существует известная проблема с QPC на некоторых наборах микросхем, поэтому вы можете убедиться, что у вас нет этого набора микросхем. Кроме того, некоторые двухъядерные процессоры AMD также могут вызывать проблемы . См. Второй пост Себбби, где он заявляет:
РЕДАКТИРОВАТЬ 2013/07/16:
Похоже, что есть некоторые разногласия относительно эффективности QPC при определенных обстоятельствах, как указано в http://msdn.microsoft.com/en-us/library/windows/desktop/ee417693(v=vs.85).aspx
Однако в этом ответе StackOverflow https://stackoverflow.com/a/4588605/34329 говорится, что QPC должен нормально работать на любой ОС MS после пакета обновления 2 для Win XP.
В этой статье показано, что Windows 7 может определить, имеет ли процессор (-ы) инвариантный TSC, и откатится к внешнему таймеру, если этого не произошло. http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html Синхронизация между процессорами по-прежнему остается проблемой.
Другое хорошее чтение, связанное с таймерами:
См. Комментарии для более подробной информации.
источник
CLOCK_MONOTONIC_RAW
, если это возможно, чтобы получить аппаратное время, не регулируемое NTP.Этот новый ответ использует возможности C ++ 11
<chrono>
. Хотя есть и другие ответы, которые показывают, как использовать<chrono>
, ни один из них не показывает, как использовать<chrono>
сRDTSC
средством, упомянутым в нескольких других ответах здесь. Я подумал, что покажу, как использоватьRDTSC
с<chrono>
. Кроме того, я продемонстрирую, как вы можете шаблонизировать тестовый код на часах, чтобы вы могли быстро переключаться междуRDTSC
и встроенными средствами синхронизации вашей системы (которые, вероятно, будут основаны наclock()
,clock_gettime()
и / илиQueryPerformanceCounter
.Обратите внимание, что
RDTSC
инструкция предназначена для x86.QueryPerformanceCounter
есть только Windows. Иclock_gettime()
только POSIX. Ниже я представляю два новых тактовых генератора:std::chrono::high_resolution_clock
иstd::chrono::system_clock
, которые, если предположить C ++ 11, теперь являются кроссплатформенными.Во-первых, вот как вы создаете часы, совместимые с C ++ 11, из
rdtsc
инструкции по сборке Intel . Я назову этоx::clock
:Все эти часы подсчитывают циклы процессора и сохраняют их в виде 64-битного целого числа без знака. Возможно, вам потребуется настроить синтаксис языка ассемблера для вашего компилятора. Или ваш компилятор может предложить встроенную функцию, которую вы можете использовать вместо этого (например
now() {return __rdtsc();}
).Чтобы построить часы, вы должны дать им представление (тип хранилища). Вы также должны указать период тактовой частоты, который должен быть постоянной времени компиляции, даже если ваша машина может изменять тактовую частоту в различных режимах питания. И по ним вы можете легко определить «родную» продолжительность и точку времени своих часов с точки зрения этих основ.
Если все, что вы хотите сделать, это вывести количество тактов часов, на самом деле не имеет значения, какое число вы укажете для периода времени. Эта константа используется только в том случае, если вы хотите преобразовать количество тактов часов в некоторую единицу реального времени, такую как наносекунды. И в этом случае, чем точнее вы сможете указать тактовую частоту, тем точнее будет преобразование в наносекунды (миллисекунды и т. Д.).
Ниже приведен пример кода, который показывает, как использовать
x::clock
. На самом деле я создал шаблон кода для часов, поскольку хочу показать, как можно использовать много разных часов с одним и тем же синтаксисом. Этот конкретный тест показывает, какие накладные расходы возникают при выполнении того, что вы хотите выполнить в цикле:Первое, что делает этот код, - это создает единицу измерения «реального времени» для отображения результатов. Я выбрал пикосекунды, но вы можете выбрать любые единицы, которые вам нравятся, либо целые, либо с плавающей запятой. В качестве примера есть готовое
std::chrono::nanoseconds
устройство, которое я мог бы использовать.В качестве другого примера я хочу распечатать среднее количество тактовых циклов на итерацию как число с плавающей запятой, поэтому я создаю другую длительность, основанную на double, которая имеет те же единицы, что и тик часов (вызывается
Cycle
в коде).Цикл рассчитан на вызовы с
clock::now()
обеих сторон. Если вы хотите назвать тип, возвращаемый этой функцией, это:(как ясно показано в
x::clock
примере, а также для системных часов).Чтобы получить длительность в виде тактов часов с плавающей запятой, нужно просто вычесть две точки времени, а для получения значения на итерацию разделить эту продолжительность на количество итераций.
Вы можете получить счет за любую продолжительность, используя
count()
функцию-член. Это возвращает внутреннее представление. Наконец, я использую,std::chrono::duration_cast
чтобы преобразовать продолжительностьCycle
в продолжительностьpicoseconds
и распечатать это.Использовать этот код просто:
Выше я проверил тест, используя наши самодельные
x::clock
часы, и сравнил эти результаты с использованием двух системных часов:std::chrono::high_resolution_clock
иstd::chrono::system_clock
. Для меня это распечатывает:Это показывает, что у каждого из этих часов есть свой период тика, поскольку тики на итерацию сильно различаются для каждого времени. Однако при преобразовании в известную единицу времени (например, пикосекунды) я получаю примерно одинаковый результат для каждых часов (ваш пробег может отличаться).
Обратите внимание на то, что мой код полностью свободен от «магических констант преобразования». Действительно, во всем примере всего два магических числа:
x::clock
.источник
rdtsc
Часы, вероятно, будут иметь неточные преобразования в другие единицы. Рекомендуется настроить измерения таким образом, чтобы вы могли легко изменять и сравнивать часы (как показано в этом ответе).С таким уровнем точности было бы лучше рассуждать в тике ЦП, а не в системном вызове, таком как clock () . И не забывайте, что если для выполнения инструкции требуется более одной наносекунды ... получение точности с наносекундной точностью практически невозможно.
Тем не менее, что-то вроде этого - начало:
Вот фактический код для получения количества тактов процессора 80x86, прошедших с момента последнего запуска процессора. Он будет работать на Pentium и выше (386/486 не поддерживается). Этот код на самом деле специфичен для MS Visual C ++, но его, вероятно, очень легко перенести на что-нибудь еще, если он поддерживает встроенную сборку.
Эта функция также имеет то преимущество, что она очень быстрая - обычно для ее выполнения требуется не более 50 циклов процессора.
Использование цифр времени :
если вам нужно перевести счетчики часов в истинное истекшее время, разделите результаты на тактовую частоту вашего чипа. Помните, что "номинальная" частота ГГц может немного отличаться от реальной скорости вашего чипа. Чтобы проверить истинную скорость вашего чипа, вы можете использовать несколько очень хороших утилит или вызов Win32, QueryPerformanceFrequency ().
источник
Чтобы сделать это правильно, вы можете использовать один из двух способов: пойти с
RDTSC
или сclock_gettime()
. Второй примерно в 2 раза быстрее и дает точное абсолютное время. Обратите внимание, что дляRDTSC
правильной работы вам необходимо использовать его, как указано (другие комментарии на этой странице содержат ошибки и могут давать неверные значения времени на определенных процессорах)и для clock_gettime: (я произвольно выбрал микросекундное разрешение)
сроки и произведенные ценности:
источник
Для получения желаемых результатов я использую следующее:
источник
Для C ++ 11 вот простая оболочка:
Или для C ++ 03 на * nix,
Пример использования:
С https://gist.github.com/gongzhitaao/7062087
источник
В общем, чтобы определить время, необходимое для вызова функции, вам нужно сделать это гораздо чаще, чем один раз. Если вы вызываете свою функцию только один раз и для ее выполнения требуется очень короткое время, у вас все еще есть накладные расходы на фактический вызов функций таймера, и вы не знаете, сколько времени это займет.
Например, если вы оцениваете, что выполнение вашей функции может занять 800 нс, вызовите ее в цикле десять миллионов раз (что тогда займет около 8 секунд). Разделите общее время на десять миллионов, чтобы получить время на звонок.
источник
Вы можете использовать следующую функцию с gcc, работающим на процессорах x86:
с Digital Mars C ++:
который считывает высокопроизводительный таймер на чипе. Я использую это при профилировании.
источник
unsigned int
как внутренний тип.Если вам нужна субсекундная точность, вам нужно использовать системные расширения, и вам придется сверяться с документацией для операционной системы. POSIX поддерживает до микросекунд с gettimeofday , но ничего более точного, поскольку компьютеры не имеют частот выше 1 ГГц.
Если вы используете Boost, вы можете проверить boost :: posix_time .
источник
Я использую код Borland, вот код ti_hund иногда дает мне отрицательное число, но время довольно хорошее.
источник
Используя метод Брока Адамса с простым классом:
Пример использования:
Результат:
тест занял: 0,0002 мс
Есть некоторые накладные расходы на вызов функции, но все равно должно быть более чем достаточно быстро :)
источник
Вы можете использовать Embedded Profiler (бесплатно для Windows и Linux), который имеет интерфейс для мультиплатформенного таймера (в счетчике циклов процессора) и может дать вам количество циклов в секунду:
Пересчет количества циклов во время, возможно, опасная операция для современных процессоров, где частота процессора может изменяться динамически. Поэтому, чтобы быть уверенным в правильности пересчета времени, необходимо перед профилированием зафиксировать частоту процессора.
источник
Если это для Linux, я использовал функцию "gettimeofday", которая возвращает структуру, которая дает секунды и микросекунды с эпохи. Затем вы можете использовать timersub, чтобы вычесть два, чтобы получить разницу во времени, и преобразовать ее в нужную вам точность времени. Однако вы указываете наносекунды, и похоже, что функция clock_gettime () - это то, что вы ищете. Он помещает время в секунды и наносекунды в структуру, которую вы в нее передаете.
источник
Что ты об этом думаешь:
источник
Вот хороший таймер Boost, который хорошо работает:
источник
Минималистичная структура копирования и вставки + ленивое использование
Если идея состоит в том, чтобы иметь минималистичную структуру, которую вы можете использовать для быстрых тестов, то я предлагаю вам просто скопировать и вставить в любом месте вашего файла C ++ сразу после
#include
. Это единственный случай, когда я жертвую форматированием в стиле Allman.Вы можете легко настроить точность в первой строке структуры. Возможные значения:
nanoseconds
,microseconds
,milliseconds
,seconds
,minutes
, илиhours
.использование
Стандартный выходной результат
Если вам нужна сводка после казни
Если вы хотите получить отчет позже, потому что, например, ваш промежуточный код также записывает в стандартный вывод. Затем добавьте в структуру следующую функцию (непосредственно перед MeasureTime ()):
Итак, вы можете просто использовать:
В нем будут перечислены все отметки, как и раньше, но затем после выполнения другого кода. Обратите внимание, что вы не должны использовать оба
m.s()
иm.t()
.источник