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