Fri, 10 Oct 2014 15:51:58 +0200
8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso
1 /*
2 * Copyright (c) 2013, 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 #include "precompiled.hpp"
26 #include "gc_implementation/g1/concurrentG1Refine.hpp"
27 #include "gc_implementation/g1/concurrentG1RefineThread.hpp"
28 #include "gc_implementation/g1/heapRegion.hpp"
29 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
30 #include "gc_implementation/g1/g1RemSet.inline.hpp"
31 #include "gc_implementation/g1/g1RemSetSummary.hpp"
32 #include "gc_implementation/g1/heapRegionRemSet.hpp"
33 #include "runtime/thread.inline.hpp"
35 class GetRSThreadVTimeClosure : public ThreadClosure {
36 private:
37 G1RemSetSummary* _summary;
38 uint _counter;
40 public:
41 GetRSThreadVTimeClosure(G1RemSetSummary * summary) : ThreadClosure(), _summary(summary), _counter(0) {
42 assert(_summary != NULL, "just checking");
43 }
45 virtual void do_thread(Thread* t) {
46 ConcurrentG1RefineThread* crt = (ConcurrentG1RefineThread*) t;
47 _summary->set_rs_thread_vtime(_counter, crt->vtime_accum());
48 _counter++;
49 }
50 };
52 void G1RemSetSummary::update() {
53 _num_refined_cards = remset()->conc_refine_cards();
54 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
55 _num_processed_buf_mutator = dcqs.processed_buffers_mut();
56 _num_processed_buf_rs_threads = dcqs.processed_buffers_rs_thread();
58 _num_coarsenings = HeapRegionRemSet::n_coarsenings();
60 ConcurrentG1Refine * cg1r = G1CollectedHeap::heap()->concurrent_g1_refine();
61 if (_rs_threads_vtimes != NULL) {
62 GetRSThreadVTimeClosure p(this);
63 cg1r->worker_threads_do(&p);
64 }
65 set_sampling_thread_vtime(cg1r->sampling_thread()->vtime_accum());
66 }
68 void G1RemSetSummary::set_rs_thread_vtime(uint thread, double value) {
69 assert(_rs_threads_vtimes != NULL, "just checking");
70 assert(thread < _num_vtimes, "just checking");
71 _rs_threads_vtimes[thread] = value;
72 }
74 double G1RemSetSummary::rs_thread_vtime(uint thread) const {
75 assert(_rs_threads_vtimes != NULL, "just checking");
76 assert(thread < _num_vtimes, "just checking");
77 return _rs_threads_vtimes[thread];
78 }
80 void G1RemSetSummary::initialize(G1RemSet* remset) {
81 assert(_rs_threads_vtimes == NULL, "just checking");
82 assert(remset != NULL, "just checking");
84 _remset = remset;
85 _num_vtimes = ConcurrentG1Refine::thread_num();
86 _rs_threads_vtimes = NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC);
87 memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes);
89 update();
90 }
92 void G1RemSetSummary::set(G1RemSetSummary* other) {
93 assert(other != NULL, "just checking");
94 assert(remset() == other->remset(), "just checking");
95 assert(_num_vtimes == other->_num_vtimes, "just checking");
97 _num_refined_cards = other->num_concurrent_refined_cards();
99 _num_processed_buf_mutator = other->num_processed_buf_mutator();
100 _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads();
102 _num_coarsenings = other->_num_coarsenings;
104 memcpy(_rs_threads_vtimes, other->_rs_threads_vtimes, sizeof(double) * _num_vtimes);
106 set_sampling_thread_vtime(other->sampling_thread_vtime());
107 }
109 void G1RemSetSummary::subtract_from(G1RemSetSummary* other) {
110 assert(other != NULL, "just checking");
111 assert(remset() == other->remset(), "just checking");
112 assert(_num_vtimes == other->_num_vtimes, "just checking");
114 _num_refined_cards = other->num_concurrent_refined_cards() - _num_refined_cards;
116 _num_processed_buf_mutator = other->num_processed_buf_mutator() - _num_processed_buf_mutator;
117 _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads() - _num_processed_buf_rs_threads;
119 _num_coarsenings = other->num_coarsenings() - _num_coarsenings;
121 for (uint i = 0; i < _num_vtimes; i++) {
122 set_rs_thread_vtime(i, other->rs_thread_vtime(i) - rs_thread_vtime(i));
123 }
125 _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime;
126 }
128 static double percent_of(size_t numerator, size_t denominator) {
129 if (denominator != 0) {
130 return (double)numerator / denominator * 100.0f;
131 } else {
132 return 0.0f;
133 }
134 }
136 static size_t round_to_K(size_t value) {
137 return value / K;
138 }
140 class RegionTypeCounter VALUE_OBJ_CLASS_SPEC {
141 private:
142 const char* _name;
144 size_t _rs_mem_size;
145 size_t _cards_occupied;
146 size_t _amount;
148 size_t _code_root_mem_size;
149 size_t _code_root_elems;
151 double rs_mem_size_percent_of(size_t total) {
152 return percent_of(_rs_mem_size, total);
153 }
155 double cards_occupied_percent_of(size_t total) {
156 return percent_of(_cards_occupied, total);
157 }
159 double code_root_mem_size_percent_of(size_t total) {
160 return percent_of(_code_root_mem_size, total);
161 }
163 double code_root_elems_percent_of(size_t total) {
164 return percent_of(_code_root_elems, total);
165 }
167 size_t amount() const { return _amount; }
169 public:
171 RegionTypeCounter(const char* name) : _name(name), _rs_mem_size(0), _cards_occupied(0),
172 _amount(0), _code_root_mem_size(0), _code_root_elems(0) { }
174 void add(size_t rs_mem_size, size_t cards_occupied, size_t code_root_mem_size,
175 size_t code_root_elems) {
176 _rs_mem_size += rs_mem_size;
177 _cards_occupied += cards_occupied;
178 _code_root_mem_size += code_root_mem_size;
179 _code_root_elems += code_root_elems;
180 _amount++;
181 }
183 size_t rs_mem_size() const { return _rs_mem_size; }
184 size_t cards_occupied() const { return _cards_occupied; }
186 size_t code_root_mem_size() const { return _code_root_mem_size; }
187 size_t code_root_elems() const { return _code_root_elems; }
189 void print_rs_mem_info_on(outputStream * out, size_t total) {
190 out->print_cr(" "SIZE_FORMAT_W(8)"K (%5.1f%%) by "SIZE_FORMAT" %s regions",
191 round_to_K(rs_mem_size()), rs_mem_size_percent_of(total), amount(), _name);
192 }
194 void print_cards_occupied_info_on(outputStream * out, size_t total) {
195 out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) entries by "SIZE_FORMAT" %s regions",
196 cards_occupied(), cards_occupied_percent_of(total), amount(), _name);
197 }
199 void print_code_root_mem_info_on(outputStream * out, size_t total) {
200 out->print_cr(" "SIZE_FORMAT_W(8)"K (%5.1f%%) by "SIZE_FORMAT" %s regions",
201 round_to_K(code_root_mem_size()), code_root_mem_size_percent_of(total), amount(), _name);
202 }
204 void print_code_root_elems_info_on(outputStream * out, size_t total) {
205 out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) elements by "SIZE_FORMAT" %s regions",
206 code_root_elems(), code_root_elems_percent_of(total), amount(), _name);
207 }
208 };
211 class HRRSStatsIter: public HeapRegionClosure {
212 private:
213 RegionTypeCounter _young;
214 RegionTypeCounter _humonguous;
215 RegionTypeCounter _free;
216 RegionTypeCounter _old;
217 RegionTypeCounter _all;
219 size_t _max_rs_mem_sz;
220 HeapRegion* _max_rs_mem_sz_region;
222 size_t total_rs_mem_sz() const { return _all.rs_mem_size(); }
223 size_t total_cards_occupied() const { return _all.cards_occupied(); }
225 size_t max_rs_mem_sz() const { return _max_rs_mem_sz; }
226 HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; }
228 size_t _max_code_root_mem_sz;
229 HeapRegion* _max_code_root_mem_sz_region;
231 size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); }
232 size_t total_code_root_elems() const { return _all.code_root_elems(); }
234 size_t max_code_root_mem_sz() const { return _max_code_root_mem_sz; }
235 HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; }
237 public:
238 HRRSStatsIter() : _all("All"), _young("Young"), _humonguous("Humonguous"),
239 _free("Free"), _old("Old"), _max_code_root_mem_sz_region(NULL), _max_rs_mem_sz_region(NULL),
240 _max_rs_mem_sz(0), _max_code_root_mem_sz(0)
241 {}
243 bool doHeapRegion(HeapRegion* r) {
244 HeapRegionRemSet* hrrs = r->rem_set();
246 // HeapRegionRemSet::mem_size() includes the
247 // size of the strong code roots
248 size_t rs_mem_sz = hrrs->mem_size();
249 if (rs_mem_sz > _max_rs_mem_sz) {
250 _max_rs_mem_sz = rs_mem_sz;
251 _max_rs_mem_sz_region = r;
252 }
253 size_t occupied_cards = hrrs->occupied();
254 size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size();
255 if (code_root_mem_sz > max_code_root_mem_sz()) {
256 _max_code_root_mem_sz = code_root_mem_sz;
257 _max_code_root_mem_sz_region = r;
258 }
259 size_t code_root_elems = hrrs->strong_code_roots_list_length();
261 RegionTypeCounter* current = NULL;
262 if (r->is_free()) {
263 current = &_free;
264 } else if (r->is_young()) {
265 current = &_young;
266 } else if (r->isHumongous()) {
267 current = &_humonguous;
268 } else if (r->is_old()) {
269 current = &_old;
270 } else {
271 ShouldNotReachHere();
272 }
273 current->add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems);
274 _all.add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems);
276 return false;
277 }
279 void print_summary_on(outputStream* out) {
280 RegionTypeCounter* counters[] = { &_young, &_humonguous, &_free, &_old, NULL };
282 out->print_cr("\n Current rem set statistics");
283 out->print_cr(" Total per region rem sets sizes = "SIZE_FORMAT"K."
284 " Max = "SIZE_FORMAT"K.",
285 round_to_K(total_rs_mem_sz()), round_to_K(max_rs_mem_sz()));
286 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) {
287 (*current)->print_rs_mem_info_on(out, total_rs_mem_sz());
288 }
290 out->print_cr(" Static structures = "SIZE_FORMAT"K,"
291 " free_lists = "SIZE_FORMAT"K.",
292 round_to_K(HeapRegionRemSet::static_mem_size()),
293 round_to_K(HeapRegionRemSet::fl_mem_size()));
295 out->print_cr(" "SIZE_FORMAT" occupied cards represented.",
296 total_cards_occupied());
297 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) {
298 (*current)->print_cards_occupied_info_on(out, total_cards_occupied());
299 }
301 // Largest sized rem set region statistics
302 HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set();
303 out->print_cr(" Region with largest rem set = "HR_FORMAT", "
304 "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.",
305 HR_FORMAT_PARAMS(max_rs_mem_sz_region()),
306 round_to_K(rem_set->mem_size()),
307 round_to_K(rem_set->occupied()));
309 // Strong code root statistics
310 HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set();
311 out->print_cr(" Total heap region code root sets sizes = "SIZE_FORMAT"K."
312 " Max = "SIZE_FORMAT"K.",
313 round_to_K(total_code_root_mem_sz()),
314 round_to_K(max_code_root_rem_set->strong_code_roots_mem_size()));
315 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) {
316 (*current)->print_code_root_mem_info_on(out, total_code_root_mem_sz());
317 }
319 out->print_cr(" "SIZE_FORMAT" code roots represented.",
320 total_code_root_elems());
321 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) {
322 (*current)->print_code_root_elems_info_on(out, total_code_root_elems());
323 }
325 out->print_cr(" Region with largest amount of code roots = "HR_FORMAT", "
326 "size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".",
327 HR_FORMAT_PARAMS(max_code_root_mem_sz_region()),
328 round_to_K(max_code_root_rem_set->strong_code_roots_mem_size()),
329 round_to_K(max_code_root_rem_set->strong_code_roots_list_length()));
330 }
331 };
333 void G1RemSetSummary::print_on(outputStream* out) {
334 out->print_cr("\n Recent concurrent refinement statistics");
335 out->print_cr(" Processed "SIZE_FORMAT" cards",
336 num_concurrent_refined_cards());
337 out->print_cr(" Of "SIZE_FORMAT" completed buffers:", num_processed_buf_total());
338 out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) by concurrent RS threads.",
339 num_processed_buf_total(),
340 percent_of(num_processed_buf_rs_threads(), num_processed_buf_total()));
341 out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) by mutator threads.",
342 num_processed_buf_mutator(),
343 percent_of(num_processed_buf_mutator(), num_processed_buf_total()));
344 out->print_cr(" Did "SIZE_FORMAT" coarsenings.", num_coarsenings());
345 out->print_cr(" Concurrent RS threads times (s)");
346 out->print(" ");
347 for (uint i = 0; i < _num_vtimes; i++) {
348 out->print(" %5.2f", rs_thread_vtime(i));
349 }
350 out->cr();
351 out->print_cr(" Concurrent sampling threads times (s)");
352 out->print_cr(" %5.2f", sampling_thread_vtime());
354 HRRSStatsIter blk;
355 G1CollectedHeap::heap()->heap_region_iterate(&blk);
356 blk.print_summary_on(out);
357 }