#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, для получения метки времени требуется нетривиальное количество времени (хотя все еще меньше миллисекунды), что прискорбно для функции синхронизации, но, похоже, этого достаточно для моих целей.
Я собираюсь оставить этот ответ без пометки как принятый, хотя на случай, если кто-то другой может предложить лучший метод.