Re: os::javaTimeSystemUTC to call nanosecond precision OS API, so Clock.systemUTC() can give nanosecond precision UTC
Hi Mark, Thanks for the very detailed proposal and write up! It's a holiday weekend so I can't dig into this right now but we tried using a high-precision clock source for systemUTC() in the past but it didn't work because systemUTC() and currentTimeMillis() have to use the same time base, and currentTimeMillis() has to use gettimeofday(). I thought this cross-dependency was documented somewhere but can't find it right now. If gettimeofday and clock_gettime(CLOCK_REALTIME) actually have the same time characteristics wrt. wall-clock time then changing both as suggested may indeed work. Note however that we are still not yet in a position to use clock_gettime unconditionally at runtime - its use is predicated on os::supports_monotonic_clock() (which despite the name also indicates clock_gettime exists). Regarding Windows please see: https://bugs.openjdk.java.net/browse/JDK-8180466 More next week. Cheers, David On 11/04/2020 3:03 am, Mark Kralj-Taylor wrote:
I'd like to help Java Clock.systemUTC() expose nanosecond precision UTC realtime (wall-time) clock, where OS and CPU allow.
Please let me know if this would be acceptable for OpenJDK, and what next steps I can take to progress this towards submitting a patch. - I have some time at the moment. I've signed the OCA, but don't have login to the OpenJDK bugtracker, if you want me to submit a proper hg patch there. - This mail includes the patch as `hg diff` outputs together with JMH and test output from it.
The patch here improves the existing API java.time.Instant.now() i.e. Clock.systemUTC().instant() on Linux to return Linux clock_gettime(CLOCK_REALTIME) which can be nanosecond precision (and very low cost, se JMH results) when Linux has a suitable clocksource (tsc).
The nice thing about this is that it doesn't add a new JDK API, nor change semantics of the existing Clock.systemUTC().instant() API which already supports nanosecond granularity.
Clock.systemUTC().instant() is backed by Hotspot os::javaTimeSystemUTC, which can be updated to call higher precision OS real-time clock API when available (and has similar performance), rather than the current code that multiplies microseconds from gettimeofday() by 1000 to get nanoseconds.
In Linux this means calling the Posix clock_gettime(CLOCK_REALTIME) API instead of the older gettimeofday() whose output is limited to microsecond precision. On a suitable CPU Linux can back clock_gettime(CLOCK_REALTIME) with a nanosecond precision CPU TSC clocksource. Whereas the output of gettimeofday() is limited to microsecond precision (even when Linux is using a higher precision clocksource).
A similar change could be made for other OS that offer a performant API to get hi-precision wall-time. - OSX: Unfortunately on my Mac I found that clock_gettime(CLOCK_REALTIME) is limited to microseconds precision (source shows it calling gettimeofday() and multiplying by 1000 - see note on recent Linux change to discourage that). An alternate approach that did get nanosecond precision wall-time was too slow to be of interest (>900ns!): Calling OSX host_get_clock_service CALENDAR_CLOCK in JVM init, then clock_get_time(clockPortFromPrev,...). - Windows: GetSystemTimePreciseAsFileTime looks promising. See https://docs.microsoft.com/en-gb/windows/win32/api/sysinfoapi/nf-sysinfoapi-... . Unfortunately I don't have access to a Windows machine to try this on, but if you are interested in the Linux patch I could buy windows for a laptop we have to see how fares in JMH.
Details, patch and JMH / test outputs follow below. Thanks, Mark
-----------------
# RATIONAL: Why does Java need nanosecond precision real-time clock?
Like many others working on lower-latency Java systems running on Linux I have been using JNI to call clock_gettime(CLOCK_REALTIME, ...) to do this for years. Hi-precision (nanosecond) UTC timestamps have been essential in understanding and improving end-to-end latency and performance of multi-process systems. Including nanosecond wall-time after-receive and before-send timestamps in messages sent over the wire (or shared memory, or in stored events) gives tremendous transparency on latency in multi-process and multi-host event processing and workflows.
Java has evolved to remove more and more common cases for JNI. Getting a nanosecond real-time clock timestamp feels a good candidate for that process, especially because it looks like hi-precision real-time UTC clock APIs are common in the minimum OS versions Java is built for (even if some OS still give microsecond precision wall-time behind an API that returns nanoseconds - as OSX 10.15 did for me - built with XCode 10.1 as per JDK docs.
Timestamps from a monotonic clock can only be compared within the same host, or for Java's System.nanoTime() within the same Java process. This is very useful, but doesn't help with multi-process, multi-host, multi-language use-cases.
Realtime (wall-time) UTC clock timestamps are useful because they can be compared between different processes, possibly running on a different host, as well as within a process. Within the same data-centre latency between processes is typically well under a millisecond for UDP / multicast between hosts. Latency can be sub-microsecond for shared-memory between processes on the same host.
A monotonic clock is often favoured for timing latency, because real-time clocks on different hosts are subject to slewing and stepping. Clock-sync technologies drastically reduce impact of these on a host and also time offsets between different hosts (especially in the same data centre). For high event rate systems you can look at latency as percentiles over time-windows. With many time-windows you get an idea of clock sync quality because you see the distribution move when you look at a time-series of percentiles for time-windows if different hosts have different clock stepping time synchronisation.
-----------------
# IS THIS A SAFE CHANGE for the JDK?
It makes no change to semantics of Clock.systemUTC(), whose JavaDoc says: "This clock is based on the best available system clock. This may use System.currentTimeMillis(), or a higher resolution clock if one is available.".
Because there is no new JDK API, nor change in API semantics. This enhancement can be made on an OS by OS basis.
-----------------
# IS THIS A SAFE CHANGE for Linux?
The "clock_gettime(3) - Linux man page" says: "All implementations support the system-wide realtime clock, which is identified by CLOCK_REALTIME. Its time represents seconds and nanoseconds since the Epoch.". See: https://linux.die.net/man/3/clock_gettime
FYI Some older Linux ports used to implement clock_gettime(CLOCK_REALTIME,) by calling gettimeofday() and multiplying by 1000. This would be fine with the patch proposed, but means that resolution would be limited to microseconds by the OS. A Linux change 6 months ago has discouraged that in ports: "Use clock_gettime to implement gettimeofday" https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=5e46749c64d51f50f8511... .
-----------------
# Related OpenJDK BugTrackers
Comments on these enhancements requests suggest some interest in calling Linux clock_gettime(REALTIME) intsead of gettimeofday(). Although the enhancement requests themselves are not the same as this mail, which asks to enhance an existing API, within its existing semantics. - JDK-6709908 - JDK-8185891
Since Java 9 Clock.systemUTC() has up to microsecond resolution on Linux - JDK-8068730 Increase the precision of the implementation of java.time.Clock.systemUTC()
-----------------
# POSSIBLE FOLLOW ON (that is NOT part of the patch or proposal discussed here)
A possible follow-on would be to add a JDK API to give more direct (lower cost) access to a hi-precision timestamp as a nanoseconds since UTC epoc in a long. For example System.curretTimeNanos(). This would be different to the proposal above in that its range would be limited to year 2262 for a unsigned long, which is more than 200 years in the future, but less than Instant.MAX. A JMH benchmarks with systemTimeNanos() as an intrinsic (following the style of currentTimeMillis) demonstrated that this is attractive, with similar cost to System.currentTimeMillis()/nanoTime(), so better than Instant.now() or JNI that I used. But initially I'd rather focus on improving Java without adding any new APIs, or discussing if ~200 years is enough of a range.
-----------------
# PATCHES to Hotspot, tests and output of those tests
## PATCH to hotspot/os/linux/os_linux.cpp
This patch changes both os::javaTimeMillis and os::javaTimeSystemUTC to call clock_gettime(CLOCK_REALTIME, ..) instead of gettimeofday(). This keeps the 2 methods obviously consistent, and avoids someone reading the code having questions on the consistency of different Linux APIs. Results form JMH benchmark (see below) show this is ok.
This seams consistent with direction being taken by Linux, based on change: "Use clock_gettime to implement gettimeofday" at https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=5e46749c64d51f50f8511...
``` diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -88,6 +88,7 @@ # include <errno.h> # include <dlfcn.h> # include <stdio.h> +# include <time.h> # include <unistd.h> # include <sys/resource.h> # include <pthread.h> @@ -1374,18 +1375,18 @@ } jlong os::javaTimeMillis() { - timeval time; - int status = gettimeofday(&time, NULL); + timespec time; + int status = clock_gettime(CLOCK_REALTIME, &time); assert(status != -1, "linux error"); - return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000); + return jlong(time.tv_sec) * 1000 + jlong(time.tv_nsec / 1000000); } void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { - timeval time; - int status = gettimeofday(&time, NULL); + timespec time; + int status = clock_gettime(CLOCK_REALTIME, &time); assert(status != -1, "linux error"); seconds = jlong(time.tv_sec); - nanos = jlong(time.tv_usec) * 1000; + nanos = jlong(time.tv_nsec); } void os::Linux::fast_thread_clock_init() { ```
## PATCH to test/micro JMH benchmark to assess impact of change on Instant.now(), and show its performance relative to System.currentTimeMillis()/nanoTime().
Where would the best place be to add an Instant.now() JMH bennchmark? - While I'd guess the convention is to follow the package of the API being benchmarked. I like that by putting benchmarks of system timestamping APIs in one class its easy and natural to spot them all and compare them. Could the benchmark be added here, then the class renamed to SystemTime.java to focus on benchmarking those features?
``` diff --git a/test/micro/org/openjdk/bench/java/lang/Systems.java b/test/micro/org/openjdk/bench/java/lang/Systems.java --- a/test/micro/org/openjdk/bench/java/lang/Systems.java +++ b/test/micro/org/openjdk/bench/java/lang/Systems.java @@ -28,6 +28,7 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import java.util.concurrent.TimeUnit; +import java.time.Instant; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @@ -43,4 +44,9 @@ return System.nanoTime(); } + @Benchmark + public long instant_now_asEpocNanos() { + Instant now = Instant.now(); + return now.getEpochSecond() * 1_000_000_000L + now.getNano(); + } ```
### RESULTS from JDK Micro benchmark: Run on Linux with clocksource=tsc on a 3GHz Intel i5 CPU (see details below).
`make test TEST="micro:java.lang.Systems"`
WITH change to os_linux.cpp: ``` Benchmark Mode Cnt Score Error Units Systems.currentTimeMillis avgt 25 19.190 ? 0.166 ns/op Systems.instant_now_asEpocNanos avgt 25 29.809 ? 0.191 ns/op Systems.nanoTime avgt 25 18.534 ? 0.024 ns/op ```
WITHOUT change to os_linux.cpp: (but with the added JMH benchmark for purpose of comparison) ``` Benchmark Mode Cnt Score Error Units Systems.currentTimeMillis avgt 25 19.013 ? 0.033 ns/op Systems.instant_now_asEpocNanos avgt 25 30.459 ? 0.017 ns/op Systems.nanoTime avgt 25 18.971 ? 0.053 ns/op ```
### Platform details: System: Linux (Ubuntu) running on Mac Mini 2018 3 GHz Intel i5 ``` $ uname -a Linux MacMiniLinux 5.3.0-42-generic #34-Ubuntu SMP Fri Feb 28 05:49:40 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource tsc
$ ldd --version ldd (Ubuntu GLIBC 2.30-0ubuntu2.1) 2.30
$ lscpu | egrep '(Model name|CPU.s.:)' CPU(s): 6 Model name: Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz NUMA node0 CPU(s): 0-5
$ lscpu | grep Flags | sed 's@ @\n@g' | grep -i tsc tsc rdtscp constant_tsc nonstop_tsc tsc_deadline_timer tsc_adjust ```
## PATCH to JDK test code - that logs realtime clock precision:
``` diff --git a/test/jdk/java/time/test/java/time/TestClock_System.java b/test/jdk/java/time/test/java/time/TestClock_System.java --- a/test/jdk/java/time/test/java/time/TestClock_System.java +++ b/test/jdk/java/time/test/java/time/TestClock_System.java @@ -177,7 +177,8 @@ + formatTime("\n\thighest1", highest1)); } - int count=0; + int count_betterThanMillisPrecision=0; + int count_betterThanMicrosPrecision=0; // let's preheat the system a bit: int lastNanos = 0; for (int i = 0; i < 1000 ; i++) { @@ -191,7 +192,10 @@ lastNanos = nanos; if ((nanos % 1000000) > 0) { - count++; // we have micro seconds + count_betterThanMillisPrecision++; // we have microseconds + } + if ((nanos % 1000) > 0) { + count_betterThanMicrosPrecision++; // we have nanoseconds } if ((sysnan % 1000000) > 0) { throw new RuntimeException("Expected only millisecconds " @@ -200,10 +204,12 @@ } } System.out.println("\nNumber of time stamps which had better than" - + " millisecond precision: "+count+"/"+1000); + + " millisecond precision: "+count_betterThanMillisPrecision+"/"+1000); + System.out.println("\nNumber of time stamps which had better than" + + " microsecond precision: "+count_betterThanMicrosPrecision+"/"+1000); System.out.println(formatTime("\nsystemUTC ", system1)); System.out.println(formatTime("highestResolutionUTC ", highest1)); - if (count == 0) { + if (count_betterThanMillisPrecision == 0) { System.err.println("Something is strange: no microsecond " + "precision with highestResolutionUTC?"); throw new RuntimeException("Micro second preccision not reached"); ```
### OUTPUT of JDK Test logs observed clock precision
Extract of test log when test patch run on same host as JMH below. Shows nanosecond precision (`999/1000 better than microsecond`).
`make test TEST="jtreg:test/jdk/java/time/test/java/time/TestClock_System.java" JTREG="VERBOSE=all"`
``` Number of time stamps which had better than millisecond precision: 1000/1000
Number of time stamps which had better than microsecond precision: 999/1000
systemUTC : 2020-04-03T23:14:12.276Z - seconds: 1585955652, nanos: 276000000 highestResolutionUTC : 2020-04-03T23:14:12.276472680Z - seconds: 1585955652, nanos: 276472680 ```
Update: On 11/04/2020 9:45 am, David Holmes wrote:
Hi Mark,
Thanks for the very detailed proposal and write up!
It's a holiday weekend so I can't dig into this right now but we tried using a high-precision clock source for systemUTC() in the past but it didn't work because systemUTC() and currentTimeMillis() have to use the same time base, and currentTimeMillis() has to use gettimeofday(). I thought this cross-dependency was documented somewhere but can't find it right now. If gettimeofday and clock_gettime(CLOCK_REALTIME) actually have the same time characteristics wrt. wall-clock time then changing both as suggested may indeed work.
Found this from last time things were discussed in detail: https://bugs.openjdk.java.net/browse/JDK-8185891?focusedCommentId=14107380&p... so it does seem like a switch from gettimeofday to clock_gettime(CLOCK_REALTIME) may be viable. Cheers, David
Note however that we are still not yet in a position to use clock_gettime unconditionally at runtime - its use is predicated on os::supports_monotonic_clock() (which despite the name also indicates clock_gettime exists).
Regarding Windows please see:
https://bugs.openjdk.java.net/browse/JDK-8180466
More next week.
Cheers, David
On 11/04/2020 3:03 am, Mark Kralj-Taylor wrote:
I'd like to help Java Clock.systemUTC() expose nanosecond precision UTC realtime (wall-time) clock, where OS and CPU allow.
Please let me know if this would be acceptable for OpenJDK, and what next steps I can take to progress this towards submitting a patch. - I have some time at the moment. I've signed the OCA, but don't have login to the OpenJDK bugtracker, if you want me to submit a proper hg patch there. - This mail includes the patch as `hg diff` outputs together with JMH and test output from it.
The patch here improves the existing API java.time.Instant.now() i.e. Clock.systemUTC().instant() on Linux to return Linux clock_gettime(CLOCK_REALTIME) which can be nanosecond precision (and very low cost, se JMH results) when Linux has a suitable clocksource (tsc).
The nice thing about this is that it doesn't add a new JDK API, nor change semantics of the existing Clock.systemUTC().instant() API which already supports nanosecond granularity.
Clock.systemUTC().instant() is backed by Hotspot os::javaTimeSystemUTC, which can be updated to call higher precision OS real-time clock API when available (and has similar performance), rather than the current code that multiplies microseconds from gettimeofday() by 1000 to get nanoseconds.
In Linux this means calling the Posix clock_gettime(CLOCK_REALTIME) API instead of the older gettimeofday() whose output is limited to microsecond precision. On a suitable CPU Linux can back clock_gettime(CLOCK_REALTIME) with a nanosecond precision CPU TSC clocksource. Whereas the output of gettimeofday() is limited to microsecond precision (even when Linux is using a higher precision clocksource).
A similar change could be made for other OS that offer a performant API to get hi-precision wall-time. - OSX: Unfortunately on my Mac I found that clock_gettime(CLOCK_REALTIME) is limited to microseconds precision (source shows it calling gettimeofday() and multiplying by 1000 - see note on recent Linux change to discourage that). An alternate approach that did get nanosecond precision wall-time was too slow to be of interest (>900ns!): Calling OSX host_get_clock_service CALENDAR_CLOCK in JVM init, then clock_get_time(clockPortFromPrev,...). - Windows: GetSystemTimePreciseAsFileTime looks promising. See https://docs.microsoft.com/en-gb/windows/win32/api/sysinfoapi/nf-sysinfoapi-...
. Unfortunately I don't have access to a Windows machine to try this on, but if you are interested in the Linux patch I could buy windows for a laptop we have to see how fares in JMH.
Details, patch and JMH / test outputs follow below. Thanks, Mark
-----------------
# RATIONAL: Why does Java need nanosecond precision real-time clock?
Like many others working on lower-latency Java systems running on Linux I have been using JNI to call clock_gettime(CLOCK_REALTIME, ...) to do this for years. Hi-precision (nanosecond) UTC timestamps have been essential in understanding and improving end-to-end latency and performance of multi-process systems. Including nanosecond wall-time after-receive and before-send timestamps in messages sent over the wire (or shared memory, or in stored events) gives tremendous transparency on latency in multi-process and multi-host event processing and workflows.
Java has evolved to remove more and more common cases for JNI. Getting a nanosecond real-time clock timestamp feels a good candidate for that process, especially because it looks like hi-precision real-time UTC clock APIs are common in the minimum OS versions Java is built for (even if some OS still give microsecond precision wall-time behind an API that returns nanoseconds - as OSX 10.15 did for me - built with XCode 10.1 as per JDK docs.
Timestamps from a monotonic clock can only be compared within the same host, or for Java's System.nanoTime() within the same Java process. This is very useful, but doesn't help with multi-process, multi-host, multi-language use-cases.
Realtime (wall-time) UTC clock timestamps are useful because they can be compared between different processes, possibly running on a different host, as well as within a process. Within the same data-centre latency between processes is typically well under a millisecond for UDP / multicast between hosts. Latency can be sub-microsecond for shared-memory between processes on the same host.
A monotonic clock is often favoured for timing latency, because real-time clocks on different hosts are subject to slewing and stepping. Clock-sync technologies drastically reduce impact of these on a host and also time offsets between different hosts (especially in the same data centre). For high event rate systems you can look at latency as percentiles over time-windows. With many time-windows you get an idea of clock sync quality because you see the distribution move when you look at a time-series of percentiles for time-windows if different hosts have different clock stepping time synchronisation.
-----------------
# IS THIS A SAFE CHANGE for the JDK?
It makes no change to semantics of Clock.systemUTC(), whose JavaDoc says: "This clock is based on the best available system clock. This may use System.currentTimeMillis(), or a higher resolution clock if one is available.".
Because there is no new JDK API, nor change in API semantics. This enhancement can be made on an OS by OS basis.
-----------------
# IS THIS A SAFE CHANGE for Linux?
The "clock_gettime(3) - Linux man page" says: "All implementations support the system-wide realtime clock, which is identified by CLOCK_REALTIME. Its time represents seconds and nanoseconds since the Epoch.". See: https://linux.die.net/man/3/clock_gettime
FYI Some older Linux ports used to implement clock_gettime(CLOCK_REALTIME,) by calling gettimeofday() and multiplying by 1000. This would be fine with the patch proposed, but means that resolution would be limited to microseconds by the OS. A Linux change 6 months ago has discouraged that in ports: "Use clock_gettime to implement gettimeofday" https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=5e46749c64d51f50f8511...
.
-----------------
# Related OpenJDK BugTrackers
Comments on these enhancements requests suggest some interest in calling Linux clock_gettime(REALTIME) intsead of gettimeofday(). Although the enhancement requests themselves are not the same as this mail, which asks to enhance an existing API, within its existing semantics. - JDK-6709908 - JDK-8185891
Since Java 9 Clock.systemUTC() has up to microsecond resolution on Linux - JDK-8068730 Increase the precision of the implementation of java.time.Clock.systemUTC()
-----------------
# POSSIBLE FOLLOW ON (that is NOT part of the patch or proposal discussed here)
A possible follow-on would be to add a JDK API to give more direct (lower cost) access to a hi-precision timestamp as a nanoseconds since UTC epoc in a long. For example System.curretTimeNanos(). This would be different to the proposal above in that its range would be limited to year 2262 for a unsigned long, which is more than 200 years in the future, but less than Instant.MAX. A JMH benchmarks with systemTimeNanos() as an intrinsic (following the style of currentTimeMillis) demonstrated that this is attractive, with similar cost to System.currentTimeMillis()/nanoTime(), so better than Instant.now() or JNI that I used. But initially I'd rather focus on improving Java without adding any new APIs, or discussing if ~200 years is enough of a range.
-----------------
# PATCHES to Hotspot, tests and output of those tests
## PATCH to hotspot/os/linux/os_linux.cpp
This patch changes both os::javaTimeMillis and os::javaTimeSystemUTC to call clock_gettime(CLOCK_REALTIME, ..) instead of gettimeofday(). This keeps the 2 methods obviously consistent, and avoids someone reading the code having questions on the consistency of different Linux APIs. Results form JMH benchmark (see below) show this is ok.
This seams consistent with direction being taken by Linux, based on change: "Use clock_gettime to implement gettimeofday" at https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=5e46749c64d51f50f8511...
``` diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -88,6 +88,7 @@ # include <errno.h> # include <dlfcn.h> # include <stdio.h> +# include <time.h> # include <unistd.h> # include <sys/resource.h> # include <pthread.h> @@ -1374,18 +1375,18 @@ } jlong os::javaTimeMillis() { - timeval time; - int status = gettimeofday(&time, NULL); + timespec time; + int status = clock_gettime(CLOCK_REALTIME, &time); assert(status != -1, "linux error"); - return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000); + return jlong(time.tv_sec) * 1000 + jlong(time.tv_nsec / 1000000); } void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { - timeval time; - int status = gettimeofday(&time, NULL); + timespec time; + int status = clock_gettime(CLOCK_REALTIME, &time); assert(status != -1, "linux error"); seconds = jlong(time.tv_sec); - nanos = jlong(time.tv_usec) * 1000; + nanos = jlong(time.tv_nsec); } void os::Linux::fast_thread_clock_init() { ```
## PATCH to test/micro JMH benchmark to assess impact of change on Instant.now(), and show its performance relative to System.currentTimeMillis()/nanoTime().
Where would the best place be to add an Instant.now() JMH bennchmark? - While I'd guess the convention is to follow the package of the API being benchmarked. I like that by putting benchmarks of system timestamping APIs in one class its easy and natural to spot them all and compare them. Could the benchmark be added here, then the class renamed to SystemTime.java to focus on benchmarking those features?
``` diff --git a/test/micro/org/openjdk/bench/java/lang/Systems.java b/test/micro/org/openjdk/bench/java/lang/Systems.java --- a/test/micro/org/openjdk/bench/java/lang/Systems.java +++ b/test/micro/org/openjdk/bench/java/lang/Systems.java @@ -28,6 +28,7 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import java.util.concurrent.TimeUnit; +import java.time.Instant; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @@ -43,4 +44,9 @@ return System.nanoTime(); } + @Benchmark + public long instant_now_asEpocNanos() { + Instant now = Instant.now(); + return now.getEpochSecond() * 1_000_000_000L + now.getNano(); + } ```
### RESULTS from JDK Micro benchmark: Run on Linux with clocksource=tsc on a 3GHz Intel i5 CPU (see details below).
`make test TEST="micro:java.lang.Systems"`
WITH change to os_linux.cpp: ``` Benchmark Mode Cnt Score Error Units Systems.currentTimeMillis avgt 25 19.190 ? 0.166 ns/op Systems.instant_now_asEpocNanos avgt 25 29.809 ? 0.191 ns/op Systems.nanoTime avgt 25 18.534 ? 0.024 ns/op ```
WITHOUT change to os_linux.cpp: (but with the added JMH benchmark for purpose of comparison) ``` Benchmark Mode Cnt Score Error Units Systems.currentTimeMillis avgt 25 19.013 ? 0.033 ns/op Systems.instant_now_asEpocNanos avgt 25 30.459 ? 0.017 ns/op Systems.nanoTime avgt 25 18.971 ? 0.053 ns/op ```
### Platform details: System: Linux (Ubuntu) running on Mac Mini 2018 3 GHz Intel i5 ``` $ uname -a Linux MacMiniLinux 5.3.0-42-generic #34-Ubuntu SMP Fri Feb 28 05:49:40 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource tsc
$ ldd --version ldd (Ubuntu GLIBC 2.30-0ubuntu2.1) 2.30
$ lscpu | egrep '(Model name|CPU.s.:)' CPU(s): 6 Model name: Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz NUMA node0 CPU(s): 0-5
$ lscpu | grep Flags | sed 's@ @\n@g' | grep -i tsc tsc rdtscp constant_tsc nonstop_tsc tsc_deadline_timer tsc_adjust ```
## PATCH to JDK test code - that logs realtime clock precision:
``` diff --git a/test/jdk/java/time/test/java/time/TestClock_System.java b/test/jdk/java/time/test/java/time/TestClock_System.java --- a/test/jdk/java/time/test/java/time/TestClock_System.java +++ b/test/jdk/java/time/test/java/time/TestClock_System.java @@ -177,7 +177,8 @@ + formatTime("\n\thighest1", highest1)); } - int count=0; + int count_betterThanMillisPrecision=0; + int count_betterThanMicrosPrecision=0; // let's preheat the system a bit: int lastNanos = 0; for (int i = 0; i < 1000 ; i++) { @@ -191,7 +192,10 @@ lastNanos = nanos; if ((nanos % 1000000) > 0) { - count++; // we have micro seconds + count_betterThanMillisPrecision++; // we have microseconds + } + if ((nanos % 1000) > 0) { + count_betterThanMicrosPrecision++; // we have nanoseconds } if ((sysnan % 1000000) > 0) { throw new RuntimeException("Expected only millisecconds " @@ -200,10 +204,12 @@ } } System.out.println("\nNumber of time stamps which had better than" - + " millisecond precision: "+count+"/"+1000); + + " millisecond precision: "+count_betterThanMillisPrecision+"/"+1000); + System.out.println("\nNumber of time stamps which had better than" + + " microsecond precision: "+count_betterThanMicrosPrecision+"/"+1000); System.out.println(formatTime("\nsystemUTC ", system1)); System.out.println(formatTime("highestResolutionUTC ", highest1)); - if (count == 0) { + if (count_betterThanMillisPrecision == 0) { System.err.println("Something is strange: no microsecond " + "precision with highestResolutionUTC?"); throw new RuntimeException("Micro second preccision not reached"); ```
### OUTPUT of JDK Test logs observed clock precision
Extract of test log when test patch run on same host as JMH below. Shows nanosecond precision (`999/1000 better than microsecond`).
`make test TEST="jtreg:test/jdk/java/time/test/java/time/TestClock_System.java" JTREG="VERBOSE=all"`
``` Number of time stamps which had better than millisecond precision: 1000/1000
Number of time stamps which had better than microsecond precision: 999/1000
systemUTC : 2020-04-03T23:14:12.276Z - seconds: 1585955652, nanos: 276000000 highestResolutionUTC : 2020-04-03T23:14:12.276472680Z - seconds: 1585955652, nanos: 276472680 ```
Hi, On 11/04/2020 00:53, David Holmes wrote:
Update:
It's a holiday weekend so I can't dig into this right now but we tried using a high-precision clock source for systemUTC() in the past but it didn't work because systemUTC() and currentTimeMillis() have to use the same time base, and currentTimeMillis() has to use gettimeofday(). I thought this cross-dependency was documented somewhere but can't find it right now. If gettimeofday and clock_gettime(CLOCK_REALTIME) actually have the same time characteristics wrt. wall-clock time then changing both as suggested may indeed work.
Just to emphasize David's comment: System::currentTimeMillis() and Clock::systemUTC() should use the same time source: if they don't - then some tests will fail, and because it can be tricky to assert things in tests, they might (and probably will) fail only intermittently. I'm probably the culprit here, I added those tests when I upgraded Clock::systemUTC() to report sub millisecond granularity [1] - as was available in the underlying clock that System::currentTimeMillis() already used. However, I think I would be disturbed if System::currentTimeMillis() and Clock::systemUTC() were using different clocks and could report a different notion of time (by drifting away from each other). best regards, -- daniel [1] https://bugs.openjdk.java.net/browse/JDK-8068730
Daniel, Yes System.currentTimeMillis() and Clock.systemUTC() must be consistent, so should use the same OS time source (as shown by ). The patch to os_linux.cpp ensures this by calling the same Linux API: clock_gettime(CLOCK_REALTIME) for both, from: - os::javaTimeMillis() that backs System.currentTimeMillis() - os::javaTimeSystemUTC() that backs Clock.systemUTC() Looking at Linux / glibc source I think that gettimeofday() and clock_gettime(CLOCK_REALTIME) are supposed to be the same clocksource. i.e. that given by: cat /sys/devices/system/clocksource/clocksource0/current_clocksource Mark On Tue, 14 Apr 2020 at 13:29, Daniel Fuchs <daniel.fuchs@oracle.com> wrote:
Hi,
On 11/04/2020 00:53, David Holmes wrote:
Update:
It's a holiday weekend so I can't dig into this right now but we tried using a high-precision clock source for systemUTC() in the past but it didn't work because systemUTC() and currentTimeMillis() have to use the same time base, and currentTimeMillis() has to use gettimeofday(). I thought this cross-dependency was documented somewhere but can't find it right now. If gettimeofday and clock_gettime(CLOCK_REALTIME) actually have the same time characteristics wrt. wall-clock time then changing both as suggested may indeed work.
Just to emphasize David's comment: System::currentTimeMillis() and Clock::systemUTC() should use the same time source: if they don't - then some tests will fail, and because it can be tricky to assert things in tests, they might (and probably will) fail only intermittently.
I'm probably the culprit here, I added those tests when I upgraded Clock::systemUTC() to report sub millisecond granularity [1] - as was available in the underlying clock that System::currentTimeMillis() already used.
However, I think I would be disturbed if System::currentTimeMillis() and Clock::systemUTC() were using different clocks and could report a different notion of time (by drifting away from each other).
best regards,
-- daniel [1] https://bugs.openjdk.java.net/browse/JDK-8068730
David, Daniel, What is the oldest (lowest) version of Linux and glibc for openjdk 15? The availability of clock_gettime(CLOCK_REALTIME) on the oldest Linux/glibc supported by openjdk 15 is likely to be the deciding factor on if Hotspot Linux code can call clock_gettime(CLOCK_REALTIME). doc/building.md suggests minimum Linux is Oracle Enterprise Linux 6.4 (i.e. RHEL 6.4). Which I think uses glibc 2.12-1.107 (based on https://yum.oracle.com/repo/OracleLinux/OL6/4/base/x86_64/index_src.html). Searching for glibc sources it looks like this supports clock_gettime(CLOCK_REALTIME). The wording of Linux docs suggests that clock_gettime(CLOCK_REALTIME) should be supported if the clock_gettime() API exists. But other clock sources are not mandatory. So CLOCK_REALTIME should be available even if CLOCK_MONOTONIC is not. - See: https://linux.die.net/man/2/clock_gettime. - Also "POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead." from: https://linux.die.net/man/2/gettimeofday Note that Hotspot os_posix.cpp checks for non-error return from clock_gettime(CLOCK_MONOTONIC) to guard setting the _clock_gettime function pointer. Which was why in the patch I called clock_gettime directly for Linux specific os_linux.cpp (a subset of Posix OS-s). Also os_linux.cpp has: #ifndef SUPPORTS_CLOCK_MONOTONIC #error "Build platform doesn't support clock_gettime and related functionality" #endif Which made me wonder if openjdk might require CLOCK_MONOTONIC - which would mean clock_gettime(CLOCK_REALTIME) is supported. Mark On Tue, 14 Apr 2020 at 18:04, Mark Kralj-Taylor <kralj.mark@gmail.com> wrote:
Daniel, Yes System.currentTimeMillis() and Clock.systemUTC() must be consistent, so should use the same OS time source (as shown by ).
The patch to os_linux.cpp ensures this by calling the same Linux API: clock_gettime(CLOCK_REALTIME) for both, from: - os::javaTimeMillis() that backs System.currentTimeMillis() - os::javaTimeSystemUTC() that backs Clock.systemUTC()
Looking at Linux / glibc source I think that gettimeofday() and clock_gettime(CLOCK_REALTIME) are supposed to be the same clocksource. i.e. that given by: cat /sys/devices/system/clocksource/clocksource0/current_clocksource
Mark
On Tue, 14 Apr 2020 at 13:29, Daniel Fuchs <daniel.fuchs@oracle.com> wrote:
Hi,
On 11/04/2020 00:53, David Holmes wrote:
Update:
It's a holiday weekend so I can't dig into this right now but we tried using a high-precision clock source for systemUTC() in the past but it didn't work because systemUTC() and currentTimeMillis() have to use the same time base, and currentTimeMillis() has to use gettimeofday(). I thought this cross-dependency was documented somewhere but can't find it right now. If gettimeofday and clock_gettime(CLOCK_REALTIME) actually have the same time characteristics wrt. wall-clock time then changing both as suggested may indeed work.
Just to emphasize David's comment: System::currentTimeMillis() and Clock::systemUTC() should use the same time source: if they don't - then some tests will fail, and because it can be tricky to assert things in tests, they might (and probably will) fail only intermittently.
I'm probably the culprit here, I added those tests when I upgraded Clock::systemUTC() to report sub millisecond granularity [1] - as was available in the underlying clock that System::currentTimeMillis() already used.
However, I think I would be disturbed if System::currentTimeMillis() and Clock::systemUTC() were using different clocks and could report a different notion of time (by drifting away from each other).
best regards,
-- daniel [1] https://bugs.openjdk.java.net/browse/JDK-8068730
* Mark Kralj-Taylor:
The wording of Linux docs suggests that clock_gettime(CLOCK_REALTIME) should be supported if the clock_gettime() API exists. But other clock sources are not mandatory.
Really old glibc emulates clock_gettime (CLOCK_REALTIME) using gettimeofday, yes. clock_gettime was already in Linux 2.12 (and possibly quite a bit earlier, I did not check), so that is not likely to be a limitation. A tricky question is whether it's possible to avoid loading librt. The present code already uses dlopen, but I think it could try a little bit harder (try resolving clock_gettime first, and then load librt, and try again). For distribution builds that do not need to be compatible with glibc versions before 2.17, directly calling clock_gettime would also be an option. (clock_gettime moved to libc.so.6 in glibc 2.17, but a lot of software keeps linking against librt for the definition of clock_gettime, something that we are finally tackling on the glibc side.) Making a direct system call instead is a bit tricky because it's absolutely required to use the vDSO if possible, for performance reasons. But it's possible to obtain the address of the vDSO function using dlvsym, so that might be an option as well.
* Florian Weimer:
* Mark Kralj-Taylor:
The wording of Linux docs suggests that clock_gettime(CLOCK_REALTIME) should be supported if the clock_gettime() API exists. But other clock sources are not mandatory.
Really old glibc emulates clock_gettime (CLOCK_REALTIME) using gettimeofday, yes.
clock_gettime was already in Linux 2.12 (and possibly quite a bit
That should have been Linux 2.6.12, sorry.
earlier, I did not check), so that is not likely to be a limitation.
A tricky question is whether it's possible to avoid loading librt. The present code already uses dlopen, but I think it could try a little bit harder (try resolving clock_gettime first, and then load librt, and try again). For distribution builds that do not need to be compatible with glibc versions before 2.17, directly calling clock_gettime would also be an option. (clock_gettime moved to libc.so.6 in glibc 2.17, but a lot of software keeps linking against librt for the definition of clock_gettime, something that we are finally tackling on the glibc side.)
Making a direct system call instead is a bit tricky because it's absolutely required to use the vDSO if possible, for performance reasons. But it's possible to obtain the address of the vDSO function using dlvsym, so that might be an option as well.
Hi Mark, On 15/04/2020 3:09 am, Mark Kralj-Taylor wrote:
David, Daniel, What is the oldest (lowest) version of Linux and glibc for openjdk 15?
I'm not clear on that.
The availability of clock_gettime(CLOCK_REALTIME) on the oldest Linux/glibc supported by openjdk 15 is likely to be the deciding factor on if Hotspot Linux code can call clock_gettime(CLOCK_REALTIME).
doc/building.md suggests minimum Linux is Oracle Enterprise Linux 6.4 (i.e. RHEL 6.4). Which I think uses glibc 2.12-1.107 (based on https://yum.oracle.com/repo/OracleLinux/OL6/4/base/x86_64/index_src.html). Searching for glibc sources it looks like this supports clock_gettime(CLOCK_REALTIME).
The wording of Linux docs suggests that clock_gettime(CLOCK_REALTIME) should be supported if the clock_gettime() API exists. But other clock sources are not mandatory. So CLOCK_REALTIME should be available even if CLOCK_MONOTONIC is not. - See: https://linux.die.net/man/2/clock_gettime. - Also "POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead." from: https://linux.die.net/man/2/gettimeofday
Note that Hotspot os_posix.cpp checks for non-error return from clock_gettime(CLOCK_MONOTONIC) to guard setting the _clock_gettime function pointer. Which was why in the patch I called clock_gettime directly for Linux specific os_linux.cpp (a subset of Posix OS-s).
Also os_linux.cpp has: #ifndef SUPPORTS_CLOCK_MONOTONIC #error "Build platform doesn't support clock_gettime and related functionality" #endif Which made me wonder if openjdk might require CLOCK_MONOTONIC - which would mean clock_gettime(CLOCK_REALTIME) is supported.
So we require that the build platform supports CLOCK_MONOTONIC and clock_gettime, but not that the runtime platform supports CLOCK_MONOTONIC (without which we don't/didn't need clock_gettime(). So we can switch to using clock_gettime(CLOCK_REALTIME) at build time with no problem. We can probably also require clock_gettime(CLOCK_REALTIME) at runtime, but we need to double-check that. I recall encountering a platform where clock_gettime was not available, but I can't recall if it was mainstream or on one of the other OpenJDK projects - nor do I recall exactly how long ago this was. Keeping the dynamic lookup of clock_gettime would be a conservative approach here - but we would need to make the distinction between the ability to use CLOCK_REALTIME and CLOCK_MONOTONIC. Or someone puts in the time and effort to establish exactly what the kernel and glibc dependencies are and whether we can just rely on everything existing on all platforms we care about. I don't have time to do that nor validate the results if someone else does it. Cheers, David
Mark
On Tue, 14 Apr 2020 at 18:04, Mark Kralj-Taylor <kralj.mark@gmail.com> wrote:
Daniel, Yes System.currentTimeMillis() and Clock.systemUTC() must be consistent, so should use the same OS time source (as shown by ).
The patch to os_linux.cpp ensures this by calling the same Linux API: clock_gettime(CLOCK_REALTIME) for both, from: - os::javaTimeMillis() that backs System.currentTimeMillis() - os::javaTimeSystemUTC() that backs Clock.systemUTC()
Looking at Linux / glibc source I think that gettimeofday() and clock_gettime(CLOCK_REALTIME) are supposed to be the same clocksource. i.e. that given by: cat /sys/devices/system/clocksource/clocksource0/current_clocksource
Mark
On Tue, 14 Apr 2020 at 13:29, Daniel Fuchs <daniel.fuchs@oracle.com> wrote:
Hi,
On 11/04/2020 00:53, David Holmes wrote:
Update:
It's a holiday weekend so I can't dig into this right now but we tried using a high-precision clock source for systemUTC() in the past but it didn't work because systemUTC() and currentTimeMillis() have to use the same time base, and currentTimeMillis() has to use gettimeofday(). I thought this cross-dependency was documented somewhere but can't find it right now. If gettimeofday and clock_gettime(CLOCK_REALTIME) actually have the same time characteristics wrt. wall-clock time then changing both as suggested may indeed work.
Just to emphasize David's comment: System::currentTimeMillis() and Clock::systemUTC() should use the same time source: if they don't - then some tests will fail, and because it can be tricky to assert things in tests, they might (and probably will) fail only intermittently.
I'm probably the culprit here, I added those tests when I upgraded Clock::systemUTC() to report sub millisecond granularity [1] - as was available in the underlying clock that System::currentTimeMillis() already used.
However, I think I would be disturbed if System::currentTimeMillis() and Clock::systemUTC() were using different clocks and could report a different notion of time (by drifting away from each other).
best regards,
-- daniel [1] https://bugs.openjdk.java.net/browse/JDK-8068730
Hi David, So the issue is that while glibc 2.12 (in OEL6.4) supports clock_gettime(CLOCK_REALTIME) it requires a runtime dependency on librt.so, which is an optional runtime dependency, hence the dynamic lookup you mention. The complexity of dynamic lookup makes this enhancement unattractive. But when openjdk updates to require glibc
=2.17 it would be trivial, because clock_gettime() was moved into the core libc.so.
With glibc >= 2.17 there would still need to be a call to clock_gettime() to see if the optional CLOCK_MONOTONIC is supported, whereas CLOCK_REALTIME is required by the Posix spec and header docs. --- This leads me to ask a different question: What is the openjdk process for reviewing and updating its minimum dependencies? - When are dependencies reviewed? - What is the mailgroup to look at? (please let me know if there is a better place to ask this question) The info I found was last updated for JDK 13: https://wiki.openjdk.java.net/display/Build/Supported+Build+Platforms - Glibc 2.12 was released in 2010 and glibc 2.17 in 2012 - The current openjdk LTS release is Java SE 11 in September 2018, supported through to October 2024 (extended support to September 2026): https://en.wikipedia.org/wiki/Java_version_history). - Oracle Enterprise Linux 7.0 released in 2014 included glibc 2.17 These dates suggest an update of openjdk's glibc dependency might be due. But I guess the driving factor is how the timelines of openjdk LTS release support fits with those of Oracle Enterprise Linux versions. --- FYI some observations on my experience of building and testing openjdk. I installed OEL6.4, but found it very tricky to build a `real` openjdk distribution on a current Ubuntu that would run with all features on OEL6.4. - The base openjdk build was easy to use, but it built a JDK with elf dependencies based on my OS, so of course would not run on OLE6. - The openjdk make/devkit infrastructure didn't work for me to make an OEL6 build, after lots of attempts (including running in chroot or docker isolation). I'm sure it works reliably, provided you have the correct OS setup. But its not easy for an outsider to replicate that. - The AdoptOpenJDK Docker build was super easy to use, and I liked that it used Docker to use a reproducible and fully scripted OS build environment. https://github.com/AdoptOpenJDK/openjdk-build - But AdoptOpenJDK Docker build doesn't support building and using an OEL6 devkit. AdoptOpenJDK build targets RHEL 7.4+: https://github.com/AdoptOpenJDK/openjdk-build/wiki/%5BWIP%5D-Minimum-OS-leve... openjdk's devkit infra must pre-date the rise of Docker, and fully reproducible build environments becoming the norm. Maybe one day there will be time to use Docker or similar to simplify the openjdk build, and making it easy for anyone to reproduce. As with using newer glibc features (glibc 2.17 vs 2.12), its likely to be drastically simpler when openjdk is able to update dependencies to newer OS versions. Especially if openjdk can be built on its minimum required per-platform OS version in a (Docker) container. Mark On Tue, 14 Apr 2020 at 23:34, David Holmes <david.holmes@oracle.com> wrote:
Hi Mark,
On 15/04/2020 3:09 am, Mark Kralj-Taylor wrote:
David, Daniel, What is the oldest (lowest) version of Linux and glibc for openjdk 15?
I'm not clear on that.
The availability of clock_gettime(CLOCK_REALTIME) on the oldest Linux/glibc supported by openjdk 15 is likely to be the deciding factor on if Hotspot Linux code can call clock_gettime(CLOCK_REALTIME).
doc/building.md suggests minimum Linux is Oracle Enterprise Linux 6.4 (i.e. RHEL 6.4). Which I think uses glibc 2.12-1.107 (based on https://yum.oracle.com/repo/OracleLinux/OL6/4/base/x86_64/index_src.html). Searching for glibc sources it looks like this supports clock_gettime(CLOCK_REALTIME).
The wording of Linux docs suggests that clock_gettime(CLOCK_REALTIME) should be supported if the clock_gettime() API exists. But other clock sources are not mandatory. So CLOCK_REALTIME should be available even if CLOCK_MONOTONIC is not. - See: https://linux.die.net/man/2/clock_gettime. - Also "POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead." from: https://linux.die.net/man/2/gettimeofday
Note that Hotspot os_posix.cpp checks for non-error return from clock_gettime(CLOCK_MONOTONIC) to guard setting the _clock_gettime function pointer. Which was why in the patch I called clock_gettime directly for Linux specific os_linux.cpp (a subset of Posix OS-s).
Also os_linux.cpp has: #ifndef SUPPORTS_CLOCK_MONOTONIC #error "Build platform doesn't support clock_gettime and related functionality" #endif Which made me wonder if openjdk might require CLOCK_MONOTONIC - which would mean clock_gettime(CLOCK_REALTIME) is supported.
So we require that the build platform supports CLOCK_MONOTONIC and clock_gettime, but not that the runtime platform supports CLOCK_MONOTONIC (without which we don't/didn't need clock_gettime().
So we can switch to using clock_gettime(CLOCK_REALTIME) at build time with no problem.
We can probably also require clock_gettime(CLOCK_REALTIME) at runtime, but we need to double-check that. I recall encountering a platform where clock_gettime was not available, but I can't recall if it was mainstream or on one of the other OpenJDK projects - nor do I recall exactly how long ago this was. Keeping the dynamic lookup of clock_gettime would be a conservative approach here - but we would need to make the distinction between the ability to use CLOCK_REALTIME and CLOCK_MONOTONIC.
Or someone puts in the time and effort to establish exactly what the kernel and glibc dependencies are and whether we can just rely on everything existing on all platforms we care about. I don't have time to do that nor validate the results if someone else does it.
Cheers, David
Mark
On Tue, 14 Apr 2020 at 18:04, Mark Kralj-Taylor <kralj.mark@gmail.com> wrote:
Daniel, Yes System.currentTimeMillis() and Clock.systemUTC() must be consistent, so should use the same OS time source (as shown by ).
The patch to os_linux.cpp ensures this by calling the same Linux API: clock_gettime(CLOCK_REALTIME) for both, from: - os::javaTimeMillis() that backs System.currentTimeMillis() - os::javaTimeSystemUTC() that backs Clock.systemUTC()
Looking at Linux / glibc source I think that gettimeofday() and clock_gettime(CLOCK_REALTIME) are supposed to be the same clocksource. i.e. that given by: cat /sys/devices/system/clocksource/clocksource0/current_clocksource
Mark
On Tue, 14 Apr 2020 at 13:29, Daniel Fuchs <daniel.fuchs@oracle.com> wrote:
Hi,
On 11/04/2020 00:53, David Holmes wrote:
Update:
It's a holiday weekend so I can't dig into this right now but we tried using a high-precision clock source for systemUTC() in the past but it didn't work because systemUTC() and currentTimeMillis() have to use the same time base, and currentTimeMillis() has to use gettimeofday(). I thought this cross-dependency was documented somewhere but can't find it right now. If gettimeofday and clock_gettime(CLOCK_REALTIME) actually have the same time characteristics wrt. wall-clock time then changing both as suggested may indeed work.
Just to emphasize David's comment: System::currentTimeMillis() and Clock::systemUTC() should use the same time source: if they don't - then some tests will fail, and because it can be tricky to assert things in tests, they might (and probably will) fail only intermittently.
I'm probably the culprit here, I added those tests when I upgraded Clock::systemUTC() to report sub millisecond granularity [1] - as was available in the underlying clock that System::currentTimeMillis() already used.
However, I think I would be disturbed if System::currentTimeMillis() and Clock::systemUTC() were using different clocks and could report a different notion of time (by drifting away from each other).
best regards,
-- daniel [1] https://bugs.openjdk.java.net/browse/JDK-8068730
Hi Mark, On 6/05/2020 1:50 am, Mark Kralj-Taylor wrote:
Hi David,
So the issue is that while glibc 2.12 (in OEL6.4) supports clock_gettime(CLOCK_REALTIME) it requires a runtime dependency on librt.so, which is an optional runtime dependency, hence the dynamic lookup you mention. The complexity of dynamic lookup makes this enhancement unattractive. But when openjdk updates to require glibc
=2.17 it would be trivial, because clock_gettime() was moved into the core libc.so.
It would be good to be able to remove the need to link librt. In general we try to avoid needing to track libc/glibc changes in detail, and which versions on which Linux distributions contain which libc/glibc version - and even whether they are necessarily equivalent ie. are all glibc 2.17 the same?
With glibc >= 2.17 there would still need to be a call to clock_gettime() to see if the optional CLOCK_MONOTONIC is supported, whereas CLOCK_REALTIME is required by the Posix spec and header docs.
I would have hoped/expected that glibc 2.17 either did or did not support CLOCK_MONOTONIC without any need to do a dynamic runtime check. :( You seem to be suggesting that two Linux distributions claiming to have glibc 2.17 may have different support for CLOCK_MONOTONIC - is that really the case?
--- This leads me to ask a different question:
What is the openjdk process for reviewing and updating its minimum dependencies? - When are dependencies reviewed? - What is the mailgroup to look at? (please let me know if there is a better place to ask this question)
The info I found was last updated for JDK 13: https://wiki.openjdk.java.net/display/Build/Supported+Build+Platforms
So there are two issues: build platforms and runtime platforms. The minimum build platform is generally determined by the Build group (build-dev@openjdk.java.net) and is generally driven by the regular toolchain upgrade process - ie if we want to support gcc X.Y and it no longer runs on SomeLinux A.B then we have to decide if it is okay drop that support and bump the minimum SomeLinux version. That may depend on the other OpenJDK members and what they need to support in their build farms etc. The wiki above should be tracking that but the build team (aka Magnus and Erik) are busy folk and it can fall behind. This is further complicated by the fact that we may use a devkit for an older OS version, but run it on a later one. For runtime platforms there is no official OpenJDK minimum supported platform as far as I am aware. Obviously given the source code + toolchain there is an implied minimum version, you just won't necessarily find it clearly documented at any given point in time - nor know when it suddenly changes. My understanding is that each OpenJDK distributor determines their own minimum supported OS versions - potentially maintaining custom patches to achieve that. Any OpenJDK change that implicitly changes those minimum versions should result in feedback that then influences whether such a change should be kept or reverted. And of course there is a difference between an officially supported OS version and one where it happens to still run okay. For example, for a long time Windows XP was not officially supported but we actively tried to not break it.
- Glibc 2.12 was released in 2010 and glibc 2.17 in 2012 - The current openjdk LTS release is Java SE 11 in September 2018, supported through to October 2024 (extended support to September 2026): https://en.wikipedia.org/wiki/Java_version_history). - Oracle Enterprise Linux 7.0 released in 2014 included glibc 2.17
These dates suggest an update of openjdk's glibc dependency might be due. But I guess the driving factor is how the timelines of openjdk LTS release support fits with those of Oracle Enterprise Linux versions.
And with other OpenJDK distributors/vendors. Here's the information for the Oracle JDK 14: https://www.oracle.com/java/technologies/javase/products-doc-jdk14certconfig...
--- FYI some observations on my experience of building and testing openjdk.
I installed OEL6.4, but found it very tricky to build a `real` openjdk distribution on a current Ubuntu that would run with all features on OEL6.4.
Right that is not a supported build platform.
- The base openjdk build was easy to use, but it built a JDK with elf dependencies based on my OS, so of course would not run on OLE6. - The openjdk make/devkit infrastructure didn't work for me to make an OEL6 build, after lots of attempts (including running in chroot or docker isolation). I'm sure it works reliably, provided you have the correct OS setup. But its not easy for an outsider to replicate that. - The AdoptOpenJDK Docker build was super easy to use, and I liked that it used Docker to use a reproducible and fully scripted OS build environment. https://github.com/AdoptOpenJDK/openjdk-build - But AdoptOpenJDK Docker build doesn't support building and using an OEL6 devkit. AdoptOpenJDK build targets RHEL 7.4+: https://github.com/AdoptOpenJDK/openjdk-build/wiki/%5BWIP%5D-Minimum-OS-leve...
Yes I think 7.4 is current minimum build platform.
openjdk's devkit infra must pre-date the rise of Docker, and fully reproducible build environments becoming the norm.
Have they become the norm? :) I don't play in that space so have no idea. But yes this all pre-dates Docker et al by a very long time. Cheers, David -----
Maybe one day there will be time to use Docker or similar to simplify the openjdk build, and making it easy for anyone to reproduce.
As with using newer glibc features (glibc 2.17 vs 2.12), its likely to be drastically simpler when openjdk is able to update dependencies to newer OS versions. Especially if openjdk can be built on its minimum required per-platform OS version in a (Docker) container.
Mark
On Tue, 14 Apr 2020 at 23:34, David Holmes <david.holmes@oracle.com> wrote:
Hi Mark,
On 15/04/2020 3:09 am, Mark Kralj-Taylor wrote:
David, Daniel, What is the oldest (lowest) version of Linux and glibc for openjdk 15?
I'm not clear on that.
The availability of clock_gettime(CLOCK_REALTIME) on the oldest Linux/glibc supported by openjdk 15 is likely to be the deciding factor on if Hotspot Linux code can call clock_gettime(CLOCK_REALTIME).
doc/building.md suggests minimum Linux is Oracle Enterprise Linux 6.4 (i.e. RHEL 6.4). Which I think uses glibc 2.12-1.107 (based on https://yum.oracle.com/repo/OracleLinux/OL6/4/base/x86_64/index_src.html). Searching for glibc sources it looks like this supports clock_gettime(CLOCK_REALTIME).
The wording of Linux docs suggests that clock_gettime(CLOCK_REALTIME) should be supported if the clock_gettime() API exists. But other clock sources are not mandatory. So CLOCK_REALTIME should be available even if CLOCK_MONOTONIC is not. - See: https://linux.die.net/man/2/clock_gettime. - Also "POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead." from: https://linux.die.net/man/2/gettimeofday
Note that Hotspot os_posix.cpp checks for non-error return from clock_gettime(CLOCK_MONOTONIC) to guard setting the _clock_gettime function pointer. Which was why in the patch I called clock_gettime directly for Linux specific os_linux.cpp (a subset of Posix OS-s).
Also os_linux.cpp has: #ifndef SUPPORTS_CLOCK_MONOTONIC #error "Build platform doesn't support clock_gettime and related functionality" #endif Which made me wonder if openjdk might require CLOCK_MONOTONIC - which would mean clock_gettime(CLOCK_REALTIME) is supported.
So we require that the build platform supports CLOCK_MONOTONIC and clock_gettime, but not that the runtime platform supports CLOCK_MONOTONIC (without which we don't/didn't need clock_gettime().
So we can switch to using clock_gettime(CLOCK_REALTIME) at build time with no problem.
We can probably also require clock_gettime(CLOCK_REALTIME) at runtime, but we need to double-check that. I recall encountering a platform where clock_gettime was not available, but I can't recall if it was mainstream or on one of the other OpenJDK projects - nor do I recall exactly how long ago this was. Keeping the dynamic lookup of clock_gettime would be a conservative approach here - but we would need to make the distinction between the ability to use CLOCK_REALTIME and CLOCK_MONOTONIC.
Or someone puts in the time and effort to establish exactly what the kernel and glibc dependencies are and whether we can just rely on everything existing on all platforms we care about. I don't have time to do that nor validate the results if someone else does it.
Cheers, David
Mark
On Tue, 14 Apr 2020 at 18:04, Mark Kralj-Taylor <kralj.mark@gmail.com> wrote:
Daniel, Yes System.currentTimeMillis() and Clock.systemUTC() must be consistent, so should use the same OS time source (as shown by ).
The patch to os_linux.cpp ensures this by calling the same Linux API: clock_gettime(CLOCK_REALTIME) for both, from: - os::javaTimeMillis() that backs System.currentTimeMillis() - os::javaTimeSystemUTC() that backs Clock.systemUTC()
Looking at Linux / glibc source I think that gettimeofday() and clock_gettime(CLOCK_REALTIME) are supposed to be the same clocksource. i.e. that given by: cat /sys/devices/system/clocksource/clocksource0/current_clocksource
Mark
On Tue, 14 Apr 2020 at 13:29, Daniel Fuchs <daniel.fuchs@oracle.com> wrote:
Hi,
On 11/04/2020 00:53, David Holmes wrote:
Update: > It's a holiday weekend so I can't dig into this right now but we tried > using a high-precision clock source for systemUTC() in the past but it > didn't work because systemUTC() and currentTimeMillis() have to use > the same time base, and currentTimeMillis() has to use gettimeofday(). > I thought this cross-dependency was documented somewhere but can't > find it right now. If gettimeofday and clock_gettime(CLOCK_REALTIME) > actually have the same time characteristics wrt. wall-clock time then > changing both as suggested may indeed work.
Just to emphasize David's comment: System::currentTimeMillis() and Clock::systemUTC() should use the same time source: if they don't - then some tests will fail, and because it can be tricky to assert things in tests, they might (and probably will) fail only intermittently.
I'm probably the culprit here, I added those tests when I upgraded Clock::systemUTC() to report sub millisecond granularity [1] - as was available in the underlying clock that System::currentTimeMillis() already used.
However, I think I would be disturbed if System::currentTimeMillis() and Clock::systemUTC() were using different clocks and could report a different notion of time (by drifting away from each other).
best regards,
-- daniel [1] https://bugs.openjdk.java.net/browse/JDK-8068730
participants (4)
-
Daniel Fuchs
-
David Holmes
-
Florian Weimer
-
Mark Kralj-Taylor