clock_gettime in hotspot
22 Nov 2015JVM issues clock_gettime syscall quite often as we saw in the last article. Now I dig into hotspot code to see where/why clock_gettime is called.
clock_init()
in os_linux.cpp checks if clock_gettime()
is available, and assign its function pointer to _clock_gettime
variable.
void os::Linux::clock_init() {
// we do dlopen's in this particular order due to bug in linux
// dynamical loader (see 6348968) leading to crash on exit
void* handle = dlopen("librt.so.1", RTLD_LAZY);
if (handle == NULL) {
handle = dlopen("librt.so", RTLD_LAZY);
}
if (handle) {
int (*clock_getres_func)(clockid_t, struct timespec*) =
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
int (*clock_gettime_func)(clockid_t, struct timespec*) =
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime");
if (clock_getres_func && clock_gettime_func) {
// See if monotonic clock is supported by the kernel. Note that some
// early implementations simply return kernel jiffies (updated every
// 1/100 or 1/1000 second). It would be bad to use such a low res clock
// for nano time (though the monotonic property is still nice to have).
// It's fixed in newer kernels, however clock_getres() still returns
// 1/HZ. We check if clock_getres() works, but will ignore its reported
// resolution for now. Hopefully as people move to new kernels, this
// won't be a problem.
struct timespec res;
struct timespec tp;
if (clock_getres_func (CLOCK_MONOTONIC, &res) == 0 &&
clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
// yes, monotonic clock is supported
_clock_gettime = clock_gettime_func;
return;
} else {
// close librt if there is no monotonic clock
dlclose(handle);
}
}
}
warning("No monotonic clock was available - timed services may " \
"be adversely affected if the time-of-day clock changes");
}
OS independent function os::javaTimeNanos
calls clock_gettime
here. Although there’re some other call sites of clock_gettime
in os_linux.cpp, I’ll look into os::javaTimeNanos
first.
jlong os::javaTimeNanos() {
if (Linux::supports_monotonic_clock()) {
struct timespec tp;
int status = Linux::clock_gettime(CLOCK_MONOTONIC, &tp);
assert(status == 0, "gettime error");
jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
return result;
} else {
timeval time;
int status = gettimeofday(&time, NULL);
assert(status != -1, "linux error");
jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);
return 1000 * usecs;
}
}
On the assumption that the behavior of calling clock_gettime is OS independent, which may be wrong though, I grepped javaTimeNanos under “src/share”, and got this list.
$ cd hotspot-87ee5ee27509/src/share
$ grep -r -l javaTimeNanos *
vm/c1/c1_LIRGenerator.cpp
vm/c1/c1_Runtime1.cpp
vm/classfile/altHashing.cpp
vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
vm/gc_implementation/parNew/parNewGeneration.cpp
vm/memory/defNewGeneration.cpp
vm/memory/genCollectedHeap.cpp
vm/memory/genMarkSweep.cpp
vm/memory/referenceProcessor.cpp
vm/opto/library_call.cpp
vm/prims/jvm.cpp
vm/prims/jvmtiEnv.cpp
vm/runtime/os.hpp
vm/runtime/safepoint.cpp
vm/runtime/thread.cpp
The first few files are to support java’s System.nanoTime()
and for GC.
So let’s ignore them.
I’ll look into vm/{memory,runtime} next.