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_SHENANDOAHAGECENSUS_HPP 26 #define SHARE_GC_SHENANDOAH_SHENANDOAHAGECENSUS_HPP 27 28 #include "gc/shared/ageTable.hpp" 29 30 #ifndef PRODUCT 31 // Enable noise instrumentation 32 #define SHENANDOAH_CENSUS_NOISE 1 33 #endif // PRODUCT 34 35 #ifdef SHENANDOAH_CENSUS_NOISE 36 37 #define CENSUS_NOISE(x) x 38 #define NO_CENSUS_NOISE(x) 39 40 class LogStream; 41 42 struct ShenandoahNoiseStats { 43 size_t skipped; // Volume of objects skipped 44 size_t aged; // Volume of objects from aged regions 45 size_t clamped; // Volume of objects whose ages were clamped 46 size_t young; // Volume of (rejuvenated) objects of retrograde age 47 48 ShenandoahNoiseStats() { 49 clear(); 50 } 51 52 void clear() { 53 skipped = 0; 54 aged = 0; 55 clamped = 0; 56 young = 0; 57 } 58 59 #ifndef PRODUCT 60 bool is_clear() { 61 return (skipped + aged + clamped + young) == 0; 62 } 63 #endif // !PRODUCT 64 65 void merge(ShenandoahNoiseStats& other) { 66 skipped += other.skipped; 67 aged += other.aged; 68 clamped += other.clamped; 69 young += other.young; 70 } 71 72 void print(LogStream& ls, size_t total); 73 }; 74 #else // SHENANDOAH_CENSUS_NOISE 75 #define CENSUS_NOISE(x) 76 #define NO_CENSUS_NOISE(x) x 77 #endif // SHENANDOAH_CENSUS_NOISE 78 79 // A class for tracking a sequence of cohort population vectors (or, 80 // interchangeably, age tables) for up to C=MAX_COHORTS age cohorts, where a cohort 81 // represents the set of objects allocated during a specific inter-GC epoch. 82 // Epochs are demarcated by GC cycles, with those surviving a cycle aging by 83 // an epoch. The census tracks the historical variation of cohort demographics 84 // across N=MAX_SNAPSHOTS recent epochs. Since there are at most C age cohorts in 85 // the population, we need only track at most N=C epochal snapshots to track a 86 // maximal longitudinal demographics of every object's longitudinal cohort in 87 // the young generation. The _global_age_table is thus, currently, a C x N (row-major) 88 // matrix, with C=16, and, for now N=C=16, currently. 89 // In theory, we might decide to track even longer (N=MAX_SNAPSHOTS) demographic 90 // histories, but that isn't the case today. In particular, the current tenuring 91 // threshold algorithm uses only 2 most recent snapshots, with the remaining 92 // MAX_SNAPSHOTS-2=14 reserved for research purposes. 93 // 94 // In addition, this class also maintains per worker population vectors into which 95 // census for the current minor GC is accumulated (during marking or, optionally, during 96 // evacuation). These are cleared after each marking (respectively, evacuation) cycle, 97 // once the per-worker data is consolidated into the appropriate population vector 98 // per minor collection. The _local_age_table is thus C x N, for N GC workers. 99 class ShenandoahAgeCensus: public CHeapObj<mtGC> { 100 AgeTable** _global_age_table; // Global age table used for adapting tenuring threshold, one per snapshot 101 AgeTable** _local_age_table; // Local scratch age tables to track object ages, one per worker 102 103 #ifdef SHENANDOAH_CENSUS_NOISE 104 ShenandoahNoiseStats* _global_noise; // Noise stats, one per snapshot 105 ShenandoahNoiseStats* _local_noise; // Local scratch table for noise stats, one per worker 106 107 size_t _skipped; // net size of objects encountered, but skipped during census, 108 // because their age was indeterminate 109 #endif // SHENANDOAH_CENSUS_NOISE 110 111 #ifndef PRODUCT 112 size_t _counted; // net size of objects counted in census 113 size_t _total; // net size of objects encountered (counted or skipped) in census 114 #endif 115 116 uint _epoch; // Current epoch (modulo max age) 117 uint* _tenuring_threshold; // An array of the last N tenuring threshold values we 118 // computed. 119 120 uint _max_workers; // Maximum number of workers for parallel tasks 121 122 // Mortality rate of a cohort, given its population in 123 // previous and current epochs 124 double mortality_rate(size_t prev_pop, size_t cur_pop); 125 126 // Update to a new epoch, creating a slot for new census. 127 void prepare_for_census_update(); 128 129 // Update the tenuring threshold, calling 130 // compute_tenuring_threshold() to calculate the new 131 // value 132 void update_tenuring_threshold(); 133 134 // Use _global_age_table and the current _epoch to compute a new tenuring 135 // threshold, which will be remembered until the next invocation of 136 // compute_tenuring_threshold. 137 uint compute_tenuring_threshold(); 138 139 // Return the tenuring threshold computed for the previous epoch 140 uint previous_tenuring_threshold() const { 141 assert(_epoch < MAX_SNAPSHOTS, "Error"); 142 uint prev = _epoch - 1; 143 if (prev >= MAX_SNAPSHOTS) { 144 // _epoch is 0 145 assert(_epoch == 0, "Error"); 146 prev = MAX_SNAPSHOTS - 1; 147 } 148 return _tenuring_threshold[prev]; 149 } 150 151 #ifndef PRODUCT 152 // Return the sum of size of objects of all ages recorded in the 153 // census at snapshot indexed by snap. 154 size_t get_all_ages(uint snap); 155 156 // Return the size of all objects that were encountered, but skipped, 157 // during the census, because their age was indeterminate. 158 size_t get_skipped(uint snap); 159 160 // Update the total size of objects counted or skipped at the census for 161 // the most recent epoch. 162 void update_total(); 163 #endif // !PRODUCT 164 165 public: 166 enum { 167 MAX_COHORTS = AgeTable::table_size, // = markWord::max_age + 1 168 MAX_SNAPSHOTS = MAX_COHORTS // May change in the future 169 }; 170 171 ShenandoahAgeCensus(); 172 ShenandoahAgeCensus(uint max_workers); 173 ~ShenandoahAgeCensus(); 174 175 // Return the local age table (population vector) for worker_id. 176 // Only used in the case of (ShenandoahGenerationalAdaptiveTenuring && !ShenandoahGenerationalCensusAtEvac) 177 AgeTable* get_local_age_table(uint worker_id) const { 178 return _local_age_table[worker_id]; 179 } 180 181 // Return the most recently computed tenuring threshold. 182 // Visible for testing. Use is_tenurable for consistent tenuring comparisons. 183 uint tenuring_threshold() const { return _tenuring_threshold[_epoch]; } 184 185 // Return true if this age is at or above the tenuring threshold. 186 bool is_tenurable(uint age) const { 187 return age >= tenuring_threshold(); 188 } 189 190 // Update the local age table for worker_id by size for 191 // given obj_age, region_age, and region_youth 192 CENSUS_NOISE(void add(uint obj_age, uint region_age, uint region_youth, size_t size, uint worker_id);) 193 NO_CENSUS_NOISE(void add(uint obj_age, uint region_age, size_t size, uint worker_id);) 194 195 #ifdef SHENANDOAH_CENSUS_NOISE 196 // Update the local skip table for worker_id by size 197 void add_skipped(size_t size, uint worker_id); 198 // Update the local aged region volume table for worker_id by size 199 void add_aged(size_t size, uint worker_id); 200 // Update the local clamped object volume table for worker_id by size 201 void add_clamped(size_t size, uint worker_id); 202 // Update the local (rejuvenated) object volume (retrograde age) for worker_id by size 203 void add_young(size_t size, uint worker_id); 204 #endif // SHENANDOAH_CENSUS_NOISE 205 206 // Update the census data, and compute the new tenuring threshold. 207 // This method should be called at the end of each marking (or optionally 208 // evacuation) cycle to update the tenuring threshold to be used in 209 // the next cycle. 210 // age0_pop is the population of Cohort 0 that may have been missed in 211 // the regular census during the marking cycle, corresponding to objects 212 // allocated when the concurrent marking was in progress. 213 // Optional parameters, pv1 and pv2 are population vectors that together 214 // provide object census data (only) for the case when 215 // ShenandoahGenerationalCensusAtEvac. In this case, the age0_pop 216 // is 0, because the evacuated objects have all had their ages incremented. 217 void update_census(size_t age0_pop, AgeTable* pv1 = nullptr, AgeTable* pv2 = nullptr); 218 219 // Reset the epoch, clearing accumulated census history 220 // Note: this isn't currently used, but reserved for planned 221 // future usage. 222 void reset_global(); 223 224 // Reset any (potentially partial) census information in worker-local age tables 225 void reset_local(); 226 227 #ifndef PRODUCT 228 // Check whether census information is clear 229 bool is_clear_global(); 230 bool is_clear_local(); 231 232 // Return the net size of objects encountered (counted or skipped) in census 233 // at most recent epoch. 234 size_t get_total() { return _total; } 235 #endif // !PRODUCT 236 237 // Print the age census information 238 void print(); 239 }; 240 241 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHAGECENSUS_HPP