diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 0ecfd3ab3bb9bbcf314464b650295f2b24ecb9f8..eff0efc6e0f0ec22aebd33a8b6199cc03e7ea931 100644 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -3681,6 +3681,11 @@ void G1CollectedHeap::gc_prologue(bool full /* Ignored */) { assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer"); // Fill TLAB's and such ensure_parsability(true); + + if (G1SummarizeRSetStats && (G1SummarizeRSetStatsPeriod > 0) && + (total_collections() % G1SummarizeRSetStatsPeriod == 0)) { + g1_rem_set()->print_periodic_summary_info("Before GC RS summary"); + } } void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { @@ -3689,7 +3694,7 @@ void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { (G1SummarizeRSetStatsPeriod > 0) && // we are at the end of the GC. Total collections has already been increased. ((total_collections() - 1) % G1SummarizeRSetStatsPeriod == 0)) { - g1_rem_set()->print_periodic_summary_info(); + g1_rem_set()->print_periodic_summary_info("After GC RS summary"); } // FIXME: what is this about? diff --git a/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 5a1b92d3422ef3822a0a3a9935ccf2e4ae77c231..a8c580b60cd197bfe750ecc8d3d4f4aa1bf11d3b 100644 --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -731,12 +731,12 @@ bool G1RemSet::refine_card(jbyte* card_ptr, int worker_i, return has_refs_into_cset; } -void G1RemSet::print_periodic_summary_info() { +void G1RemSet::print_periodic_summary_info(const char* header) { G1RemSetSummary current; current.initialize(this, n_workers()); _prev_period_summary.subtract_from(¤t); - print_summary_info(&_prev_period_summary); + print_summary_info(&_prev_period_summary, header); _prev_period_summary.set(¤t); } diff --git a/src/share/vm/gc_implementation/g1/g1RemSet.hpp b/src/share/vm/gc_implementation/g1/g1RemSet.hpp index 513945609fc1d76e78fff744b6b8ac1dc7ba6bf1..7c010f9daf68d897c187b4838b489d3f67dea22a 100644 --- a/src/share/vm/gc_implementation/g1/g1RemSet.hpp +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp @@ -145,7 +145,7 @@ public: virtual void print_summary_info(); // Print accumulated summary info from the last time called. - virtual void print_periodic_summary_info(); + virtual void print_periodic_summary_info(const char* header); // Prepare remembered set for verification. virtual void prepare_for_verify(); diff --git a/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp b/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp index 4a6b37654d774e3e9f394f25740a32e3b302b2ed..02e90d651039c575fbeecdad3c11b33fd9802724 100644 --- a/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp @@ -125,25 +125,115 @@ void G1RemSetSummary::subtract_from(G1RemSetSummary* other) { _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime; } +static double percent_of(size_t numerator, size_t denominator) { + if (denominator != 0) { + return (double)numerator / denominator * 100.0f; + } else { + return 0.0f; + } +} + +static size_t round_to_K(size_t value) { + return value / K; +} + +class RegionTypeCounter VALUE_OBJ_CLASS_SPEC { +private: + const char* _name; + + size_t _rs_mem_size; + size_t _cards_occupied; + size_t _amount; + + size_t _code_root_mem_size; + size_t _code_root_elems; + + double rs_mem_size_percent_of(size_t total) { + return percent_of(_rs_mem_size, total); + } + + double cards_occupied_percent_of(size_t total) { + return percent_of(_cards_occupied, total); + } + + double code_root_mem_size_percent_of(size_t total) { + return percent_of(_code_root_mem_size, total); + } + + double code_root_elems_percent_of(size_t total) { + return percent_of(_code_root_elems, total); + } + + size_t amount() const { return _amount; } + +public: + + RegionTypeCounter(const char* name) : _name(name), _rs_mem_size(0), _cards_occupied(0), + _amount(0), _code_root_mem_size(0), _code_root_elems(0) { } + + void add(size_t rs_mem_size, size_t cards_occupied, size_t code_root_mem_size, + size_t code_root_elems) { + _rs_mem_size += rs_mem_size; + _cards_occupied += cards_occupied; + _code_root_mem_size += code_root_mem_size; + _code_root_elems += code_root_elems; + _amount++; + } + + size_t rs_mem_size() const { return _rs_mem_size; } + size_t cards_occupied() const { return _cards_occupied; } + + size_t code_root_mem_size() const { return _code_root_mem_size; } + size_t code_root_elems() const { return _code_root_elems; } + + void print_rs_mem_info_on(outputStream * out, size_t total) { + out->print_cr(" %8dK (%5.1f%%) by %zd %s regions", round_to_K(rs_mem_size()), rs_mem_size_percent_of(total), amount(), _name); + } + + void print_cards_occupied_info_on(outputStream * out, size_t total) { + out->print_cr(" %8d (%5.1f%%) entries by %zd %s regions", cards_occupied(), cards_occupied_percent_of(total), amount(), _name); + } + + void print_code_root_mem_info_on(outputStream * out, size_t total) { + out->print_cr(" %8dK (%5.1f%%) by %zd %s regions", round_to_K(code_root_mem_size()), code_root_mem_size_percent_of(total), amount(), _name); + } + + void print_code_root_elems_info_on(outputStream * out, size_t total) { + out->print_cr(" %8d (%5.1f%%) elements by %zd %s regions", code_root_elems(), code_root_elems_percent_of(total), amount(), _name); + } +}; + + class HRRSStatsIter: public HeapRegionClosure { - size_t _occupied; +private: + RegionTypeCounter _young; + RegionTypeCounter _humonguous; + RegionTypeCounter _free; + RegionTypeCounter _old; + RegionTypeCounter _all; - size_t _total_rs_mem_sz; size_t _max_rs_mem_sz; HeapRegion* _max_rs_mem_sz_region; - size_t _total_code_root_mem_sz; + size_t total_rs_mem_sz() const { return _all.rs_mem_size(); } + size_t total_cards_occupied() const { return _all.cards_occupied(); } + + size_t max_rs_mem_sz() const { return _max_rs_mem_sz; } + HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; } + size_t _max_code_root_mem_sz; HeapRegion* _max_code_root_mem_sz_region; + + size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); } + size_t total_code_root_elems() const { return _all.code_root_elems(); } + + size_t max_code_root_mem_sz() const { return _max_code_root_mem_sz; } + HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; } + public: - HRRSStatsIter() : - _occupied(0), - _total_rs_mem_sz(0), - _max_rs_mem_sz(0), - _max_rs_mem_sz_region(NULL), - _total_code_root_mem_sz(0), - _max_code_root_mem_sz(0), - _max_code_root_mem_sz_region(NULL) + HRRSStatsIter() : _all("All"), _young("Young"), _humonguous("Humonguous"), + _free("Free"), _old("Old"), _max_code_root_mem_sz_region(NULL), _max_rs_mem_sz_region(NULL), + _max_rs_mem_sz(0), _max_code_root_mem_sz(0) {} bool doHeapRegion(HeapRegion* r) { @@ -156,46 +246,95 @@ public: _max_rs_mem_sz = rs_mem_sz; _max_rs_mem_sz_region = r; } - _total_rs_mem_sz += rs_mem_sz; - + size_t occupied_cards = hrrs->occupied(); size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size(); - if (code_root_mem_sz > _max_code_root_mem_sz) { - _max_code_root_mem_sz = code_root_mem_sz; + if (code_root_mem_sz > max_code_root_mem_sz()) { _max_code_root_mem_sz_region = r; } - _total_code_root_mem_sz += code_root_mem_sz; + size_t code_root_elems = hrrs->strong_code_roots_list_length(); + + RegionTypeCounter* current = NULL; + if (r->is_young()) { + current = &_young; + } else if (r->isHumongous()) { + current = &_humonguous; + } else if (r->is_empty()) { + current = &_free; + } else { + current = &_old; + } + current->add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); + _all.add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); - size_t occ = hrrs->occupied(); - _occupied += occ; return false; } - size_t total_rs_mem_sz() { return _total_rs_mem_sz; } - size_t max_rs_mem_sz() { return _max_rs_mem_sz; } - HeapRegion* max_rs_mem_sz_region() { return _max_rs_mem_sz_region; } - size_t total_code_root_mem_sz() { return _total_code_root_mem_sz; } - size_t max_code_root_mem_sz() { return _max_code_root_mem_sz; } - HeapRegion* max_code_root_mem_sz_region() { return _max_code_root_mem_sz_region; } - size_t occupied() { return _occupied; } -}; -double calc_percentage(size_t numerator, size_t denominator) { - if (denominator != 0) { - return (double)numerator / denominator * 100.0; - } else { - return 0.0f; + void print_summary_on(outputStream* out) { + RegionTypeCounter* counters[] = { &_young, &_humonguous, &_free, &_old, NULL }; + + out->print_cr("\n Current rem set statistics"); + out->print_cr(" Total per region rem sets sizes = "SIZE_FORMAT"K." + " Max = "SIZE_FORMAT"K.", + round_to_K(total_rs_mem_sz()), round_to_K(max_rs_mem_sz())); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_rs_mem_info_on(out, total_rs_mem_sz()); + } + + out->print_cr(" Static structures = "SIZE_FORMAT"K," + " free_lists = "SIZE_FORMAT"K.", + round_to_K(HeapRegionRemSet::static_mem_size()), + round_to_K(HeapRegionRemSet::fl_mem_size())); + + out->print_cr(" "SIZE_FORMAT" occupied cards represented.", + total_cards_occupied()); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_cards_occupied_info_on(out, total_cards_occupied()); + } + + // Largest sized rem set region statistics + HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set(); + out->print_cr(" Region with largest rem set = "HR_FORMAT", " + "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", + HR_FORMAT_PARAMS(max_rs_mem_sz_region()), + round_to_K(rem_set->mem_size()), + round_to_K(rem_set->occupied())); + + // Strong code root statistics + HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set(); + out->print_cr(" Total heap region code root sets sizes = "SIZE_FORMAT"K." + " Max = "SIZE_FORMAT"K.", + round_to_K(total_code_root_mem_sz()), + round_to_K(max_code_root_rem_set->strong_code_roots_mem_size())); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_code_root_mem_info_on(out, total_code_root_mem_sz()); + } + + out->print_cr(" "SIZE_FORMAT" code roots represented.", + total_code_root_elems()); + for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { + (*current)->print_code_root_elems_info_on(out, total_code_root_elems()); + } + + out->print_cr(" Region with largest amount of code roots = "HR_FORMAT", " + "size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".", + HR_FORMAT_PARAMS(max_code_root_mem_sz_region()), + round_to_K(max_code_root_rem_set->strong_code_roots_mem_size()), + round_to_K(max_code_root_rem_set->strong_code_roots_list_length())); } -} +}; void G1RemSetSummary::print_on(outputStream* out) { - out->print_cr("\n Concurrent RS processed "SIZE_FORMAT" cards", + out->print_cr("\n Recent concurrent refinement statistics"); + out->print_cr(" Processed "SIZE_FORMAT" cards", num_concurrent_refined_cards()); out->print_cr(" Of %d completed buffers:", num_processed_buf_total()); out->print_cr(" %8d (%5.1f%%) by concurrent RS threads.", num_processed_buf_total(), - calc_percentage(num_processed_buf_rs_threads(), num_processed_buf_total())); + percent_of(num_processed_buf_rs_threads(), num_processed_buf_total())); out->print_cr(" %8d (%5.1f%%) by mutator threads.", num_processed_buf_mutator(), - calc_percentage(num_processed_buf_mutator(), num_processed_buf_total())); + percent_of(num_processed_buf_mutator(), num_processed_buf_total())); + out->print_cr(" Did %d coarsenings.", num_coarsenings()); out->print_cr(" Concurrent RS threads times (s)"); out->print(" "); for (uint i = 0; i < _num_vtimes; i++) { @@ -207,33 +346,5 @@ void G1RemSetSummary::print_on(outputStream* out) { HRRSStatsIter blk; G1CollectedHeap::heap()->heap_region_iterate(&blk); - // RemSet stats - out->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K." - " Max = "SIZE_FORMAT"K.", - blk.total_rs_mem_sz()/K, blk.max_rs_mem_sz()/K); - out->print_cr(" Static structures = "SIZE_FORMAT"K," - " free_lists = "SIZE_FORMAT"K.", - HeapRegionRemSet::static_mem_size() / K, - HeapRegionRemSet::fl_mem_size() / K); - out->print_cr(" "SIZE_FORMAT" occupied cards represented.", - blk.occupied()); - HeapRegion* max_rs_mem_sz_region = blk.max_rs_mem_sz_region(); - HeapRegionRemSet* max_rs_rem_set = max_rs_mem_sz_region->rem_set(); - out->print_cr(" Max size region = "HR_FORMAT", " - "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", - HR_FORMAT_PARAMS(max_rs_mem_sz_region), - (max_rs_rem_set->mem_size() + K - 1)/K, - (max_rs_rem_set->occupied() + K - 1)/K); - out->print_cr(" Did %d coarsenings.", num_coarsenings()); - // Strong code root stats - out->print_cr(" Total heap region code-root set sizes = "SIZE_FORMAT"K." - " Max = "SIZE_FORMAT"K.", - blk.total_code_root_mem_sz()/K, blk.max_code_root_mem_sz()/K); - HeapRegion* max_code_root_mem_sz_region = blk.max_code_root_mem_sz_region(); - HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region->rem_set(); - out->print_cr(" Max size region = "HR_FORMAT", " - "size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".", - HR_FORMAT_PARAMS(max_code_root_mem_sz_region), - (max_code_root_rem_set->strong_code_roots_mem_size() + K - 1)/K, - (max_code_root_rem_set->strong_code_roots_list_length())); + blk.print_summary_on(out); } diff --git a/test/gc/g1/TestSummarizeRSetStats.java b/test/gc/g1/TestSummarizeRSetStats.java index 1990d4c6f39ce7a1fbff3060b011a6254fef39c0..e78e2df21a3ad3d50868838046d800bcd29d4644 100644 --- a/test/gc/g1/TestSummarizeRSetStats.java +++ b/test/gc/g1/TestSummarizeRSetStats.java @@ -25,140 +25,61 @@ * @test TestSummarizeRSetStats.java * @bug 8013895 * @library /testlibrary - * @build TestSummarizeRSetStats + * @build TestSummarizeRSetStatsTools TestSummarizeRSetStats * @summary Verify output of -XX:+G1SummarizeRSetStats * @run main TestSummarizeRSetStats * * Test the output of G1SummarizeRSetStats in conjunction with G1SummarizeRSetStatsPeriod. */ -import com.oracle.java.testlibrary.*; -import java.lang.Thread; -import java.util.ArrayList; -import java.util.Arrays; - -class RunSystemGCs { - // 4M size, both are directly allocated into the old gen - static Object[] largeObject1 = new Object[1024 * 1024]; - static Object[] largeObject2 = new Object[1024 * 1024]; - - static int[] temp; - - public static void main(String[] args) { - // create some cross-references between these objects - for (int i = 0; i < largeObject1.length; i++) { - largeObject1[i] = largeObject2; - } - - for (int i = 0; i < largeObject2.length; i++) { - largeObject2[i] = largeObject1; - } - - int numGCs = Integer.parseInt(args[0]); - - if (numGCs > 0) { - // try to force a minor collection: the young gen is 4M, the - // amount of data allocated below is roughly that (4*1024*1024 + - // some header data) - for (int i = 0; i < 1024 ; i++) { - temp = new int[1024]; - } - } - - for (int i = 0; i < numGCs - 1; i++) { - System.gc(); - } - } -} - public class TestSummarizeRSetStats { - public static String runTest(String[] additionalArgs, int numGCs) throws Exception { - ArrayList finalargs = new ArrayList(); - String[] defaultArgs = new String[] { - "-XX:+UseG1GC", - "-Xmn4m", - "-Xmx20m", - "-XX:InitiatingHeapOccupancyPercent=100", // we don't want the additional GCs due to initial marking - "-XX:+PrintGC", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:G1HeapRegionSize=1M", - }; - - finalargs.addAll(Arrays.asList(defaultArgs)); - - if (additionalArgs != null) { - finalargs.addAll(Arrays.asList(additionalArgs)); - } - - finalargs.add(RunSystemGCs.class.getName()); - finalargs.add(String.valueOf(numGCs)); - - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - finalargs.toArray(new String[0])); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - output.shouldHaveExitValue(0); - - String result = output.getStdout(); - return result; - } - - private static void expectStatistics(String result, int expectedCumulative, int expectedPeriodic) throws Exception { - int actualTotal = result.split("Concurrent RS processed").length - 1; - int actualCumulative = result.split("Cumulative RS summary").length - 1; - - if (expectedCumulative != actualCumulative) { - throw new Exception("Incorrect amount of RSet summaries at the end. Expected " + expectedCumulative + ", got " + actualCumulative); - } - - if (expectedPeriodic != (actualTotal - actualCumulative)) { - throw new Exception("Incorrect amount of per-period RSet summaries at the end. Expected " + expectedPeriodic + ", got " + (actualTotal - actualCumulative)); - } - } - public static void main(String[] args) throws Exception { String result; - // no RSet statistics output - result = runTest(null, 0); - expectStatistics(result, 0, 0); + if (!TestSummarizeRSetStatsTools.testingG1GC()) { + return; + } + + // no remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(null, 0); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - // no RSet statistics output - result = runTest(null, 2); - expectStatistics(result, 0, 0); + // no remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(null, 2); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - // no RSet statistics output - result = runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); - expectStatistics(result, 0, 0); + // no remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - // single RSet statistics output at the end - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); - expectStatistics(result, 1, 0); + // single remembered set summary output at the end + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - // single RSet statistics output at the end - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 2); - expectStatistics(result, 1, 0); + // single remembered set summary output at the end + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 2); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - // single RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); - expectStatistics(result, 1, 0); + // single remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - // two times RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); - expectStatistics(result, 1, 1); + // two times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 2); - // four times RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); - expectStatistics(result, 1, 3); + // four times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 6); - // three times RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); - expectStatistics(result, 1, 2); + // three times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 4); - // single RSet statistics output - result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); - expectStatistics(result, 1, 1); + // single remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); + TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 2); } } diff --git a/test/gc/g1/TestSummarizeRSetStatsPerRegion.java b/test/gc/g1/TestSummarizeRSetStatsPerRegion.java new file mode 100644 index 0000000000000000000000000000000000000000..437cbc2c70e6ecb77796e401cecaeeb62aa0f7eb --- /dev/null +++ b/test/gc/g1/TestSummarizeRSetStatsPerRegion.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestSummarizeRSetStatsPerRegion.java + * @bug 8014078 + * @library /testlibrary + * @build TestSummarizeRSetStatsTools TestSummarizeRSetStatsPerRegion + * @summary Verify output of -XX:+G1SummarizeRSetStats in regards to per-region type output + * @run main TestSummarizeRSetStatsPerRegion + */ + +import com.oracle.java.testlibrary.*; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.Arrays; + +public class TestSummarizeRSetStatsPerRegion { + + public static void main(String[] args) throws Exception { + String result; + + if (!TestSummarizeRSetStatsTools.testingG1GC()) { + return; + } + + // single remembered set summary output at the end + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); + TestSummarizeRSetStatsTools.expectPerRegionRSetSummaries(result, 1, 0); + + // two times remembered set summary output + result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); + TestSummarizeRSetStatsTools.expectPerRegionRSetSummaries(result, 1, 2); + } +} diff --git a/test/gc/g1/TestSummarizeRSetStatsTools.java b/test/gc/g1/TestSummarizeRSetStatsTools.java new file mode 100644 index 0000000000000000000000000000000000000000..096a7c675b5486f6fecc528b8c4e47b7446911d5 --- /dev/null +++ b/test/gc/g1/TestSummarizeRSetStatsTools.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Common helpers for TestSummarizeRSetStats* tests + */ + +import sun.management.ManagementFactoryHelper; +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; + +import com.oracle.java.testlibrary.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.Arrays; + +class VerifySummaryOutput { + // 4M size, both are directly allocated into the old gen + static Object[] largeObject1 = new Object[1024 * 1024]; + static Object[] largeObject2 = new Object[1024 * 1024]; + + static int[] temp; + + public static void main(String[] args) { + // create some cross-references between these objects + for (int i = 0; i < largeObject1.length; i++) { + largeObject1[i] = largeObject2; + } + + for (int i = 0; i < largeObject2.length; i++) { + largeObject2[i] = largeObject1; + } + + int numGCs = Integer.parseInt(args[0]); + + if (numGCs > 0) { + // try to force a minor collection: the young gen is 4M, the + // amount of data allocated below is roughly that (4*1024*1024 + + // some header data) + for (int i = 0; i < 1024 ; i++) { + temp = new int[1024]; + } + } + + for (int i = 0; i < numGCs - 1; i++) { + System.gc(); + } + } +} + +public class TestSummarizeRSetStatsTools { + + // the VM is currently run using G1GC, i.e. trying to test G1 functionality. + public static boolean testingG1GC() { + HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); + + VMOption option = diagnostic.getVMOption("UseG1GC"); + if (option.getValue().equals("false")) { + System.out.println("Skipping this test. It is only a G1 test."); + return false; + } + return true; + } + + public static String runTest(String[] additionalArgs, int numGCs) throws Exception { + ArrayList finalargs = new ArrayList(); + String[] defaultArgs = new String[] { + "-XX:+UseG1GC", + "-XX:+UseCompressedOops", + "-Xmn4m", + "-Xmx20m", + "-XX:InitiatingHeapOccupancyPercent=100", // we don't want the additional GCs due to initial marking + "-XX:+PrintGC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:G1HeapRegionSize=1M", + }; + + finalargs.addAll(Arrays.asList(defaultArgs)); + + if (additionalArgs != null) { + finalargs.addAll(Arrays.asList(additionalArgs)); + } + + finalargs.add(VerifySummaryOutput.class.getName()); + finalargs.add(String.valueOf(numGCs)); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + finalargs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(0); + + String result = output.getStdout(); + return result; + } + + private static void checkCounts(int expected, int actual, String which) throws Exception { + if (expected != actual) { + throw new Exception("RSet summaries mention " + which + " regions an incorrect number of times. Expected " + expected + ", got " + actual); + } + } + + public static void expectPerRegionRSetSummaries(String result, int expectedCumulative, int expectedPeriodic) throws Exception { + expectRSetSummaries(result, expectedCumulative, expectedPeriodic); + int actualYoung = result.split("Young regions").length - 1; + int actualHumonguous = result.split("Humonguous regions").length - 1; + int actualFree = result.split("Free regions").length - 1; + int actualOther = result.split("Old regions").length - 1; + + // the strings we check for above are printed four times per summary + int expectedPerRegionTypeInfo = (expectedCumulative + expectedPeriodic) * 4; + + checkCounts(expectedPerRegionTypeInfo, actualYoung, "Young"); + checkCounts(expectedPerRegionTypeInfo, actualHumonguous, "Humonguous"); + checkCounts(expectedPerRegionTypeInfo, actualFree, "Free"); + checkCounts(expectedPerRegionTypeInfo, actualOther, "Old"); + } + + public static void expectRSetSummaries(String result, int expectedCumulative, int expectedPeriodic) throws Exception { + int actualTotal = result.split("concurrent refinement").length - 1; + int actualCumulative = result.split("Cumulative RS summary").length - 1; + + if (expectedCumulative != actualCumulative) { + throw new Exception("Incorrect amount of RSet summaries at the end. Expected " + expectedCumulative + ", got " + actualCumulative); + } + + if (expectedPeriodic != (actualTotal - actualCumulative)) { + throw new Exception("Incorrect amount of per-period RSet summaries at the end. Expected " + expectedPeriodic + ", got " + (actualTotal - actualCumulative)); + } + } +} +