1 /*
  2  * Copyright (c) 2002, 2023, Oracle and/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_MEMORY_HEAPINSPECTION_HPP
 26 #define SHARE_MEMORY_HEAPINSPECTION_HPP
 27 
 28 #include "gc/shared/workerThread.hpp"
 29 #include "memory/allocation.hpp"
 30 #include "oops/objArrayOop.hpp"
 31 #include "oops/oop.hpp"
 32 #include "oops/annotations.hpp"
 33 #include "utilities/macros.hpp"
 34 
 35 class ParallelObjectIterator;
 36 
 37 #if INCLUDE_SERVICES
 38 
 39 
 40 // HeapInspection
 41 
 42 // KlassInfoTable is a bucket hash table that
 43 // maps Klass*s to extra information:
 44 //    instance count and instance word size.
 45 //
 46 // A KlassInfoBucket is the head of a link list
 47 // of KlassInfoEntry's
 48 //
 49 // KlassInfoHisto is a growable array of pointers
 50 // to KlassInfoEntry's and is used to sort
 51 // the entries.
 52 
 53 class KlassInfoEntry: public CHeapObj<mtInternal> {
 54  private:
 55   KlassInfoEntry* _next;
 56   Klass*          _klass;
 57   uint64_t        _instance_count;
 58   size_t          _instance_words;
 59   int64_t         _index;
 60   bool            _do_print; // True if we should print this class when printing the class hierarchy.
 61   GrowableArray<KlassInfoEntry*>* _subclasses;
 62 
 63  public:
 64   KlassInfoEntry(Klass* k, KlassInfoEntry* next) :
 65     _next(next), _klass(k), _instance_count(0), _instance_words(0), _index(-1),
 66     _do_print(false), _subclasses(nullptr)
 67   {}
 68   ~KlassInfoEntry();
 69   KlassInfoEntry* next() const   { return _next; }
 70   bool is_equal(const Klass* k)  { return k == _klass; }
 71   Klass* klass()  const          { return _klass; }
 72   uint64_t count()    const      { return _instance_count; }
 73   void set_count(uint64_t ct)    { _instance_count = ct; }
 74   size_t words()  const          { return _instance_words; }
 75   void set_words(size_t wds)     { _instance_words = wds; }
 76   void set_index(int64_t index)  { _index = index; }
 77   int64_t index()    const       { return _index; }
 78   GrowableArray<KlassInfoEntry*>* subclasses() const { return _subclasses; }
 79   void add_subclass(KlassInfoEntry* cie);
 80   void set_do_print(bool do_print) { _do_print = do_print; }
 81   bool do_print() const      { return _do_print; }
 82   int compare(KlassInfoEntry* e1, KlassInfoEntry* e2);
 83   void print_on(outputStream* st) const;
 84   const char* name() const;
 85 };
 86 
 87 class KlassInfoClosure : public StackObj {
 88  public:
 89   // Called for each KlassInfoEntry.
 90   virtual void do_cinfo(KlassInfoEntry* cie) = 0;
 91 };
 92 
 93 class KlassInfoBucket: public CHeapObj<mtInternal> {
 94  private:
 95   KlassInfoEntry* _list;
 96   KlassInfoEntry* list()           { return _list; }
 97   void set_list(KlassInfoEntry* l) { _list = l; }
 98  public:
 99   KlassInfoEntry* lookup(Klass* k);
100   void initialize() { _list = nullptr; }
101   void empty();
102   void iterate(KlassInfoClosure* cic);
103 };
104 
105 class KlassInfoTable: public StackObj {
106  private:
107   static const int _num_buckets = 20011;
108   size_t _size_of_instances_in_words;
109 
110   // An aligned reference address (typically the least
111   // address in the metaspace) used for hashing klasses.
112   uintptr_t _ref;
113 
114   KlassInfoBucket* _buckets;
115   uint hash(const Klass* p);
116   KlassInfoEntry* lookup(Klass* k); // allocates if not found!
117 
118   class AllClassesFinder;
119 
120  public:
121   KlassInfoTable(bool add_all_classes);
122   ~KlassInfoTable();
123   bool record_instance(const oop obj);
124   void iterate(KlassInfoClosure* cic);
125   bool allocation_failed() { return _buckets == nullptr; }
126   size_t size_of_instances_in_words() const;
127   bool merge(KlassInfoTable* table);
128   bool merge_entry(const KlassInfoEntry* cie);
129 
130   friend class KlassInfoHisto;
131   friend class KlassHierarchy;
132 };
133 
134 class KlassHierarchy : AllStatic {
135  public:
136   static void print_class_hierarchy(outputStream* st, bool print_interfaces,  bool print_subclasses,
137                                     char* classname);
138 
139  private:
140   static void set_do_print_for_class_hierarchy(KlassInfoEntry* cie, KlassInfoTable* cit,
141                                                bool print_subclasse);
142   static void print_class(outputStream* st, KlassInfoEntry* cie, bool print_subclasses);
143 };
144 
145 class KlassInfoHisto : public StackObj {
146  private:
147   static const int _histo_initial_size = 1000;
148   KlassInfoTable *_cit;
149   GrowableArray<KlassInfoEntry*>* _elements;
150   GrowableArray<KlassInfoEntry*>* elements() const { return _elements; }
151   static int sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2);
152   void print_elements(outputStream* st) const;
153   bool is_selected(const char *col_name);
154 
155   static void print_julong(outputStream* st, int width, julong n) {
156     int num_spaces = width - julong_width(n);
157     if (num_spaces > 0) {
158       st->print("%*s", num_spaces, "");
159     }
160     st->print(JULONG_FORMAT, n);
161   }
162 
163   static int julong_width(julong n) {
164     if (n == 0) {
165       return 1;
166     }
167     int w = 0;
168     while (n > 0) {
169       n /= 10;
170       w += 1;
171     }
172     return w;
173   }
174 
175   static int col_width(julong n, const char *name) {
176     int w = julong_width(n);
177     int min = (int)(strlen(name));
178     if (w < min) {
179         w = min;
180     }
181     // add a leading space for separation.
182     return w + 1;
183   }
184 
185  public:
186   KlassInfoHisto(KlassInfoTable* cit);
187   ~KlassInfoHisto();
188   void add(KlassInfoEntry* cie);
189   void print_histo_on(outputStream* st);
190   void sort();
191 };
192 
193 #endif // INCLUDE_SERVICES
194 
195 // These declarations are needed since the declaration of KlassInfoTable and
196 // KlassInfoClosure are guarded by #if INLCUDE_SERVICES
197 class KlassInfoTable;
198 class KlassInfoClosure;
199 
200 class HeapInspection : public StackObj {
201  public:
202   void heap_inspection(outputStream* st, WorkerThreads* workers) NOT_SERVICES_RETURN;
203   uintx populate_table(KlassInfoTable* cit, BoolObjectClosure* filter, WorkerThreads* workers) NOT_SERVICES_RETURN_(0);
204   static void find_instances_at_safepoint(Klass* k, GrowableArray<oop>* result) NOT_SERVICES_RETURN;
205 };
206 
207 // Parallel heap inspection task. Parallel inspection can fail due to
208 // a native OOM when allocating memory for TL-KlassInfoTable.
209 // _success will be set false on an OOM, and serial inspection tried.
210 class ParHeapInspectTask : public WorkerTask {
211  private:
212   ParallelObjectIterator* _poi;
213   KlassInfoTable* _shared_cit;
214   BoolObjectClosure* _filter;
215   uintx _missed_count;
216   bool _success;
217   Mutex _mutex;
218 
219  public:
220   ParHeapInspectTask(ParallelObjectIterator* poi,
221                      KlassInfoTable* shared_cit,
222                      BoolObjectClosure* filter) :
223       WorkerTask("Iterating heap"),
224       _poi(poi),
225       _shared_cit(shared_cit),
226       _filter(filter),
227       _missed_count(0),
228       _success(true),
229       _mutex(Mutex::nosafepoint, "ParHeapInspectTask_lock") {}
230 
231   uintx missed_count() const {
232     return _missed_count;
233   }
234 
235   bool success() {
236     return _success;
237   }
238 
239   virtual void work(uint worker_id);
240 };
241 
242 #endif // SHARE_MEMORY_HEAPINSPECTION_HPP