2016-12-05 2 views
7

Я ожидаю, что gettimeofday() вызовет системный вызов, чтобы выполнить работу, фактически получая время. Однако, выполнив следующую программуПолучает ли gettimeofday() на macOS системный вызов?

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

int main(int argc, char const *argv[]) 
{ 
    struct timeval tv; 

    printf("Before gettimeofday() %ld!\n", tv.tv_sec); 

    int rc = gettimeofday(&tv, NULL); 

    printf("After gettimeofday() %ld\n", tv.tv_sec); 

    if (rc == -1) { 
     printf("Error: gettimeofday() failed\n"); 
     exit(1); 
    } 

    printf("Exiting ! %ld\n", tv.tv_sec); 
    return 0; 
} 

под dtruss -d возвращает длинный список системных вызовов, последний из которых являются:

RELATIVE SYSCALL(args)   = return 

... lots of syscalls with earlier timestamps ... 

    3866 fstat64(0x1, 0x7FFF56ABC8D8, 0x11)  = 0 0 
    3868 ioctl(0x1, 0x4004667A, 0x7FFF56ABC91C)  = 0 0 
    3882 write_nocancel(0x1, "Before gettimeofday() 0!\n\0", 0x19)  = 25 0 
    3886 write_nocancel(0x1, "After gettimeofday() 1480913810\n\0", 0x20)  = 32 0 
    3887 write_nocancel(0x1, "Exiting ! 1480913810\n\0", 0x15)  = 21 0 

Похоже gettimeofday() не использует системный вызов, но это, кажется, неправильно - конечно, ядро ​​отвечает за системные часы? Есть dtruss что-то отсутствует? Я читаю выход неправильно?

+2

В Solaris 'gettimeofday()' просто считывает местоположение памяти. Вполне возможно, что что-то похожее на macOS Sierra (или предыдущие версии Mac OS X). Вам может быть интересно или не интересно, что macOS Sierra (но не более ранние версии) поддерживает 'clock_gettime()' в конце концов. –

+2

Вы можете увидеть системный вызов 'gettimeofday()' в [исходный код] (https://opensource.apple.com/source/xnu/xnu-3789.1.32/bsd/kern/syscalls.master.auto.html) - # 116 – TheDarkKnight

+2

В Linux системный вызов, например 'gettimeofday()', может быть реализован как * нормальный вызов функции и несколько обращений к памяти "*: [vDSO] (http://man7.org/linux/ man-pages/man7/vdso.7.html) – jfs

ответ

6

Как TheDarkKnight pointed out, есть gettimeofday системный вызов. Тем не менее, функция user gettimeofday часто выполняет , а не вызывает соответствующий системный вызов, а скорее __commpage_gettimeofday, который пытается прочитать время со специальной части адресного пространства процесса, которое называется .. Только в случае сбоя вызова системный вызов gettimeofday используется в качестве резервной копии. Это уменьшает стоимость большинства вызовов до gettimeofday по сравнению с обычным системным вызовом только для чтения в памяти.

Книга Mac OSX Internals: A Systems Approach описывает страницу для печати. Вкратце, это специальная область памяти ядра, которая отображается на последние восемь страниц адресного пространства каждого процесса. Помимо всего прочего, он содержит значения времени, которые «обновляются асинхронно от ядра и читаются атомарно из пользовательского пространства, что приводит к случайным сбоям при чтении».

Чтобы увидеть, как часто gettimeofday() системный вызов называется функцией пользовательского пространства, я написал тестовую программу, которая под названием gettimeofday() 100 миллионов раз в тугой петле:

#include <sys/time.h> 
int main(int argc, char const *argv[]) 
{ 
    const int NUM_TRIALS = 100000000; 
    struct timeval tv; 
    for (int i = 0; i < NUM_TRIALS; i++) { 
     gettimeofday(&tv, NULL); 
    } 
    return 0; 
} 

Бегом это под dtruss -d на моей машину показала что это вызвано между 10-20 вызовами системных вызовов gettimeofday() (0,00001% -0,00002% всех вызовов в пользовательском пространстве).


Для тех, кто заинтересован, соответствующие строки в source code для функции gettimeofday() (в пользовательском пространстве для MacOS 10.11 - Эль Capitan) являются

if (__commpage_gettimeofday(tp)) {  /* first try commpage */ 
    if (__gettimeofday(tp, NULL) < 0) { /* if it fails, use syscall */ 
     return (-1); 
    } 
} 

Функция __commpage_gettimeofdaycombines метка времени считывается из commpage и чтения времени штампа счетчика регистра для расчета времени с начала эпохи в секундах и микросекундах. (Инструкция rdstc находится внутри _mach_absolute_time.)

+0

Очень интересно. Спасибо. –

+0

Хороший ответ. Вы указываете: _ Это уменьшает стоимость большинства вызовов до gettimeofday от обычного вызова системы только для чтения в памяти. Это не выглядит строго истинным: функции '___ commpage_gettimeofday' и' _mach_absolute_time' (при первом вызове последнего) - это несколько десятков инструкций, причем между ними, пожалуй, всего 10 общих чтений, а сам вызов «rdtsc» - два десятка циклов или более (плюс у них есть две команды «lfence» там по какой-то причине). Так что, вероятно, вы смотрите как минимум на 50 циклов. Еще намного лучше, чем вызов ядра! – BeeOnRope

1

Использование dtrace вместо dtruss устранит ваши сомнения. gettimeofday() сам является системным вызовом. Вы можете увидеть, как этот вызов системы вызывается, если вы запускаете скрипт dtrace.

Вы можете использовать следующий скрипт DTrace "dtrace1.d"

syscall:::entry 
/execname == "foo"/
{ 
} 

(Foo это имя исполняемого файла)

для запуска выше использования Dtrace: DTrace -s dtrace1.d

, а затем выполните свою программу, чтобы просмотреть весь системный вызов, используемый вашей программой.

+0

Я выполнил ваши инструкции, и 'dtrace' не идентифицирует системный вызов' gettimeofday'. Его вывод почти идентичен 'dtruss', и кроме перечисления вызова' exit() 'в самом конце программы, последние пять системных вызовов (см. Вопрос) одинаковы. Я управляю El Capitan (10.11.6). Вы видите что-то другое на вашем компьютере? – asnr

Смежные вопросы