--- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2014-02-24 12:41:51.563334631 +0100 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2014-02-24 12:41:51.459334633 +0100 @@ -5966,7 +5966,7 @@ void G1CollectedHeap::free_region(HeapRegion* hr, size_t* pre_used, FreeRegionList* free_list, - bool par) { + bool par, bool locked) { assert(!hr->isHumongous(), "this is only for non-humongous regions"); assert(!hr->is_empty(), "the region should not be empty"); assert(free_list != NULL, "pre-condition"); @@ -5978,7 +5978,7 @@ _cg1r->hot_card_cache()->reset_card_counts(hr); } *pre_used += hr->used(); - hr->hr_clear(par, true /* clear_space */); + hr->hr_clear(par, true /* clear_space */, locked); free_list->add_as_head(hr); } @@ -6200,7 +6200,7 @@ } } - rs_lengths += cur->rem_set()->occupied(); + rs_lengths += cur->rem_set()->occupied_locked(); HeapRegion* next = cur->next_in_collection_set(); assert(cur->in_collection_set(), "bad CS"); @@ -6233,7 +6233,7 @@ // And the region is empty. assert(!used_mr.is_empty(), "Should not have empty regions in a CS."); - free_region(cur, &pre_used, &local_free_list, false /* par */); + free_region(cur, &pre_used, &local_free_list, false /* par */, true /* locked */); } else { cur->uninstall_surv_rate_group(); if (cur->is_young()) { --- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp 2014-02-24 12:41:52.351334614 +0100 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp 2014-02-24 12:41:52.227334616 +0100 @@ -839,10 +839,12 @@ // list later). The used bytes of freed regions are accumulated in // pre_used. If par is true, the region's RSet will not be freed // up. The assumption is that this will be done later. + // The locked parameter indicates if the caller has already taken + // care of proper synchronization. This may allow some optimizations. void free_region(HeapRegion* hr, size_t* pre_used, FreeRegionList* free_list, - bool par); + bool par, bool locked = false); // Frees a humongous region by collapsing it into individual regions // and calling free_region() for each of them. The freed regions --- old/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp 2014-02-24 12:41:53.367334591 +0100 +++ new/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp 2014-02-24 12:41:53.219334595 +0100 @@ -317,6 +317,10 @@ print_stats(2, "Free CSet", (_recorded_young_free_cset_time_ms + _recorded_non_young_free_cset_time_ms)); + if (G1Log::finest()) { + print_stats(3, "Young Free CSet", _recorded_young_free_cset_time_ms); + print_stats(3, "Non-Young Free CSet", _recorded_non_young_free_cset_time_ms); + } if (_cur_verify_after_time_ms > 0.0) { print_stats(2, "Verify After", _cur_verify_after_time_ms); } --- old/src/share/vm/gc_implementation/g1/heapRegion.cpp 2014-02-24 12:41:54.431334568 +0100 +++ new/src/share/vm/gc_implementation/g1/heapRegion.cpp 2014-02-24 12:41:54.255334572 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -205,7 +205,7 @@ init_top_at_mark_start(); } -void HeapRegion::hr_clear(bool par, bool clear_space) { +void HeapRegion::hr_clear(bool par, bool clear_space, bool locked) { assert(_humongous_type == NotHumongous, "we should have already filtered out humongous regions"); assert(_humongous_start_region == NULL, @@ -223,7 +223,11 @@ if (!par) { // If this is parallel, this will be done later. HeapRegionRemSet* hrrs = rem_set(); - hrrs->clear(); + if (locked) { + hrrs->clear_locked(); + } else { + hrrs->clear(); + } _claimed = InitialClaimValue; } zero_marked_bytes(); --- old/src/share/vm/gc_implementation/g1/heapRegion.hpp 2014-02-24 12:41:54.931334557 +0100 +++ new/src/share/vm/gc_implementation/g1/heapRegion.hpp 2014-02-24 12:41:54.859334559 +0100 @@ -596,7 +596,7 @@ void save_marks(); // Reset HR stuff to default values. - void hr_clear(bool par, bool clear_space); + void hr_clear(bool par, bool clear_space, bool locked = false); void par_clear(); // Get the start of the unmarked area in this region. --- old/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp 2014-02-24 12:41:55.419334546 +0100 +++ new/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp 2014-02-24 12:41:55.343334548 +0100 @@ -362,17 +362,18 @@ size_t OtherRegionsTable::_from_card_cache_mem_size = 0; void OtherRegionsTable::init_from_card_cache(size_t max_regions) { - _from_card_cache_max_regions = max_regions; + // pad rows to cache line sizes. + _from_card_cache_max_regions = align_size_up(max_regions, DEFAULT_CACHE_LINE_SIZE / sizeof(int)); int n_par_rs = HeapRegionRemSet::num_par_rem_sets(); _from_card_cache = NEW_C_HEAP_ARRAY(int*, n_par_rs, mtGC); for (int i = 0; i < n_par_rs; i++) { - _from_card_cache[i] = NEW_C_HEAP_ARRAY(int, max_regions, mtGC); - for (size_t j = 0; j < max_regions; j++) { + _from_card_cache[i] = NEW_C_HEAP_ARRAY(int, _from_card_cache_max_regions, mtGC); + for (size_t j = 0; j < _from_card_cache_max_regions; j++) { _from_card_cache[i][j] = -1; // An invalid value. } } - _from_card_cache_mem_size = n_par_rs * max_regions * sizeof(int); + _from_card_cache_mem_size = n_par_rs * _from_card_cache_max_regions * sizeof(int); } void OtherRegionsTable::shrink_from_card_cache(size_t new_n_regs) { @@ -728,7 +729,8 @@ void OtherRegionsTable::clear_fcc() { size_t hrs_idx = hr()->hrs_index(); - for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { + uint num_par_remsets = HeapRegionRemSet::num_par_rem_sets(); + for (uint i = 0; i < num_par_remsets; i++) { _from_card_cache[i][hrs_idx] = -1; } } --- old/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp 2014-02-24 12:41:55.903334536 +0100 +++ new/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp 2014-02-24 12:41:55.819334538 +0100 @@ -159,6 +159,7 @@ bool contains_reference_locked(OopOrNarrowOopStar from) const; void clear(); + void clear_locked(); // Specifically clear the from_card_cache. void clear_fcc(); --- old/test/gc/g1/TestGCLogMessages.java 2014-02-24 12:41:56.391334525 +0100 +++ new/test/gc/g1/TestGCLogMessages.java 2014-02-24 12:41:56.315334527 +0100 @@ -23,7 +23,7 @@ /* * @test TestPrintGCDetails - * @bug 8035406 + * @bug 8035406 8027295 * @summary Ensure that the PrintGCDetails output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -38,13 +38,41 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-Xmx10M", - "-XX:+PrintGCDetails", GCTest.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("[Code Root Purge"); + output.shouldNotContain("[Young Free CSet"); + output.shouldNotContain("[Non-Young Free CSet"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + "-XX:+PrintGCDetails", + GCTest.class.getName()); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("[Code Root Purge"); + output.shouldNotContain("[Young Free CSet"); + output.shouldNotContain("[Non-Young Free CSet"); output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + "-XX:+PrintGCDetails", + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1LogLevel=finest", + GCTest.class.getName()); + + output = new OutputAnalyzer(pb.start()); + + output.shouldContain("[Code Root Purge"); + output.shouldContain("[Young Free CSet"); + output.shouldContain("[Non-Young Free CSet"); + output.shouldHaveExitValue(0); + } static class GCTest {