1 /*
2 * Copyright (c) 2002, 2024, 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/annotations.hpp"
31 #include "oops/objArrayOop.hpp"
32 #include "oops/oop.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 class PrintClassLayout : AllStatic {
194 public:
195 static void print_class_layout(outputStream* st, char* classname);
196 };
197
198 #endif // INCLUDE_SERVICES
199
200 // These declarations are needed since the declaration of KlassInfoTable and
201 // KlassInfoClosure are guarded by #if INLCUDE_SERVICES
202 class KlassInfoTable;
203 class KlassInfoClosure;
204
205 class HeapInspection : public StackObj {
206 public:
207 void heap_inspection(outputStream* st, WorkerThreads* workers) NOT_SERVICES_RETURN;
208 uintx populate_table(KlassInfoTable* cit, BoolObjectClosure* filter, WorkerThreads* workers) NOT_SERVICES_RETURN_(0);
209 static void find_instances_at_safepoint(Klass* k, GrowableArray<oop>* result) NOT_SERVICES_RETURN;
210 };
211
212 // Parallel heap inspection task. Parallel inspection can fail due to
213 // a native OOM when allocating memory for TL-KlassInfoTable.
214 // _success will be set false on an OOM, and serial inspection tried.
215 class ParHeapInspectTask : public WorkerTask {
216 private:
217 ParallelObjectIterator* _poi;
218 KlassInfoTable* _shared_cit;
219 BoolObjectClosure* _filter;
220 uintx _missed_count;
221 bool _success;
222 Mutex _mutex;
223
224 public:
225 ParHeapInspectTask(ParallelObjectIterator* poi,
226 KlassInfoTable* shared_cit,
227 BoolObjectClosure* filter) :
228 WorkerTask("Iterating heap"),
229 _poi(poi),
230 _shared_cit(shared_cit),
231 _filter(filter),
232 _missed_count(0),
233 _success(true),
234 _mutex(Mutex::nosafepoint, "ParHeapInspectTask_lock") {}
235
236 uintx missed_count() const {
237 return _missed_count;
238 }
239
240 bool success() {
241 return _success;
242 }
243
244 virtual void work(uint worker_id);
245 };
246
247 #endif // SHARE_MEMORY_HEAPINSPECTION_HPP
--- EOF ---