8223961: ZGC: Unexpected behaviour due to ZMetronome::wait_for_tick() oversleeping

Co-authored-by: Jie Fu <fujie@loongson.cn>
Reviewed-by: pliden, stefank
This commit is contained in:
Per Lidén 2019-05-17 12:06:03 +02:00
parent 5db94d085a
commit 4ded8e61df
3 changed files with 28 additions and 10 deletions

View File

@ -34,10 +34,6 @@ ZMetronome::ZMetronome(uint64_t hz) :
_nticks(0),
_stopped(false) {}
uint64_t ZMetronome::nticks() const {
return _nticks;
}
bool ZMetronome::wait_for_tick() {
if (_nticks++ == 0) {
// First tick, set start time
@ -45,7 +41,9 @@ bool ZMetronome::wait_for_tick() {
_start_ms = TimeHelper::counter_to_millis(now.value());
}
for (;;) {
MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag);
while (!_stopped) {
// We might wake up spuriously from wait, so always recalculate
// the timeout after a wakeup to see if we need to wait again.
const Ticks now = Ticks::now();
@ -53,15 +51,27 @@ bool ZMetronome::wait_for_tick() {
const uint64_t next_ms = _start_ms + (_interval_ms * _nticks);
const int64_t timeout_ms = next_ms - now_ms;
MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag);
if (!_stopped && timeout_ms > 0) {
if (timeout_ms > 0) {
// Wait
ml.wait(timeout_ms);
} else {
// Tick
return !_stopped;
if (timeout_ms < 0) {
const uint64_t overslept = -timeout_ms;
if (overslept > _interval_ms) {
// Missed one or more ticks. Bump _nticks accordingly to
// avoid firing a string of immediate ticks to make up
// for the ones we missed.
_nticks += overslept / _interval_ms;
}
}
return true;
}
}
// Stopped
return false;
}
void ZMetronome::stop() {

View File

@ -38,7 +38,6 @@ private:
public:
ZMetronome(uint64_t hz);
uint64_t nticks() const;
bool wait_for_tick();
void stop();
};

View File

@ -850,7 +850,16 @@ void ZStat::sample_and_collect(ZStatSamplerHistory* history) const {
}
bool ZStat::should_print(LogTargetHandle log) const {
return log.is_enabled() && (_metronome.nticks() % ZStatisticsInterval == 0);
static uint64_t print_at = ZStatisticsInterval;
const uint64_t now = os::elapsedTime();
if (now < print_at) {
return false;
}
print_at = ((now / ZStatisticsInterval) * ZStatisticsInterval) + ZStatisticsInterval;
return log.is_enabled();
}
void ZStat::print(LogTargetHandle log, const ZStatSamplerHistory* history) const {