-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Last updated: 2017-10-09
Abstract
Use the Linux vDSO __vdso_clock_gettime
function (if available) to accelerate calls to time.Now()
on linux/386
.
Background
The Linux kernel can provide a "fast path" for some heavily used system calls which can be satisfied in user space more efficiently. The vDSO is an ELF-formatted virtual dynamic shared library injected into a process address space by the kernel, usually provided through an auxv
entry at process startup. Several clock and time-related functions are included in this set of functions. When the vDSO is not present, normal syscalls must be used.
This mechanism is already in use on linux/amd64
to accelerate time.Now()
.
Proposal
The proposal is to use the same approach as used on linux/amd64
to locate the relevant vDSO function, and use it if available, to accelerate time.Now()
on linux/386
.
The proposal is to only accelerate the clock functions required to implement time.Now()
.
No other calls will be affected.
Rationale
There is a significant performance difference between a syscall to obtain a clock, and a corresponding vDSO-based call.
A prototype implementation found that the vDSO path is 5x to 10x faster than the syscall equivalent, depending on processor, virtualization etc.
For certain applications that make heavy use of timestamping (for example, metrics and telemetry), improving the performance of timestamping can make a significant performance improvement overall.
As of go 1.9, time.Now()
on linux/386
requires two syscalls, which has doubled the call cost over previous versions. Adding vDSO support would more than pay for this.
Compatibility
If the vDSO-accelerated function is not found at runtime, then the existing syscall implementation will automatically be used as fallback.
The change will be limited to the time functions provided internally in runtime
, and used by time.Now()
, so that other calls will not be affected.
Implementation
Adapt the code currently in src/runtime/vdso_linux_amd64.go
so that it can also be used for ELF32 on linux/386
. The initial implementation will be based on a code copy-and-edit so that only linux/386
is affected by the change.
Adapt the runtime.walltime()
and runtime.nanotime()
functions (in src/runtime/sys_linux_386.s
) to check for and use __vdso_clock_gettime
if it was found during startup, or fallback to the existing syscall if not.
Refactor The vDSO ELF symbol lookup code to eliminate duplication between linux/386
and linux/amd64
. The ELF structure definitions, and required symbols differ between 32-bit and 64-bit, but the lookup code is the same.
Open issues
Number of changesets
I propose implementing this with two changesets:
- support
linux/386
by duplicating code fromlinux/amd64
, so that 386 support can be reviewed/added without disturbing code for other platforms. - refactor code affecting both
linux/amd64
andlinux/386
to eliminate code duplication.
Is this OK, or should a single changeset be used?
Tests
There don't appear to be any explicit tests for linux/amd64
to verify that the fallback path can be called. I'll include a basic test for this covering linux/386
and linux/amd64
, though I am unsure if it is necessary, or alternatively - if the test should be enhanced further.