0

我正在编写一个 macOS x86-64 应用程序,由于仅 x86-64 的库依赖关系,该应用程序当前无法编译为通用二进制文件。

此应用程序需要与在 Apple Silicon mac 上作为 arm64 运行的其他进程进行交互,并且在这样做时,它需要以原始刻度获取系统时钟的值,如mach_absolute_time().

但是,在 Apple Silicon mac 上,mach_absolute_time()从本机 arm64 应用程序调用和从 Rosetta 2 下的 x86-64 应用程序调用时具有不同的行为。

在 Intel mac 上,mach_absolute_time()以纳秒为单位返回系统时钟,并mach_timebase_info()返回 1:1 的纳秒与时钟滴答比。

在 Apple Silicon mac 上,系统时钟的单位不再以纳秒为单位,因此mach_timebase_info()不会返回 1:1 的比率。(在我的 M1 Mac Mini 上,我得到 125:3 的比率。)

但是,在 Rosetta 2 下运行的 x86-64 应用程序将获得与在 Intel 处理器上相同的值,即 1:1 的比率并mach_absolute_time()返回以纳秒为单位的值。

这对我来说是个问题,因为我需要我的 x86-64 应用程序来获得真正的价值,mach_absolute_time()就好像它是从 arm64 进程中调用的一样。

到目前为止,我还没有找到一种方法来做到这一点。我知道的每个与时钟相关的函数在 Rosetta 2 下调用时都会返回“假”值。我能想到的唯一解决方案是将作为通用二进制文件的可执行文件捆绑到我的应用程序中,从我的应用程序调用它,拥有它获取作为 arm64 本地运行的时基信息,并将值传回。但这比我想要的解决方案要重得多。

有没有办法在 Rosetta 2 下运行的 x86-64 应用程序中获取真正的系统时钟时基?

4

1 回答 1

1

我找到了一种方法来做到这一点,但它并不完美。当运行在 Rosetta 中的 x86_64 应用程序执行以下函数时,将返回与mach_absolute_time()arm64 应用程序相同的时间:

uint64_t machAbsoluteTimeFromSysctl()
{
    uint64_t vals[2];
    size_t size = sizeof(vals);
    
    if (sysctlbyname("kern.monotonicclock_usecs", &vals, &size, NULL, 0) == -1) {
        printf("Error: sysctl kern.monotonicclock_usecs failed with error: %d\n", errno);
        return mach_absolute_time();
    }
    
    return vals[1];
}

由于这是使用 sysctl ,因此需要花费大量时间来获取时间戳(尽管仍不到一毫秒),这对于计时功能来说是不幸的,但对于我的目的来说似乎已经足够了。

我将不将此答案标记为已接受的答案,以防万一其他人可以提出更好的方法。

于 2021-09-24T20:54:48.043 回答