src/os/bsd/vm/os_bsd.cpp

Print this page
rev 6280 : 8040140: System.nanoTime() is slow and non-monotonic on OS X
Reviewed-by: sspitsyn, shade

*** 125,136 **** #define LARGEPAGES_BIT (1 << 6) //////////////////////////////////////////////////////////////////////////////// // global variables julong os::Bsd::_physical_memory = 0; ! int (*os::Bsd::_clock_gettime)(clockid_t, struct timespec *) = NULL; pthread_t os::Bsd::_main_thread; int os::Bsd::_page_size = -1; static jlong initial_time_count=0; --- 125,140 ---- #define LARGEPAGES_BIT (1 << 6) //////////////////////////////////////////////////////////////////////////////// // 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; static jlong initial_time_count=0;
*** 984,1000 **** int status = gettimeofday(&time, NULL); assert(status != -1, "bsd error"); return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000); } #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC (1) #endif #ifdef __APPLE__ void os::Bsd::clock_init() { ! // XXXDARWIN: Investigate replacement monotonic clock } #else void os::Bsd::clock_init() { struct timespec res; struct timespec tp; --- 988,1006 ---- int status = gettimeofday(&time, NULL); assert(status != -1, "bsd error"); 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() { ! mach_timebase_info(&_timebase_info); } #else void os::Bsd::clock_init() { struct timespec res; struct timespec tp;
*** 1005,1018 **** } } #endif jlong os::javaTimeNanos() { if (os::supports_monotonic_clock()) { struct timespec 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; } else { timeval time; --- 1011,1057 ---- } } #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); assert(status == 0, "gettime error"); jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec); return result; } else { timeval time;
*** 1021,1030 **** --- 1060,1071 ---- jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec); return 1000 * usecs; } } + #endif // __APPLE__ + void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { if (os::supports_monotonic_clock()) { info_ptr->max_value = ALL_64_BITS; // CLOCK_MONOTONIC - amount of time since some arbitrary point in the past