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