Является ли clock_gettime () достаточным для субмикросекундной синхронизации? - PullRequest
19 голосов
/ 29 октября 2011

Мне нужен таймер высокого разрешения для встроенного профилировщика в сборке Linux нашего приложения. Наш профилировщик измеряет области видимости как отдельные функции, поэтому для него требуется точность таймера, превышающая 25 наносекунд.

Ранее наша реализация использовала встроенную сборку и операцию rdtsc для запроса высокочастотного таймера напрямую от ЦП, но это проблематично и требует частой повторной калибровки.

Поэтому я попытался использовать вместо этого функцию clock_gettime для запроса CLOCK_PROCESS_CPUTIME_ID. Документы утверждают, что это дает мне наносекундное время, но я обнаружил, что накладные расходы на один вызов clock_gettime() превысили 250 нс. Это делает невозможным синхронизацию событий длительностью 100 нс, а такие высокие накладные расходы на функцию таймера серьезно снижают производительность приложения, искажая профили за пределами ценности. (У нас есть сотни тысяч узлов профилирования в секунду.)

Есть ли способ вызова clock_gettime(), который имеет меньше служебных данных? Или есть какой-то другой способ, которым я могу надежно получить счетчик метки времени с издержками <25 нс? Или я застрял с использованием <code>rdtsc?

Ниже приведен код, который я использовал для времени clock_gettime().

// calls gettimeofday() to return wall-clock time in seconds:
extern double Get_FloatTime();
enum { TESTRUNS = 10244 };

// time the high-frequency timer against the wall clock
{
    double fa = Get_FloatTime();
    timespec spec; 
    clock_getres( CLOCK_PROCESS_CPUTIME_ID, &spec );
    printf("CLOCK_PROCESS_CPUTIME_ID resolution: %ld sec %ld nano\n", 
            spec.tv_sec, spec.tv_nsec );
    for ( int i = 0 ; i < TESTRUNS ; ++ i )
    {
        clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &spec );
    }
    double fb = Get_FloatTime();
    printf( "clock_gettime %d iterations : %.6f msec %.3f microsec / call\n",
        TESTRUNS, ( fb - fa ) * 1000.0, (( fb - fa ) * 1000000.0) / TESTRUNS );
}
// and so on for CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_THREAD_CPUTIME_ID.
*1024* Результаты:
CLOCK_PROCESS_CPUTIME_ID resolution: 0 sec 1 nano
clock_gettime 8388608 iterations : 3115.784947 msec 0.371 microsec / call
CLOCK_MONOTONIC resolution: 0 sec 1 nano
clock_gettime 8388608 iterations : 2505.122119 msec 0.299 microsec / call
CLOCK_REALTIME resolution: 0 sec 1 nano
clock_gettime 8388608 iterations : 2456.186031 msec 0.293 microsec / call
CLOCK_THREAD_CPUTIME_ID resolution: 0 sec 1 nano
clock_gettime 8388608 iterations : 2956.633930 msec 0.352 microsec / call

Это на стандартном ядре Ubuntu. Приложение представляет собой порт приложения Windows (где наша встроенная сборка rdtsc работает просто отлично).

Приложение:

Имеет ли x86-64 GCC свойственный эквивалент __rdtsc () , так что я могу хотя бы избежать встроенной сборки?

Ответы [ 6 ]

7 голосов
/ 29 октября 2011

Нет.Вы должны будете использовать специфичный для платформы код, чтобы сделать это.В x86 и x86-64 вы можете использовать rdtsc для считывания счетчика меток времени .

Просто перенесите используемую сборку rdtsc.

__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;
}
6 голосов
/ 28 июля 2014

Я выполнил несколько тестов в моей системе, которая представляет собой четырехъядерный процессор E5645 Xeon, поддерживающий постоянное TSC с работающим ядром 3.2.54, и результаты были такими:(принятый ответ) rdtsc - худший путь для спуска.

1 голос
/ 10 сентября 2013

Дать clockid_t CLOCK_MONOTONIC_RAW попробовать?

CLOCK_MONOTONIC_RAW (начиная с Linux 2.6.28; для Linux) Аналогичен CLOCK_MONOTONIC, но обеспечивает доступ к сырое аппаратное время, которое не подчиняется NTP корректировки или дополнительные корректировки, выполняемые adjtime (3).

С Man7.org

1 голос
/ 29 октября 2011

Мне нужен таймер высокого разрешения для встроенного профилировщика в сборке Linux нашего приложения. Наш профилировщик измеряет области видимости как отдельные функции, поэтому для него требуется точность таймера, превышающая 25 наносекунд.

Рассматривали ли вы oprofile или perf? Вы можете использовать аппаратное обеспечение счетчика производительности вашего ЦП для получения данных профилирования без добавления инструментария в сам код. Вы можете увидеть данные для каждой функции или даже для каждой строки кода. Единственным недостатком является то, что он не будет измерять время, затраченное на настенные часы, он будет измерять время, затрачиваемое на процессор, поэтому он не подходит для всех исследований.

0 голосов
/ 24 мая 2018

Да, большинство современных платформ будут иметь подходящий вызов clock_gettime, который реализован исключительно в пространстве пользователя с использованием механизма VDSO, и для его завершения потребуется около 20–30 наносекунд.

Внутренне,при этом используется rdtsc или rdtscp для мелкозернистой части хронометража, а также настройки для синхронизации с настенными часами (в зависимости от выбранных часов) и умножения для преобразования из любых единицrdtsc имеет на вашей платформе наносекунды.

Не все часов, предлагаемых clock_gettime, будут реализовывать этот быстрый метод, и не всегда очевидный , которыйодни делают.Обычно CLOCK_MONOTONIC является хорошим вариантом, но вы должны проверить это на своей собственной системе .

0 голосов
/ 29 октября 2011

Вы вызываете clock_getttime с управляющим параметром, который означает, что API разветвляется через дерево if-else, чтобы увидеть, какое время вы хотите.Я знаю, что вы не можете избежать этого с помощью этого вызова, но посмотрите, сможете ли вы покопаться в системном коде и вызвать то, что в итоге вызывает кернал.Также отмечу, что вы включаете время цикла (i ++ и условная ветвь).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...