1 /*
  2  * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2018, 2020 SAP SE. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #include "precompiled.hpp"
 27 #include "cds/cdsConfig.hpp"
 28 #include "classfile/classLoaderData.hpp"
 29 #include "classfile/classLoaderDataGraph.hpp"
 30 #include "memory/metaspace.hpp"
 31 #include "memory/metaspace/chunkHeaderPool.hpp"
 32 #include "memory/metaspace/chunkManager.hpp"
 33 #include "memory/metaspace/internalStats.hpp"
 34 #include "memory/metaspace/metaspaceCommon.hpp"
 35 #include "memory/metaspace/metaspaceReporter.hpp"
 36 #include "memory/metaspace/metaspaceSettings.hpp"
 37 #include "memory/metaspace/metaspaceStatistics.hpp"
 38 #include "memory/metaspace/printCLDMetaspaceInfoClosure.hpp"
 39 #include "memory/metaspace/runningCounters.hpp"
 40 #include "memory/metaspace/virtualSpaceList.hpp"
 41 #include "memory/metaspaceUtils.hpp"
 42 #include "oops/compressedKlass.hpp"
 43 #include "runtime/os.hpp"
 44 
 45 namespace metaspace {
 46 
 47 static const char* describe_spacetype(Metaspace::MetaspaceType st) {
 48   const char* s = nullptr;
 49   switch (st) {
 50     case Metaspace::StandardMetaspaceType: s = "Standard"; break;
 51     case Metaspace::BootMetaspaceType: s = "Boot"; break;
 52     case Metaspace::ClassMirrorHolderMetaspaceType: s = "ClassMirrorHolder"; break;
 53     case Metaspace::ReflectionMetaspaceType: s = "Reflection"; break;
 54     default: ShouldNotReachHere();
 55   }
 56   return s;
 57 }
 58 
 59 static void print_vs(outputStream* out, size_t scale) {
 60   const size_t reserved_nc = RunningCounters::reserved_words_nonclass();
 61   const size_t committed_nc = RunningCounters::committed_words_nonclass();
 62   const int num_nodes_nc = VirtualSpaceList::vslist_nonclass()->num_nodes();
 63 
 64   if (Metaspace::using_class_space()) {
 65     const size_t reserved_c = RunningCounters::reserved_words_class();
 66     const size_t committed_c = RunningCounters::committed_words_class();
 67     const int num_nodes_c = VirtualSpaceList::vslist_class()->num_nodes();
 68 
 69     out->print("  Non-class space:  ");
 70     print_scaled_words(out, reserved_nc, scale, 7);
 71     out->print(" reserved, ");
 72     print_scaled_words_and_percentage(out, committed_nc, reserved_nc, scale, 7);
 73     out->print(" committed, ");
 74     out->print(" %d nodes.", num_nodes_nc);
 75     out->cr();
 76     out->print("      Class space:  ");
 77     print_scaled_words(out, reserved_c, scale, 7);
 78     out->print(" reserved, ");
 79     print_scaled_words_and_percentage(out, committed_c, reserved_c, scale, 7);
 80     out->print(" committed, ");
 81     out->print(" %d nodes.", num_nodes_c);
 82     out->cr();
 83     out->print("             Both:  ");
 84     print_scaled_words(out, reserved_c + reserved_nc, scale, 7);
 85     out->print(" reserved, ");
 86     print_scaled_words_and_percentage(out, committed_c + committed_nc, reserved_c + reserved_nc, scale, 7);
 87     out->print(" committed. ");
 88     out->cr();
 89   } else {
 90     print_scaled_words(out, reserved_nc, scale, 7);
 91     out->print(" reserved, ");
 92     print_scaled_words_and_percentage(out, committed_nc, reserved_nc, scale, 7);
 93     out->print(" committed, ");
 94     out->print(" %d nodes.", num_nodes_nc);
 95     out->cr();
 96   }
 97 }
 98 
 99 static void print_settings(outputStream* out, size_t scale) {
100   out->print("MaxMetaspaceSize: ");
101   if (MaxMetaspaceSize == max_uintx) {
102     out->print("unlimited");
103   } else {
104     print_human_readable_size(out, MaxMetaspaceSize, scale);
105   }
106   out->cr();
107   if (Metaspace::using_class_space()) {
108     out->print("CompressedClassSpaceSize: ");
109     print_human_readable_size(out, CompressedClassSpaceSize, scale);
110   } else {
111     out->print("No class space");
112   }
113   out->cr();
114   out->print("Initial GC threshold: ");
115   print_human_readable_size(out, MetaspaceSize, scale);
116   out->cr();
117   out->print("Current GC threshold: ");
118   print_human_readable_size(out, MetaspaceGC::capacity_until_GC(), scale);
119   out->cr();
120   out->print_cr("CDS: %s", (UseSharedSpaces ? "on" : (CDSConfig::is_dumping_static_archive() ? "dump" : "off")));
121   Settings::print_on(out);
122 #ifdef _LP64
123   CompressedKlassPointers::print_mode(out);
124 #endif
125 }
126 
127 // This will print out a basic metaspace usage report but
128 // unlike print_report() is guaranteed not to lock or to walk the CLDG.
129 void MetaspaceReporter::print_basic_report(outputStream* out, size_t scale) {
130   if (!Metaspace::initialized()) {
131     out->print_cr("Metaspace not yet initialized.");
132     return;
133   }
134   out->cr();
135   out->print_cr("Usage:");
136   if (Metaspace::using_class_space()) {
137     out->print("  Non-class:  ");
138   }
139 
140   // Note: since we want to purely rely on counters, without any locking or walking the CLDG,
141   // for Usage stats (statistics over in-use chunks) all we can print is the
142   // used words. We cannot print committed areas, or free/waste areas, of in-use chunks require
143   // walking.
144   const size_t used_nc = MetaspaceUtils::used_words(Metaspace::NonClassType);
145 
146   print_scaled_words(out, used_nc, scale, 5);
147   out->print(" used.");
148   out->cr();
149   if (Metaspace::using_class_space()) {
150     const size_t used_c = MetaspaceUtils::used_words(Metaspace::ClassType);
151     out->print("      Class:  ");
152     print_scaled_words(out, used_c, scale, 5);
153     out->print(" used.");
154     out->cr();
155     out->print("       Both:  ");
156     const size_t used = used_nc + used_c;
157     print_scaled_words(out, used, scale, 5);
158     out->print(" used.");
159     out->cr();
160   }
161   out->cr();
162   out->print_cr("Virtual space:");
163   print_vs(out, scale);
164   out->cr();
165   out->print_cr("Chunk freelists:");
166   if (Metaspace::using_class_space()) {
167     out->print("   Non-Class:  ");
168   }
169   print_scaled_words(out, ChunkManager::chunkmanager_nonclass()->total_word_size(), scale);
170   out->cr();
171   if (Metaspace::using_class_space()) {
172     out->print("       Class:  ");
173     print_scaled_words(out, ChunkManager::chunkmanager_class()->total_word_size(), scale);
174     out->cr();
175     out->print("        Both:  ");
176     print_scaled_words(out, ChunkManager::chunkmanager_nonclass()->total_word_size() +
177                             ChunkManager::chunkmanager_class()->total_word_size(), scale);
178     out->cr();
179   }
180   out->cr();
181 
182   // Print basic settings
183   print_settings(out, scale);
184   out->cr();
185   out->cr();
186   out->print_cr("Internal statistics:");
187   out->cr();
188   InternalStats::print_on(out);
189   out->cr();
190 }
191 
192 void MetaspaceReporter::print_report(outputStream* out, size_t scale, int flags) {
193   if (!Metaspace::initialized()) {
194     out->print_cr("Metaspace not yet initialized.");
195     return;
196   }
197   const bool print_loaders = (flags & (int)Option::ShowLoaders) > 0;
198   const bool print_classes = (flags & (int)Option::ShowClasses) > 0;
199   const bool print_by_chunktype = (flags & (int)Option::BreakDownByChunkType) > 0;
200   const bool print_by_spacetype = (flags & (int)Option::BreakDownBySpaceType) > 0;
201 
202   // Some report options require walking the class loader data graph.
203   metaspace::PrintCLDMetaspaceInfoClosure cl(out, scale, print_loaders, print_classes, print_by_chunktype);
204   if (print_loaders) {
205     out->cr();
206     out->print_cr("Usage per loader:");
207     out->cr();
208   }
209 
210   ClassLoaderDataGraph::loaded_cld_do(&cl); // collect data and optionally print
211 
212   // Print totals, broken up by space type.
213   if (print_by_spacetype) {
214     out->cr();
215     out->print_cr("Usage per space type:");
216     out->cr();
217     for (int space_type = (int)Metaspace::ZeroMetaspaceType;
218          space_type < (int)Metaspace::MetaspaceTypeCount; space_type++)
219     {
220       uintx num_loaders = cl._num_loaders_by_spacetype[space_type];
221       uintx num_classes = cl._num_classes_by_spacetype[space_type];
222       out->print("%s - " UINTX_FORMAT " %s",
223         describe_spacetype((Metaspace::MetaspaceType)space_type),
224         num_loaders, loaders_plural(num_loaders));
225       if (num_classes > 0) {
226         out->print(", ");
227 
228         print_number_of_classes(out, num_classes, cl._num_classes_shared_by_spacetype[space_type]);
229         out->print(":");
230         cl._stats_by_spacetype[space_type].print_on(out, scale, print_by_chunktype);
231       } else {
232         out->print(".");
233         out->cr();
234       }
235       out->cr();
236     }
237   }
238 
239   // Print totals for in-use data:
240   out->cr();
241   {
242     uintx num_loaders = cl._num_loaders;
243     out->print("Total Usage - " UINTX_FORMAT " %s, ",
244       num_loaders, loaders_plural(num_loaders));
245     print_number_of_classes(out, cl._num_classes, cl._num_classes_shared);
246     out->print(":");
247     cl._stats_total.print_on(out, scale, print_by_chunktype);
248     out->cr();
249   }
250 
251   /////////////////////////////////////////////////
252   // -- Print Virtual space.
253   out->cr();
254   out->print_cr("Virtual space:");
255 
256   print_vs(out, scale);
257 
258   // -- Print VirtualSpaceList details.
259   if ((flags & (int)Option::ShowVSList) > 0) {
260     out->cr();
261     out->print_cr("Virtual space list%s:", Metaspace::using_class_space() ? "s" : "");
262 
263     if (Metaspace::using_class_space()) {
264       out->print_cr("   Non-Class:");
265     }
266     VirtualSpaceList::vslist_nonclass()->print_on(out);
267     out->cr();
268     if (Metaspace::using_class_space()) {
269       out->print_cr("       Class:");
270       VirtualSpaceList::vslist_class()->print_on(out);
271       out->cr();
272     }
273   }
274   out->cr();
275 
276   //////////// Freelists (ChunkManager) section ///////////////////////////
277 
278   out->cr();
279   out->print_cr("Chunk freelist%s:", Metaspace::using_class_space() ? "s" : "");
280 
281   ChunkManagerStats non_class_cm_stat;
282   ChunkManagerStats class_cm_stat;
283   ChunkManagerStats total_cm_stat;
284 
285   ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat);
286   if (Metaspace::using_class_space()) {
287     ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat);
288     ChunkManager::chunkmanager_class()->add_to_statistics(&class_cm_stat);
289     total_cm_stat.add(non_class_cm_stat);
290     total_cm_stat.add(class_cm_stat);
291 
292     out->print_cr("   Non-Class:");
293     non_class_cm_stat.print_on(out, scale);
294     out->cr();
295     out->print_cr("       Class:");
296     class_cm_stat.print_on(out, scale);
297     out->cr();
298     out->print_cr("        Both:");
299     total_cm_stat.print_on(out, scale);
300     out->cr();
301   } else {
302     ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat);
303     non_class_cm_stat.print_on(out, scale);
304     out->cr();
305   }
306 
307   // -- Print Chunkmanager details.
308   if ((flags & (int)Option::ShowChunkFreeList) > 0) {
309     out->cr();
310     out->print_cr("Chunk freelist details:");
311     if (Metaspace::using_class_space()) {
312       out->print_cr("   Non-Class:");
313     }
314     ChunkManager::chunkmanager_nonclass()->print_on(out);
315     out->cr();
316     if (Metaspace::using_class_space()) {
317       out->print_cr("       Class:");
318       ChunkManager::chunkmanager_class()->print_on(out);
319       out->cr();
320     }
321   }
322   out->cr();
323 
324 
325   //////////// Waste section ///////////////////////////
326   // As a convenience, print a summary of common waste.
327   out->cr();
328   out->print("Waste (unused committed space):");
329   // For all wastages, print percentages from total. As total use the total size of memory committed for metaspace.
330   const size_t committed_words = RunningCounters::committed_words();
331 
332   out->print(" (percentages refer to total committed size ");
333   print_scaled_words(out, committed_words, scale);
334   out->print_cr("):");
335 
336   // Print waste for in-use chunks.
337   InUseChunkStats ucs_nonclass = cl._stats_total._arena_stats_nonclass.totals();
338   InUseChunkStats ucs_class = cl._stats_total._arena_stats_class.totals();
339   const size_t waste_in_chunks_in_use = ucs_nonclass._waste_words + ucs_class._waste_words;
340   const size_t free_in_chunks_in_use = ucs_nonclass._free_words + ucs_class._free_words;
341 
342   out->print("        Waste in chunks in use: ");
343   print_scaled_words_and_percentage(out, waste_in_chunks_in_use, committed_words, scale, 6);
344   out->cr();
345   out->print("        Free in chunks in use: ");
346   print_scaled_words_and_percentage(out, free_in_chunks_in_use, committed_words, scale, 6);
347   out->cr();
348 
349   // Print waste in free chunks.
350   const size_t committed_in_free_chunks = total_cm_stat.total_committed_word_size();
351   out->print("                In free chunks: ");
352   print_scaled_words_and_percentage(out, committed_in_free_chunks, committed_words, scale, 6);
353   out->cr();
354 
355   // Print waste in deallocated blocks.
356   const uintx free_blocks_num =
357       cl._stats_total._arena_stats_nonclass._free_blocks_num +
358       cl._stats_total._arena_stats_class._free_blocks_num;
359   const size_t free_blocks_cap_words =
360       cl._stats_total._arena_stats_nonclass._free_blocks_word_size +
361       cl._stats_total._arena_stats_class._free_blocks_word_size;
362   out->print("Deallocated from chunks in use: ");
363   print_scaled_words_and_percentage(out, free_blocks_cap_words, committed_words, scale, 6);
364   out->print(" (" UINTX_FORMAT " blocks)", free_blocks_num);
365   out->cr();
366 
367   // Print total waste.
368   const size_t total_waste =
369       waste_in_chunks_in_use +
370       free_in_chunks_in_use +
371       committed_in_free_chunks +
372       free_blocks_cap_words;
373   out->print("                       -total-: ");
374   print_scaled_words_and_percentage(out, total_waste, committed_words, scale, 6);
375   out->cr();
376 
377   // Also print chunk header pool size.
378   out->cr();
379   out->print("chunk header pool: %u items, ", ChunkHeaderPool::pool()->used());
380   print_scaled_words(out, ChunkHeaderPool::pool()->memory_footprint_words(), scale);
381   out->print(".");
382   out->cr();
383 
384   // Print internal statistics
385   out->cr();
386   out->print_cr("Internal statistics:");
387   out->cr();
388   InternalStats::print_on(out);
389   out->cr();
390 
391   // Print some interesting settings
392   out->cr();
393   out->print_cr("Settings:");
394   print_settings(out, scale);
395 
396   out->cr();
397   out->cr();
398 
399   DEBUG_ONLY(MetaspaceUtils::verify();)
400 } // MetaspaceUtils::print_report()
401 
402 } // namespace metaspace
403