Tue, 21 Aug 2012 14:10:39 -0700
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
1 /*
2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
25 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1MONITORINGSUPPORT_HPP
26 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1MONITORINGSUPPORT_HPP
28 #include "gc_implementation/shared/hSpaceCounters.hpp"
30 class G1CollectedHeap;
32 // Class for monitoring logical spaces in G1. It provides data for
33 // both G1's jstat counters as well as G1's memory pools.
34 //
35 // G1 splits the heap into heap regions and each heap region belongs
36 // to one of the following categories:
37 //
38 // * eden : regions that have been allocated since the last GC
39 // * survivors : regions with objects that survived the last few GCs
40 // * old : long-lived non-humongous regions
41 // * humongous : humongous regions
42 // * free : free regions
43 //
44 // The combination of eden and survivor regions form the equivalent of
45 // the young generation in the other GCs. The combination of old and
46 // humongous regions form the equivalent of the old generation in the
47 // other GCs. Free regions do not have a good equivalent in the other
48 // GCs given that they can be allocated as any of the other region types.
49 //
50 // The monitoring tools expect the heap to contain a number of
51 // generations (young, old, perm) and each generation to contain a
52 // number of spaces (young: eden, survivors, old). Given that G1 does
53 // not maintain those spaces physically (e.g., the set of
54 // non-contiguous eden regions can be considered as a "logical"
55 // space), we'll provide the illusion that those generations and
56 // spaces exist. In reality, each generation and space refers to a set
57 // of heap regions that are potentially non-contiguous.
58 //
59 // This class provides interfaces to access the min, current, and max
60 // capacity and current occupancy for each of G1's logical spaces and
61 // generations we expose to the monitoring tools. Also provided are
62 // counters for G1 concurrent collections and stop-the-world full heap
63 // collections.
64 //
65 // Below is a description of how the various sizes are calculated.
66 //
67 // * Current Capacity
68 //
69 // - heap_capacity = current heap capacity (e.g., current committed size)
70 // - young_gen_capacity = current max young gen target capacity
71 // (i.e., young gen target capacity + max allowed expansion capacity)
72 // - survivor_capacity = current survivor region capacity
73 // - eden_capacity = young_gen_capacity - survivor_capacity
74 // - old_capacity = heap_capacity - young_gen_capacity
75 //
76 // What we do in the above is to distribute the free regions among
77 // eden_capacity and old_capacity.
78 //
79 // * Occupancy
80 //
81 // - young_gen_used = current young region capacity
82 // - survivor_used = survivor_capacity
83 // - eden_used = young_gen_used - survivor_used
84 // - old_used = overall_used - young_gen_used
85 //
86 // Unfortunately, we currently only keep track of the number of
87 // currently allocated young and survivor regions + the overall used
88 // bytes in the heap, so the above can be a little inaccurate.
89 //
90 // * Min Capacity
91 //
92 // We set this to 0 for all spaces.
93 //
94 // * Max Capacity
95 //
96 // For jstat, we set the max capacity of all spaces to heap_capacity,
97 // given that we don't always have a reasonable upper bound on how big
98 // each space can grow. For the memory pools, we make the max
99 // capacity undefined with the exception of the old memory pool for
100 // which we make the max capacity same as the max heap capacity.
101 //
102 // If we had more accurate occupancy / capacity information per
103 // region set the above calculations would be greatly simplified and
104 // be made more accurate.
105 //
106 // We update all the above synchronously and we store the results in
107 // fields so that we just read said fields when needed. A subtle point
108 // is that all the above sizes need to be recalculated when the old
109 // gen changes capacity (after a GC or after a humongous allocation)
110 // but only the eden occupancy changes when a new eden region is
111 // allocated. So, in the latter case we have minimal recalcuation to
112 // do which is important as we want to keep the eden region allocation
113 // path as low-overhead as possible.
115 class G1MonitoringSupport : public CHeapObj<mtGC> {
116 friend class VMStructs;
118 G1CollectedHeap* _g1h;
120 // jstat performance counters
121 // incremental collections both young and mixed
122 CollectorCounters* _incremental_collection_counters;
123 // full stop-the-world collections
124 CollectorCounters* _full_collection_counters;
125 // young collection set counters. The _eden_counters,
126 // _from_counters, and _to_counters are associated with
127 // this "generational" counter.
128 GenerationCounters* _young_collection_counters;
129 // old collection set counters. The _old_space_counters
130 // below are associated with this "generational" counter.
131 GenerationCounters* _old_collection_counters;
132 // Counters for the capacity and used for
133 // the whole heap
134 HSpaceCounters* _old_space_counters;
135 // the young collection
136 HSpaceCounters* _eden_counters;
137 // the survivor collection (only one, _to_counters, is actively used)
138 HSpaceCounters* _from_counters;
139 HSpaceCounters* _to_counters;
141 // When it's appropriate to recalculate the various sizes (at the
142 // end of a GC, when a new eden region is allocated, etc.) we store
143 // them here so that we can easily report them when needed and not
144 // have to recalculate them every time.
146 size_t _overall_reserved;
147 size_t _overall_committed;
148 size_t _overall_used;
150 uint _young_region_num;
151 size_t _young_gen_committed;
152 size_t _eden_committed;
153 size_t _eden_used;
154 size_t _survivor_committed;
155 size_t _survivor_used;
157 size_t _old_committed;
158 size_t _old_used;
160 G1CollectedHeap* g1h() { return _g1h; }
162 // It returns x - y if x > y, 0 otherwise.
163 // As described in the comment above, some of the inputs to the
164 // calculations we have to do are obtained concurrently and hence
165 // may be inconsistent with each other. So, this provides a
166 // defensive way of performing the subtraction and avoids the value
167 // going negative (which would mean a very large result, given that
168 // the parameter are size_t).
169 static size_t subtract_up_to_zero(size_t x, size_t y) {
170 if (x > y) {
171 return x - y;
172 } else {
173 return 0;
174 }
175 }
177 // Recalculate all the sizes.
178 void recalculate_sizes();
179 // Recalculate only what's necessary when a new eden region is allocated.
180 void recalculate_eden_size();
182 public:
183 G1MonitoringSupport(G1CollectedHeap* g1h);
185 // Unfortunately, the jstat tool assumes that no space has 0
186 // capacity. In our case, given that each space is logical, it's
187 // possible that no regions will be allocated to it, hence to have 0
188 // capacity (e.g., if there are no survivor regions, the survivor
189 // space has 0 capacity). The way we deal with this is to always pad
190 // each capacity value we report to jstat by a very small amount to
191 // make sure that it's never zero. Given that we sometimes have to
192 // report a capacity of a generation that contains several spaces
193 // (e.g., young gen includes one eden, two survivor spaces), the
194 // mult parameter is provided in order to adding the appropriate
195 // padding multiple times so that the capacities add up correctly.
196 static size_t pad_capacity(size_t size_bytes, size_t mult = 1) {
197 return size_bytes + MinObjAlignmentInBytes * mult;
198 }
200 // Recalculate all the sizes from scratch and update all the jstat
201 // counters accordingly.
202 void update_sizes();
203 // Recalculate only what's necessary when a new eden region is
204 // allocated and update any jstat counters that need to be updated.
205 void update_eden_size();
207 CollectorCounters* incremental_collection_counters() {
208 return _incremental_collection_counters;
209 }
210 CollectorCounters* full_collection_counters() {
211 return _full_collection_counters;
212 }
213 GenerationCounters* young_collection_counters() {
214 return _young_collection_counters;
215 }
216 GenerationCounters* old_collection_counters() {
217 return _old_collection_counters;
218 }
219 HSpaceCounters* old_space_counters() { return _old_space_counters; }
220 HSpaceCounters* eden_counters() { return _eden_counters; }
221 HSpaceCounters* from_counters() { return _from_counters; }
222 HSpaceCounters* to_counters() { return _to_counters; }
224 // Monitoring support used by
225 // MemoryService
226 // jstat counters
228 size_t overall_reserved() { return _overall_reserved; }
229 size_t overall_committed() { return _overall_committed; }
230 size_t overall_used() { return _overall_used; }
232 size_t young_gen_committed() { return _young_gen_committed; }
233 size_t young_gen_max() { return overall_reserved(); }
234 size_t eden_space_committed() { return _eden_committed; }
235 size_t eden_space_used() { return _eden_used; }
236 size_t survivor_space_committed() { return _survivor_committed; }
237 size_t survivor_space_used() { return _survivor_used; }
239 size_t old_gen_committed() { return old_space_committed(); }
240 size_t old_gen_max() { return overall_reserved(); }
241 size_t old_space_committed() { return _old_committed; }
242 size_t old_space_used() { return _old_used; }
243 };
245 class G1GenerationCounters: public GenerationCounters {
246 protected:
247 G1MonitoringSupport* _g1mm;
249 public:
250 G1GenerationCounters(G1MonitoringSupport* g1mm,
251 const char* name, int ordinal, int spaces,
252 size_t min_capacity, size_t max_capacity,
253 size_t curr_capacity);
254 };
256 class G1YoungGenerationCounters: public G1GenerationCounters {
257 public:
258 G1YoungGenerationCounters(G1MonitoringSupport* g1mm, const char* name);
259 virtual void update_all();
260 };
262 class G1OldGenerationCounters: public G1GenerationCounters {
263 public:
264 G1OldGenerationCounters(G1MonitoringSupport* g1mm, const char* name);
265 virtual void update_all();
266 };
268 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1MONITORINGSUPPORT_HPP