changeset 59491:f1f88e6fad02

8242504: Enhance the system clock to nanosecond precision Reviewed-by: dfuchs, rriggs, dcubed, vtewari Contributed-by: Mark Kralj-Taylor <kralj.mark@gmail.com>, David Holmes <david.holmes@oracle.com>
author dholmes
date Thu, 28 May 2020 22:34:02 -0400
parents c6c981b12f69
children 4d5a58b0146f 8ece8196671e
files src/hotspot/os/linux/os_linux.cpp src/hotspot/os/posix/os_posix.cpp src/hotspot/os/posix/os_posix.hpp src/hotspot/os/posix/os_posix.inline.hpp test/jdk/java/time/test/java/time/TestClock_System.java test/micro/org/openjdk/bench/java/lang/SystemTime.java test/micro/org/openjdk/bench/java/lang/Systems.java
diffstat 7 files changed, 106 insertions(+), 75 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/os/linux/os_linux.cpp	Thu May 28 21:40:35 2020 -0400
+++ b/src/hotspot/os/linux/os_linux.cpp	Thu May 28 22:34:02 2020 -0400
@@ -1376,18 +1376,35 @@
 }
 
 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() {
--- a/src/hotspot/os/posix/os_posix.cpp	Thu May 28 21:40:35 2020 -0400
+++ b/src/hotspot/os/posix/os_posix.cpp	Thu May 28 22:34:02 2020 -0400
@@ -1638,6 +1638,8 @@
 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* 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 @@
   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 @@
     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;
     }
   }
 
--- a/src/hotspot/os/posix/os_posix.hpp	Thu May 28 21:40:35 2020 -0400
+++ b/src/hotspot/os/posix/os_posix.hpp	Thu May 28 22:34:02 2020 -0400
@@ -128,18 +128,18 @@
 #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);
--- a/src/hotspot/os/posix/os_posix.inline.hpp	Thu May 28 21:40:35 2020 -0400
+++ b/src/hotspot/os/posix/os_posix.inline.hpp	Thu May 28 22:34:02 2020 -0400
@@ -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;
 }
 
--- a/test/jdk/java/time/test/java/time/TestClock_System.java	Thu May 28 21:40:35 2020 -0400
+++ b/test/jdk/java/time/test/java/time/TestClock_System.java	Thu May 28 22:34:02 2020 -0400
@@ -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 @@
                         + 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 @@
                 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 @@
                 }
             }
             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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/micro/org/openjdk/bench/java/lang/SystemTime.java	Thu May 28 22:34:02 2020 -0400
@@ -0,0 +1,52 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.bench.java.lang;
+
+import org.openjdk.jmh.annotations.Benchmark;
+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 SystemTime {
+
+    @Benchmark
+    public long currentTimeMillis() {
+        return System.currentTimeMillis();
+    }
+
+    @Benchmark
+    public long nanoTime() {
+        return System.nanoTime();
+    }
+
+    @Benchmark
+    public long instantNowAsEpochNanos() {
+        Instant now = Instant.now();
+        return now.getEpochSecond() * 1_000_000_000L + now.getNano();
+    }
+}
--- a/test/micro/org/openjdk/bench/java/lang/Systems.java	Thu May 28 21:40:35 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2014, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.openjdk.bench.java.lang;
-
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Mode;
-import org.openjdk.jmh.annotations.OutputTimeUnit;
-
-import java.util.concurrent.TimeUnit;
-
-@BenchmarkMode(Mode.AverageTime)
-@OutputTimeUnit(TimeUnit.NANOSECONDS)
-public class Systems {
-
-    @Benchmark
-    public long currentTimeMillis() {
-        return System.currentTimeMillis();
-    }
-
-    @Benchmark
-    public long nanoTime() {
-        return System.nanoTime();
-    }
-
-}