Mercurial > hg > shenandoah-preopenjdk-archive > openjdk8 > hotspot
view src/share/vm/gc_implementation/shenandoah/shenandoahCollectorPolicy.cpp @ 7449:ac5d21fb6715
Improve summary output: include full-gc, final evacuation and final update-refs pauses, and concurrent mark timing. Only print heap regions when Verbose.
author | Roman Kennke <rkennke@redhat.com> |
---|---|
date | Fri, 16 Jan 2015 12:30:35 +0100 |
parents | 7d70accd6b5a |
children | 0f18b2da554c |
line wrap: on
line source
#include "gc_implementation/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc_implementation/shenandoah/shenandoahHeap.hpp" #include "utilities/numberSeq.hpp" class ShenandoahHeuristics : public CHeapObj<mtGC> { private: NumberSeq _init_mark_ms; NumberSeq _final_mark_ms; NumberSeq _final_evac_ms; NumberSeq _final_uprefs_ms; NumberSeq _fullgc_ms; NumberSeq _concurrent_mark_times_ms; NumberSeq _concurrent_evacuation_times_ms; NumberSeq _allocation_rate_bytes; NumberSeq _reclamation_rate_bytes; double _init_mark_start; double _concurrent_mark_start; double _final_mark_start; double _final_evac_start; double _final_uprefs_start; double _concurrent_evacuation_start; double _fullgc_start; int _init_mark_count; int _final_mark_count; int _final_evac_count; int _final_uprefs_count; int _concurrent_evacuation_count; int _concurrent_mark_count; int _fullgc_count; size_t _bytes_allocated_since_CM; size_t _bytes_reclaimed_this_cycle; public: ShenandoahHeuristics(); void record_init_mark_start(); void record_init_mark_end(); void record_concurrent_mark_start(); void record_concurrent_mark_end(); void record_final_mark_start(); void record_final_mark_end(); void record_final_evacuation_start(); void record_final_evacuation_end(); void record_final_update_refs_start(); void record_final_update_refs_end(); void record_concurrent_evacuation_start(); void record_concurrent_evacuation_end(); void record_fullgc_start(); void record_fullgc_end(); void record_bytes_allocated(size_t bytes); void record_bytes_reclaimed(size_t bytes); virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const=0; virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set, ShenandoahHeapRegionSet* collection_set, ShenandoahHeapRegionSet* free_set) =0; void print_tracing_info(); }; ShenandoahHeuristics::ShenandoahHeuristics() : _init_mark_start(0), _concurrent_mark_start(0), _final_mark_start(0), _final_evac_start(0), _final_uprefs_start(0), _concurrent_evacuation_start(0), _fullgc_start(0), _bytes_allocated_since_CM(0), _bytes_reclaimed_this_cycle(0), _init_mark_count(0), _final_mark_count(0), _final_evac_count(0), _final_uprefs_count(0), _fullgc_count(0), _concurrent_mark_count(0), _concurrent_evacuation_count(0) { if (PrintGCDetails) tty->print_cr("initializing heuristics"); } void ShenandoahHeuristics::record_init_mark_start() { _init_mark_start = os::elapsedTime(); } void ShenandoahHeuristics::record_init_mark_end() { double end = os::elapsedTime(); double elapsed = (os::elapsedTime() - _init_mark_start); _init_mark_ms.add(elapsed * 1000); if (ShenandoahGCVerbose && PrintGCDetails) tty->print_cr("PolicyPrint: InitialMark %d took %lf ms", _init_mark_count++, elapsed * 1000); } void ShenandoahHeuristics::record_final_mark_start() { _final_mark_start = os::elapsedTime(); } void ShenandoahHeuristics::record_final_mark_end() { double elapsed = os::elapsedTime() - _final_mark_start; _final_mark_ms.add(elapsed * 1000); if (ShenandoahGCVerbose && PrintGCDetails) tty->print_cr("PolicyPrint: FinalMark %d took %lf ms", _final_mark_count++, elapsed * 1000); } void ShenandoahHeuristics::record_final_evacuation_start() { _final_evac_start = os::elapsedTime(); } void ShenandoahHeuristics::record_final_evacuation_end() { double elapsed = os::elapsedTime() - _final_evac_start; _final_evac_ms.add(elapsed * 1000); if (ShenandoahGCVerbose && PrintGCDetails) { tty->print_cr("PolicyPrint: FinalEvacuation "INT32_FORMAT" took %lf ms", _final_evac_count++, elapsed * 1000); } } void ShenandoahHeuristics::record_final_update_refs_start() { _final_uprefs_start = os::elapsedTime(); } void ShenandoahHeuristics::record_final_update_refs_end() { double elapsed = os::elapsedTime() - _final_uprefs_start; _final_uprefs_ms.add(elapsed * 1000); if (ShenandoahGCVerbose && PrintGCDetails) tty->print_cr("PolicyPrint: FinalUpdateRefs "INT32_FORMAT" took %lf ms", _final_uprefs_count++, elapsed * 1000); } void ShenandoahHeuristics::record_concurrent_evacuation_start() { _concurrent_evacuation_start = os::elapsedTime(); } void ShenandoahHeuristics::record_concurrent_evacuation_end() { double elapsed = os::elapsedTime() - _concurrent_evacuation_start; _concurrent_evacuation_times_ms.add(elapsed * 1000); if (ShenandoahGCVerbose && PrintGCDetails) tty->print_cr("PolicyPrint: Concurrent Evacuation %d took %lf ms", _concurrent_evacuation_count++, elapsed * 1000); } void ShenandoahHeuristics::record_concurrent_mark_start() { _concurrent_mark_start = os::elapsedTime(); } void ShenandoahHeuristics::record_concurrent_mark_end() { double elapsed = os::elapsedTime() - _concurrent_mark_start; _concurrent_mark_times_ms.add(elapsed * 1000); if (ShenandoahGCVerbose && PrintGCDetails) tty->print_cr("PolicyPrint: Concurrent Marking "INT32_FORMAT" took %lf ms", _concurrent_mark_count++, elapsed * 1000); } void ShenandoahHeuristics::record_fullgc_start() { _fullgc_start = os::elapsedTime(); } void ShenandoahHeuristics::record_fullgc_end() { double elapsed = os::elapsedTime() - _fullgc_start; _fullgc_ms.add(elapsed * 1000); if (ShenandoahGCVerbose && PrintGCDetails) tty->print_cr("PolicyPrint: Full GC "INT32_FORMAT" took %lf ms", _fullgc_count++, elapsed * 1000); } void ShenandoahHeuristics::record_bytes_allocated(size_t bytes) { _bytes_allocated_since_CM = bytes; _allocation_rate_bytes.add(bytes); } void ShenandoahHeuristics::record_bytes_reclaimed(size_t bytes) { _bytes_reclaimed_this_cycle = bytes; _reclamation_rate_bytes.add(bytes); } class AggressiveHeuristics : public ShenandoahHeuristics { public: AggressiveHeuristics() : ShenandoahHeuristics(){ if (PrintGCDetails) tty->print_cr("Initializing aggressive heuristics"); } virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { return true; } virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set, ShenandoahHeapRegionSet* collection_set, ShenandoahHeapRegionSet* free_set) { region_set->set_garbage_threshold(8); region_set->choose_collection_and_free_sets(collection_set, free_set); } }; class HalfwayHeuristics : public ShenandoahHeuristics { public: HalfwayHeuristics() : ShenandoahHeuristics() { if (PrintGCDetails) tty->print_cr("Initializing halfway heuristics"); } bool should_start_concurrent_mark(size_t used, size_t capacity) const { ShenandoahHeap* heap = ShenandoahHeap::heap(); size_t threshold_bytes_allocated = heap->capacity() / 4; if (used * 2 > capacity && heap->_bytesAllocSinceCM > threshold_bytes_allocated) return true; else return false; } void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set, ShenandoahHeapRegionSet* collection_set, ShenandoahHeapRegionSet* free_set) { region_set->set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes / 2); region_set->choose_collection_and_free_sets(collection_set, free_set); } }; // GC as little as possible class LazyHeuristics : public ShenandoahHeuristics { public: LazyHeuristics() : ShenandoahHeuristics() { if (PrintGCDetails) { tty->print_cr("Initializing lazy heuristics"); } } virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { size_t targetStartMarking = (capacity / 5) * 4; if (used > targetStartMarking) { return true; } else { return false; } } virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set, ShenandoahHeapRegionSet* collection_set, ShenandoahHeapRegionSet* free_set) { region_set->choose_collection_and_free_sets(collection_set, free_set); } }; // These are the heuristics in place when we made this class class StatusQuoHeuristics : public ShenandoahHeuristics { public: StatusQuoHeuristics() : ShenandoahHeuristics() { if (PrintGCDetails) { tty->print_cr("Initializing status quo heuristics"); } } virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { size_t targetStartMarking = capacity / 16; ShenandoahHeap* heap = ShenandoahHeap::heap(); size_t threshold_bytes_allocated = heap->capacity() / 4; if (used > targetStartMarking && heap->_bytesAllocSinceCM > threshold_bytes_allocated) { // Need to check that an appropriate number of regions have // been allocated since last concurrent mark too. return true; } else { return false; } } virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set, ShenandoahHeapRegionSet* collection_set, ShenandoahHeapRegionSet* free_set) { region_set->choose_collection_and_free_sets(collection_set, free_set); } }; static uintx clamp(uintx value, uintx min, uintx max) { value = MAX2(value, min); value = MIN2(value, max); return value; } static double get_percent(uintx value) { double _percent = static_cast<double>(clamp(value, 0, 100)); return _percent / 100.; } class DynamicHeuristics : public ShenandoahHeuristics { private: double _used_threshold_factor; double _garbage_threshold_factor; double _allocation_threshold_factor; uintx _used_threshold; uintx _garbage_threshold; uintx _allocation_threshold; public: DynamicHeuristics() : ShenandoahHeuristics() { if (PrintGCDetails) { tty->print_cr("Initializing dynamic heuristics"); } _used_threshold = 0; _garbage_threshold = 0; _allocation_threshold = 0; _used_threshold_factor = 0.; _garbage_threshold_factor = 0.; _allocation_threshold_factor = 0.; } virtual ~DynamicHeuristics() {} virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { bool shouldStartConcurrentMark = false; ShenandoahHeap* heap = ShenandoahHeap::heap(); size_t targetStartMarking = capacity * _used_threshold_factor; size_t threshold_bytes_allocated = heap->capacity() * _allocation_threshold_factor; if (used > targetStartMarking && heap->_bytesAllocSinceCM > threshold_bytes_allocated) { // Need to check that an appropriate number of regions have // been allocated since last concurrent mark too. shouldStartConcurrentMark = true; } return shouldStartConcurrentMark; } virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set, ShenandoahHeapRegionSet* collection_set, ShenandoahHeapRegionSet* free_set) { region_set->set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * _garbage_threshold_factor); region_set->choose_collection_and_free_sets(collection_set, free_set); } void set_used_threshold(uintx used_threshold) { this->_used_threshold_factor = get_percent(used_threshold); this->_used_threshold = used_threshold; } void set_garbage_threshold(uintx garbage_threshold) { this->_garbage_threshold_factor = get_percent(garbage_threshold); this->_garbage_threshold = _garbage_threshold; } void set_allocation_threshold(uintx allocationThreshold) { this->_allocation_threshold_factor = get_percent(allocationThreshold); this->_allocation_threshold = allocationThreshold; } uintx get_allocation_threshold() { return this->_allocation_threshold; } uintx get_garbage_threshold() { return this->_garbage_threshold; } uintx get_used_threshold() { return this->_used_threshold; } }; class AdaptiveHeuristics : public ShenandoahHeuristics { private: size_t _max_live_data; double _used_threshold_factor; double _garbage_threshold_factor; double _allocation_threshold_factor; uintx _used_threshold; uintx _garbage_threshold; uintx _allocation_threshold; public: AdaptiveHeuristics() : ShenandoahHeuristics() { if (PrintGCDetails) { tty->print_cr("Initializing dynamic heuristics"); } _max_live_data = 0; _used_threshold = 0; _garbage_threshold = 0; _allocation_threshold = 0; _used_threshold_factor = 0.; _garbage_threshold_factor = 0.1; _allocation_threshold_factor = 0.; } virtual ~AdaptiveHeuristics() {} virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { ShenandoahHeap* _heap = ShenandoahHeap::heap(); bool shouldStartConcurrentMark = false; size_t max_live_data = _max_live_data; if (max_live_data == 0) { max_live_data = capacity * 0.2; // Very generous initial value. } else { max_live_data *= 1.3; // Add some wiggle room. } size_t max_cycle_allocated = _heap->_max_allocated_gc; if (max_cycle_allocated == 0) { max_cycle_allocated = capacity * 0.3; // Very generous. } else { max_cycle_allocated *= 1.3; // Add 20% wiggle room. Should be enough. } size_t threshold = _heap->capacity() - max_cycle_allocated - max_live_data; if (used > threshold) { shouldStartConcurrentMark = true; } return shouldStartConcurrentMark; } virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set, ShenandoahHeapRegionSet* collection_set, ShenandoahHeapRegionSet* free_set) { size_t bytes_alloc = ShenandoahHeap::heap()->_bytesAllocSinceCM; size_t min_garbage = bytes_alloc/* * 1.1*/; region_set->set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * _garbage_threshold_factor); region_set->choose_collection_and_free_sets_min_garbage(collection_set, free_set, min_garbage); /* tty->print_cr("garbage to be collected: %u", collection_set->garbage()); tty->print_cr("objects to be evacuated: %u", collection_set->live_data()); */ _max_live_data = MAX2(_max_live_data, collection_set->live_data()); } void set_used_threshold(uintx used_threshold) { this->_used_threshold_factor = get_percent(used_threshold); this->_used_threshold = used_threshold; } void set_garbage_threshold(uintx garbage_threshold) { this->_garbage_threshold_factor = get_percent(garbage_threshold); this->_garbage_threshold = _garbage_threshold; } void set_allocation_threshold(uintx allocationThreshold) { this->_allocation_threshold_factor = get_percent(allocationThreshold); this->_allocation_threshold = allocationThreshold; } uintx get_allocation_threshold() { return this->_allocation_threshold; } uintx get_garbage_threshold() { return this->_garbage_threshold; } uintx get_used_threshold() { return this->_used_threshold; } }; static DynamicHeuristics *configureDynamicHeuristics() { DynamicHeuristics *heuristics = new DynamicHeuristics(); heuristics->set_garbage_threshold(ShenandoahGarbageThreshold); heuristics->set_allocation_threshold(ShenandoahAllocationThreshold); heuristics->set_used_threshold(ShenandoahUsedThreshold); if (ShenandoahLogConfig) { tty->print_cr("Shenandoah dynamic heuristics thresholds: allocation "UINTX_FORMAT", used "UINTX_FORMAT", garbage "UINTX_FORMAT, heuristics->get_allocation_threshold(), heuristics->get_used_threshold(), heuristics->get_garbage_threshold()); } return heuristics; } ShenandoahCollectorPolicy::ShenandoahCollectorPolicy() { initialize_all(); if (ShenandoahGCHeuristics != NULL) { if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) { if (ShenandoahLogConfig) { tty->print_cr("Shenandoah heuristics: aggressive"); } _heuristics = new AggressiveHeuristics(); } else if (strcmp(ShenandoahGCHeuristics, "statusquo") == 0) { if (ShenandoahLogConfig) { tty->print_cr("Shenandoah heuristics: statusquo"); } _heuristics = new StatusQuoHeuristics(); } else if (strcmp(ShenandoahGCHeuristics, "halfway") == 0) { if (ShenandoahLogConfig) { tty->print_cr("Shenandoah heuristics: halfway"); } _heuristics = new HalfwayHeuristics(); } else if (strcmp(ShenandoahGCHeuristics, "lazy") == 0) { if (ShenandoahLogConfig) { tty->print_cr("Shenandoah heuristics: lazy"); } _heuristics = new LazyHeuristics(); } else if (strcmp(ShenandoahGCHeuristics, "dynamic") == 0) { if (ShenandoahLogConfig) { tty->print_cr("Shenandoah heuristics: dynamic"); } _heuristics = configureDynamicHeuristics(); } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) { if (ShenandoahLogConfig) { tty->print_cr("Shenandoah heuristics: adaptive"); } _heuristics = new AdaptiveHeuristics(); } else { fatal("Unknown -XX:ShenandoahGCHeuristics option"); } } else { if (ShenandoahLogConfig) { tty->print_cr("Shenandoah heuristics: statusquo (default)"); } _heuristics = new StatusQuoHeuristics(); } } ShenandoahCollectorPolicy* ShenandoahCollectorPolicy::as_pgc_policy() { return this; } ShenandoahCollectorPolicy::Name ShenandoahCollectorPolicy::kind() { return CollectorPolicy::ShenandoahCollectorPolicyKind; } BarrierSet::Name ShenandoahCollectorPolicy::barrier_set_name() { return BarrierSet::ShenandoahBarrierSet; } GenRemSet::Name ShenandoahCollectorPolicy::rem_set_name() { return GenRemSet::Other; } HeapWord* ShenandoahCollectorPolicy::mem_allocate_work(size_t size, bool is_tlab, bool* gc_overhead_limit_was_exceeded) { guarantee(false, "Not using this policy feature yet."); return NULL; } HeapWord* ShenandoahCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_tlab) { guarantee(false, "Not using this policy feature yet."); return NULL; } void ShenandoahCollectorPolicy::initialize_alignments() { // This is expected by our algorithm for ShenandoahHeap::heap_region_containing(). _space_alignment = ShenandoahHeapRegion::RegionSizeBytes; _heap_alignment = ShenandoahHeapRegion::RegionSizeBytes; } void ShenandoahCollectorPolicy::post_heap_initialize() { // Nothing to do here (yet). } void ShenandoahCollectorPolicy::record_init_mark_start() { _heuristics->record_init_mark_start(); } void ShenandoahCollectorPolicy::record_init_mark_end() { _heuristics->record_init_mark_end(); } void ShenandoahCollectorPolicy::record_final_mark_start() { _heuristics->record_final_mark_start(); } void ShenandoahCollectorPolicy::record_final_mark_end() { _heuristics->record_final_mark_end(); } void ShenandoahCollectorPolicy::record_final_evacuation_start() { _heuristics->record_final_evacuation_start(); } void ShenandoahCollectorPolicy::record_final_evacuation_end() { _heuristics->record_final_evacuation_end(); } void ShenandoahCollectorPolicy::record_final_update_refs_start() { _heuristics->record_final_update_refs_start(); } void ShenandoahCollectorPolicy::record_final_update_refs_end() { _heuristics->record_final_update_refs_end(); } void ShenandoahCollectorPolicy::record_concurrent_evacuation_start() { _heuristics->record_concurrent_evacuation_start(); } void ShenandoahCollectorPolicy::record_concurrent_evacuation_end() { _heuristics->record_concurrent_evacuation_end(); } void ShenandoahCollectorPolicy::record_concurrent_mark_start() { _heuristics->record_concurrent_mark_start(); } void ShenandoahCollectorPolicy::record_concurrent_mark_end() { _heuristics->record_concurrent_mark_end(); } void ShenandoahCollectorPolicy::record_fullgc_start() { _heuristics->record_fullgc_start(); } void ShenandoahCollectorPolicy::record_fullgc_end() { _heuristics->record_fullgc_end(); } void ShenandoahCollectorPolicy::record_bytes_allocated(size_t bytes) { _heuristics->record_bytes_allocated(bytes); } void ShenandoahCollectorPolicy::record_bytes_reclaimed(size_t bytes) { _heuristics->record_bytes_reclaimed(bytes); } bool ShenandoahCollectorPolicy::should_start_concurrent_mark(size_t used, size_t capacity) { ShenandoahHeap* heap = ShenandoahHeap::heap(); return _heuristics->should_start_concurrent_mark(used, capacity); } void ShenandoahCollectorPolicy::choose_collection_and_free_sets( ShenandoahHeapRegionSet* region_set, ShenandoahHeapRegionSet* collection_set, ShenandoahHeapRegionSet* free_set) { _heuristics->choose_collection_and_free_sets(region_set, collection_set, free_set); } void ShenandoahCollectorPolicy::print_tracing_info() { _heuristics->print_tracing_info(); } void print_summary(const char* str, const NumberSeq* seq) { double sum = seq->sum(); gclog_or_tty->print_cr("%-27s = %8.2lf s (avg = %8.2lf ms)", str, sum / 1000.0, seq->avg()); } void print_summary_sd(const char* str, const NumberSeq* seq) { print_summary(str, seq); gclog_or_tty->print_cr("(num = %5d, std dev = %8.2lf ms, max = %8.2lf ms)", seq->num(), seq->sd(), seq->maximum()); } void ShenandoahHeuristics::print_tracing_info() { print_summary_sd("Initial Mark Pauses", &_init_mark_ms); print_summary_sd("Final Mark Pauses", &_final_mark_ms); print_summary_sd("Final Evacuation Pauses", &_final_evac_ms); print_summary_sd("Final Update Refs Pauses", &_final_uprefs_ms); print_summary_sd("Concurrent Marking Times", &_concurrent_mark_times_ms); print_summary_sd("Concurrent Evacuation Times", &_concurrent_evacuation_times_ms); print_summary_sd("Full GC Times", &_fullgc_ms); }