1 /* 2 * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved. 3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #ifndef SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHHEURISTICS_HPP 27 #define SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHHEURISTICS_HPP 28 29 #include "gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp" 30 #include "gc/shenandoah/shenandoahSharedVariables.hpp" 31 #include "memory/allocation.hpp" 32 #include "runtime/globals_extension.hpp" 33 #include "utilities/numberSeq.hpp" 34 35 #define SHENANDOAH_ERGO_DISABLE_FLAG(name) \ 36 do { \ 37 if (FLAG_IS_DEFAULT(name) && (name)) { \ 38 log_info(gc)("Heuristics ergonomically sets -XX:-" #name); \ 39 FLAG_SET_DEFAULT(name, false); \ 40 } \ 41 } while (0) 42 43 #define SHENANDOAH_ERGO_ENABLE_FLAG(name) \ 44 do { \ 45 if (FLAG_IS_DEFAULT(name) && !(name)) { \ 46 log_info(gc)("Heuristics ergonomically sets -XX:+" #name); \ 47 FLAG_SET_DEFAULT(name, true); \ 48 } \ 49 } while (0) 50 51 #define SHENANDOAH_ERGO_OVERRIDE_DEFAULT(name, value) \ 52 do { \ 53 if (FLAG_IS_DEFAULT(name)) { \ 54 log_info(gc)("Heuristics ergonomically sets -XX:" #name "=" #value); \ 55 FLAG_SET_DEFAULT(name, value); \ 56 } \ 57 } while (0) 58 59 class ShenandoahCollectionSet; 60 class ShenandoahHeapRegion; 61 62 /* 63 * Shenandoah heuristics are primarily responsible for deciding when to start 64 * a collection cycle and choosing which regions will be evacuated during the 65 * cycle. 66 */ 67 class ShenandoahHeuristics : public CHeapObj<mtGC> { 68 static const intx Concurrent_Adjust = -1; // recover from penalties 69 static const intx Degenerated_Penalty = 10; // how much to penalize average GC duration history on Degenerated GC 70 static const intx Full_Penalty = 20; // how much to penalize average GC duration history on Full GC 71 72 #ifdef ASSERT 73 enum UnionTag { 74 is_uninitialized, is_garbage, is_live_data 75 }; 76 #endif 77 78 protected: 79 static const uint Moving_Average_Samples = 10; // Number of samples to store in moving averages 80 81 class RegionData { 82 private: 83 ShenandoahHeapRegion* _region; 84 union { 85 size_t _garbage; // Not used by old-gen heuristics. 86 size_t _live_data; // Only used for old-gen heuristics, which prioritizes retention of _live_data over garbage reclaim 87 } _region_union; 88 #ifdef ASSERT 89 UnionTag _union_tag; 90 #endif 91 public: 92 93 inline void clear() { 94 _region = nullptr; 95 _region_union._garbage = 0; 96 #ifdef ASSERT 97 _union_tag = is_uninitialized; 98 #endif 99 } 100 101 inline void set_region_and_garbage(ShenandoahHeapRegion* region, size_t garbage) { 102 _region = region; 103 _region_union._garbage = garbage; 104 #ifdef ASSERT 105 _union_tag = is_garbage; 106 #endif 107 } 108 109 inline void set_region_and_livedata(ShenandoahHeapRegion* region, size_t live) { 110 _region = region; 111 _region_union._live_data = live; 112 #ifdef ASSERT 113 _union_tag = is_live_data; 114 #endif 115 } 116 117 inline ShenandoahHeapRegion* get_region() const { 118 assert(_union_tag != is_uninitialized, "Cannot fetch region from uninitialized RegionData"); 119 return _region; 120 } 121 122 inline size_t get_garbage() const { 123 assert(_union_tag == is_garbage, "Invalid union fetch"); 124 return _region_union._garbage; 125 } 126 127 inline size_t get_livedata() const { 128 assert(_union_tag == is_live_data, "Invalid union fetch"); 129 return _region_union._live_data; 130 } 131 }; 132 133 // Source of information about the memory space managed by this heuristic 134 ShenandoahSpaceInfo* _space_info; 135 136 // Depending on generation mode, region data represents the results of the relevant 137 // most recently completed marking pass: 138 // - in GLOBAL mode, global marking pass 139 // - in OLD mode, old-gen marking pass 140 // - in YOUNG mode, young-gen marking pass 141 // 142 // Note that there is some redundancy represented in region data because 143 // each instance is an array large enough to hold all regions. However, 144 // any region in young-gen is not in old-gen. And any time we are 145 // making use of the GLOBAL data, there is no need to maintain the 146 // YOUNG or OLD data. Consider this redundancy of data structure to 147 // have negligible cost unless proven otherwise. 148 RegionData* _region_data; 149 150 size_t _guaranteed_gc_interval; 151 152 double _cycle_start; 153 double _last_cycle_end; 154 155 size_t _gc_times_learned; 156 intx _gc_time_penalties; 157 TruncatedSeq* _gc_cycle_time_history; 158 159 // There may be many threads that contend to set this flag 160 ShenandoahSharedFlag _metaspace_oom; 161 162 static int compare_by_garbage(RegionData a, RegionData b); 163 164 virtual void choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, 165 RegionData* data, size_t data_size, 166 size_t free) = 0; 167 168 void adjust_penalty(intx step); 169 170 public: 171 ShenandoahHeuristics(ShenandoahSpaceInfo* space_info); 172 virtual ~ShenandoahHeuristics(); 173 174 void record_metaspace_oom() { _metaspace_oom.set(); } 175 void clear_metaspace_oom() { _metaspace_oom.unset(); } 176 bool has_metaspace_oom() const { return _metaspace_oom.is_set(); } 177 178 void set_guaranteed_gc_interval(size_t guaranteed_gc_interval) { 179 _guaranteed_gc_interval = guaranteed_gc_interval; 180 } 181 182 virtual void record_cycle_start(); 183 184 virtual void record_cycle_end(); 185 186 virtual bool should_start_gc(); 187 188 virtual bool should_degenerate_cycle(); 189 190 virtual void record_success_concurrent(); 191 192 virtual void record_success_degenerated(); 193 194 virtual void record_success_full(); 195 196 virtual void record_allocation_failure_gc(); 197 198 virtual void record_requested_gc(); 199 200 virtual void choose_collection_set(ShenandoahCollectionSet* collection_set); 201 202 virtual bool can_unload_classes(); 203 204 // This indicates whether or not the current cycle should unload classes. 205 // It does NOT indicate that a cycle should be started. 206 virtual bool should_unload_classes(); 207 208 virtual const char* name() = 0; 209 virtual bool is_diagnostic() = 0; 210 virtual bool is_experimental() = 0; 211 virtual void initialize(); 212 213 double elapsed_cycle_time() const; 214 215 // Format prefix and emit log message indicating a GC cycle hs been triggered 216 void log_trigger(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3); 217 }; 218 219 #endif // SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHHEURISTICS_HPP