mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Use vDSO clock_gettime
The vDSO calls are much faster. For exeample, here are results of read_benchmark_test_tmpfs_kvm before and after this change: Before: BM_Read/65536/real_time 7309 ns 7260 ns 82640 bytes_per_second=8.35016G/s After: BM_Read/65536/real_time 2065 ns 2080 ns 346151 bytes_per_second=29.558G/s PiperOrigin-RevId: 409547486
This commit is contained in:
@@ -27,10 +27,12 @@ go_library(
|
||||
"sampler.go",
|
||||
"sampler_amd64.go",
|
||||
"sampler_arm64.go",
|
||||
"sampler_unsafe.go",
|
||||
"seqatomic_parameters_unsafe.go",
|
||||
"tsc_amd64.s",
|
||||
"tsc_arm64.s",
|
||||
"vdso.go",
|
||||
"vdso_amd64.s",
|
||||
"vdso_arm64.s",
|
||||
],
|
||||
visibility = ["//:sandbox"],
|
||||
deps = [
|
||||
@@ -49,6 +51,11 @@ go_test(
|
||||
"calibrated_clock_test.go",
|
||||
"parameters_test.go",
|
||||
"sampler_test.go",
|
||||
"vdso_test.go",
|
||||
],
|
||||
library = ":time",
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"@org_golang_x_sys//unix:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -17,6 +17,7 @@ package time
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
)
|
||||
|
||||
@@ -216,3 +217,35 @@ func (s *sampler) Range() (sample, sample, bool) {
|
||||
|
||||
return s.samples[0], s.samples[len(s.samples)-1], true
|
||||
}
|
||||
|
||||
// syscallTSCReferenceClocks is the standard referenceClocks, collecting
|
||||
// samples using CLOCK_GETTIME and RDTSC.
|
||||
type syscallTSCReferenceClocks struct {
|
||||
tscCycleClock
|
||||
}
|
||||
|
||||
// Sample implements sampler.Sample.
|
||||
func (syscallTSCReferenceClocks) Sample(c ClockID) (sample, error) {
|
||||
var s sample
|
||||
|
||||
s.before = Rdtsc()
|
||||
|
||||
// Don't call clockGettime to avoid a call which may call morestack.
|
||||
var ts unix.Timespec
|
||||
|
||||
vdsoClockGettime(c, &ts)
|
||||
|
||||
s.after = Rdtsc()
|
||||
s.ref = ReferenceNS(ts.Nano())
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// clockGettime calls SYS_CLOCK_GETTIME, returning time in nanoseconds.
|
||||
func clockGettime(c ClockID) (ReferenceNS, error) {
|
||||
var ts unix.Timespec
|
||||
|
||||
vdsoClockGettime(c, &ts)
|
||||
|
||||
return ReferenceNS(ts.Nano()), nil
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright 2018 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package time
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// syscallTSCReferenceClocks is the standard referenceClocks, collecting
|
||||
// samples using CLOCK_GETTIME and RDTSC.
|
||||
type syscallTSCReferenceClocks struct {
|
||||
tscCycleClock
|
||||
}
|
||||
|
||||
// Sample implements sampler.Sample.
|
||||
func (syscallTSCReferenceClocks) Sample(c ClockID) (sample, error) {
|
||||
var s sample
|
||||
|
||||
s.before = Rdtsc()
|
||||
|
||||
// Don't call clockGettime to avoid a call which may call morestack.
|
||||
var ts unix.Timespec
|
||||
_, _, e := unix.RawSyscall(unix.SYS_CLOCK_GETTIME, uintptr(c), uintptr(unsafe.Pointer(&ts)), 0)
|
||||
if e != 0 {
|
||||
return sample{}, e
|
||||
}
|
||||
|
||||
s.after = Rdtsc()
|
||||
s.ref = ReferenceNS(ts.Nano())
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// clockGettime calls SYS_CLOCK_GETTIME, returning time in nanoseconds.
|
||||
func clockGettime(c ClockID) (ReferenceNS, error) {
|
||||
var ts unix.Timespec
|
||||
_, _, e := unix.RawSyscall(unix.SYS_CLOCK_GETTIME, uintptr(c), uintptr(unsafe.Pointer(&ts)), 0)
|
||||
if e != 0 {
|
||||
return 0, e
|
||||
}
|
||||
|
||||
return ReferenceNS(ts.Nano()), nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package time
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func vdsoClockGettime(clockid ClockID, ts *unix.Timespec) int
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
#define SYS_clock_gettime 228
|
||||
|
||||
TEXT ·vdsoClockGettime(SB), NOSPLIT, $0-24
|
||||
MOVL clockid+0(FP), DI
|
||||
MOVQ ts+8(FP), SI
|
||||
MOVQ runtime·vdsoClockgettimeSym(SB), AX
|
||||
CMPQ AX, $0
|
||||
JEQ fallback
|
||||
CALL AX
|
||||
MOVQ AX, ret+16(FP)
|
||||
RET
|
||||
fallback:
|
||||
MOVQ $SYS_clock_gettime, AX
|
||||
SYSCALL
|
||||
MOVQ AX, ret+16(FP)
|
||||
RET
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
#define SYS_clock_gettime 113
|
||||
|
||||
TEXT ·vdsoClockGettime(SB), NOSPLIT, $0-24
|
||||
MOVW clockid+0(FP), R0
|
||||
MOVD ts+8(FP), R1
|
||||
MOVD runtime·vdsoClockgettimeSym(SB), R2
|
||||
CBZ R2, fallback
|
||||
BL (R2)
|
||||
MOVD R0, ret+16(FP)
|
||||
RET
|
||||
fallback:
|
||||
MOVD $SYS_clock_gettime, R8
|
||||
SVC
|
||||
MOVD R0, ret+16(FP)
|
||||
RET
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package time
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
)
|
||||
|
||||
func TestClockGetTime(t *testing.T) {
|
||||
ts := unix.Timespec{}
|
||||
if ret := vdsoClockGettime(linux.CLOCK_MONOTONIC, &ts); ret != 0 {
|
||||
t.Fatalf("Unexpected error code: %v", ret)
|
||||
}
|
||||
sts := unix.Timespec{}
|
||||
if _, _, errno := unix.RawSyscall(unix.SYS_CLOCK_GETTIME,
|
||||
uintptr(linux.CLOCK_MONOTONIC),
|
||||
uintptr(unsafe.Pointer(&sts)), 0); errno != 0 {
|
||||
t.Fatalf("Unexpected error code: %v", errno)
|
||||
}
|
||||
// Check that ts.Sec is in [sts.Sec, sts.Sec + 5].
|
||||
if sts.Sec < ts.Sec || sts.Sec > ts.Sec+5 {
|
||||
t.Fatalf("Unexpected delta: vdso %+v syscall %+v", ts, sts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClockGetTimeEINVAL(t *testing.T) {
|
||||
ts := unix.Timespec{}
|
||||
if ret := vdsoClockGettime(-1, &ts); ret != -int(syscall.EINVAL) {
|
||||
t.Fatalf("Unexpected error code: %v", ret)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user