From e51b3ae0eebfacd15cad9216b8dd2d2597b860c5 Mon Sep 17 00:00:00 2001 From: Yuval Pavel Zholkover Date: Fri, 11 Mar 2022 19:54:08 +0200 Subject: [PATCH] runtime: fast clock_gettime on FreeBSD, split getHPETTimecounter Call only initHPETTimecounter on the system stack. Use O_CLOEXEC flag when opening the HPET device. FreeBSD 12.3-RELEASE-p2, AMD FX-8300 paulzhol@relic:~/go/src/time % ~/gocode/bin/benchcmp old_hpet.txt new_hpet.txt benchcmp is deprecated in favor of benchstat: https://pkg.go.dev/golang.org/x/perf/cmd/benchstat benchmark old ns/op new ns/op delta BenchmarkNow-8 1420 1397 -1.62% BenchmarkNowUnixNano-8 1421 1404 -1.20% BenchmarkNowUnixMilli-8 1423 1405 -1.26% BenchmarkNowUnixMicro-8 1423 1404 -1.34% Update #50947 Change-Id: I553b5427fb0b86d7e070af4516b36326bc0aaf00 Reviewed-on: https://go-review.googlesource.com/c/go/+/391856 Reviewed-by: Michael Knyszek Reviewed-by: Michael Pratt --- src/runtime/vdso_freebsd_x86.go | 58 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/runtime/vdso_freebsd_x86.go b/src/runtime/vdso_freebsd_x86.go index 5324a3d4cb3..66d1c654885 100644 --- a/src/runtime/vdso_freebsd_x86.go +++ b/src/runtime/vdso_freebsd_x86.go @@ -34,10 +34,8 @@ func (th *vdsoTimehands) getTSCTimecounter() uint32 { return uint32(tsc) } -//go:systemstack +//go:nosplit func (th *vdsoTimehands) getHPETTimecounter() (uint32, bool) { - const digits = "0123456789" - idx := int(th.x86_hpet_idx) if idx >= len(hpetDevMap) { return 0, false @@ -45,25 +43,7 @@ func (th *vdsoTimehands) getHPETTimecounter() (uint32, bool) { p := atomic.Loaduintptr(&hpetDevMap[idx]) if p == 0 { - var devPath [len(hpetDevPath)]byte - copy(devPath[:], hpetDevPath) - devPath[9] = digits[idx] - - fd := open(&devPath[0], 0 /* O_RDONLY */, 0) - if fd < 0 { - atomic.Casuintptr(&hpetDevMap[idx], 0, ^uintptr(0)) - return 0, false - } - - addr, mmapErr := mmap(nil, physPageSize, _PROT_READ, _MAP_SHARED, fd, 0) - closefd(fd) - newP := uintptr(addr) - if mmapErr != 0 { - newP = ^uintptr(0) - } - if !atomic.Casuintptr(&hpetDevMap[idx], 0, newP) && mmapErr == 0 { - munmap(addr, physPageSize) - } + systemstack(func() { initHPETTimecounter(idx) }) p = atomic.Loaduintptr(&hpetDevMap[idx]) } if p == ^uintptr(0) { @@ -72,20 +52,38 @@ func (th *vdsoTimehands) getHPETTimecounter() (uint32, bool) { return *(*uint32)(unsafe.Pointer(p + _HPET_MAIN_COUNTER)), true } +//go:systemstack +func initHPETTimecounter(idx int) { + const digits = "0123456789" + + var devPath [len(hpetDevPath)]byte + copy(devPath[:], hpetDevPath) + devPath[9] = digits[idx] + + fd := open(&devPath[0], 0 /* O_RDONLY */ |_O_CLOEXEC, 0) + if fd < 0 { + atomic.Casuintptr(&hpetDevMap[idx], 0, ^uintptr(0)) + return + } + + addr, mmapErr := mmap(nil, physPageSize, _PROT_READ, _MAP_SHARED, fd, 0) + closefd(fd) + newP := uintptr(addr) + if mmapErr != 0 { + newP = ^uintptr(0) + } + if !atomic.Casuintptr(&hpetDevMap[idx], 0, newP) && mmapErr == 0 { + munmap(addr, physPageSize) + } +} + //go:nosplit func (th *vdsoTimehands) getTimecounter() (uint32, bool) { switch th.algo { case _VDSO_TH_ALGO_X86_TSC: return th.getTSCTimecounter(), true case _VDSO_TH_ALGO_X86_HPET: - var ( - tc uint32 - ok bool - ) - systemstack(func() { - tc, ok = th.getHPETTimecounter() - }) - return tc, ok + return th.getHPETTimecounter() default: return 0, false }