Как получить истинное значение системных часов в необработанных тактах (т. Е. mach_absolute_time) в процессе x86_64, запущенном под управлением Rosetta 2?

#macos #time #system-clock #rosetta-2

Вопрос:

Я пишу приложение macOS x86-64, которое в настоящее время не может быть скомпилировано как универсальный двоичный файл из-за зависимостей библиотек, которые являются только x86-64.

Это приложение должно взаимодействовать с другими процессами, которые работают под управлением arm64 на компьютерах Apple Silicon mac, и при этом ему необходимо получить значение системных часов в необработанных тактах, как было бы возвращено mach_absolute_time() .

Однако на Apple Silicon mac mach_absolute_time() поведение отличается при вызове из собственного приложения arm64 и при вызове из приложения x86-64 под управлением Rosetta 2.

На Intel Mac mach_absolute_time() возвращает системные часы в наносекундах и mach_timebase_info() возвращает соотношение наносекунд 1:1 к тактам.

На Apple Silicon Mac единица измерения системных часов больше не находится в наносекундах и, следовательно mach_timebase_info() , не возвращает соотношение 1:1. (На моем M1 Mac Mini я получаю соотношение 125:3.)

Однако приложение x86-64, работающее под управлением Rosetta 2, получит те же значения, что и на процессоре Intel, что составляет соотношение 1:1 и mach_absolute_time() возвращает значение в наносекундах.

Это проблема для меня, потому что мне нужно, чтобы мое приложение x86-64 получало реальное значение mach_absolute_time() , как если бы оно было вызвано из процесса arm64.

До сих пор я не нашел способа сделать это. Каждая функция, связанная с часами, о которой я знаю, возвращает «поддельные» значения при вызове в Rosetta 2. Единственное решение, которое я могу придумать, — это включить исполняемый файл, являющийся универсальным двоичным файлом, в мое приложение, вызвать его из моего приложения, заставить его получить информацию о временной базе, работающую изначально как arm64, и передать значение обратно. Но это гораздо более тяжелое решение, чем мне бы хотелось.

Есть ли способ получить реальную базу системных часов в приложении x86-64, работающем под управлением Rosetta 2?

Ответ №1:

Я нашел способ сделать это, но он не идеален. Следующая функция, выполняемая приложением x86_64, запущенным в Rosetta, вернет то же время, что mach_absolute_time() и для приложения arm64:

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

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

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