< prev index next >
src/hotspot/os/aix/os_aix.cpp
Print this page
rev 48741 : 8196565: AIX: Clean up os::javaTimeNanos according to AIX/PASE specification
@@ -186,10 +186,11 @@
int os::Aix::_extshm = -1;
////////////////////////////////////////////////////////////////////////////////
// local variables
+static volatile jlong max_nanos = 0;
static jlong initial_time_count = 0;
static int clock_tics_per_sec = 100;
static sigset_t check_signal_done; // For diagnostics to print a message once (see run_periodic_checks)
static bool check_signals = true;
static int SR_signum = SIGUSR2; // Signal used to suspend/resume a thread (must be > SIGSEGV, see 4355769)
@@ -1074,35 +1075,50 @@
assert(status != -1, "aix error at gettimeofday()");
seconds = jlong(time.tv_sec);
nanos = jlong(time.tv_usec) * 1000;
}
+// We use mread_real_time here.
+// On AIX: If the CPU has a time register, the result will be RTC_POWER and
+// it has to be converted to real time. AIX documentations suggests to do
+// this unconditionally, so we do it.
+//
+// See: https://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.basetrf2/read_real_time.htm
+//
+// On PASE: mread_real_time will always return RTC_POWER_PC data, so no
+// conversion is necessary. However, mread_real_time will not return
+// monotonic results but merely matches read_real_time. So we need a tweak
+// to ensure monotonic results.
+//
+// For PASE no public documentation exists, just word by IBM
jlong os::javaTimeNanos() {
+ timebasestruct_t time;
+ mread_real_time(&time, TIMEBASE_SZ);
if (os::Aix::on_pase()) {
-
- timeval time;
- int status = gettimeofday(&time, NULL);
- assert(status != -1, "PASE error at gettimeofday()");
- jlong usecs = jlong((unsigned long long) time.tv_sec * (1000 * 1000) + time.tv_usec);
- return 1000 * usecs;
-
+ jlong now = jlong(time.tb_high) * (1000 * 1000 * 1000) + jlong(time.tb_low);
+ jlong prev = max_nanos;
+ if (now <= prev) {
+ return prev; // same or retrograde time;
+ }
+ jlong obsv = Atomic::cmpxchg(now, &max_nanos, 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 "obsv" is >= now then
+ // we should return "obsv". If the CAS failed and now > obsv > 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 obsv. 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 obsv 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 obsv and now.
+ // Avoiding excessive CAS operations to hot RW locations is critical.
+ // See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate
+ return (prev == obsv) ? now : obsv;
} else {
- // On AIX use the precision of processors real time clock
- // or time base registers.
- timebasestruct_t time;
- int rc;
-
- // If the CPU has a time register, it will be used and
- // we have to convert to real time first. After convertion we have following data:
- // time.tb_high [seconds since 00:00:00 UTC on 1.1.1970]
- // time.tb_low [nanoseconds after the last full second above]
- // We better use mread_real_time here instead of read_real_time
- // to ensure that we will get a monotonic increasing time.
- if (mread_real_time(&time, TIMEBASE_SZ) != RTC_POWER) {
- rc = time_base_to_time(&time, TIMEBASE_SZ);
- assert(rc != -1, "aix error at time_base_to_time()");
- }
+ int rc = time_base_to_time(&time, TIMEBASE_SZ);
+ assert(rc != -1, "error calling time_base_to_time()");
return jlong(time.tb_high) * (1000 * 1000 * 1000) + jlong(time.tb_low);
}
}
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
< prev index next >