1 /*
  2  * Copyright (c) 2022, Amazon, Inc. 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 
 54   double _generational_reference_time_s;
 55   double _process_reference_time_s;
 56   double _collector_reference_time_s;
 57 
 58   ShenandoahMmuTask* _mmu_periodic_task;
 59   TruncatedSeq _mmu_average;
 60 
 61   static double gc_thread_time_seconds();
 62   static double process_time_seconds();
 63 
 64 public:
 65   explicit ShenandoahMmuTracker();
 66   ~ShenandoahMmuTracker();
 67 
 68   // This enrolls the periodic task after everything is initialized.
 69   void initialize();
 70 
 71   // This is called at the start and end of a GC cycle. The GC thread times
 72   // will be accumulated in this generation. Note that the bootstrap cycle
 73   // for an old collection should be counted against the old generation.
 74   // When the collector is idle, it still runs a regulator and a control.
 75   // The times for these threads are attributed to the global generation.
 76   void record(ShenandoahGeneration* generation);
 77 
 78   // This is called by the periodic task timer. The interval is defined by
 79   // GCPauseIntervalMillis and defaults to 5 seconds. This method computes
 80   // the MMU over the elapsed interval and records it in a running average.
 81   // This method also logs the average MMU.
 82   void report();
 83 
 84   double average() {
 85     return _mmu_average.davg();
 86   }
 87 };
 88 
 89 class ShenandoahGenerationSizer {
 90 private:
 91   enum SizerKind {
 92     SizerDefaults,
 93     SizerNewSizeOnly,
 94     SizerMaxNewSizeOnly,
 95     SizerMaxAndNewSize,
 96     SizerNewRatio
 97   };
 98   SizerKind _sizer_kind;
 99 
100   // False when using a fixed young generation size due to command-line options,
101   // true otherwise.
102   bool _use_adaptive_sizing;
103 
104   size_t _min_desired_young_regions;
105   size_t _max_desired_young_regions;
106 
107   double _resize_increment;
108   ShenandoahMmuTracker* _mmu_tracker;
109 
110   static size_t calculate_min_young_regions(size_t heap_region_count);
111   static size_t calculate_max_young_regions(size_t heap_region_count);
112 
113   // Update the given values for minimum and maximum young gen length in regions
114   // given the number of heap regions depending on the kind of sizing algorithm.
115   void recalculate_min_max_young_length(size_t heap_region_count);
116 
117   // These two methods are responsible for enforcing the minimum and maximum
118   // constraints for the size of the generations.
119   size_t adjust_transfer_from_young(ShenandoahGeneration* from, size_t regions_to_transfer) const;
120   size_t adjust_transfer_to_young(ShenandoahGeneration* to, size_t regions_to_transfer) const;
121 
122   // This will attempt to transfer capacity from one generation to the other. It
123   // returns true if a transfer is made, false otherwise.
124   bool transfer_capacity(ShenandoahGeneration* from, ShenandoahGeneration* to) const;
125 public:
126   explicit ShenandoahGenerationSizer(ShenandoahMmuTracker* mmu_tracker);
127 
128   // Calculate the maximum length of the young gen given the number of regions
129   // depending on the sizing algorithm.
130   void heap_size_changed(size_t heap_size);
131 
132   // Minimum size of young generation in bytes as multiple of region size.
133   size_t min_young_size() const;
134   size_t min_young_regions() const {
135     return _min_desired_young_regions;
136   }
137 
138   // Maximum size of young generation in bytes as multiple of region size.
139   size_t max_young_size() const;
140   size_t max_young_regions() const {
141     return _max_desired_young_regions;
142   }
143 
144   bool use_adaptive_sizing() const {
145     return _use_adaptive_sizing;
146   }
147 
148   // This is invoked at the end of a collection. This happens on a safepoint
149   // to avoid any races with allocators (and to avoid interfering with
150   // allocators by taking the heap lock). The amount of capacity to move
151   // from one generation to another is controlled by YoungGenerationSizeIncrement
152   // and defaults to 20% of the available capacity of the donor generation.
153   // The minimum and maximum sizes of the young generation are controlled by
154   // ShenandoahMinYoungPercentage and ShenandoahMaxYoungPercentage, respectively.
155   // The method returns true when an adjustment is made, false otherwise.
156   bool adjust_generation_sizes() const;
157 
158   // This may be invoked by a heuristic (from regulator thread) before it
159   // decides to run a collection.
160   bool transfer_capacity(ShenandoahGeneration* target) const;
161 };
162 
163 #endif //SHARE_GC_SHENANDOAH_SHENANDOAHMMUTRACKER_HPP