void CSetChooserCache::insert(HeapRegion *hr) { guarantee(false, "CSetChooserCache::insert(): don't call this any more"); assert(!is_full(), "cache should not be empty"); hr->calc_gc_efficiency(); int empty_index; if (_occupancy == 0) { empty_index = _first; } else { empty_index = trim_index(_first + _occupancy); assert(_cache[empty_index] == NULL, "last slot should be empty"); int last_index = trim_index(empty_index - 1); HeapRegion *last = _cache[last_index]; assert(last != NULL,"as the cache is not empty, last should not be empty"); while (empty_index != _first && last->gc_efficiency() < hr->gc_efficiency()) { _cache[empty_index] = last; last->set_sort_index(get_sort_index(empty_index)); empty_index = last_index; last_index = trim_index(last_index - 1); last = _cache[last_index]; } } _cache[empty_index] = hr; hr->set_sort_index(get_sort_index(empty_index)); ++_occupancy; assert(verify(), "cache should be consistent"); }
void G1MMUTrackerQueue::add_pause(double start, double end, bool gc_thread) { double longest_allowed = longest_pause_internal(start); if (longest_allowed < 0.0) longest_allowed = 0.0; double duration = end - start; remove_expired_entries(end); if (_no_entries == QueueLength) { // OK, right now when we fill up we bomb out // there are a few ways of dealing with this "gracefully" // increase the array size (:-) // remove the oldest entry (this might allow more GC time for // the time slice than what's allowed) // consolidate the two entries with the minimum gap between them // (this might allow less GC time than what's allowed) guarantee(NOT_PRODUCT(ScavengeALot ||) G1UseFixedWindowMMUTracker, "array full, currently we can't recover unless +G1UseFixedWindowMMUTracker"); // In the case where ScavengeALot is true, such overflow is not // uncommon; in such cases, we can, without much loss of precision // or performance (we are GC'ing most of the time anyway!), // simply overwrite the oldest entry in the tracker: this // is also the behaviour when G1UseFixedWindowMMUTracker is enabled. _head_index = trim_index(_head_index + 1); assert(_head_index == _tail_index, "Because we have a full circular buffer"); _tail_index = trim_index(_tail_index + 1); } else {
bool CSetChooserCache::verify() { guarantee(false, "CSetChooserCache::verify(): don't call this any more"); int index = _first; HeapRegion *prev = NULL; for (int i = 0; i < _occupancy; ++i) { guarantee(_cache[index] != NULL, "cache entry should not be empty"); HeapRegion *hr = _cache[index]; guarantee(!hr->is_young(), "should not be young!"); if (prev != NULL) { guarantee(prev->gc_efficiency() >= hr->gc_efficiency(), "cache should be correctly ordered"); } guarantee(hr->sort_index() == get_sort_index(index), "sort index should be correct"); index = trim_index(index + 1); prev = hr; } for (int i = 0; i < (CacheLength - _occupancy); ++i) { guarantee(_cache[index] == NULL, "cache entry should be empty"); index = trim_index(index + 1); } guarantee(index == _first, "we should have reached where we started from"); return true; }
void G1MMUTrackerQueue::add_pause(double start, double end, bool gc_thread) { double longest_allowed = longest_pause_internal(start); if (longest_allowed < 0.0) longest_allowed = 0.0; double duration = end - start; remove_expired_entries(end); if (_no_entries == QueueLength) { // OK, we've filled up the queue. There are a few ways // of dealing with this "gracefully" // increase the array size (:-) // remove the oldest entry (this might allow more GC time for // the time slice than what's allowed) - this is what we // currently do // consolidate the two entries with the minimum gap between them // (this might allow less GC time than what's allowed) // In the case where ScavengeALot is true, such overflow is not // uncommon; in such cases, we can, without much loss of precision // or performance (we are GC'ing most of the time anyway!), // simply overwrite the oldest entry in the tracker. _head_index = trim_index(_head_index + 1); assert(_head_index == _tail_index, "Because we have a full circular buffer"); _tail_index = trim_index(_tail_index + 1); } else { _head_index = trim_index(_head_index + 1); ++_no_entries; } _array[_head_index] = G1MMUTrackerQueueElem(start, end); }
double G1MMUTrackerQueue::when_internal(double current_time, double pause_time) { // if the pause is over the maximum, just assume that it's the maximum double adjusted_pause_time = (pause_time > max_gc_time()) ? max_gc_time() : pause_time; double earliest_end = current_time + adjusted_pause_time; double limit = earliest_end - _time_slice; double gc_time = calculate_gc_time(earliest_end); double diff = gc_time + adjusted_pause_time - max_gc_time(); if (is_double_leq_0(diff)) return 0.0; int index = _tail_index; while ( 1 ) { G1MMUTrackerQueueElem *elem = &_array[index]; if (elem->end_time() > limit) { if (elem->start_time() > limit) diff -= elem->duration(); else diff -= elem->end_time() - limit; if (is_double_leq_0(diff)) return elem->end_time() + diff + _time_slice - adjusted_pause_time - current_time; } index = trim_index(index+1); guarantee(index != trim_index(_head_index + 1), "should not go past head"); } }
void G1MMUTrackerQueue::remove_expired_entries(double current_time) { double limit = current_time - _time_slice; while (_no_entries > 0) { if (is_double_geq(limit, _array[_tail_index].end_time())) { _tail_index = trim_index(_tail_index + 1); --_no_entries; } else return; } guarantee(_no_entries == 0, "should have no entries in the array"); }
double G1MMUTrackerQueue::calculate_gc_time(double current_time) { double gc_time = 0.0; double limit = current_time - _time_slice; for (int i = 0; i < _no_entries; ++i) { int index = trim_index(_tail_index + i); G1MMUTrackerQueueElem *elem = &_array[index]; if (elem->end_time() > limit) { if (elem->start_time() > limit) gc_time += elem->duration(); else gc_time += elem->end_time() - limit; } } return gc_time; }
HeapRegion *CSetChooserCache::remove_first() { guarantee(false, "CSetChooserCache::remove_first(): " "don't call this any more"); if (_occupancy > 0) { assert(_cache[_first] != NULL, "cache should have at least one region"); HeapRegion *ret = _cache[_first]; _cache[_first] = NULL; ret->set_sort_index(-1); --_occupancy; _first = trim_index(_first + 1); assert(verify(), "cache should be consistent"); return ret; } else { return NULL; } }
G1MMUTrackerQueue::G1MMUTrackerQueue(double time_slice, double max_gc_time) : G1MMUTracker(time_slice, max_gc_time), _head_index(0), _tail_index(trim_index(_head_index+1)), _no_entries(0) { }