]> Cypherpunks repositories - gostls13.git/commitdiff
Revert "runtime: use QPC for nanotime and time.now on windows/arm"
authorJordan Rhee <jordanrh@microsoft.com>
Wed, 19 Dec 2018 00:32:09 +0000 (16:32 -0800)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 19 Dec 2018 18:10:21 +0000 (18:10 +0000)
This reverts change https://golang.org/cl/154758.

Restore the previous implementations of nanotime and time.now, which
are sufficiently high resolution and more efficient than
QueryPerformanceCounter. The intent of the change was to improve
resolution of tracing timestamps, but the change was overly broad
as it was only necessary to fix cputicks(). cputicks() is fixed in
a subsequent change.

Updates #26148

Change-Id: Ib9883d02fe1af2cc4940e866d8f6dc7622d47781
Reviewed-on: https://go-review.googlesource.com/c/154761
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/runtime/os_windows.go
src/runtime/sys_windows_arm.s

index 20fe01c40375d6b3f8a42e18582fc4cd8385a8fc..9b34589874c54cea836bf0dcfce0c69745dab61a 100644 (file)
@@ -198,12 +198,9 @@ func loadOptionalSyscalls() {
        }
        _NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000"))
 
-       underWine := windowsFindfunc(n32, []byte("wine_get_version\000")) != nil
-       if underWine || GOARCH == "arm" {
-               initQPC(k32)
-       }
-       if underWine {
-               initWine()
+       if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil {
+               // running on Wine
+               initWine(k32)
        }
 }
 
@@ -360,7 +357,7 @@ func nowQPC() (sec int64, nsec int32, mono int64) {
        return
 }
 
-func initQPC(k32 uintptr) {
+func initWine(k32 uintptr) {
        _GetSystemTimeAsFileTime = windowsFindfunc(k32, []byte("GetSystemTimeAsFileTime\000"))
        if _GetSystemTimeAsFileTime == nil {
                throw("could not find GetSystemTimeAsFileTime() syscall")
@@ -397,9 +394,7 @@ func initQPC(k32 uintptr) {
        // We have to do it this way (or similar), since multiplying QPC counter by 100 millions overflows
        // int64 and resulted time will always be invalid.
        qpcMultiplier = int64(timediv(1000000000, qpcFrequency, nil))
-}
 
-func initWine() {
        useQPCTime = 1
 }
 
index 514dc5223e9c9dbeae81a45451adb3bf4fa4bdd6..60be74b95cf021e5b74ba7313bcba411affd3101 100644 (file)
@@ -487,12 +487,115 @@ TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0
        MOVW    R0, (R0)
        RET
 
-TEXT runtime·nanotime(SB),NOSPLIT|NOFRAME,$0-8
+// See http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
+// Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
+#define _INTERRUPT_TIME 0x7ffe0008
+#define _SYSTEM_TIME 0x7ffe0014
+#define time_lo 0
+#define time_hi1 4
+#define time_hi2 8
+
+TEXT runtime·nanotime(SB),NOSPLIT,$0-8
+       MOVW    $0, R0
+       MOVB    runtime·useQPCTime(SB), R0
+       CMP     $0, R0
+       BNE     useQPC
+       MOVW    $_INTERRUPT_TIME, R3
+loop:
+       MOVW    time_hi1(R3), R1
+       MOVW    time_lo(R3), R0
+       MOVW    time_hi2(R3), R2
+       CMP     R1, R2
+       BNE     loop
+
+       // wintime = R1:R0, multiply by 100
+       MOVW    $100, R2
+       MULLU   R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
+       MULA    R1, R2, R4, R4
+
+       // wintime*100 = R4:R3
+       MOVW    R3, ret_lo+0(FP)
+       MOVW    R4, ret_hi+4(FP)
+       RET
+useQPC:
        B       runtime·nanotimeQPC(SB)                // tail call
        RET
 
-TEXT time·now(SB),NOSPLIT|NOFRAME,$0-20
-       B       runtime·nowQPC(SB)             // tail call
+TEXT time·now(SB),NOSPLIT,$0-20
+       MOVW    $0, R0
+       MOVB    runtime·useQPCTime(SB), R0
+       CMP     $0, R0
+       BNE     useQPC
+       MOVW    $_INTERRUPT_TIME, R3
+loop:
+       MOVW    time_hi1(R3), R1
+       MOVW    time_lo(R3), R0
+       MOVW    time_hi2(R3), R2
+       CMP     R1, R2
+       BNE     loop
+
+       // wintime = R1:R0, multiply by 100
+       MOVW    $100, R2
+       MULLU   R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
+       MULA    R1, R2, R4, R4
+
+       // wintime*100 = R4:R3
+       MOVW    R3, mono+12(FP)
+       MOVW    R4, mono+16(FP)
+
+       MOVW    $_SYSTEM_TIME, R3
+wall:
+       MOVW    time_hi1(R3), R1
+       MOVW    time_lo(R3), R0
+       MOVW    time_hi2(R3), R2
+       CMP     R1, R2
+       BNE     wall
+
+       // w = R1:R0 in 100ns untis
+       // convert to Unix epoch (but still 100ns units)
+       #define delta 116444736000000000
+       SUB.S   $(delta & 0xFFFFFFFF), R0
+       SBC     $(delta >> 32), R1
+
+       // Convert to nSec
+       MOVW    $100, R2
+       MULLU   R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
+       MULA    R1, R2, R4, R4
+       // w = R2:R1 in nSec
+       MOVW    R3, R1        // R4:R3 -> R2:R1
+       MOVW    R4, R2
+
+       // multiply nanoseconds by reciprocal of 10**9 (scaled by 2**61)
+       // to get seconds (96 bit scaled result)
+       MOVW    $0x89705f41, R3         // 2**61 * 10**-9
+       MULLU   R1,R3,(R6,R5)           // R7:R6:R5 = R2:R1 * R3
+       MOVW    $0,R7
+       MULALU  R2,R3,(R7,R6)
+
+       // unscale by discarding low 32 bits, shifting the rest by 29
+       MOVW    R6>>29,R6               // R7:R6 = (R7:R6:R5 >> 61)
+       ORR     R7<<3,R6
+       MOVW    R7>>29,R7
+
+       // subtract (10**9 * sec) from nsec to get nanosecond remainder
+       MOVW    $1000000000, R5 // 10**9
+       MULLU   R6,R5,(R9,R8)   // R9:R8 = R7:R6 * R5
+       MULA    R7,R5,R9,R9
+       SUB.S   R8,R1           // R2:R1 -= R9:R8
+       SBC     R9,R2
+
+       // because reciprocal was a truncated repeating fraction, quotient
+       // may be slightly too small -- adjust to make remainder < 10**9
+       CMP     R5,R1   // if remainder > 10**9
+       SUB.HS  R5,R1   //    remainder -= 10**9
+       ADD.HS  $1,R6   //    sec += 1
+
+       MOVW    R6,sec_lo+0(FP)
+       MOVW    R7,sec_hi+4(FP)
+       MOVW    R1,nsec+8(FP)
+       RET
+useQPC:
+       B       runtime·nanotimeQPC(SB)                // tail call
        RET
 
 // save_g saves the g register (R10) into thread local memory