Функция таймера для обеспечения времени в нано секундах с помощью C++
Я хочу рассчитать время, которое потребовалось для API, чтобы вернуть значение. Время, необходимое для такого действия, находится в пространстве нано секунд. Поскольку API-это класс/функция C++, я использую таймер.h для того чтобы caculate то же самое:
#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;
}
приведенный выше код дает время в секундах. Как я могу получить то же самое в нано секундах и с большей точностью?
2 ответа:
то, что другие опубликовали о повторном запуске функции в цикле, является правильным.
для Linux (и BSD) вы хотите использовать при успешном выполнении функции clock_gettime().
#include <sys/time.h> int main() { timespec ts; // clock_gettime(CLOCK_MONOTONIC, &ts); // Works on FreeBSD clock_gettime(CLOCK_REALTIME, &ts); // Works on Linux }
для windows вы хотите использовать QueryPerformanceCounter. И вот еще на QPC
по-видимому, существует известная вопрос С QPC на некоторых чипсетах, поэтому вы можете убедиться, что у вас нет этих чипсетов. Кроме того, некоторые двойные ядро AMDs также может вызвать
этот новый ответ использует 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-совместимые часы из Intel
rdtsc
инструкция по монтажу. Я назову этоx::clock
:#include <chrono> namespace x { struct clock { typedef unsigned long long rep; typedef std::ratio<1, 2'800'000'000> period; // My machine is 2.8 GHz typedef std::chrono::duration<rep, period> duration; typedef std::chrono::time_point<clock> time_point; static const bool is_steady = true; static time_point now() noexcept { unsigned lo, hi; asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); return time_point(duration(static_cast<rep>(hi) << 32 | lo)); } }; } // x
все, что делают эти часы-это подсчет Циклы процессора и хранить его в 64-разрядное целое число без знака. Возможно, Вам потребуется настроить синтаксис языка ассемблера для вашего компилятора. Или ваш компилятор может предложить встроенный вы можете использовать вместо этого (например
now() {return __rdtsc();}
).построить часы, вы должны дать ему представление (тип хранения). Вы также должны указать тактовый период, который должен быть постоянной времени компиляции, даже если ваша машина может изменять тактовую частоту в разных режимах питания. И из них вы можете легко определить свой "родная" продолжительность времени и точка времени часов с точки зрения этих основ.
если все, что вы хотите сделать, это вывести количество тиков часов, на самом деле не имеет значения, какое число вы даете за период часов. Эта константа вступает в игру только в том случае, если вы хотите преобразовать количество тиков часов в некоторую единицу реального времени, такую как наносекунды. И в этом случае, чем точнее вы сможете поставить тактовую частоту, тем точнее будет преобразование в наносекунды, (миллисекунды, неважно).
ниже пример кода, который показывает, как использовать
x::clock
. На самом деле я шаблонный код на часах, как я хочу показать, как можно использовать различные часы с точно такой же синтаксис. Этот конкретный тест показывает, что накладные расходы цикла при запуске то, что вы хотите время в цикле:#include <iostream> template <class clock> void test_empty_loop() { // Define real time units typedef std::chrono::duration<unsigned long long, std::pico> picoseconds; // or: // typedef std::chrono::nanoseconds nanoseconds; // Define double-based unit of clock tick typedef std::chrono::duration<double, typename clock::period> Cycle; using std::chrono::duration_cast; const int N = 100000000; // Do it auto t0 = clock::now(); for (int j = 0; j < N; ++j) asm volatile(""); auto t1 = clock::now(); // Get the clock ticks per iteration auto ticks_per_iter = Cycle(t1-t0)/N; std::cout << ticks_per_iter.count() << " clock ticks per iteration\n"; // Convert to real time units std::cout << duration_cast<picoseconds>(ticks_per_iter).count() << "ps per iteration\n"; }
первое, что делает этот код, это создает блок "реального времени" для отображения результатов. Я выбрал пикосекунды, но вы можете выберите любые единицы измерения, которые вам нравятся, либо интегральные, либо с плавающей запятой. В качестве примера можно привести уже готовый
std::chrono::nanoseconds
блок, который я мог бы использовать.в качестве другого примера я хочу распечатать среднее количество тактов за итерацию в виде плавающей точки, поэтому я создаю другую длительность, основанную на double, которая имеет те же единицы, что и ТИК часов (называется
Cycle
в коде).цикл синхронизирован с вызовами
clock::now()
С обеих сторон. Если вы хотите назвать тип возвращаемый из этой функции это:typename clock::time_point t0 = clock::now();
(как ясно показано в
x::clock
пример, а также верно для системных часов).чтобы получить длительность в терминах часов с плавающей запятой, нужно просто вычесть две точки времени и получить значение за итерацию, разделите эту длительность на количество итераций.
вы можете получить счет в любой период с помощью
count()
функции-члена. Это возвращает внутренний представление. Наконец-то я используюstd::chrono::duration_cast
для преобразования длительностиCycle
на срокpicoseconds
и распечатать.использовать этот код просто:
int main() { std::cout << "\nUsing rdtsc:\n"; test_empty_loop<x::clock>(); std::cout << "\nUsing std::chrono::high_resolution_clock:\n"; test_empty_loop<std::chrono::high_resolution_clock>(); std::cout << "\nUsing std::chrono::system_clock:\n"; test_empty_loop<std::chrono::system_clock>(); }
выше я выполняю тест, используя наш самодельный
x::clock
, и сравните эти результаты с использованием двух системных часов:std::chrono::high_resolution_clock
иstd::chrono::system_clock
. Для меня это распечатывает:Using rdtsc: 1.72632 clock ticks per iteration 616ps per iteration Using std::chrono::high_resolution_clock: 0.620105 clock ticks per iteration 620ps per iteration Using std::chrono::system_clock: 0.00062457 clock ticks per iteration 624ps per iteration
это показывает, что каждый из этих часов имеет разный период тика, так как тики за итерацию значительно отличается для каждого часы. Однако при преобразовании в известную единицу времени (например, пикосекунды) я получаю примерно тот же результат для каждого такта (ваш пробег может отличаться).
обратите внимание, что мой код полностью свободен от "магических констант преобразования". Действительно, во всем примере есть только два магических числа:
- тактовая частота моей машины для того, чтобы определить
x::clock
.- количество итераций для тестирования. Если изменить это число делает ваши результаты сильно различаются, то вы, вероятно, должны сделать количество итераций выше, или очистить компьютер от конкурирующих процессов во время тестирования.