1 /* 2 * Copyright Amazon.com Inc. 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 */ 24 25 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHMMUTRACKER_HPP 26 #define SHARE_GC_SHENANDOAH_SHENANDOAHMMUTRACKER_HPP 27 28 #include "runtime/mutex.hpp" 29 #include "utilities/numberSeq.hpp" 30 31 class ShenandoahGeneration; 32 class ShenandoahMmuTask; 33 34 /** 35 * This class is responsible for tracking and adjusting the minimum mutator 36 * utilization (MMU). MMU is defined as the percentage of CPU time available 37 * to mutator threads over an arbitrary, fixed interval of time. This interval 38 * defaults to 5 seconds and is configured by GCPauseIntervalMillis. The class 39 * maintains a decaying average of the last 10 values. The MMU is measured 40 * by summing all of the time given to the GC threads and comparing this to 41 * the total CPU time for the process. There are OS APIs to support this on 42 * all major platforms. 43 * 44 * The time spent by GC threads is attributed to the young or old generation. 45 * The time given to the controller and regulator threads is attributed to the 46 * global generation. At the end of every collection, the average MMU is inspected. 47 * If it is below `GCTimeRatio`, this class will attempt to increase the capacity 48 * of the generation that is consuming the most CPU time. The assumption being 49 * that increasing memory will reduce the collection frequency and raise the 50 * MMU. 51 */ 52 class ShenandoahMmuTracker { 53 private: 54 // These variables hold recent snapshots of cumulative quantities that are used for calculating 55 // CPU time consumed by GC and mutator threads during each GC cycle. 56 double _most_recent_timestamp; 57 double _most_recent_gc_time; 58 double _most_recent_gcu; 59 double _most_recent_mutator_time; 60 double _most_recent_mu; 61 62 // These variables hold recent snapshots of cumulative quantities that are used for reporting 63 // periodic consumption of CPU time by GC and mutator threads. 64 double _most_recent_periodic_time_stamp; 65 double _most_recent_periodic_gc_time; 66 double _most_recent_periodic_mutator_time; 67 68 size_t _most_recent_gcid; 69 uint _active_processors; 70 71 bool _most_recent_is_full; 72 73 ShenandoahMmuTask* _mmu_periodic_task; 74 TruncatedSeq _mmu_average; 75 76 void update_utilization(ShenandoahGeneration* generation, size_t gcid, const char* msg); 77 static void fetch_cpu_times(double &gc_time, double &mutator_time); 78 79 public: 80 explicit ShenandoahMmuTracker(); 81 ~ShenandoahMmuTracker(); 82 83 // This enrolls the periodic task after everything is initialized. 84 void initialize(); 85 86 // At completion of each GC cycle (not including interrupted cycles), we invoke one of the following to record the 87 // GC utilization during this cycle. Incremental efforts spent in an interrupted GC cycle will be accumulated into 88 // the CPU time reports for the subsequent completed [degenerated or full] GC cycle. 89 // 90 // We may redundantly record degen and full in the case that a degen upgrades to full. When this happens, we will invoke 91 // both record_full() and record_degenerated() with the same value of gcid. record_full() is called first and the log 92 // reports such a cycle as a FULL cycle. 93 void record_young(ShenandoahGeneration* generation, size_t gcid); 94 void record_global(ShenandoahGeneration* generation, size_t gcid); 95 void record_bootstrap(ShenandoahGeneration* generation, size_t gcid, bool has_old_candidates); 96 void record_old_marking_increment(ShenandoahGeneration* generation, size_t gcid, bool old_marking_done, bool has_old_candidates); 97 void record_mixed(ShenandoahGeneration* generation, size_t gcid, bool is_mixed_done); 98 void record_full(ShenandoahGeneration* generation, size_t gcid); 99 void record_degenerated(ShenandoahGeneration* generation, size_t gcid, bool is_old_boostrap, bool is_mixed_done); 100 101 // This is called by the periodic task timer. The interval is defined by 102 // GCPauseIntervalMillis and defaults to 5 seconds. This method computes 103 // the MMU over the elapsed interval and records it in a running average. 104 void report(); 105 }; 106 107 class ShenandoahGenerationSizer { 108 private: 109 enum SizerKind { 110 SizerDefaults, 111 SizerNewSizeOnly, 112 SizerMaxNewSizeOnly, 113 SizerMaxAndNewSize, 114 SizerNewRatio 115 }; 116 SizerKind _sizer_kind; 117 118 // False when using a fixed young generation size due to command-line options, 119 // true otherwise. 120 bool _use_adaptive_sizing; 121 122 size_t _min_desired_young_regions; 123 size_t _max_desired_young_regions; 124 125 double _resize_increment; 126 ShenandoahMmuTracker* _mmu_tracker; 127 128 static size_t calculate_min_young_regions(size_t heap_region_count); 129 static size_t calculate_max_young_regions(size_t heap_region_count); 130 131 // Update the given values for minimum and maximum young gen length in regions 132 // given the number of heap regions depending on the kind of sizing algorithm. 133 void recalculate_min_max_young_length(size_t heap_region_count); 134 135 public: 136 explicit ShenandoahGenerationSizer(ShenandoahMmuTracker* mmu_tracker); 137 138 // Calculate the maximum length of the young gen given the number of regions 139 // depending on the sizing algorithm. 140 void heap_size_changed(size_t heap_size); 141 142 // Minimum size of young generation in bytes as multiple of region size. 143 size_t min_young_size() const; 144 size_t min_young_regions() const { 145 return _min_desired_young_regions; 146 } 147 148 // Maximum size of young generation in bytes as multiple of region size. 149 size_t max_young_size() const; 150 size_t max_young_regions() const { 151 return _max_desired_young_regions; 152 } 153 154 bool use_adaptive_sizing() const { 155 return _use_adaptive_sizing; 156 } 157 158 bool transfer_to_young(size_t regions) const; 159 bool transfer_to_old(size_t regions) const; 160 161 // force transfer is used when we promote humongous objects. May violate min/max limits on generation sizes 162 void force_transfer_to_old(size_t regions) const; 163 }; 164 165 #endif //SHARE_GC_SHENANDOAH_SHENANDOAHMMUTRACKER_HPP