From d8ff3d592088ef175222dbf69991887f0dd458d6 Mon Sep 17 00:00:00 2001 From: Giovanni Bajo Date: Sat, 30 Sep 2017 11:44:21 +0200 Subject: [PATCH] runtime: fix wall time computation in macOS High Sierra Latest macOS High Sierra changed how the wall time information is exported into the commpage. Backward compatibility was partly preserved, that is previous Go versions are basically forced to go through a syscall which is much slower and is not able to get nanosecond precision. Implement the new commpage layout and wall time computation, using a version check to fallback to the previous code on older operating systems. Fixes #22037 Change-Id: I8c2176eaca83a5d7be23443946a6b4c653ec7f68 Reviewed-on: https://go-review.googlesource.com/67332 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/runtime/sys_darwin_amd64.s | 86 ++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s index ea21ffdd37..e8ae6fac4f 100644 --- a/src/runtime/sys_darwin_amd64.s +++ b/src/runtime/sys_darwin_amd64.s @@ -107,15 +107,24 @@ TEXT runtime·madvise(SB), NOSPLIT, $0 RET // OS X comm page time offsets -// http://www.opensource.apple.com/source/xnu/xnu-1699.26.8/osfmk/i386/cpu_capabilities.h +// https://opensource.apple.com/source/xnu/xnu-4570.1.46/osfmk/i386/cpu_capabilities.h + +#define commpage_version 0x1e + #define v12_nt_tsc_base 0x50 #define v12_nt_scale 0x58 #define v12_nt_shift 0x5c #define v12_nt_ns_base 0x60 #define v12_nt_generation 0x68 -#define v12_gtod_generation 0x6c -#define v12_gtod_ns_base 0x70 -#define v12_gtod_sec_base 0x78 +#define v12_gtod_generation 0x6c // obsolete since High Sierra (v13) +#define v12_gtod_ns_base 0x70 // obsolete since High Sierra (v13) +#define v12_gtod_sec_base 0x78 // obsolete since High Sierra (v13) + +#define v13_gtod_ns_base 0xd0 +#define v13_gtod_sec_ofs 0xd8 +#define v13_gtod_frac_ofs 0xe0 +#define v13_gtod_scale 0xe8 +#define v13_gtod_tkspersec 0xf0 TEXT runtime·nanotime(SB),NOSPLIT,$0-8 MOVQ $0x7fffffe00000, BP /* comm page base */ @@ -151,6 +160,75 @@ TEXT time·now(SB), NOSPLIT, $32-24 // are used in the systime fallback, as the timeval address // filled in by the system call. MOVQ $0x7fffffe00000, BP /* comm page base */ + CMPW commpage_version(BP), $13 + JB v12 /* sierra and older */ + + // This is the new code, for macOS High Sierra (v13) and newer. +v13: + // Loop trying to take a consistent snapshot + // of the time parameters. +timeloop13: + MOVQ v13_gtod_ns_base(BP), R12 + + MOVL v12_nt_generation(BP), CX + TESTL CX, CX + JZ timeloop13 + RDTSC + MOVQ v12_nt_tsc_base(BP), SI + MOVL v12_nt_scale(BP), DI + MOVQ v12_nt_ns_base(BP), BX + CMPL v12_nt_generation(BP), CX + JNE timeloop13 + + MOVQ v13_gtod_sec_ofs(BP), R8 + MOVQ v13_gtod_frac_ofs(BP), R9 + MOVQ v13_gtod_scale(BP), R10 + MOVQ v13_gtod_tkspersec(BP), R11 + CMPQ v13_gtod_ns_base(BP), R12 + JNE timeloop13 + + // Compute monotonic time + // mono = ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base + // The multiply and shift extracts the top 64 bits of the 96-bit product. + SHLQ $32, DX + ADDQ DX, AX + SUBQ SI, AX + MULQ DI + SHRQ $32, AX:DX + ADDQ BX, AX + + // Subtract startNano base to return the monotonic runtime timer + // which is an offset from process boot. + MOVQ AX, BX + MOVQ runtime·startNano(SB), CX + SUBQ CX, BX + MOVQ BX, monotonic+16(FP) + + // Now compute the 128-bit wall time: + // wall = ((mono - gtod_ns_base) * gtod_scale) + gtod_offs + // The parameters are updated every second, so if we found them + // outdated (that is, more than one second is passed from the ns base), + // fallback to the syscall. + TESTQ R12, R12 + JZ systime + SUBQ R12, AX + CMPQ R11, AX + JB systime + MULQ R10 + ADDQ R9, AX + ADCQ R8, DX + + // Convert the 128-bit wall time into (sec,nsec). + // High part (seconds) is already good to go, while low part + // (fraction of seconds) must be converted to nanoseconds. + MOVQ DX, sec+0(FP) + MOVQ $1000000000, CX + MULQ CX + MOVQ DX, nsec+8(FP) + RET + + // This is the legacy code needed for macOS Sierra (v12) and older. +v12: // Loop trying to take a consistent snapshot // of the time parameters. timeloop: