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) 2011, 2014, 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/g1CollectedHeap.inline.hpp"
27 #include "gc_implementation/g1/heapRegionRemSet.hpp"
28 #include "gc_implementation/g1/heapRegionSet.inline.hpp"
30 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
32 uint FreeRegionList::_unrealistically_long_length = 0;
34 void HeapRegionSetBase::fill_in_ext_msg(hrs_ext_msg* msg, const char* message) {
35 msg->append("[%s] %s ln: %u cy: "SIZE_FORMAT,
36 name(), message, length(), total_capacity_bytes());
37 fill_in_ext_msg_extra(msg);
38 }
40 #ifndef PRODUCT
41 void HeapRegionSetBase::verify_region(HeapRegion* hr) {
42 assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrm_index()));
43 assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrm_index())); // currently we don't use these sets for young regions
44 assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrm_index(), name()));
45 assert(hr->is_free() == regions_free(), err_msg("Wrong free state for region %u and set %s", hr->hrm_index(), name()));
46 assert(!hr->is_free() || hr->is_empty(), err_msg("Free region %u is not empty for set %s", hr->hrm_index(), name()));
47 assert(!hr->is_empty() || hr->is_free(), err_msg("Empty region %u is not free for set %s", hr->hrm_index(), name()));
48 assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrm_index()));
49 }
50 #endif
52 void HeapRegionSetBase::verify() {
53 // It's important that we also observe the MT safety protocol even
54 // for the verification calls. If we do verification without the
55 // appropriate locks and the set changes underneath our feet
56 // verification might fail and send us on a wild goose chase.
57 check_mt_safety();
59 guarantee(( is_empty() && length() == 0 && total_capacity_bytes() == 0) ||
60 (!is_empty() && length() >= 0 && total_capacity_bytes() >= 0),
61 hrs_ext_msg(this, "invariant"));
62 }
64 void HeapRegionSetBase::verify_start() {
65 // See comment in verify() about MT safety and verification.
66 check_mt_safety();
67 assert(!_verify_in_progress,
68 hrs_ext_msg(this, "verification should not be in progress"));
70 // Do the basic verification first before we do the checks over the regions.
71 HeapRegionSetBase::verify();
73 _verify_in_progress = true;
74 }
76 void HeapRegionSetBase::verify_end() {
77 // See comment in verify() about MT safety and verification.
78 check_mt_safety();
79 assert(_verify_in_progress,
80 hrs_ext_msg(this, "verification should be in progress"));
82 _verify_in_progress = false;
83 }
85 void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) {
86 out->cr();
87 out->print_cr("Set: %s ("PTR_FORMAT")", name(), this);
88 out->print_cr(" Region Assumptions");
89 out->print_cr(" humongous : %s", BOOL_TO_STR(regions_humongous()));
90 out->print_cr(" free : %s", BOOL_TO_STR(regions_free()));
91 out->print_cr(" Attributes");
92 out->print_cr(" length : %14u", length());
93 out->print_cr(" total capacity : "SIZE_FORMAT_W(14)" bytes",
94 total_capacity_bytes());
95 }
97 HeapRegionSetBase::HeapRegionSetBase(const char* name, bool humongous, bool free, HRSMtSafeChecker* mt_safety_checker)
98 : _name(name), _verify_in_progress(false),
99 _is_humongous(humongous), _is_free(free), _mt_safety_checker(mt_safety_checker),
100 _count()
101 { }
103 void FreeRegionList::set_unrealistically_long_length(uint len) {
104 guarantee(_unrealistically_long_length == 0, "should only be set once");
105 _unrealistically_long_length = len;
106 }
108 void FreeRegionList::fill_in_ext_msg_extra(hrs_ext_msg* msg) {
109 msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, _head, _tail);
110 }
112 void FreeRegionList::remove_all() {
113 check_mt_safety();
114 verify_optional();
116 HeapRegion* curr = _head;
117 while (curr != NULL) {
118 verify_region(curr);
120 HeapRegion* next = curr->next();
121 curr->set_next(NULL);
122 curr->set_prev(NULL);
123 curr->set_containing_set(NULL);
124 curr = next;
125 }
126 clear();
128 verify_optional();
129 }
131 void FreeRegionList::add_ordered(FreeRegionList* from_list) {
132 check_mt_safety();
133 from_list->check_mt_safety();
135 verify_optional();
136 from_list->verify_optional();
138 if (from_list->is_empty()) {
139 return;
140 }
142 #ifdef ASSERT
143 FreeRegionListIterator iter(from_list);
144 while (iter.more_available()) {
145 HeapRegion* hr = iter.get_next();
146 // In set_containing_set() we check that we either set the value
147 // from NULL to non-NULL or vice versa to catch bugs. So, we have
148 // to NULL it first before setting it to the value.
149 hr->set_containing_set(NULL);
150 hr->set_containing_set(this);
151 }
152 #endif // ASSERT
154 if (is_empty()) {
155 assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant"));
156 _head = from_list->_head;
157 _tail = from_list->_tail;
158 } else {
159 HeapRegion* curr_to = _head;
160 HeapRegion* curr_from = from_list->_head;
162 while (curr_from != NULL) {
163 while (curr_to != NULL && curr_to->hrm_index() < curr_from->hrm_index()) {
164 curr_to = curr_to->next();
165 }
167 if (curr_to == NULL) {
168 // The rest of the from list should be added as tail
169 _tail->set_next(curr_from);
170 curr_from->set_prev(_tail);
171 curr_from = NULL;
172 } else {
173 HeapRegion* next_from = curr_from->next();
175 curr_from->set_next(curr_to);
176 curr_from->set_prev(curr_to->prev());
177 if (curr_to->prev() == NULL) {
178 _head = curr_from;
179 } else {
180 curr_to->prev()->set_next(curr_from);
181 }
182 curr_to->set_prev(curr_from);
184 curr_from = next_from;
185 }
186 }
188 if (_tail->hrm_index() < from_list->_tail->hrm_index()) {
189 _tail = from_list->_tail;
190 }
191 }
193 _count.increment(from_list->length(), from_list->total_capacity_bytes());
194 from_list->clear();
196 verify_optional();
197 from_list->verify_optional();
198 }
200 void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) {
201 check_mt_safety();
202 assert(num_regions >= 1, hrs_ext_msg(this, "pre-condition"));
203 assert(!is_empty(), hrs_ext_msg(this, "pre-condition"));
205 verify_optional();
206 DEBUG_ONLY(uint old_length = length();)
208 HeapRegion* curr = first;
209 uint count = 0;
210 while (count < num_regions) {
211 verify_region(curr);
212 HeapRegion* next = curr->next();
213 HeapRegion* prev = curr->prev();
215 assert(count < num_regions,
216 hrs_err_msg("[%s] should not come across more regions "
217 "pending for removal than num_regions: %u",
218 name(), num_regions));
220 if (prev == NULL) {
221 assert(_head == curr, hrs_ext_msg(this, "invariant"));
222 _head = next;
223 } else {
224 assert(_head != curr, hrs_ext_msg(this, "invariant"));
225 prev->set_next(next);
226 }
227 if (next == NULL) {
228 assert(_tail == curr, hrs_ext_msg(this, "invariant"));
229 _tail = prev;
230 } else {
231 assert(_tail != curr, hrs_ext_msg(this, "invariant"));
232 next->set_prev(prev);
233 }
234 if (_last = curr) {
235 _last = NULL;
236 }
238 curr->set_next(NULL);
239 curr->set_prev(NULL);
240 remove(curr);
242 count++;
243 curr = next;
244 }
246 assert(count == num_regions,
247 hrs_err_msg("[%s] count: %u should be == num_regions: %u",
248 name(), count, num_regions));
249 assert(length() + num_regions == old_length,
250 hrs_err_msg("[%s] new length should be consistent "
251 "new length: %u old length: %u num_regions: %u",
252 name(), length(), old_length, num_regions));
254 verify_optional();
255 }
257 void FreeRegionList::verify() {
258 // See comment in HeapRegionSetBase::verify() about MT safety and
259 // verification.
260 check_mt_safety();
262 // This will also do the basic verification too.
263 verify_start();
265 verify_list();
267 verify_end();
268 }
270 void FreeRegionList::clear() {
271 _count = HeapRegionSetCount();
272 _head = NULL;
273 _tail = NULL;
274 _last = NULL;
275 }
277 void FreeRegionList::print_on(outputStream* out, bool print_contents) {
278 HeapRegionSetBase::print_on(out, print_contents);
279 out->print_cr(" Linking");
280 out->print_cr(" head : "PTR_FORMAT, _head);
281 out->print_cr(" tail : "PTR_FORMAT, _tail);
283 if (print_contents) {
284 out->print_cr(" Contents");
285 FreeRegionListIterator iter(this);
286 while (iter.more_available()) {
287 HeapRegion* hr = iter.get_next();
288 hr->print_on(out);
289 }
290 }
292 out->cr();
293 }
295 void FreeRegionList::verify_list() {
296 HeapRegion* curr = _head;
297 HeapRegion* prev1 = NULL;
298 HeapRegion* prev0 = NULL;
299 uint count = 0;
300 size_t capacity = 0;
301 uint last_index = 0;
303 guarantee(_head == NULL || _head->prev() == NULL, "_head should not have a prev");
304 while (curr != NULL) {
305 verify_region(curr);
307 count++;
308 guarantee(count < _unrealistically_long_length,
309 hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " "prev1: "PTR_FORMAT" length: %u", name(), count, curr, prev0, prev1, length()));
311 if (curr->next() != NULL) {
312 guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up");
313 }
314 guarantee(curr->hrm_index() == 0 || curr->hrm_index() > last_index, "List should be sorted");
315 last_index = curr->hrm_index();
317 capacity += curr->capacity();
319 prev1 = prev0;
320 prev0 = curr;
321 curr = curr->next();
322 }
324 guarantee(_tail == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index()));
325 guarantee(_tail == NULL || _tail->next() == NULL, "_tail should not have a next");
326 guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count));
327 guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT,
328 name(), total_capacity_bytes(), capacity));
329 }
331 // Note on the check_mt_safety() methods below:
332 //
333 // Verification of the "master" heap region sets / lists that are
334 // maintained by G1CollectedHeap is always done during a STW pause and
335 // by the VM thread at the start / end of the pause. The standard
336 // verification methods all assert check_mt_safety(). This is
337 // important as it ensures that verification is done without
338 // concurrent updates taking place at the same time. It follows, that,
339 // for the "master" heap region sets / lists, the check_mt_safety()
340 // method should include the VM thread / STW case.
342 void MasterFreeRegionListMtSafeChecker::check() {
343 // Master Free List MT safety protocol:
344 // (a) If we're at a safepoint, operations on the master free list
345 // should be invoked by either the VM thread (which will serialize
346 // them) or by the GC workers while holding the
347 // FreeList_lock.
348 // (b) If we're not at a safepoint, operations on the master free
349 // list should be invoked while holding the Heap_lock.
351 if (SafepointSynchronize::is_at_safepoint()) {
352 guarantee(Thread::current()->is_VM_thread() ||
353 FreeList_lock->owned_by_self(), "master free list MT safety protocol at a safepoint");
354 } else {
355 guarantee(Heap_lock->owned_by_self(), "master free list MT safety protocol outside a safepoint");
356 }
357 }
359 void SecondaryFreeRegionListMtSafeChecker::check() {
360 // Secondary Free List MT safety protocol:
361 // Operations on the secondary free list should always be invoked
362 // while holding the SecondaryFreeList_lock.
364 guarantee(SecondaryFreeList_lock->owned_by_self(), "secondary free list MT safety protocol");
365 }
367 void OldRegionSetMtSafeChecker::check() {
368 // Master Old Set MT safety protocol:
369 // (a) If we're at a safepoint, operations on the master old set
370 // should be invoked:
371 // - by the VM thread (which will serialize them), or
372 // - by the GC workers while holding the FreeList_lock, if we're
373 // at a safepoint for an evacuation pause (this lock is taken
374 // anyway when an GC alloc region is retired so that a new one
375 // is allocated from the free list), or
376 // - by the GC workers while holding the OldSets_lock, if we're at a
377 // safepoint for a cleanup pause.
378 // (b) If we're not at a safepoint, operations on the master old set
379 // should be invoked while holding the Heap_lock.
381 if (SafepointSynchronize::is_at_safepoint()) {
382 guarantee(Thread::current()->is_VM_thread()
383 || FreeList_lock->owned_by_self() || OldSets_lock->owned_by_self(),
384 "master old set MT safety protocol at a safepoint");
385 } else {
386 guarantee(Heap_lock->owned_by_self(), "master old set MT safety protocol outside a safepoint");
387 }
388 }
390 void HumongousRegionSetMtSafeChecker::check() {
391 // Humongous Set MT safety protocol:
392 // (a) If we're at a safepoint, operations on the master humongous
393 // set should be invoked by either the VM thread (which will
394 // serialize them) or by the GC workers while holding the
395 // OldSets_lock.
396 // (b) If we're not at a safepoint, operations on the master
397 // humongous set should be invoked while holding the Heap_lock.
399 if (SafepointSynchronize::is_at_safepoint()) {
400 guarantee(Thread::current()->is_VM_thread() ||
401 OldSets_lock->owned_by_self(),
402 "master humongous set MT safety protocol at a safepoint");
403 } else {
404 guarantee(Heap_lock->owned_by_self(),
405 "master humongous set MT safety protocol outside a safepoint");
406 }
407 }
409 void FreeRegionList_test() {
410 FreeRegionList l("test");
412 const uint num_regions_in_test = 5;
413 // Create a fake heap. It does not need to be valid, as the HeapRegion constructor
414 // does not access it.
415 MemRegion heap(NULL, num_regions_in_test * HeapRegion::GrainWords);
416 // Allocate a fake BOT because the HeapRegion constructor initializes
417 // the BOT.
418 size_t bot_size = G1BlockOffsetSharedArray::compute_size(heap.word_size());
419 HeapWord* bot_data = NEW_C_HEAP_ARRAY(HeapWord, bot_size, mtGC);
420 ReservedSpace bot_rs(G1BlockOffsetSharedArray::compute_size(heap.word_size()));
421 G1RegionToSpaceMapper* bot_storage =
422 G1RegionToSpaceMapper::create_mapper(bot_rs,
423 os::vm_page_size(),
424 HeapRegion::GrainBytes,
425 G1BlockOffsetSharedArray::N_bytes,
426 mtGC);
427 G1BlockOffsetSharedArray oa(heap, bot_storage);
428 bot_storage->commit_regions(0, num_regions_in_test);
429 HeapRegion hr0(0, &oa, heap);
430 HeapRegion hr1(1, &oa, heap);
431 HeapRegion hr2(2, &oa, heap);
432 HeapRegion hr3(3, &oa, heap);
433 HeapRegion hr4(4, &oa, heap);
434 l.add_ordered(&hr1);
435 l.add_ordered(&hr0);
436 l.add_ordered(&hr3);
437 l.add_ordered(&hr4);
438 l.add_ordered(&hr2);
439 assert(l.length() == num_regions_in_test, "wrong length");
440 l.verify_list();
442 bot_storage->uncommit_regions(0, num_regions_in_test);
443 delete bot_storage;
444 FREE_C_HEAP_ARRAY(HeapWord, bot_data, mtGC);
445 }