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_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 private:
 54   // These variables hold recent snapshots of cumulative quantities that are used for calculating
 55   // CPU time consumed by GC and mutator threads during each GC cycle.
 56   double _most_recent_timestamp;
 57   double _most_recent_gc_time;
 58   double _most_recent_gcu;
 59   double _most_recent_mutator_time;
 60   double _most_recent_mu;
 61 
 62   // These variables hold recent snapshots of cumulative quantities that are used for reporting
 63   // periodic consumption of CPU time by GC and mutator threads.
 64   double _most_recent_periodic_time_stamp;
 65   double _most_recent_periodic_gc_time;
 66   double _most_recent_periodic_mutator_time;
 67 
 68   size_t _most_recent_gcid;
 69   uint _active_processors;
 70 
 71   bool _most_recent_is_full;
 72 
 73   ShenandoahMmuTask* _mmu_periodic_task;
 74   TruncatedSeq _mmu_average;
 75 
 76   void update_utilization(size_t gcid, const char* msg);
 77   static void fetch_cpu_times(double &gc_time, double &mutator_time);
 78 
 79 public:
 80   explicit ShenandoahMmuTracker();
 81   ~ShenandoahMmuTracker();
 82 
 83   // This enrolls the periodic task after everything is initialized.
 84   void initialize();
 85 
 86   // At completion of each GC cycle (not including interrupted cycles), we invoke one of the following to record the
 87   // GC utilization during this cycle.  Incremental efforts spent in an interrupted GC cycle will be accumulated into
 88   // the CPU time reports for the subsequent completed [degenerated or full] GC cycle.
 89   //
 90   // We may redundantly record degen and full in the case that a degen upgrades to full.  When this happens, we will invoke
 91   // both record_full() and record_degenerated() with the same value of gcid.  record_full() is called first and the log
 92   // reports such a cycle as a FULL cycle.
 93   void record_young(size_t gcid);
 94   void record_global(size_t gcid);
 95   void record_bootstrap(size_t gcid);
 96   void record_old_marking_increment(bool old_marking_done);
 97   void record_mixed(size_t gcid);
 98   void record_full(size_t gcid);
 99   void record_degenerated(size_t gcid, bool is_old_boostrap);
100 
101   // This is called by the periodic task timer. The interval is defined by
102   // GCPauseIntervalMillis and defaults to 5 seconds. This method computes
103   // the MMU over the elapsed interval and records it in a running average.
104   void report();
105 };
106 
107 class ShenandoahGenerationSizer {
108 private:
109   enum SizerKind {
110     SizerDefaults,
111     SizerNewSizeOnly,
112     SizerMaxNewSizeOnly,
113     SizerMaxAndNewSize,
114     SizerNewRatio
115   };
116   SizerKind _sizer_kind;
117 
118   size_t _min_desired_young_regions;
119   size_t _max_desired_young_regions;
120 
121   static size_t calculate_min_young_regions(size_t heap_region_count);
122   static size_t calculate_max_young_regions(size_t heap_region_count);
123 
124   // Update the given values for minimum and maximum young gen length in regions
125   // given the number of heap regions depending on the kind of sizing algorithm.
126   void recalculate_min_max_young_length(size_t heap_region_count);
127 
128   // This will attempt to transfer regions from the `src` generation to `dst` generation.
129   // If the transfer would violate the configured minimum size for the source or the configured
130   // maximum size of the destination, it will not perform the transfer and will return false.
131   // Returns true if the transfer is performed.
132   bool transfer_regions(ShenandoahGeneration* src, ShenandoahGeneration* dst, size_t regions) const;
133 
134   // Return the configured maximum size in bytes for the given generation.
135   size_t max_size_for(ShenandoahGeneration* generation) const;
136 
137   // Return the configured minimum size in bytes for the given generation.
138   size_t min_size_for(ShenandoahGeneration* generation) const;
139 
140     public:
141   ShenandoahGenerationSizer();
142 
143   // Calculate the maximum length of the young gen given the number of regions
144   // depending on the sizing algorithm.
145   void heap_size_changed(size_t heap_size);
146 
147   // Minimum size of young generation in bytes as multiple of region size.
148   size_t min_young_size() const;
149   size_t min_young_regions() const {
150     return _min_desired_young_regions;
151   }
152 
153   // Maximum size of young generation in bytes as multiple of region size.
154   size_t max_young_size() const;
155   size_t max_young_regions() const {
156     return _max_desired_young_regions;
157   }
158 
159   // True if transfer succeeds, else false. See transfer_regions.
160   bool transfer_to_young(size_t regions) const;
161   bool transfer_to_old(size_t regions) const;
162 
163   // force transfer is used when we promote humongous objects.  May violate min/max limits on generation sizes
164   void force_transfer_to_old(size_t regions) const;
165 };
166 
167 #endif //SHARE_GC_SHENANDOAH_SHENANDOAHMMUTRACKER_HPP