1 /* 2 * Copyright (c) 2022, Amazon, Inc. 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 54 double _generational_reference_time_s; 55 double _process_reference_time_s; 56 double _collector_reference_time_s; 57 58 ShenandoahMmuTask* _mmu_periodic_task; 59 TruncatedSeq _mmu_average; 60 61 static double gc_thread_time_seconds(); 62 static double process_time_seconds(); 63 64 public: 65 explicit ShenandoahMmuTracker(); 66 ~ShenandoahMmuTracker(); 67 68 // This enrolls the periodic task after everything is initialized. 69 void initialize(); 70 71 // This is called at the start and end of a GC cycle. The GC thread times 72 // will be accumulated in this generation. Note that the bootstrap cycle 73 // for an old collection should be counted against the old generation. 74 // When the collector is idle, it still runs a regulator and a control. 75 // The times for these threads are attributed to the global generation. 76 void record(ShenandoahGeneration* generation); 77 78 // This is called by the periodic task timer. The interval is defined by 79 // GCPauseIntervalMillis and defaults to 5 seconds. This method computes 80 // the MMU over the elapsed interval and records it in a running average. 81 // This method also logs the average MMU. 82 void report(); 83 84 double average() { 85 return _mmu_average.davg(); 86 } 87 }; 88 89 class ShenandoahGenerationSizer { 90 private: 91 enum SizerKind { 92 SizerDefaults, 93 SizerNewSizeOnly, 94 SizerMaxNewSizeOnly, 95 SizerMaxAndNewSize, 96 SizerNewRatio 97 }; 98 SizerKind _sizer_kind; 99 100 // False when using a fixed young generation size due to command-line options, 101 // true otherwise. 102 bool _use_adaptive_sizing; 103 104 size_t _min_desired_young_regions; 105 size_t _max_desired_young_regions; 106 107 double _resize_increment; 108 ShenandoahMmuTracker* _mmu_tracker; 109 110 static size_t calculate_min_young_regions(size_t heap_region_count); 111 static size_t calculate_max_young_regions(size_t heap_region_count); 112 113 // Update the given values for minimum and maximum young gen length in regions 114 // given the number of heap regions depending on the kind of sizing algorithm. 115 void recalculate_min_max_young_length(size_t heap_region_count); 116 117 // These two methods are responsible for enforcing the minimum and maximum 118 // constraints for the size of the generations. 119 size_t adjust_transfer_from_young(ShenandoahGeneration* from, size_t regions_to_transfer) const; 120 size_t adjust_transfer_to_young(ShenandoahGeneration* to, size_t regions_to_transfer) const; 121 122 // This will attempt to transfer capacity from one generation to the other. It 123 // returns true if a transfer is made, false otherwise. 124 bool transfer_capacity(ShenandoahGeneration* from, ShenandoahGeneration* to) const; 125 public: 126 explicit ShenandoahGenerationSizer(ShenandoahMmuTracker* mmu_tracker); 127 128 // Calculate the maximum length of the young gen given the number of regions 129 // depending on the sizing algorithm. 130 void heap_size_changed(size_t heap_size); 131 132 // Minimum size of young generation in bytes as multiple of region size. 133 size_t min_young_size() const; 134 size_t min_young_regions() const { 135 return _min_desired_young_regions; 136 } 137 138 // Maximum size of young generation in bytes as multiple of region size. 139 size_t max_young_size() const; 140 size_t max_young_regions() const { 141 return _max_desired_young_regions; 142 } 143 144 bool use_adaptive_sizing() const { 145 return _use_adaptive_sizing; 146 } 147 148 // This is invoked at the end of a collection. This happens on a safepoint 149 // to avoid any races with allocators (and to avoid interfering with 150 // allocators by taking the heap lock). The amount of capacity to move 151 // from one generation to another is controlled by YoungGenerationSizeIncrement 152 // and defaults to 20% of the available capacity of the donor generation. 153 // The minimum and maximum sizes of the young generation are controlled by 154 // ShenandoahMinYoungPercentage and ShenandoahMaxYoungPercentage, respectively. 155 // The method returns true when an adjustment is made, false otherwise. 156 bool adjust_generation_sizes() const; 157 158 // This may be invoked by a heuristic (from regulator thread) before it 159 // decides to run a collection. 160 bool transfer_capacity(ShenandoahGeneration* target) const; 161 }; 162 163 #endif //SHARE_GC_SHENANDOAH_SHENANDOAHMMUTRACKER_HPP