Действительно ли ntp_gettime() возвращает точность в наносекундах?

Следующий код в Ubuntu 12.04 LTS:

 #include <stdio.h>
 #include <sys/timex.h>
 #include <sys/time.h>

 int main(int argc, char **argv) 
 {
     struct timeval tv; 
     gettimeofday(&tv, NULL);

     struct ntptimeval ntptv;
     ntp_gettime(&ntptv);

     printf("gettimeofday: tv_sec = %ld, tv_usec = %ld\n", 
                tv.tv_sec, tv.tv_usec);
     printf("ntp_gettime:  tv_sec = %ld, tv_usec = %ld\n", 
                ntptv.time.tv_sec, ntptv.time.tv_usec);
 }

возвращает:

 gettimeofday: tv_sec = 1366209548, tv_usec = 137736
 ntp_gettime:  tv_sec = 1366209548, tv_usec = 137743081

Это немного странно, потому что значение tv_usec, если оно действительно является микросекундным счетчиком, не должно быть больше 1000000. Результат, показанный выше, заставляет меня думать, что ntp_gettime() на самом деле возвращает наносекундную точность.

ntp_gettime() Справочная страница (для точности) по адресу http://manpages.ubuntu.com/manpages/precise/man2/ntp_gettime.2freebsd.html на самом деле мало что говорит.

Более ранняя версия справочной страницы (для Hardy) http://manpages.ubuntu.com/manpages/hardy/man2/ntp_gettime.2.html утверждает, что это может быть либо наносекунда, либо микросекунда, в зависимости от того, установлен ли бит STA_NANO в слове status, возвращаемом ntp_adjtime().

Кто-нибудь знает окончательно? Кроме того, где ntp_gettime(), ntp_adjtime() и все различные внутренние функции, которые они вызывают, определены в исходном коде 12.04?


person cklin    schedule 17.04.2013    source источник


Ответы (1)


ntp_gettime и ntp_adjtime оба определены в библиотеке C. В Linux и glibc ntp_adjtime является просто оболочкой для системного вызова adjtimex, а ntp_gettime использует тот же системный вызов, передавая ему struct timex с modes, установленным в 0. Вы можете просмотреть их определения по адресу glibc LXR.

Системный вызов реализация вызывает _do_adjtimex, который вызывает getnstimeofday, чтобы получить время (в наносекундах), а затем передать его __do_adjtimex. А вот и интересная часть:

txc->time.tv_sec = ts->tv_sec;
txc->time.tv_usec = ts->tv_nsec;
if (!(time_status & STA_NANO))
        txc->time.tv_usec /= NSEC_PER_USEC;

Поэтому, если установлено STA_NANO, оно просто помещает значение наносекунды в tv_usec, что является поведением, которое вы испытывали. Если вы хотите снять этот флаг, вы можете сделать что-то вроде этого:

struct timex tmx;
tmx.modes = 0 | ADJ_MICRO;
ntp_adjtime(&tmx);

а затем прочитайте значение микросекунды из tmx.time.tv_usec. Если вы хотите сделать это, вам придется запускать свой код с sudo, но имейте в виду, что флаг не будет установлен в ядре до тех пор, пока вы не сбросите его (используя ADJ_NANO) или не перезагрузитесь.

person Samuel Peter    schedule 05.12.2013