src/share/vm/gc_implementation/g1/g1MMUTracker.cpp

Tue, 21 Aug 2012 14:10:39 -0700

author
johnc
date
Tue, 21 Aug 2012 14:10:39 -0700
changeset 3998
7383557659bd
parent 3114
20213c8a3c40
child 6876
710a3c8b516e
child 9858
b985cbb00e68
permissions
-rw-r--r--

7185699: G1: Prediction model discrepancies
Summary: Correct the result value of G1CollectedHeap::pending_card_num(). Change the code that calculates the GC efficiency of a non-young heap region to use historical data from mixed GCs and the actual number of live bytes when predicting how long it would take to collect the region. Changes were also reviewed by Thomas Schatzl.
Reviewed-by: azeemj, brutisso

ysr@777 1 /*
tonyp@3114 2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
ysr@777 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ysr@777 4 *
ysr@777 5 * This code is free software; you can redistribute it and/or modify it
ysr@777 6 * under the terms of the GNU General Public License version 2 only, as
ysr@777 7 * published by the Free Software Foundation.
ysr@777 8 *
ysr@777 9 * This code is distributed in the hope that it will be useful, but WITHOUT
ysr@777 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ysr@777 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ysr@777 12 * version 2 for more details (a copy is included in the LICENSE file that
ysr@777 13 * accompanied this code).
ysr@777 14 *
ysr@777 15 * You should have received a copy of the GNU General Public License version
ysr@777 16 * 2 along with this work; if not, write to the Free Software Foundation,
ysr@777 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ysr@777 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
ysr@777 22 *
ysr@777 23 */
ysr@777 24
stefank@2314 25 #include "precompiled.hpp"
stefank@2314 26 #include "gc_implementation/g1/g1MMUTracker.hpp"
stefank@2314 27 #include "runtime/mutexLocker.hpp"
stefank@2314 28 #include "utilities/ostream.hpp"
ysr@777 29
ysr@777 30 #define _DISABLE_MMU 0
ysr@777 31
ysr@777 32 // can't rely on comparing doubles with tolerating a small margin for error
ysr@777 33 #define SMALL_MARGIN 0.0000001
ysr@777 34 #define is_double_leq_0(_value) ( (_value) < SMALL_MARGIN )
ysr@777 35 #define is_double_leq(_val1, _val2) is_double_leq_0((_val1) - (_val2))
ysr@777 36 #define is_double_geq(_val1, _val2) is_double_leq_0((_val2) - (_val1))
ysr@777 37
ysr@777 38 /***** ALL TIMES ARE IN SECS!!!!!!! *****/
ysr@777 39
ysr@777 40 G1MMUTracker::G1MMUTracker(double time_slice, double max_gc_time) :
ysr@777 41 _time_slice(time_slice),
tonyp@1371 42 _max_gc_time(max_gc_time) { }
ysr@777 43
ysr@777 44 G1MMUTrackerQueue::G1MMUTrackerQueue(double time_slice, double max_gc_time) :
ysr@777 45 G1MMUTracker(time_slice, max_gc_time),
ysr@777 46 _head_index(0),
ysr@777 47 _tail_index(trim_index(_head_index+1)),
ysr@777 48 _no_entries(0) { }
ysr@777 49
ysr@777 50 void G1MMUTrackerQueue::remove_expired_entries(double current_time) {
ysr@777 51 double limit = current_time - _time_slice;
ysr@777 52 while (_no_entries > 0) {
ysr@777 53 if (is_double_geq(limit, _array[_tail_index].end_time())) {
ysr@777 54 _tail_index = trim_index(_tail_index + 1);
ysr@777 55 --_no_entries;
ysr@777 56 } else
ysr@777 57 return;
ysr@777 58 }
ysr@777 59 guarantee(_no_entries == 0, "should have no entries in the array");
ysr@777 60 }
ysr@777 61
ysr@777 62 double G1MMUTrackerQueue::calculate_gc_time(double current_time) {
ysr@777 63 double gc_time = 0.0;
ysr@777 64 double limit = current_time - _time_slice;
ysr@777 65 for (int i = 0; i < _no_entries; ++i) {
ysr@777 66 int index = trim_index(_tail_index + i);
ysr@777 67 G1MMUTrackerQueueElem *elem = &_array[index];
ysr@777 68 if (elem->end_time() > limit) {
ysr@777 69 if (elem->start_time() > limit)
ysr@777 70 gc_time += elem->duration();
ysr@777 71 else
ysr@777 72 gc_time += elem->end_time() - limit;
ysr@777 73 }
ysr@777 74 }
ysr@777 75 return gc_time;
ysr@777 76 }
ysr@777 77
ysr@777 78 void G1MMUTrackerQueue::add_pause(double start, double end, bool gc_thread) {
ysr@777 79 double longest_allowed = longest_pause_internal(start);
ysr@777 80 if (longest_allowed < 0.0)
ysr@777 81 longest_allowed = 0.0;
ysr@777 82 double duration = end - start;
ysr@777 83
ysr@777 84 remove_expired_entries(end);
ysr@777 85 if (_no_entries == QueueLength) {
johnc@1946 86 // OK, we've filled up the queue. There are a few ways
johnc@1946 87 // of dealing with this "gracefully"
ysr@777 88 // increase the array size (:-)
ysr@777 89 // remove the oldest entry (this might allow more GC time for
johnc@1946 90 // the time slice than what's allowed) - this is what we
johnc@1946 91 // currently do
ysr@1523 92 // consolidate the two entries with the minimum gap between them
ysr@1523 93 // (this might allow less GC time than what's allowed)
johnc@1946 94
ysr@1523 95 // In the case where ScavengeALot is true, such overflow is not
ysr@1523 96 // uncommon; in such cases, we can, without much loss of precision
ysr@1523 97 // or performance (we are GC'ing most of the time anyway!),
johnc@1946 98 // simply overwrite the oldest entry in the tracker.
johnc@1946 99
ysr@1523 100 _head_index = trim_index(_head_index + 1);
ysr@1523 101 assert(_head_index == _tail_index, "Because we have a full circular buffer");
ysr@1523 102 _tail_index = trim_index(_tail_index + 1);
ysr@1523 103 } else {
ysr@1523 104 _head_index = trim_index(_head_index + 1);
ysr@1523 105 ++_no_entries;
ysr@777 106 }
ysr@777 107 _array[_head_index] = G1MMUTrackerQueueElem(start, end);
ysr@777 108 }
ysr@777 109
ysr@777 110 // basically the _internal call does not remove expired entries
ysr@777 111 // this is for trying things out in the future and a couple
ysr@777 112 // of other places (debugging)
ysr@777 113
ysr@777 114 double G1MMUTrackerQueue::longest_pause(double current_time) {
ysr@777 115 if (_DISABLE_MMU)
ysr@777 116 return _max_gc_time;
ysr@777 117
ysr@777 118 MutexLockerEx x(MMUTracker_lock, Mutex::_no_safepoint_check_flag);
ysr@777 119 remove_expired_entries(current_time);
ysr@777 120
ysr@777 121 return longest_pause_internal(current_time);
ysr@777 122 }
ysr@777 123
ysr@777 124 double G1MMUTrackerQueue::longest_pause_internal(double current_time) {
ysr@777 125 double target_time = _max_gc_time;
ysr@777 126
ysr@777 127 while( 1 ) {
ysr@777 128 double gc_time =
tonyp@1371 129 calculate_gc_time(current_time + target_time);
ysr@777 130 double diff = target_time + gc_time - _max_gc_time;
ysr@777 131 if (!is_double_leq_0(diff)) {
ysr@777 132 target_time -= diff;
ysr@777 133 if (is_double_leq_0(target_time)) {
ysr@777 134 target_time = -1.0;
ysr@777 135 break;
ysr@777 136 }
ysr@777 137 } else {
ysr@777 138 break;
ysr@777 139 }
ysr@777 140 }
ysr@777 141
ysr@777 142 return target_time;
ysr@777 143 }
ysr@777 144
ysr@777 145 // basically the _internal call does not remove expired entries
ysr@777 146 // this is for trying things out in the future and a couple
ysr@777 147 // of other places (debugging)
ysr@777 148
ysr@777 149 double G1MMUTrackerQueue::when_sec(double current_time, double pause_time) {
ysr@777 150 if (_DISABLE_MMU)
ysr@777 151 return 0.0;
ysr@777 152
ysr@777 153 MutexLockerEx x(MMUTracker_lock, Mutex::_no_safepoint_check_flag);
ysr@777 154 remove_expired_entries(current_time);
ysr@777 155
ysr@777 156 return when_internal(current_time, pause_time);
ysr@777 157 }
ysr@777 158
ysr@777 159 double G1MMUTrackerQueue::when_internal(double current_time,
ysr@777 160 double pause_time) {
ysr@777 161 // if the pause is over the maximum, just assume that it's the maximum
ysr@777 162 double adjusted_pause_time =
ysr@777 163 (pause_time > max_gc_time()) ? max_gc_time() : pause_time;
ysr@777 164 double earliest_end = current_time + adjusted_pause_time;
ysr@777 165 double limit = earliest_end - _time_slice;
ysr@777 166 double gc_time = calculate_gc_time(earliest_end);
ysr@777 167 double diff = gc_time + adjusted_pause_time - max_gc_time();
ysr@777 168 if (is_double_leq_0(diff))
ysr@777 169 return 0.0;
ysr@777 170
ysr@777 171 int index = _tail_index;
ysr@777 172 while ( 1 ) {
ysr@777 173 G1MMUTrackerQueueElem *elem = &_array[index];
ysr@777 174 if (elem->end_time() > limit) {
ysr@777 175 if (elem->start_time() > limit)
ysr@777 176 diff -= elem->duration();
ysr@777 177 else
ysr@777 178 diff -= elem->end_time() - limit;
ysr@777 179 if (is_double_leq_0(diff))
ysr@777 180 return elem->end_time() + diff + _time_slice - adjusted_pause_time - current_time;
ysr@777 181 }
ysr@777 182 index = trim_index(index+1);
ysr@777 183 guarantee(index != trim_index(_head_index + 1), "should not go past head");
ysr@777 184 }
ysr@777 185 }

mercurial