From a439d92358bb9f341e9026664816563bd1b35ded Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Mon, 2 Dec 2024 07:43:06 +0100 Subject: [PATCH] PsychHID/OSX: Fix conversion of HID event timestamps to GetSecs time. Timestamps delivered by the HID subsystem are in mach time units, arbitrary units for a given machines clock hardware. On Intel based Macs, the units happened to be fixed across all machines to be Nanoseconds, so a simple division by 1e9 did the conversion. On Apple Silicon ARM Macs, the units are no longer Nanoseconds, but something odd - probably something like bus frequency or whatever. Therefore we need to use a proper adaptive conversion, which is querying the mach timebase frequency, via PsychGetKernelTimebaseFrequencyHz() and then dividing by that. This provides proper conversion and fixes the input event timestamps of keyboard queues - KbQueueDemo now prints proper keypress times. When we are at it, make PsychGetKernelTimebaseFrequencyHz() a tad more efficient. --- PsychSourceGL/Source/OSX/Base/PsychTimeGlue.c | 12 ++++++------ .../Source/OSX/PsychHID/PsychHIDStandardInterfaces.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/PsychSourceGL/Source/OSX/Base/PsychTimeGlue.c b/PsychSourceGL/Source/OSX/Base/PsychTimeGlue.c index fc28b28023..caf07feeb6 100644 --- a/PsychSourceGL/Source/OSX/Base/PsychTimeGlue.c +++ b/PsychSourceGL/Source/OSX/Base/PsychTimeGlue.c @@ -106,11 +106,11 @@ double PsychYieldIntervalSeconds(double delaySecs) double PsychGetKernelTimebaseFrequencyHz(void) { - long double clockPeriodNSecs; - mach_timebase_info_data_t tbinfo; + if (!isKernelTimebaseFrequencyHzInitialized) { + long double clockPeriodNSecs; + mach_timebase_info_data_t tbinfo; - if(!isKernelTimebaseFrequencyHzInitialized){ - // Retrieve the mach absolute time timebase. The kernel expresses the period in two integers, the ratio of which is the clock period. + // Retrieve the mach absolute time timebase. The kernel expresses the period in two integers, the ratio of which is the clock period. mach_timebase_info(&tbinfo); // Calculate the mach timebase period from values reported from the mach kernel. @@ -120,10 +120,10 @@ double PsychGetKernelTimebaseFrequencyHz(void) // Frequency in Hz is a convenient form because it makes converting from a period in seconds into a period in mach timebase units easy: // time_interval_in_mach_units= time_interval_in_seconds * clockFrequencyHz; kernelTimebaseFrequencyHz = 1000000000.0 / clockPeriodNSecs; - isKernelTimebaseFrequencyHzInitialized=TRUE; + isKernelTimebaseFrequencyHzInitialized = TRUE; } - return((double)kernelTimebaseFrequencyHz); + return((double) kernelTimebaseFrequencyHz); } /* Called at Module init time: */ diff --git a/PsychSourceGL/Source/OSX/PsychHID/PsychHIDStandardInterfaces.c b/PsychSourceGL/Source/OSX/PsychHID/PsychHIDStandardInterfaces.c index d15dfcfe68..407ac7e9c8 100644 --- a/PsychSourceGL/Source/OSX/PsychHID/PsychHIDStandardInterfaces.c +++ b/PsychSourceGL/Source/OSX/PsychHID/PsychHIDStandardInterfaces.c @@ -729,7 +729,7 @@ enum { kHID2VKCSize = sizeof kHID2VKC / sizeof kHID2VKC[0] }; // Convert uint64 time in nanoseconds to double value in GetSecs() seconds: static double convertTime(uint64_t timeUInt64) { double timeDouble = (double) timeUInt64; - return timeDouble / 1000000000; + return timeDouble / PsychGetKernelTimebaseFrequencyHz(); } static void PsychHIDKbQueueCallbackFunction(void *target, IOReturn result, void *sender)