代码之家  ›  专栏  ›  技术社区  ›  asnr

macOS上的gettimeofday()是否使用系统调用?

  •  7
  • asnr  · 技术社区  · 8 年前

    我希望如此 gettimeofday() 将调用系统调用来执行实际获取时间的工作。但是,运行以下程序

    #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 回复  |  直到 8 年前
        1
  •  12
  •   Community CDub    8 年前

    作为黑暗骑士 pointed out gettimeofday 系统调用。然而,用户空间 每日获取时间 功能经常 调用相应的系统调用,而是 __commpage_gettimeofday ,它尝试从进程地址空间的特殊部分读取时间,称为 通讯页 .只有当此调用失败时 每日获取时间 系统调用用作回退。这降低了大多数呼叫的成本 每日获取时间 从一个普通的系统调用到一个内存读取。

    Mac OSX Internals: A Systems Approach 描述commpage。简而言之,它是内核内存的一个特殊区域,映射到每个进程地址空间的最后八页。除其他外,它包含“从内核异步更新并从用户空间原子读取的时间值,导致偶尔读取失败”。

    看看多久 gettimeofday() 系统调用由用户空间函数调用,我编写了一个测试程序 gettimeofday()

    #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-El Capitan)包括:

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

    功能 combines 从commpage读取的时间戳和时间戳计数器寄存器的读取,以秒和微秒为单位计算自历元以来的时间。(该 rdstc 指令在里面 _mach_absolute_time .)

        2
  •  1
  •   hrishikesh chaudhari    8 年前

    使用dtrace而不是dtruss将消除您的疑虑。

    您可以使用以下dtrace脚本 “dtrace1.d”

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

    (foo是可执行文件的名称。)

    要在dtrace之上运行,请使用:dtrace-s dtrace1.d

    然后执行程序以查看程序使用的所有系统调用