diff options
| author | Rye <rye@lindenlab.com> | 2025-02-03 11:48:18 -0500 |
|---|---|---|
| committer | Rye <rye@lindenlab.com> | 2025-02-11 05:04:09 -0500 |
| commit | 9fef2a114ea7eb6c42dd29e94ba5dc3451eb4560 (patch) | |
| tree | c091795c2b3245c618ce72532030b5d4489b2a1c | |
| parent | 594a7afce6a8b2e6a658d14881b8247b3a63efd8 (diff) | |
Fix timer support on macOS under ARM64
| -rw-r--r-- | indra/llcommon/llfasttimer.cpp | 2 | ||||
| -rw-r--r-- | indra/llcommon/llfasttimer.h | 62 | ||||
| -rw-r--r-- | indra/llcommon/llprocessor.cpp | 57 |
3 files changed, 83 insertions, 38 deletions
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 722743f453..1c5fe9d2f5 100644 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -64,7 +64,7 @@ bool BlockTimer::sLog = false; std::string BlockTimer::sLogName = ""; bool BlockTimer::sMetricLog = false; -#if LL_LINUX +#if LL_LINUX || (LL_DARWIN && LL_ARM64) U64 BlockTimer::sClockResolution = 1000000000; // Nanosecond resolution #else U64 BlockTimer::sClockResolution = 1000000; // Microsecond resolution diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 09fcf8a1af..271dade097 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -30,9 +30,14 @@ #include "llinstancetracker.h" #include "lltrace.h" #include "lltreeiterators.h" +#include "llprocessor.h" +#if LL_X86 || LL_X86_64 #if LL_WINDOWS #include <intrin.h> +#else +#include <x86intrin.h> +#endif #endif #define LL_FAST_TIMER_ON 1 @@ -68,35 +73,10 @@ public: // // Windows implementation of CPU clock // - - // - // NOTE: put back in when we aren't using platform sdk anymore - // - // because MS has different signatures for these functions in winnt.h - // need to rename them to avoid conflicts - //#define _interlockedbittestandset _renamed_interlockedbittestandset - //#define _interlockedbittestandreset _renamed_interlockedbittestandreset - //#include <intrin.h> - //#undef _interlockedbittestandset - //#undef _interlockedbittestandreset - - //inline U32 getCPUClockCount32() - //{ - // U64 time_stamp = __rdtsc(); - // return (U32)(time_stamp >> 8); - //} - // - //// return full timer value, *not* shifted by 8 bits - //inline U64 getCPUClockCount64() - //{ - // return __rdtsc(); - //} - - +#if LL_FASTTIMER_USE_RDTSC // shift off lower 8 bits for lower resolution but longer term timing // on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing -#if LL_FASTTIMER_USE_RDTSC static U32 getCPUClockCount32() { unsigned __int64 val = __rdtsc(); @@ -159,23 +139,37 @@ public: #endif // (LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) -#if (LL_LINUX || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) +#if LL_DARWIN && LL_ARM64 + // + // Mac implementation of CPU clock - non-x86. + // + static U64 getCPUClockCount64() + { + return clock_gettime_nsec_np(CLOCK_UPTIME_RAW); + } + + static U32 getCPUClockCount32() + { + return (U32)(getCPUClockCount64() >> 8); + } +#endif // LL_DARWIN && LL_ARM64 + +#if (LL_LINUX || LL_DARWIN) && (LL_X86 || LL_X86_64) // // Mac+Linux FAST x86 implementation of CPU clock + // +#if LL_FASTTIMER_USE_RDTSC static U32 getCPUClockCount32() { - U32 low(0),high(0); - __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); - return (low>>8) | (high<<24); + U64 time_stamp = __rdtsc() >> 8U; + return static_cast<U32>(time_stamp); } static U64 getCPUClockCount64() { - U32 low(0),high(0); - __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); - return (U64)low | ( ((U64)high) << 32); + return static_cast<U64>(__rdtsc()); } - +#endif #endif static BlockTimerStatHandle& getRootTimeBlock(); diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index a783e18e49..a6ecad2cf7 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -628,6 +628,8 @@ private: #elif LL_DARWIN +#include <CoreFoundation/CoreFoundation.h> +#include <IOKit/IOKitLib.h> #include <mach/machine.h> #include <sys/sysctl.h> @@ -638,17 +640,58 @@ public: { getCPUIDInfo(); uint64_t frequency = getSysctlInt64("hw.cpufrequency"); + if(frequency == 0) // Attempt to query IO Services for pcore frequency + { + CFMutableDictionaryRef arm_io_matching = IOServiceMatching("AppleARMIODevice"); + io_iterator_t iter; + kern_return_t ret = IOServiceGetMatchingServices(kIOMasterPortDefault, arm_io_matching, &iter); + if(ret == KERN_SUCCESS) + { + io_object_t obj; + while ((obj = IOIteratorNext(iter))) + { + io_name_t obj_class; + ret = IOObjectGetClass(obj, obj_class); + if(ret == KERN_SUCCESS) + { + io_name_t obj_name; + ret = IORegistryEntryGetName(obj, obj_name); + if(ret == KERN_SUCCESS) + { + if (strncmp(obj_name, "pmgr", sizeof(obj_name)) == 0) + { + CFTypeRef cfData = IORegistryEntryCreateCFProperty(obj, CFSTR("voltage-states5-sram"), kCFAllocatorDefault, 0); // pcore frequency + if(cfData) + { + CFIndex size = CFDataGetLength((CFDataRef)cfData); + std::vector<U8> databuf(size); + CFDataGetBytes((CFDataRef)cfData, CFRangeMake(0, size), databuf.data()); + + frequency = 0x00000000FFFFFFFF & ((databuf[size-5] << 24) | (databuf[size-6] << 16) | (databuf[size-7] << 8) | (databuf[size-8])); + CFRelease(cfData); + } + break; + } + } + } + } + } + } + if (frequency == 0) // fallback to clockrate and tbfrequency + { + frequency = getSysctlClockrate() * getSysctlInt64("hw.tbfrequency"); + } setInfo(eFrequency, (F64)frequency / (F64)1000000); } - virtual ~LLProcessorInfoDarwinImpl() {} + virtual ~LLProcessorInfoDarwinImpl() = default; private: int getSysctlInt(const char* name) { int result = 0; size_t len = sizeof(int); - int error = sysctlbyname(name, (void*)&result, &len, NULL, 0); + int error = sysctlbyname(name, (void*)&result, &len, nullptr, 0); return error == -1 ? 0 : result; } @@ -656,7 +699,7 @@ private: { uint64_t value = 0; size_t size = sizeof(value); - int result = sysctlbyname(name, (void*)&value, &size, NULL, 0); + int result = sysctlbyname(name, (void*)&value, &size, nullptr, 0); if ( result == 0 ) { if ( size == sizeof( uint64_t ) ) @@ -676,6 +719,14 @@ private: return result == -1 ? 0 : value; } + uint64_t getSysctlClockrate() + { + struct clockinfo clockrate{}; + size_t size = sizeof(clockrate); + int error = sysctlbyname("kern.clockrate", &clockrate, &size, nullptr, 0); + return error == -1 ? 0 : clockrate.hz; + } + void getCPUIDInfo() { size_t len = 0; |
