Tue, 28 May 2013 09:32:06 +0200
8013895: G1: G1SummarizeRSetStats output on Linux needs improvemen
Summary: Fixed the output of G1SummarizeRSetStats: too small datatype for the number of concurrently processed cards, added concurrent remembered set thread time retrieval for Linux and Windows (BSD uses os::elapsedTime() now), and other cleanup. The information presented during VM operation is now relative to the previous output, not always cumulative if G1SummarizeRSetStatsPeriod > 0. At VM exit, the code prints a cumulative summary.
Reviewed-by: johnc, jwilhelm
1.1 --- a/make/excludeSrc.make Sat Jun 01 10:00:56 2013 +0200 1.2 +++ b/make/excludeSrc.make Tue May 28 09:32:06 2013 +0200 1.3 @@ -87,7 +87,7 @@ 1.4 g1BlockOffsetTable.cpp g1CardCounts.cpp g1CollectedHeap.cpp g1CollectorPolicy.cpp \ 1.5 g1ErgoVerbose.cpp g1GCPhaseTimes.cpp g1HRPrinter.cpp g1HotCardCache.cpp g1Log.cpp \ 1.6 g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp \ 1.7 - g1RemSet.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \ 1.8 + g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \ 1.9 heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \ 1.10 ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp \ 1.11 adjoiningGenerations.cpp adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp \
2.1 --- a/src/os/bsd/vm/os_bsd.cpp Sat Jun 01 10:00:56 2013 +0200 2.2 +++ b/src/os/bsd/vm/os_bsd.cpp Tue May 28 09:32:06 2013 +0200 2.3 @@ -935,10 +935,10 @@ 2.4 return (1000 * 1000); 2.5 } 2.6 2.7 -// XXX: For now, code this as if BSD does not support vtime. 2.8 -bool os::supports_vtime() { return false; } 2.9 +bool os::supports_vtime() { return true; } 2.10 bool os::enable_vtime() { return false; } 2.11 bool os::vtime_enabled() { return false; } 2.12 + 2.13 double os::elapsedVTime() { 2.14 // better than nothing, but not much 2.15 return elapsedTime();
3.1 --- a/src/os/linux/vm/os_linux.cpp Sat Jun 01 10:00:56 2013 +0200 3.2 +++ b/src/os/linux/vm/os_linux.cpp Tue May 28 09:32:06 2013 +0200 3.3 @@ -101,6 +101,12 @@ 3.4 # include <inttypes.h> 3.5 # include <sys/ioctl.h> 3.6 3.7 +// if RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling 3.8 +// getrusage() is prepared to handle the associated failure. 3.9 +#ifndef RUSAGE_THREAD 3.10 +#define RUSAGE_THREAD (1) /* only the calling thread */ 3.11 +#endif 3.12 + 3.13 #define MAX_PATH (2 * K) 3.14 3.15 // for timer info max values which include all bits 3.16 @@ -1336,15 +1342,19 @@ 3.17 return (1000 * 1000); 3.18 } 3.19 3.20 -// For now, we say that linux does not support vtime. I have no idea 3.21 -// whether it can actually be made to (DLD, 9/13/05). 3.22 - 3.23 -bool os::supports_vtime() { return false; } 3.24 +bool os::supports_vtime() { return true; } 3.25 bool os::enable_vtime() { return false; } 3.26 bool os::vtime_enabled() { return false; } 3.27 + 3.28 double os::elapsedVTime() { 3.29 - // better than nothing, but not much 3.30 - return elapsedTime(); 3.31 + struct rusage usage; 3.32 + int retval = getrusage(RUSAGE_THREAD, &usage); 3.33 + if (retval == 0) { 3.34 + return (double) (usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) + (double) (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / (1000 * 1000); 3.35 + } else { 3.36 + // better than nothing, but not much 3.37 + return elapsedTime(); 3.38 + } 3.39 } 3.40 3.41 jlong os::javaTimeMillis() {
4.1 --- a/src/os/windows/vm/os_windows.cpp Sat Jun 01 10:00:56 2013 +0200 4.2 +++ b/src/os/windows/vm/os_windows.cpp Tue May 28 09:32:06 2013 +0200 4.3 @@ -813,15 +813,21 @@ 4.4 return result; 4.5 } 4.6 4.7 -// For now, we say that Windows does not support vtime. I have no idea 4.8 -// whether it can actually be made to (DLD, 9/13/05). 4.9 - 4.10 -bool os::supports_vtime() { return false; } 4.11 +bool os::supports_vtime() { return true; } 4.12 bool os::enable_vtime() { return false; } 4.13 bool os::vtime_enabled() { return false; } 4.14 + 4.15 double os::elapsedVTime() { 4.16 - // better than nothing, but not much 4.17 - return elapsedTime(); 4.18 + FILETIME created; 4.19 + FILETIME exited; 4.20 + FILETIME kernel; 4.21 + FILETIME user; 4.22 + if (GetThreadTimes(GetCurrentThread(), &created, &exited, &kernel, &user) != 0) { 4.23 + // the resolution of windows_to_java_time() should be sufficient (ms) 4.24 + return (double) (windows_to_java_time(kernel) + windows_to_java_time(user)) / MILLIUNITS; 4.25 + } else { 4.26 + return elapsedTime(); 4.27 + } 4.28 } 4.29 4.30 jlong os::javaTimeMillis() {
5.1 --- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Sat Jun 01 10:00:56 2013 +0200 5.2 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Tue May 28 09:32:06 2013 +0200 5.3 @@ -114,6 +114,14 @@ 5.4 } 5.5 } 5.6 5.7 +void ConcurrentG1Refine::worker_threads_do(ThreadClosure * tc) { 5.8 + if (_threads != NULL) { 5.9 + for (int i = 0; i < worker_thread_num(); i++) { 5.10 + tc->do_thread(_threads[i]); 5.11 + } 5.12 + } 5.13 +} 5.14 + 5.15 int ConcurrentG1Refine::thread_num() { 5.16 int n_threads = (G1ConcRefinementThreads > 0) ? G1ConcRefinementThreads 5.17 : ParallelGCThreads; 5.18 @@ -126,3 +134,7 @@ 5.19 st->cr(); 5.20 } 5.21 } 5.22 + 5.23 +ConcurrentG1RefineThread * ConcurrentG1Refine::sampling_thread() const { 5.24 + return _threads[worker_thread_num()]; 5.25 +}
6.1 --- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Sat Jun 01 10:00:56 2013 +0200 6.2 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Tue May 28 09:32:06 2013 +0200 6.3 @@ -35,6 +35,7 @@ 6.4 class G1CollectedHeap; 6.5 class G1HotCardCache; 6.6 class G1RemSet; 6.7 +class DirtyCardQueue; 6.8 6.9 class ConcurrentG1Refine: public CHeapObj<mtGC> { 6.10 ConcurrentG1RefineThread** _threads; 6.11 @@ -78,9 +79,15 @@ 6.12 6.13 void reinitialize_threads(); 6.14 6.15 - // Iterate over the conc refine threads 6.16 + // Iterate over all concurrent refinement threads 6.17 void threads_do(ThreadClosure *tc); 6.18 6.19 + // Iterate over all worker refinement threads 6.20 + void worker_threads_do(ThreadClosure * tc); 6.21 + 6.22 + // The RS sampling thread 6.23 + ConcurrentG1RefineThread * sampling_thread() const; 6.24 + 6.25 static int thread_num(); 6.26 6.27 void print_worker_threads_on(outputStream* st) const;
7.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Sat Jun 01 10:00:56 2013 +0200 7.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue May 28 09:32:06 2013 +0200 7.3 @@ -3539,6 +3539,14 @@ 7.4 } 7.5 7.6 void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { 7.7 + 7.8 + if (G1SummarizeRSetStats && 7.9 + (G1SummarizeRSetStatsPeriod > 0) && 7.10 + // we are at the end of the GC. Total collections has already been increased. 7.11 + ((total_collections() - 1) % G1SummarizeRSetStatsPeriod == 0)) { 7.12 + g1_rem_set()->print_periodic_summary_info(); 7.13 + } 7.14 + 7.15 // FIXME: what is this about? 7.16 // I'm ignoring the "fill_newgen()" call if "alloc_event_enabled" 7.17 // is set. 7.18 @@ -4093,12 +4101,6 @@ 7.19 g1mm()->update_sizes(); 7.20 } 7.21 7.22 - if (G1SummarizeRSetStats && 7.23 - (G1SummarizeRSetStatsPeriod > 0) && 7.24 - (total_collections() % G1SummarizeRSetStatsPeriod == 0)) { 7.25 - g1_rem_set()->print_summary_info(); 7.26 - } 7.27 - 7.28 // It should now be safe to tell the concurrent mark thread to start 7.29 // without its logging output interfering with the logging output 7.30 // that came from the pause.
8.1 --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Sat Jun 01 10:00:56 2013 +0200 8.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Tue May 28 09:32:06 2013 +0200 8.3 @@ -34,6 +34,7 @@ 8.4 #include "gc_implementation/g1/g1OopClosures.inline.hpp" 8.5 #include "gc_implementation/g1/g1RemSet.inline.hpp" 8.6 #include "gc_implementation/g1/heapRegionSeq.inline.hpp" 8.7 +#include "gc_implementation/g1/heapRegionRemSet.hpp" 8.8 #include "memory/iterator.hpp" 8.9 #include "oops/oop.inline.hpp" 8.10 #include "utilities/intHisto.hpp" 8.11 @@ -73,7 +74,8 @@ 8.12 _ct_bs(ct_bs), _g1p(_g1->g1_policy()), 8.13 _cg1r(g1->concurrent_g1_refine()), 8.14 _cset_rs_update_cl(NULL), 8.15 - _cards_scanned(NULL), _total_cards_scanned(0) 8.16 + _cards_scanned(NULL), _total_cards_scanned(0), 8.17 + _prev_period_summary() 8.18 { 8.19 _seq_task = new SubTasksDone(NumSeqTasks); 8.20 guarantee(n_workers() > 0, "There should be some workers"); 8.21 @@ -81,6 +83,7 @@ 8.22 for (uint i = 0; i < n_workers(); i++) { 8.23 _cset_rs_update_cl[i] = NULL; 8.24 } 8.25 + _prev_period_summary.initialize(this, n_workers()); 8.26 } 8.27 8.28 G1RemSet::~G1RemSet() { 8.29 @@ -697,47 +700,29 @@ 8.30 return has_refs_into_cset; 8.31 } 8.32 8.33 -class HRRSStatsIter: public HeapRegionClosure { 8.34 - size_t _occupied; 8.35 - size_t _total_mem_sz; 8.36 - size_t _max_mem_sz; 8.37 - HeapRegion* _max_mem_sz_region; 8.38 -public: 8.39 - HRRSStatsIter() : 8.40 - _occupied(0), 8.41 - _total_mem_sz(0), 8.42 - _max_mem_sz(0), 8.43 - _max_mem_sz_region(NULL) 8.44 - {} 8.45 +void G1RemSet::print_periodic_summary_info() { 8.46 + G1RemSetSummary current; 8.47 + current.initialize(this, n_workers()); 8.48 8.49 - bool doHeapRegion(HeapRegion* r) { 8.50 - if (r->continuesHumongous()) return false; 8.51 - size_t mem_sz = r->rem_set()->mem_size(); 8.52 - if (mem_sz > _max_mem_sz) { 8.53 - _max_mem_sz = mem_sz; 8.54 - _max_mem_sz_region = r; 8.55 - } 8.56 - _total_mem_sz += mem_sz; 8.57 - size_t occ = r->rem_set()->occupied(); 8.58 - _occupied += occ; 8.59 - return false; 8.60 - } 8.61 - size_t total_mem_sz() { return _total_mem_sz; } 8.62 - size_t max_mem_sz() { return _max_mem_sz; } 8.63 - size_t occupied() { return _occupied; } 8.64 - HeapRegion* max_mem_sz_region() { return _max_mem_sz_region; } 8.65 -}; 8.66 + _prev_period_summary.subtract_from(¤t); 8.67 + print_summary_info(&_prev_period_summary); 8.68 8.69 -class PrintRSThreadVTimeClosure : public ThreadClosure { 8.70 -public: 8.71 - virtual void do_thread(Thread *t) { 8.72 - ConcurrentG1RefineThread* crt = (ConcurrentG1RefineThread*) t; 8.73 - gclog_or_tty->print(" %5.2f", crt->vtime_accum()); 8.74 - } 8.75 -}; 8.76 + _prev_period_summary.set(¤t); 8.77 +} 8.78 8.79 void G1RemSet::print_summary_info() { 8.80 - G1CollectedHeap* g1 = G1CollectedHeap::heap(); 8.81 + G1RemSetSummary current; 8.82 + current.initialize(this, n_workers()); 8.83 + 8.84 + print_summary_info(¤t, " Cumulative RS summary"); 8.85 +} 8.86 + 8.87 +void G1RemSet::print_summary_info(G1RemSetSummary * summary, const char * header) { 8.88 + assert(summary != NULL, "just checking"); 8.89 + 8.90 + if (header != NULL) { 8.91 + gclog_or_tty->print_cr("%s", header); 8.92 + } 8.93 8.94 #if CARD_REPEAT_HISTO 8.95 gclog_or_tty->print_cr("\nG1 card_repeat count histogram: "); 8.96 @@ -745,46 +730,7 @@ 8.97 card_repeat_count.print_on(gclog_or_tty); 8.98 #endif 8.99 8.100 - gclog_or_tty->print_cr("\n Concurrent RS processed %d cards", 8.101 - _conc_refine_cards); 8.102 - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 8.103 - jint tot_processed_buffers = 8.104 - dcqs.processed_buffers_mut() + dcqs.processed_buffers_rs_thread(); 8.105 - gclog_or_tty->print_cr(" Of %d completed buffers:", tot_processed_buffers); 8.106 - gclog_or_tty->print_cr(" %8d (%5.1f%%) by conc RS threads.", 8.107 - dcqs.processed_buffers_rs_thread(), 8.108 - 100.0*(float)dcqs.processed_buffers_rs_thread()/ 8.109 - (float)tot_processed_buffers); 8.110 - gclog_or_tty->print_cr(" %8d (%5.1f%%) by mutator threads.", 8.111 - dcqs.processed_buffers_mut(), 8.112 - 100.0*(float)dcqs.processed_buffers_mut()/ 8.113 - (float)tot_processed_buffers); 8.114 - gclog_or_tty->print_cr(" Conc RS threads times(s)"); 8.115 - PrintRSThreadVTimeClosure p; 8.116 - gclog_or_tty->print(" "); 8.117 - g1->concurrent_g1_refine()->threads_do(&p); 8.118 - gclog_or_tty->print_cr(""); 8.119 - 8.120 - HRRSStatsIter blk; 8.121 - g1->heap_region_iterate(&blk); 8.122 - gclog_or_tty->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K." 8.123 - " Max = "SIZE_FORMAT"K.", 8.124 - blk.total_mem_sz()/K, blk.max_mem_sz()/K); 8.125 - gclog_or_tty->print_cr(" Static structures = "SIZE_FORMAT"K," 8.126 - " free_lists = "SIZE_FORMAT"K.", 8.127 - HeapRegionRemSet::static_mem_size() / K, 8.128 - HeapRegionRemSet::fl_mem_size() / K); 8.129 - gclog_or_tty->print_cr(" "SIZE_FORMAT" occupied cards represented.", 8.130 - blk.occupied()); 8.131 - HeapRegion* max_mem_sz_region = blk.max_mem_sz_region(); 8.132 - HeapRegionRemSet* rem_set = max_mem_sz_region->rem_set(); 8.133 - gclog_or_tty->print_cr(" Max size region = "HR_FORMAT", " 8.134 - "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", 8.135 - HR_FORMAT_PARAMS(max_mem_sz_region), 8.136 - (rem_set->mem_size() + K - 1)/K, 8.137 - (rem_set->occupied() + K - 1)/K); 8.138 - gclog_or_tty->print_cr(" Did %d coarsenings.", 8.139 - HeapRegionRemSet::n_coarsenings()); 8.140 + summary->print_on(gclog_or_tty); 8.141 } 8.142 8.143 void G1RemSet::prepare_for_verify() {
9.1 --- a/src/share/vm/gc_implementation/g1/g1RemSet.hpp Sat Jun 01 10:00:56 2013 +0200 9.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp Tue May 28 09:32:06 2013 +0200 9.3 @@ -25,6 +25,8 @@ 9.4 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSET_HPP 9.5 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSET_HPP 9.6 9.7 +#include "gc_implementation/g1/g1RemSetSummary.hpp" 9.8 + 9.9 // A G1RemSet provides ways of iterating over pointers into a selected 9.10 // collection set. 9.11 9.12 @@ -37,9 +39,11 @@ 9.13 // so that they can be used to update the individual region remsets. 9.14 9.15 class G1RemSet: public CHeapObj<mtGC> { 9.16 +private: 9.17 + G1RemSetSummary _prev_period_summary; 9.18 protected: 9.19 G1CollectedHeap* _g1; 9.20 - unsigned _conc_refine_cards; 9.21 + size_t _conc_refine_cards; 9.22 uint n_workers(); 9.23 9.24 protected: 9.25 @@ -66,6 +70,8 @@ 9.26 // references into the collection set. 9.27 OopsInHeapRegionClosure** _cset_rs_update_cl; 9.28 9.29 + // Print the given summary info 9.30 + virtual void print_summary_info(G1RemSetSummary * summary, const char * header = NULL); 9.31 public: 9.32 // This is called to reset dual hash tables after the gc pause 9.33 // is finished and the initial hash table is no longer being 9.34 @@ -123,11 +129,18 @@ 9.35 int worker_i, 9.36 bool check_for_refs_into_cset); 9.37 9.38 - // Print any relevant summary info. 9.39 + // Print accumulated summary info from the start of the VM. 9.40 virtual void print_summary_info(); 9.41 9.42 + // Print accumulated summary info from the last time called. 9.43 + virtual void print_periodic_summary_info(); 9.44 + 9.45 // Prepare remembered set for verification. 9.46 virtual void prepare_for_verify(); 9.47 + 9.48 + size_t conc_refine_cards() const { 9.49 + return _conc_refine_cards; 9.50 + } 9.51 }; 9.52 9.53 class CountNonCleanMemRegionClosure: public MemRegionClosure {
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Tue May 28 09:32:06 2013 +0200 10.3 @@ -0,0 +1,205 @@ 10.4 +/* 10.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10.7 + * 10.8 + * This code is free software; you can redistribute it and/or modify it 10.9 + * under the terms of the GNU General Public License version 2 only, as 10.10 + * published by the Free Software Foundation. 10.11 + * 10.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 10.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 10.15 + * version 2 for more details (a copy is included in the LICENSE file that 10.16 + * accompanied this code). 10.17 + * 10.18 + * You should have received a copy of the GNU General Public License version 10.19 + * 2 along with this work; if not, write to the Free Software Foundation, 10.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 10.21 + * 10.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 10.23 + * or visit www.oracle.com if you need additional information or have any 10.24 + * questions. 10.25 + * 10.26 + */ 10.27 + 10.28 +#include "precompiled.hpp" 10.29 +#include "gc_implementation/g1/concurrentG1Refine.hpp" 10.30 +#include "gc_implementation/g1/concurrentG1RefineThread.hpp" 10.31 +#include "gc_implementation/g1/heapRegion.hpp" 10.32 +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" 10.33 +#include "gc_implementation/g1/g1RemSet.inline.hpp" 10.34 +#include "gc_implementation/g1/g1RemSetSummary.hpp" 10.35 +#include "gc_implementation/g1/heapRegionRemSet.hpp" 10.36 +#include "runtime/thread.inline.hpp" 10.37 + 10.38 +class GetRSThreadVTimeClosure : public ThreadClosure { 10.39 +private: 10.40 + G1RemSetSummary* _summary; 10.41 + uint _counter; 10.42 + 10.43 +public: 10.44 + GetRSThreadVTimeClosure(G1RemSetSummary * summary) : ThreadClosure(), _summary(summary), _counter(0) { 10.45 + assert(_summary != NULL, "just checking"); 10.46 + } 10.47 + 10.48 + virtual void do_thread(Thread* t) { 10.49 + ConcurrentG1RefineThread* crt = (ConcurrentG1RefineThread*) t; 10.50 + _summary->set_rs_thread_vtime(_counter, crt->vtime_accum()); 10.51 + _counter++; 10.52 + } 10.53 +}; 10.54 + 10.55 +void G1RemSetSummary::update() { 10.56 + _num_refined_cards = remset()->conc_refine_cards(); 10.57 + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 10.58 + _num_processed_buf_mutator = dcqs.processed_buffers_mut(); 10.59 + _num_processed_buf_rs_threads = dcqs.processed_buffers_rs_thread(); 10.60 + 10.61 + _num_coarsenings = HeapRegionRemSet::n_coarsenings(); 10.62 + 10.63 + ConcurrentG1Refine * cg1r = G1CollectedHeap::heap()->concurrent_g1_refine(); 10.64 + if (_rs_threads_vtimes != NULL) { 10.65 + GetRSThreadVTimeClosure p(this); 10.66 + cg1r->worker_threads_do(&p); 10.67 + } 10.68 + set_sampling_thread_vtime(cg1r->sampling_thread()->vtime_accum()); 10.69 +} 10.70 + 10.71 +void G1RemSetSummary::set_rs_thread_vtime(uint thread, double value) { 10.72 + assert(_rs_threads_vtimes != NULL, "just checking"); 10.73 + assert(thread < _num_vtimes, "just checking"); 10.74 + _rs_threads_vtimes[thread] = value; 10.75 +} 10.76 + 10.77 +double G1RemSetSummary::rs_thread_vtime(uint thread) const { 10.78 + assert(_rs_threads_vtimes != NULL, "just checking"); 10.79 + assert(thread < _num_vtimes, "just checking"); 10.80 + return _rs_threads_vtimes[thread]; 10.81 +} 10.82 + 10.83 +void G1RemSetSummary::initialize(G1RemSet* remset, uint num_workers) { 10.84 + assert(_rs_threads_vtimes == NULL, "just checking"); 10.85 + assert(remset != NULL, "just checking"); 10.86 + 10.87 + _remset = remset; 10.88 + _num_vtimes = num_workers; 10.89 + _rs_threads_vtimes = NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC); 10.90 + memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes); 10.91 + 10.92 + update(); 10.93 +} 10.94 + 10.95 +void G1RemSetSummary::set(G1RemSetSummary* other) { 10.96 + assert(other != NULL, "just checking"); 10.97 + assert(remset() == other->remset(), "just checking"); 10.98 + assert(_num_vtimes == other->_num_vtimes, "just checking"); 10.99 + 10.100 + _num_refined_cards = other->num_concurrent_refined_cards(); 10.101 + 10.102 + _num_processed_buf_mutator = other->num_processed_buf_mutator(); 10.103 + _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads(); 10.104 + 10.105 + _num_coarsenings = other->_num_coarsenings; 10.106 + 10.107 + memcpy(_rs_threads_vtimes, other->_rs_threads_vtimes, sizeof(double) * _num_vtimes); 10.108 + 10.109 + set_sampling_thread_vtime(other->sampling_thread_vtime()); 10.110 +} 10.111 + 10.112 +void G1RemSetSummary::subtract_from(G1RemSetSummary* other) { 10.113 + assert(other != NULL, "just checking"); 10.114 + assert(remset() == other->remset(), "just checking"); 10.115 + assert(_num_vtimes == other->_num_vtimes, "just checking"); 10.116 + 10.117 + _num_refined_cards = other->num_concurrent_refined_cards() - _num_refined_cards; 10.118 + 10.119 + _num_processed_buf_mutator = other->num_processed_buf_mutator() - _num_processed_buf_mutator; 10.120 + _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads() - _num_processed_buf_rs_threads; 10.121 + 10.122 + _num_coarsenings = other->num_coarsenings() - _num_coarsenings; 10.123 + 10.124 + for (uint i = 0; i < _num_vtimes; i++) { 10.125 + set_rs_thread_vtime(i, other->rs_thread_vtime(i) - rs_thread_vtime(i)); 10.126 + } 10.127 + 10.128 + _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime; 10.129 +} 10.130 + 10.131 +class HRRSStatsIter: public HeapRegionClosure { 10.132 + size_t _occupied; 10.133 + size_t _total_mem_sz; 10.134 + size_t _max_mem_sz; 10.135 + HeapRegion* _max_mem_sz_region; 10.136 +public: 10.137 + HRRSStatsIter() : 10.138 + _occupied(0), 10.139 + _total_mem_sz(0), 10.140 + _max_mem_sz(0), 10.141 + _max_mem_sz_region(NULL) 10.142 + {} 10.143 + 10.144 + bool doHeapRegion(HeapRegion* r) { 10.145 + size_t mem_sz = r->rem_set()->mem_size(); 10.146 + if (mem_sz > _max_mem_sz) { 10.147 + _max_mem_sz = mem_sz; 10.148 + _max_mem_sz_region = r; 10.149 + } 10.150 + _total_mem_sz += mem_sz; 10.151 + size_t occ = r->rem_set()->occupied(); 10.152 + _occupied += occ; 10.153 + return false; 10.154 + } 10.155 + size_t total_mem_sz() { return _total_mem_sz; } 10.156 + size_t max_mem_sz() { return _max_mem_sz; } 10.157 + size_t occupied() { return _occupied; } 10.158 + HeapRegion* max_mem_sz_region() { return _max_mem_sz_region; } 10.159 +}; 10.160 + 10.161 +double calc_percentage(size_t numerator, size_t denominator) { 10.162 + if (denominator != 0) { 10.163 + return (double)numerator / denominator * 100.0; 10.164 + } else { 10.165 + return 0.0f; 10.166 + } 10.167 +} 10.168 + 10.169 +void G1RemSetSummary::print_on(outputStream* out) { 10.170 + out->print_cr("\n Concurrent RS processed "SIZE_FORMAT" cards", 10.171 + num_concurrent_refined_cards()); 10.172 + out->print_cr(" Of %d completed buffers:", num_processed_buf_total()); 10.173 + out->print_cr(" %8d (%5.1f%%) by concurrent RS threads.", 10.174 + num_processed_buf_total(), 10.175 + calc_percentage(num_processed_buf_rs_threads(), num_processed_buf_total())); 10.176 + out->print_cr(" %8d (%5.1f%%) by mutator threads.", 10.177 + num_processed_buf_mutator(), 10.178 + calc_percentage(num_processed_buf_mutator(), num_processed_buf_total())); 10.179 + out->print_cr(" Concurrent RS threads times (s)"); 10.180 + out->print(" "); 10.181 + for (uint i = 0; i < _num_vtimes; i++) { 10.182 + out->print(" %5.2f", rs_thread_vtime(i)); 10.183 + } 10.184 + out->cr(); 10.185 + out->print_cr(" Concurrent sampling threads times (s)"); 10.186 + out->print_cr(" %5.2f", sampling_thread_vtime()); 10.187 + 10.188 + HRRSStatsIter blk; 10.189 + G1CollectedHeap::heap()->heap_region_iterate(&blk); 10.190 + out->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K." 10.191 + " Max = "SIZE_FORMAT"K.", 10.192 + blk.total_mem_sz()/K, blk.max_mem_sz()/K); 10.193 + out->print_cr(" Static structures = "SIZE_FORMAT"K," 10.194 + " free_lists = "SIZE_FORMAT"K.", 10.195 + HeapRegionRemSet::static_mem_size() / K, 10.196 + HeapRegionRemSet::fl_mem_size() / K); 10.197 + out->print_cr(" "SIZE_FORMAT" occupied cards represented.", 10.198 + blk.occupied()); 10.199 + HeapRegion* max_mem_sz_region = blk.max_mem_sz_region(); 10.200 + HeapRegionRemSet* rem_set = max_mem_sz_region->rem_set(); 10.201 + out->print_cr(" Max size region = "HR_FORMAT", " 10.202 + "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", 10.203 + HR_FORMAT_PARAMS(max_mem_sz_region), 10.204 + (rem_set->mem_size() + K - 1)/K, 10.205 + (rem_set->occupied() + K - 1)/K); 10.206 + 10.207 + out->print_cr(" Did %d coarsenings.", num_coarsenings()); 10.208 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.hpp Tue May 28 09:32:06 2013 +0200 11.3 @@ -0,0 +1,118 @@ 11.4 +/* 11.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.7 + * 11.8 + * This code is free software; you can redistribute it and/or modify it 11.9 + * under the terms of the GNU General Public License version 2 only, as 11.10 + * published by the Free Software Foundation. 11.11 + * 11.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 11.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11.15 + * version 2 for more details (a copy is included in the LICENSE file that 11.16 + * accompanied this code). 11.17 + * 11.18 + * You should have received a copy of the GNU General Public License version 11.19 + * 2 along with this work; if not, write to the Free Software Foundation, 11.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 11.21 + * 11.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 11.23 + * or visit www.oracle.com if you need additional information or have any 11.24 + * questions. 11.25 + * 11.26 + */ 11.27 + 11.28 +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSETSUMMARY_HPP 11.29 +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSETSUMMARY_HPP 11.30 + 11.31 +#include "utilities/ostream.hpp" 11.32 + 11.33 +class G1RemSet; 11.34 + 11.35 +// A G1RemSetSummary manages statistical information about the G1RemSet 11.36 + 11.37 +class G1RemSetSummary VALUE_OBJ_CLASS_SPEC { 11.38 +private: 11.39 + friend class GetRSThreadVTimeClosure; 11.40 + 11.41 + G1RemSet* _remset; 11.42 + 11.43 + G1RemSet* remset() const { 11.44 + return _remset; 11.45 + } 11.46 + 11.47 + size_t _num_refined_cards; 11.48 + size_t _num_processed_buf_mutator; 11.49 + size_t _num_processed_buf_rs_threads; 11.50 + 11.51 + size_t _num_coarsenings; 11.52 + 11.53 + double* _rs_threads_vtimes; 11.54 + size_t _num_vtimes; 11.55 + 11.56 + double _sampling_thread_vtime; 11.57 + 11.58 + void set_rs_thread_vtime(uint thread, double value); 11.59 + void set_sampling_thread_vtime(double value) { 11.60 + _sampling_thread_vtime = value; 11.61 + } 11.62 + 11.63 + void free_and_null() { 11.64 + if (_rs_threads_vtimes) { 11.65 + FREE_C_HEAP_ARRAY(double, _rs_threads_vtimes, mtGC); 11.66 + _rs_threads_vtimes = NULL; 11.67 + _num_vtimes = 0; 11.68 + } 11.69 + } 11.70 + 11.71 + // update this summary with current data from various places 11.72 + void update(); 11.73 + 11.74 +public: 11.75 + G1RemSetSummary() : _remset(NULL), _num_refined_cards(0), 11.76 + _num_processed_buf_mutator(0), _num_processed_buf_rs_threads(0), _num_coarsenings(0), 11.77 + _rs_threads_vtimes(NULL), _num_vtimes(0), _sampling_thread_vtime(0.0f) { 11.78 + } 11.79 + 11.80 + ~G1RemSetSummary() { 11.81 + free_and_null(); 11.82 + } 11.83 + 11.84 + // set the counters in this summary to the values of the others 11.85 + void set(G1RemSetSummary* other); 11.86 + // subtract all counters from the other summary, and set them in the current 11.87 + void subtract_from(G1RemSetSummary* other); 11.88 + 11.89 + // initialize and get the first sampling 11.90 + void initialize(G1RemSet* remset, uint num_workers); 11.91 + 11.92 + void print_on(outputStream* out); 11.93 + 11.94 + double rs_thread_vtime(uint thread) const; 11.95 + 11.96 + double sampling_thread_vtime() const { 11.97 + return _sampling_thread_vtime; 11.98 + } 11.99 + 11.100 + size_t num_concurrent_refined_cards() const { 11.101 + return _num_refined_cards; 11.102 + } 11.103 + 11.104 + size_t num_processed_buf_mutator() const { 11.105 + return _num_processed_buf_mutator; 11.106 + } 11.107 + 11.108 + size_t num_processed_buf_rs_threads() const { 11.109 + return _num_processed_buf_rs_threads; 11.110 + } 11.111 + 11.112 + size_t num_processed_buf_total() const { 11.113 + return num_processed_buf_mutator() + num_processed_buf_rs_threads(); 11.114 + } 11.115 + 11.116 + size_t num_coarsenings() const { 11.117 + return _num_coarsenings; 11.118 + } 11.119 +}; 11.120 + 11.121 +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSETSUMMARY_HPP
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/gc/g1/TestSummarizeRSetStats.java Tue May 28 09:32:06 2013 +0200 12.3 @@ -0,0 +1,164 @@ 12.4 +/* 12.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.7 + * 12.8 + * This code is free software; you can redistribute it and/or modify it 12.9 + * under the terms of the GNU General Public License version 2 only, as 12.10 + * published by the Free Software Foundation. 12.11 + * 12.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 12.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12.15 + * version 2 for more details (a copy is included in the LICENSE file that 12.16 + * accompanied this code). 12.17 + * 12.18 + * You should have received a copy of the GNU General Public License version 12.19 + * 2 along with this work; if not, write to the Free Software Foundation, 12.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 12.21 + * 12.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 12.23 + * or visit www.oracle.com if you need additional information or have any 12.24 + * questions. 12.25 + */ 12.26 + 12.27 +/* 12.28 + * @test TestSummarizeRSetStats.java 12.29 + * @bug 8013895 12.30 + * @library /testlibrary 12.31 + * @build TestSummarizeRSetStats 12.32 + * @summary Verify output of -XX:+G1SummarizeRSetStats 12.33 + * @run main TestSummarizeRSetStats 12.34 + * 12.35 + * Test the output of G1SummarizeRSetStats in conjunction with G1SummarizeRSetStatsPeriod. 12.36 + */ 12.37 + 12.38 +import com.oracle.java.testlibrary.*; 12.39 +import java.lang.Thread; 12.40 +import java.util.ArrayList; 12.41 +import java.util.Arrays; 12.42 + 12.43 +class RunSystemGCs { 12.44 + // 4M size, both are directly allocated into the old gen 12.45 + static Object[] largeObject1 = new Object[1024 * 1024]; 12.46 + static Object[] largeObject2 = new Object[1024 * 1024]; 12.47 + 12.48 + static int[] temp; 12.49 + 12.50 + public static void main(String[] args) { 12.51 + // create some cross-references between these objects 12.52 + for (int i = 0; i < largeObject1.length; i++) { 12.53 + largeObject1[i] = largeObject2; 12.54 + } 12.55 + 12.56 + for (int i = 0; i < largeObject2.length; i++) { 12.57 + largeObject2[i] = largeObject1; 12.58 + } 12.59 + 12.60 + int numGCs = Integer.parseInt(args[0]); 12.61 + 12.62 + if (numGCs > 0) { 12.63 + // try to force a minor collection: the young gen is 4M, the 12.64 + // amount of data allocated below is roughly that (4*1024*1024 + 12.65 + // some header data) 12.66 + for (int i = 0; i < 1024 ; i++) { 12.67 + temp = new int[1024]; 12.68 + } 12.69 + } 12.70 + 12.71 + for (int i = 0; i < numGCs - 1; i++) { 12.72 + System.gc(); 12.73 + } 12.74 + } 12.75 +} 12.76 + 12.77 +public class TestSummarizeRSetStats { 12.78 + 12.79 + public static String runTest(String[] additionalArgs, int numGCs) throws Exception { 12.80 + ArrayList<String> finalargs = new ArrayList<String>(); 12.81 + String[] defaultArgs = new String[] { 12.82 + "-XX:+UseG1GC", 12.83 + "-Xmn4m", 12.84 + "-Xmx20m", 12.85 + "-XX:InitiatingHeapOccupancyPercent=100", // we don't want the additional GCs due to initial marking 12.86 + "-XX:+PrintGC", 12.87 + "-XX:+UnlockDiagnosticVMOptions", 12.88 + "-XX:G1HeapRegionSize=1M", 12.89 + }; 12.90 + 12.91 + finalargs.addAll(Arrays.asList(defaultArgs)); 12.92 + 12.93 + if (additionalArgs != null) { 12.94 + finalargs.addAll(Arrays.asList(additionalArgs)); 12.95 + } 12.96 + 12.97 + finalargs.add(RunSystemGCs.class.getName()); 12.98 + finalargs.add(String.valueOf(numGCs)); 12.99 + 12.100 + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( 12.101 + finalargs.toArray(new String[0])); 12.102 + OutputAnalyzer output = new OutputAnalyzer(pb.start()); 12.103 + 12.104 + output.shouldHaveExitValue(0); 12.105 + 12.106 + String result = output.getStdout(); 12.107 + return result; 12.108 + } 12.109 + 12.110 + private static void expectStatistics(String result, int expectedCumulative, int expectedPeriodic) throws Exception { 12.111 + int actualTotal = result.split("Concurrent RS processed").length - 1; 12.112 + int actualCumulative = result.split("Cumulative RS summary").length - 1; 12.113 + 12.114 + if (expectedCumulative != actualCumulative) { 12.115 + throw new Exception("Incorrect amount of RSet summaries at the end. Expected " + expectedCumulative + ", got " + actualCumulative); 12.116 + } 12.117 + 12.118 + if (expectedPeriodic != (actualTotal - actualCumulative)) { 12.119 + throw new Exception("Incorrect amount of per-period RSet summaries at the end. Expected " + expectedPeriodic + ", got " + (actualTotal - actualCumulative)); 12.120 + } 12.121 + } 12.122 + 12.123 + public static void main(String[] args) throws Exception { 12.124 + String result; 12.125 + 12.126 + // no RSet statistics output 12.127 + result = runTest(null, 0); 12.128 + expectStatistics(result, 0, 0); 12.129 + 12.130 + // no RSet statistics output 12.131 + result = runTest(null, 2); 12.132 + expectStatistics(result, 0, 0); 12.133 + 12.134 + // no RSet statistics output 12.135 + result = runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); 12.136 + expectStatistics(result, 0, 0); 12.137 + 12.138 + // single RSet statistics output at the end 12.139 + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); 12.140 + expectStatistics(result, 1, 0); 12.141 + 12.142 + // single RSet statistics output at the end 12.143 + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 2); 12.144 + expectStatistics(result, 1, 0); 12.145 + 12.146 + // single RSet statistics output 12.147 + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); 12.148 + expectStatistics(result, 1, 0); 12.149 + 12.150 + // two times RSet statistics output 12.151 + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); 12.152 + expectStatistics(result, 1, 1); 12.153 + 12.154 + // four times RSet statistics output 12.155 + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); 12.156 + expectStatistics(result, 1, 3); 12.157 + 12.158 + // three times RSet statistics output 12.159 + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); 12.160 + expectStatistics(result, 1, 2); 12.161 + 12.162 + // single RSet statistics output 12.163 + result = runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); 12.164 + expectStatistics(result, 1, 1); 12.165 + } 12.166 +} 12.167 +