8242504: Enhance the system clock to nanosecond precision
Co-authored-by: Mark Kralj-Taylor <kralj.mark@gmail.com> Reviewed-by: dfuchs, rriggs, dcubed, vtewari
This commit is contained in:
parent
60ac615aa8
commit
7228978b19
@ -1376,18 +1376,35 @@ double os::elapsedVTime() {
|
||||
}
|
||||
|
||||
jlong os::javaTimeMillis() {
|
||||
timeval time;
|
||||
int status = gettimeofday(&time, NULL);
|
||||
assert(status != -1, "linux error");
|
||||
return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000);
|
||||
if (os::Posix::supports_clock_gettime()) {
|
||||
struct timespec ts;
|
||||
int status = os::Posix::clock_gettime(CLOCK_REALTIME, &ts);
|
||||
assert_status(status == 0, status, "gettime error");
|
||||
return jlong(ts.tv_sec) * MILLIUNITS +
|
||||
jlong(ts.tv_nsec) / NANOUNITS_PER_MILLIUNIT;
|
||||
} else {
|
||||
timeval time;
|
||||
int status = gettimeofday(&time, NULL);
|
||||
assert(status != -1, "linux error");
|
||||
return jlong(time.tv_sec) * MILLIUNITS +
|
||||
jlong(time.tv_usec) / (MICROUNITS / MILLIUNITS);
|
||||
}
|
||||
}
|
||||
|
||||
void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) {
|
||||
timeval time;
|
||||
int status = gettimeofday(&time, NULL);
|
||||
assert(status != -1, "linux error");
|
||||
seconds = jlong(time.tv_sec);
|
||||
nanos = jlong(time.tv_usec) * 1000;
|
||||
if (os::Posix::supports_clock_gettime()) {
|
||||
struct timespec ts;
|
||||
int status = os::Posix::clock_gettime(CLOCK_REALTIME, &ts);
|
||||
assert_status(status == 0, status, "gettime error");
|
||||
seconds = jlong(ts.tv_sec);
|
||||
nanos = jlong(ts.tv_nsec);
|
||||
} else {
|
||||
timeval time;
|
||||
int status = gettimeofday(&time, NULL);
|
||||
assert(status != -1, "linux error");
|
||||
seconds = jlong(time.tv_sec);
|
||||
nanos = jlong(time.tv_usec) * (NANOUNITS / MICROUNITS);
|
||||
}
|
||||
}
|
||||
|
||||
void os::Linux::fast_thread_clock_init() {
|
||||
|
@ -1638,6 +1638,8 @@ void os::Posix::save_preinstalled_handler(int sig, struct sigaction& oldAct) {
|
||||
int (*os::Posix::_clock_gettime)(clockid_t, struct timespec *) = NULL;
|
||||
int (*os::Posix::_clock_getres)(clockid_t, struct timespec *) = NULL;
|
||||
|
||||
bool os::Posix::_supports_monotonic_clock = false;
|
||||
|
||||
static int (*_pthread_condattr_setclock)(pthread_condattr_t *, clockid_t) = NULL;
|
||||
|
||||
static bool _use_clock_monotonic_condattr = false;
|
||||
@ -1653,7 +1655,7 @@ void os::Posix::init(void) {
|
||||
|
||||
void* handle = NULL;
|
||||
|
||||
// For linux we need librt, for other OS we can find
|
||||
// For older linux we need librt, for other OS we can find
|
||||
// this function in regular libc.
|
||||
#ifdef NEEDS_LIBRT
|
||||
// We do dlopen's in this particular order due to bug in linux
|
||||
@ -1673,6 +1675,8 @@ void os::Posix::init(void) {
|
||||
int (*clock_gettime_func)(clockid_t, struct timespec*) =
|
||||
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime");
|
||||
if (clock_getres_func != NULL && clock_gettime_func != NULL) {
|
||||
_clock_gettime = clock_gettime_func;
|
||||
_clock_getres = clock_getres_func;
|
||||
// We assume that if both clock_gettime and clock_getres support
|
||||
// CLOCK_MONOTONIC then the OS provides true high-res monotonic clock.
|
||||
struct timespec res;
|
||||
@ -1680,15 +1684,7 @@ void os::Posix::init(void) {
|
||||
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;
|
||||
_clock_getres = clock_getres_func;
|
||||
} else {
|
||||
#ifdef NEEDS_LIBRT
|
||||
// Close librt if there is no monotonic clock.
|
||||
if (handle != RTLD_DEFAULT) {
|
||||
dlclose(handle);
|
||||
}
|
||||
#endif
|
||||
_supports_monotonic_clock = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,18 +128,18 @@ public:
|
||||
#ifdef SUPPORTS_CLOCK_MONOTONIC
|
||||
|
||||
private:
|
||||
static bool _supports_monotonic_clock;
|
||||
// These need to be members so we can access them from inline functions
|
||||
static int (*_clock_gettime)(clockid_t, struct timespec *);
|
||||
static int (*_clock_getres)(clockid_t, struct timespec *);
|
||||
public:
|
||||
static bool supports_monotonic_clock();
|
||||
static bool supports_clock_gettime();
|
||||
static int clock_gettime(clockid_t clock_id, struct timespec *tp);
|
||||
static int clock_getres(clockid_t clock_id, struct timespec *tp);
|
||||
|
||||
#else
|
||||
|
||||
static bool supports_monotonic_clock() { return false; }
|
||||
|
||||
static bool supports_clock_gettime() { return false; }
|
||||
#endif
|
||||
|
||||
static void to_RTC_abstime(timespec* abstime, int64_t millis);
|
||||
|
@ -32,6 +32,10 @@
|
||||
// Exported clock functionality
|
||||
|
||||
inline bool os::Posix::supports_monotonic_clock() {
|
||||
return _supports_monotonic_clock;
|
||||
}
|
||||
|
||||
inline bool os::Posix::supports_clock_gettime() {
|
||||
return _clock_gettime != NULL;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -177,7 +177,8 @@ public class TestClock_System {
|
||||
+ formatTime("\n\thighest1", highest1));
|
||||
}
|
||||
|
||||
int count=0;
|
||||
int countBetterThanMillisPrecision = 0;
|
||||
int countBetterThanMicrosPrecision = 0;
|
||||
// let's preheat the system a bit:
|
||||
int lastNanos = 0;
|
||||
for (int i = 0; i < 1000 ; i++) {
|
||||
@ -191,7 +192,10 @@ public class TestClock_System {
|
||||
lastNanos = nanos;
|
||||
|
||||
if ((nanos % 1000000) > 0) {
|
||||
count++; // we have micro seconds
|
||||
countBetterThanMillisPrecision++; // we have microseconds
|
||||
}
|
||||
if ((nanos % 1000) > 0) {
|
||||
countBetterThanMicrosPrecision++; // we have nanoseconds
|
||||
}
|
||||
if ((sysnan % 1000000) > 0) {
|
||||
throw new RuntimeException("Expected only millisecconds "
|
||||
@ -200,13 +204,17 @@ public class TestClock_System {
|
||||
}
|
||||
}
|
||||
System.out.println("\nNumber of time stamps which had better than"
|
||||
+ " millisecond precision: "+count+"/"+1000);
|
||||
+ " millisecond precision: "
|
||||
+ countBetterThanMillisPrecision + "/" + 1000);
|
||||
System.out.println("\nNumber of time stamps which had better than"
|
||||
+ " microsecond precision: "
|
||||
+ countBetterThanMicrosPrecision + "/" + 1000);
|
||||
System.out.println(formatTime("\nsystemUTC ", system1));
|
||||
System.out.println(formatTime("highestResolutionUTC ", highest1));
|
||||
if (count == 0) {
|
||||
if (countBetterThanMillisPrecision == 0) {
|
||||
System.err.println("Something is strange: no microsecond "
|
||||
+ "precision with highestResolutionUTC?");
|
||||
throw new RuntimeException("Micro second preccision not reached");
|
||||
+ "precision with highestResolutionUTC?");
|
||||
throw new RuntimeException("Micro second precision not reached");
|
||||
}
|
||||
|
||||
// check again
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,11 +27,12 @@ import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public class Systems {
|
||||
public class SystemTime {
|
||||
|
||||
@Benchmark
|
||||
public long currentTimeMillis() {
|
||||
@ -43,4 +44,9 @@ public class Systems {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public long instantNowAsEpochNanos() {
|
||||
Instant now = Instant.now();
|
||||
return now.getEpochSecond() * 1_000_000_000L + now.getNano();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user