< 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,195 ****
--- 186,196 ----
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,1108 ****
assert(status != -1, "aix error at gettimeofday()");
seconds = jlong(time.tv_sec);
nanos = jlong(time.tv_usec) * 1000;
}
jlong os::javaTimeNanos() {
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;
!
} 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()");
! }
return jlong(time.tb_high) * (1000 * 1000 * 1000) + jlong(time.tb_low);
}
}
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
--- 1075,1124 ----
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()) {
! 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 {
! 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 >