Skip to content

Commit 6e70fdd

Browse files
committed
runtime: fix cputicks on x86
See the following issue for context: #9729 (comment) In short, RDTSC can produce skewed results without preceding LFENCE/MFENCE. Information on this matter is very scrappy in the internet. But this is what linux kernel does (see rdtsc_barrier). It also fixes the test program on my machine. Update #9729 Change-Id: I3c1ffbf129fdfdd388bd5b7911b392b319248e68 Reviewed-on: https://go-review.googlesource.com/5033 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 5868ce3 commit 6e70fdd

File tree

4 files changed

+50
-12
lines changed

4 files changed

+50
-12
lines changed

src/runtime/asm_386.s

+23-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
3030
CPUID
3131
CMPL AX, $0
3232
JE nocpuinfo
33+
34+
// Figure out how to serialize RDTSC.
35+
// On Intel processors LFENCE is enough. AMD requires MFENCE.
36+
// Don't know about the rest, so let's do MFENCE.
37+
CMPL BX, $0x756E6547 // "Genu"
38+
JNE notintel
39+
CMPL DX, $0x49656E69 // "ineI"
40+
JNE notintel
41+
CMPL CX, $0x6C65746E // "ntel"
42+
JNE notintel
43+
MOVB $1, runtime·lfenceBeforeRdtsc(SB)
44+
notintel:
45+
3346
MOVL $1, AX
3447
CPUID
3548
MOVL CX, runtime·cpuid_ecx(SB)
@@ -868,9 +881,17 @@ TEXT runtime·gogetcallersp(SB),NOSPLIT,$0-8
868881
MOVL AX, ret+4(FP)
869882
RET
870883

871-
// int64 runtime·cputicks(void), so really
872-
// void runtime·cputicks(int64 *ticks)
884+
// func cputicks() int64
873885
TEXT runtime·cputicks(SB),NOSPLIT,$0-8
886+
TESTL $0x4000000, runtime·cpuid_edx(SB) // no sse2, no mfence
887+
JEQ done
888+
CMPB runtime·lfenceBeforeRdtsc(SB), $1
889+
JNE mfence
890+
BYTE $0x0f; BYTE $0xae; BYTE $0xe8 // LFENCE
891+
JMP done
892+
mfence:
893+
BYTE $0x0f; BYTE $0xae; BYTE $0xf0 // MFENCE
894+
done:
874895
RDTSC
875896
MOVL AX, ret_lo+0(FP)
876897
MOVL DX, ret_hi+4(FP)

src/runtime/asm_amd64.s

+21-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
3030
CPUID
3131
CMPQ AX, $0
3232
JE nocpuinfo
33+
34+
// Figure out how to serialize RDTSC.
35+
// On Intel processors LFENCE is enough. AMD requires MFENCE.
36+
// Don't know about the rest, so let's do MFENCE.
37+
CMPL BX, $0x756E6547 // "Genu"
38+
JNE notintel
39+
CMPL DX, $0x49656E69 // "ineI"
40+
JNE notintel
41+
CMPL CX, $0x6C65746E // "ntel"
42+
JNE notintel
43+
MOVB $1, runtime·lfenceBeforeRdtsc(SB)
44+
notintel:
45+
3346
MOVQ $1, AX
3447
CPUID
3548
MOVL CX, runtime·cpuid_ecx(SB)
@@ -865,8 +878,15 @@ TEXT runtime·gogetcallersp(SB),NOSPLIT,$0-16
865878
MOVQ AX, ret+8(FP)
866879
RET
867880

868-
// int64 runtime·cputicks(void)
881+
// func cputicks() int64
869882
TEXT runtime·cputicks(SB),NOSPLIT,$0-0
883+
CMPB runtime·lfenceBeforeRdtsc(SB), $1
884+
JNE mfence
885+
BYTE $0x0f; BYTE $0xae; BYTE $0xe8 // LFENCE
886+
JMP done
887+
mfence:
888+
BYTE $0x0f; BYTE $0xae; BYTE $0xf0 // MFENCE
889+
done:
870890
RDTSC
871891
SHLQ $32, DX
872892
ADDQ DX, AX

src/runtime/runtime1.go

-7
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,6 @@ var (
5858
iswindows int32
5959
)
6060

61-
// Information about what cpu features are available.
62-
// Set on startup in asm_{x86/amd64}.s.
63-
var (
64-
//cpuid_ecx uint32
65-
//cpuid_edx uint32
66-
)
67-
6861
func goargs() {
6962
if GOOS == "windows" {
7063
return

src/runtime/runtime2.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -562,12 +562,16 @@ var (
562562
goos *int8
563563
ncpu int32
564564
iscgo bool
565-
cpuid_ecx uint32
566-
cpuid_edx uint32
567565
signote note
568566
forcegc forcegcstate
569567
sched schedt
570568
newprocs int32
569+
570+
// Information about what cpu features are available.
571+
// Set on startup in asm_{x86,amd64}.s.
572+
cpuid_ecx uint32
573+
cpuid_edx uint32
574+
lfenceBeforeRdtsc bool
571575
)
572576

573577
/*

0 commit comments

Comments
 (0)