# HG changeset patch # User sla # Date 1397486642 -7200 # Mon Apr 14 16:44:02 2014 +0200 # Node ID 5009c0e976b27a48ef786f9af6129cb2b45836fd # Parent 3f9cfa1f9f0f364b46808d96b6ead053a7a2cb2c [mq]: osx-clock diff --git a/src/os/bsd/vm/os_bsd.cpp b/src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp +++ b/src/os/bsd/vm/os_bsd.cpp @@ -127,8 +127,12 @@ // global variables julong os::Bsd::_physical_memory = 0; - +#ifdef __APPLE__ +mach_timebase_info_data_t os::Bsd::_timebase_info = {0, 0}; +volatile uint64_t os::Bsd::_max_abstime = 0; +#else int (*os::Bsd::_clock_gettime)(clockid_t, struct timespec *) = NULL; +#endif pthread_t os::Bsd::_main_thread; int os::Bsd::_page_size = -1; @@ -986,13 +990,15 @@ return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000); } +#ifndef __APPLE__ #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC (1) #endif +#endif #ifdef __APPLE__ void os::Bsd::clock_init() { - // XXXDARWIN: Investigate replacement monotonic clock + mach_timebase_info(&_timebase_info); } #else void os::Bsd::clock_init() { @@ -1007,10 +1013,43 @@ #endif + +#ifdef __APPLE__ + +jlong os::javaTimeNanos() { + const uint64_t tm = mach_absolute_time(); + const uint64_t now = (tm * Bsd::_timebase_info.numer) / Bsd::_timebase_info.denom; + if (AssumeMonotonicOSTimers) { + return now; + } + + const uint64_t prev = Bsd::_max_abstime; + if (now <= prev) { + return prev; // same or retrograde time; + } + const uint64_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&Bsd::_max_abstime, prev); + assert(obsv >= prev, "invariant"); // Monotonicity + // If the CAS succeeded then we're done and return "now". + // If the CAS failed and the observed value "obs" is >= now then + // we should return "obs". If the CAS failed and now > obs > prv then + // some other thread raced this thread and installed a new value, in which case + // we could either (a) retry the entire operation, (b) retry trying to install now + // or (c) just return obs. We use (c). No loop is required although in some cases + // we might discard a higher "now" value in deference to a slightly lower but freshly + // installed obs value. That's entirely benign -- it admits no new orderings compared + // to (a) or (b) -- and greatly reduces coherence traffic. + // We might also condition (c) on the magnitude of the delta between obs and now. + // Avoiding excessive CAS operations to hot RW locations is critical. + // See http://blogs.sun.com/dave/entry/cas_and_cache_trivia_invalidate + return (prev == obsv) ? now : obsv; +} + +#else // __APPLE__ + jlong os::javaTimeNanos() { if (os::supports_monotonic_clock()) { struct timespec tp; - int status = Bsd::clock_gettime(CLOCK_MONOTONIC, &tp); + int status = Bsd::_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; @@ -1023,6 +1062,8 @@ } } +#endif // __APPLE__ + void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { if (os::supports_monotonic_clock()) { info_ptr->max_value = ALL_64_BITS; diff --git a/src/os/bsd/vm/os_bsd.hpp b/src/os/bsd/vm/os_bsd.hpp --- a/src/os/bsd/vm/os_bsd.hpp +++ b/src/os/bsd/vm/os_bsd.hpp @@ -58,7 +58,13 @@ // For signal flags diagnostics static int sigflags[MAXSIGNUM]; +#ifdef __APPLE__ + // mach_absolute_time + static mach_timebase_info_data_t _timebase_info; + static volatile uint64_t _max_abstime; +#else static int (*_clock_gettime)(clockid_t, struct timespec *); +#endif static GrowableArray* _cpu_to_node; @@ -134,10 +140,6 @@ // Real-time clock functions static void clock_init(void); - static int clock_gettime(clockid_t clock_id, struct timespec *tp) { - return _clock_gettime ? _clock_gettime(clock_id, tp) : -1; - } - // Stack repair handling // none present diff --git a/src/os/bsd/vm/os_bsd.inline.hpp b/src/os/bsd/vm/os_bsd.inline.hpp --- a/src/os/bsd/vm/os_bsd.inline.hpp +++ b/src/os/bsd/vm/os_bsd.inline.hpp @@ -287,7 +287,11 @@ } inline bool os::supports_monotonic_clock() { +#ifdef __APPLE__ + return true; +#else return Bsd::_clock_gettime != NULL; +#endif } #endif // OS_BSD_VM_OS_BSD_INLINE_HPP diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp +++ b/src/os/solaris/vm/os_solaris.cpp @@ -1395,9 +1395,14 @@ inline hrtime_t getTimeNanos() { if (VM_Version::supports_cx8()) { const hrtime_t now = gethrtime(); - // Use atomic long load since 32-bit x86 uses 2 registers to keep long. - const hrtime_t prev = Atomic::load((volatile jlong*)&max_hrtime); - if (now <= prev) return prev; // same or retrograde time; + if (AssumeMonotonicOSTimers) { + return now; + } + + const hrtime_t prev = max_hrtime; + if (now <= prev) { + return prev; // same or retrograde time; + } const hrtime_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&max_hrtime, prev); assert(obsv >= prev, "invariant"); // Monotonicity // If the CAS succeeded then we're done and return "now". diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -616,6 +616,9 @@ product(bool, ForceTimeHighResolution, false, \ "Using high time resolution (for Win32 only)") \ \ + experimental(bool, AssumeMonotonicOSTimers, false, \ + "Assume that the OS system timers are monotonic") \ + \ develop(bool, TraceItables, false, \ "Trace initialization and use of itables") \ \ diff --git a/src/share/vm/runtime/os.hpp b/src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp +++ b/src/share/vm/runtime/os.hpp @@ -48,6 +48,7 @@ #ifdef TARGET_OS_FAMILY_bsd # include "jvm_bsd.h" # include +# include #endif class AgentLibrary;