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 #ifdef ASSERT 94 inline void clear() { 95 _union_tag = is_uninitialized; 96 } 97 #endif 98 99 inline void set_region_and_garbage(ShenandoahHeapRegion* region, size_t garbage) { 100 _region = region; 101 _region_union._garbage = garbage; 102 #ifdef ASSERT 103 _union_tag = is_garbage; 104 #endif 105 } 106 107 inline void set_region_and_livedata(ShenandoahHeapRegion* region, size_t live) { 108 _region = region; 109 _region_union._live_data = live; 110 #ifdef ASSERT 111 _union_tag = is_live_data; 112 #endif 113 } 114 115 inline ShenandoahHeapRegion* get_region() const { 116 #ifdef ASSERT 117 assert(_union_tag != is_uninitialized, "Cannot fetch region from uninialized RegionData"); 118 #endif 119 return _region; 120 } 121 122 inline size_t get_garbage() const { 123 #ifdef ASSERT 124 assert(_union_tag == is_garbage, "Invalid union fetch"); 125 #endif 126 return _region_union._garbage; 127 } 128 129 inline size_t get_livedata() const { 130 #ifdef ASSERT 131 assert(_union_tag == is_live_data, "Invalid union fetch"); 132 #endif 133 return _region_union._live_data; 134 } 135 }; 136 137 // Source of information about the memory space managed by this heuristic 138 ShenandoahSpaceInfo* _space_info; 139 140 // Depending on generation mode, region data represents the results of the relevant 141 // most recently completed marking pass: 142 // - in GLOBAL mode, global marking pass 143 // - in OLD mode, old-gen marking pass 144 // - in YOUNG mode, young-gen marking pass 145 // 146 // Note that there is some redundancy represented in region data because 147 // each instance is an array large enough to hold all regions. However, 148 // any region in young-gen is not in old-gen. And any time we are 149 // making use of the GLOBAL data, there is no need to maintain the 150 // YOUNG or OLD data. Consider this redundancy of data structure to 151 // have negligible cost unless proven otherwise. 152 RegionData* _region_data; 153 154 size_t _guaranteed_gc_interval; 155 156 double _cycle_start; 157 double _last_cycle_end; 158 159 size_t _gc_times_learned; 160 intx _gc_time_penalties; 161 TruncatedSeq* _gc_cycle_time_history; 162 163 // There may be many threads that contend to set this flag 164 ShenandoahSharedFlag _metaspace_oom; 165 166 static int compare_by_garbage(RegionData a, RegionData b); 167 168 virtual void choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, 169 RegionData* data, size_t data_size, 170 size_t free) = 0; 171 172 void adjust_penalty(intx step); 173 174 public: 175 ShenandoahHeuristics(ShenandoahSpaceInfo* space_info); 176 virtual ~ShenandoahHeuristics(); 177 178 void record_metaspace_oom() { _metaspace_oom.set(); } 179 void clear_metaspace_oom() { _metaspace_oom.unset(); } 180 bool has_metaspace_oom() const { return _metaspace_oom.is_set(); } 181 182 void set_guaranteed_gc_interval(size_t guaranteed_gc_interval) { 183 _guaranteed_gc_interval = guaranteed_gc_interval; 184 } 185 186 virtual void record_cycle_start(); 187 188 virtual void record_cycle_end(); 189 190 virtual bool should_start_gc(); 191 192 virtual bool should_degenerate_cycle(); 193 194 virtual void record_success_concurrent(); 195 196 virtual void record_success_degenerated(); 197 198 virtual void record_success_full(); 199 200 virtual void record_allocation_failure_gc(); 201 202 virtual void record_requested_gc(); 203 204 virtual void choose_collection_set(ShenandoahCollectionSet* collection_set); 205 206 virtual bool can_unload_classes(); 207 208 // This indicates whether or not the current cycle should unload classes. 209 // It does NOT indicate that a cycle should be started. 210 virtual bool should_unload_classes(); 211 212 virtual const char* name() = 0; 213 virtual bool is_diagnostic() = 0; 214 virtual bool is_experimental() = 0; 215 virtual void initialize(); 216 217 double elapsed_cycle_time() const; 218 }; 219 220 #endif // SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHHEURISTICS_HPP