Intereting Posts
Упражнение 1-18 K & R. Как я должен удалить пробел? Разбить массив строк на основе символа Неполный тип в C struct Петля над 256 значениями с использованием 8-разрядной целочисленной переменной без знака в качестве счетчика Могу ли я использовать указатель в scanf для ввода ввода в массив? Почему этот fragment кода не меняет строку? GCC псевдоним для работы вне единицы перевода -AKA- – это даже правильный инструмент для работы? Что такое «…» в коммутаторе в коде C select () не позволяет printf () без “\ n” в конце В C, как определить макрос, используя другие macros, когда эти другие macros вызывают конфликты имен Получить статус экрана с позиции мира Множественное выполнение одной и той же подпрограммы streamа при комментировании pthread_join для этого streamа элемент доступа структуры, переданный в указатель void * Как правильно встроить и использовать встроенную функцию в C99? (сбой сборки) Как изменить входящий пакет из NIC в C?

Таймер, чтобы найти прошедшее время в вызове функции в C

Я хочу рассчитать время, прошедшее во время вызова функции в C, с точностью до 1 наносекунды.

Есть ли функция таймера, доступная в C, чтобы сделать это?

Если да, укажите примерный fragment кода.

Псевдокод

Timer.Start() foo(); Timer.Stop() Display time elapsed in execution of foo() 

Сведения об окружающей среде: – с использованием компилятора gcc 3.4 на машине RHEL

Могу ли я спросить, какой процессор вы используете? Если вы используете процессор x86, вы можете посмотреть счетчик tsc времени ( tsc ). Этот fragment кода:

 #define rdtsc(low,high) \ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) 

поставит количество циклов, которые CPU выполнил на low и high соответственно (он ожидает 2 long s, вы можете сохранить результат в long long int ) следующим образом:

 inline void getcycles (long long int * cycles) { unsigned long low; long high; rdtsc(low,high); *cycles = high; *cycles <<= 32; *cycles |= low; } 

Обратите внимание, что это возвращает количество циклов, выполненных вашим процессором. Вам нужно будет получить скорость вашего процессора, а затем выяснить, сколько циклов за ns, чтобы получить количество ns, прошедших.

Чтобы сделать это, я проанализировал строку «cpu MHz» из /proc/cpuinfo и преобразовал ее в десятичную. После этого это всего лишь немного математики, и помните, что 1 МГц = 1 000 000 циклов в секунду и что 1 миллиард нс / сек.

На Intel и совместимых процессорах вы можете использовать команду rdtsc, которая может быть легко перенесена в блок asm () кода C. Он возвращает значение встроенного счетчика циклов процессора, который увеличивается на каждый цикл. Вы получаете высокое разрешение, и такое время очень быстро.

Чтобы узнать, как быстро это приращение вам потребуется, выполните калибровку – дважды вызовите эту инструкцию за фиксированный период времени, например пять секунд. Если вы сделаете это на процессоре, который сдвигает частоту, чтобы снизить потребление энергии, у вас могут быть проблемы с калибровкой.

Используйте clock_gettime(3) . Для получения дополнительной информации введите man 3 clock_gettime . При этом точность наносекунд редко необходима.

Любая функция таймера должна быть специфичной для платформы, особенно с учетом этой точности.

Стандартное решение в системах POSIX – gettimeofday() , но оно имеет только микросекундную точность.

Если это относится к бенчмаркингу производительности, стандартный способ заключается в том, чтобы сделать тест кода достаточным для того, чтобы сделать точность требований менее серьезной. Другими словами, запустите тестовый код в течение целой секунды (или более).

В таймере нет таймера с гарантированной точностью в 1 наносекунду. Вы можете посмотреть в clock() или еще лучше. POSIX gettimeofday()

Я не знаю, найдете ли вы таймеры, обеспечивающие разрешение одной наносекунды – это будет зависеть от разрешения системных часов – но вы можете посмотреть http://code.google.com/ p / high-resolution-timer / . Они указывают, что они могут обеспечить разрешение микросекундного уровня на большинстве систем Linux и в наносекундах на системах Sun.

Создание контрольных показателей в этой шкале не является хорошей идеей. У вас есть накладные расходы, чтобы получить время, по крайней мере, что может сделать ваши результаты ненадежными, если вы работаете над наносекундами. Вы можете использовать системные вызовы своих платформ или boost :: Date_Time в более крупном масштабе [предпочтительнее].

Можете ли вы просто запустить его 10 ^ 9 раз и секундомер?

Вы можете использовать стандартные системные вызовы, такие как gettimeofday, если вы уверены, что ваш процесс получает 100%, если процессорное время. Я могу придумать много ситуаций, в которых, пока вы выполняете foo (), другие streamи и процессы могут украсть процессорное время.

Вы просите что-то, что не возможно таким образом. Вам понадобится поддержка уровня HW, чтобы достичь такого уровня точности и даже тогда тщательно контролировать переменные. Что произойдет, если вы получите прерывание при запуске кода? Что делать, если ОС решает запустить какой-либо другой код?

И что делает ваш код? Использует ли он оперативную память? Что делать, если ваш код и / или данные находятся или не находятся в кеше?

В некоторых средах вы можете использовать счетчики уровня HW для этого задания, если вы контролируете эти переменные. Но как вы предотвращаете контекстные переключатели в Linux?

Например, в инструментах DSP Texas Instruments (Code Composer Studio) вы можете точно профилировать код, потому что вся среда отладки настроена так, что эмулятор (например, Blackhawk) получает информацию о каждом запуске операции. Вы также можете установить точки наблюдения, которые кодируются непосредственно в блок HW внутри чипа в некоторых процессорах. Это работает, потому что полосы памяти также направляются в этот блок отладки.

Они предлагают функции в своей библиотеке CSL (Chip Support Library), которую вы запрашиваете, с накладными затратами времени, которые состоят из нескольких циклов. Но это доступно только для их процессоров и полностью зависит от считывания значений таймера из регистров HW.

Мы все тратим наше время на воссоздание этого тестового образца. Почему бы не написать что-нибудь компилируемое? Во всяком случае, вот мои результаты.

 CLOCK_PROCESS_CPUTIME_ID resolution: 0 sec 1 nano clock_gettime 4194304 iterations : 459.427311 msec 0.110 microsec / call CLOCK_MONOTONIC resolution: 0 sec 1 nano clock_gettime 4194304 iterations : 64.498347 msec 0.015 microsec / call CLOCK_REALTIME resolution: 0 sec 1 nano clock_gettime 4194304 iterations : 65.494828 msec 0.016 microsec / call CLOCK_THREAD_CPUTIME_ID resolution: 0 sec 1 nano clock_gettime 4194304 iterations : 427.133157 msec 0.102 microsec / call rdtsc 4194304 iterations : 115.427895 msec 0.028 microsec / call Dummy 16110479703957395943 rdtsc in milliseconds 4194304 iterations : 197.259866 msec 0.047 microsec / call Dummy 4.84682e+08 UltraHRTimerMs 197 HRTimerMs 197.26 #include  #include  #include  #include  #include  #include  enum { TESTRUNS = 1024*1024*4 }; class HRCounter { private: timespec start, tmp; public: HRCounter(bool init = true) { if(init) SetStart(); } void SetStart() { clock_gettime(CLOCK_MONOTONIC, &start); } double GetElapsedMs() { clock_gettime(CLOCK_MONOTONIC, &tmp); return (double)(tmp.tv_nsec - start.tv_nsec) / 1000000 + (tmp.tv_sec - start.tv_sec) * 1000; } }; __inline__ uint64_t rdtsc(void) { uint32_t lo, hi; __asm__ __volatile__ ( // serialize "xorl %%eax,%%eax \n cpuid" ::: "%rax", "%rbx", "%rcx", "%rdx"); /* We cannot use "=A", since this would use %rax on x86_64 and return only the lower 32bits of the TSC */ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); return (uint64_t)hi << 32 | lo; } inline uint64_t GetCyclesPerMillisecondImpl() { uint64_t start_cyles = rdtsc(); HRCounter counter; std::this_thread::sleep_for (std::chrono::seconds(3)); uint64_t end_cyles = rdtsc(); double elapsed_ms = counter.GetElapsedMs(); return (end_cyles - start_cyles) / elapsed_ms; } inline uint64_t GetCyclesPerMillisecond() { static uint64_t cycles_in_millisecond = GetCyclesPerMillisecondImpl(); return cycles_in_millisecond; } class UltraHRCounter { private: uint64_t start_cyles; public: UltraHRCounter(bool init = true) { GetCyclesPerMillisecond(); if(init) SetStart(); } void SetStart() { start_cyles = rdtsc(); } double GetElapsedMs() { uint64_t end_cyles = rdtsc(); return (end_cyles - start_cyles) / GetCyclesPerMillisecond(); } }; int main() { auto Run = [](std::string const& clock_name, clockid_t clock_id) { HRCounter counter(false); timespec spec; clock_getres( clock_id, &spec ); printf("%s resolution: %ld sec %ld nano\n", clock_name.c_str(), spec.tv_sec, spec.tv_nsec ); counter.SetStart(); for ( int i = 0 ; i < TESTRUNS ; ++ i ) { clock_gettime( clock_id, &spec ); } double fb = counter.GetElapsedMs(); printf( "clock_gettime %d iterations : %.6f msec %.3f microsec / call\n", TESTRUNS, ( fb ), (( fb ) * 1000) / TESTRUNS ); }; Run("CLOCK_PROCESS_CPUTIME_ID",CLOCK_PROCESS_CPUTIME_ID); Run("CLOCK_MONOTONIC",CLOCK_MONOTONIC); Run("CLOCK_REALTIME",CLOCK_REALTIME); Run("CLOCK_THREAD_CPUTIME_ID",CLOCK_THREAD_CPUTIME_ID); { HRCounter counter(false); uint64_t dummy; counter.SetStart(); for ( int i = 0 ; i < TESTRUNS ; ++ i ) { dummy += rdtsc(); } double fb = counter.GetElapsedMs(); printf( "rdtsc %d iterations : %.6f msec %.3f microsec / call\n", TESTRUNS, ( fb ), (( fb ) * 1000) / TESTRUNS ); std::cout << "Dummy " << dummy << std::endl; } { double dummy; UltraHRCounter ultra_hr_counter; HRCounter counter; for ( int i = 0 ; i < TESTRUNS ; ++ i ) { dummy += ultra_hr_counter.GetElapsedMs(); } double fb = counter.GetElapsedMs(); double final = ultra_hr_counter.GetElapsedMs(); printf( "rdtsc in milliseconds %d iterations : %.6f msec %.3f microsec / call\n", TESTRUNS, ( fb ), (( fb ) * 1000) / TESTRUNS ); std::cout << "Dummy " << dummy << " UltraHRTimerMs " << final << " HRTimerMs " << fb << std::endl; } return 0; }