241 } |
241 } |
242 |
242 |
243 bool reading() const { return false; } |
243 bool reading() const { return false; } |
244 }; |
244 }; |
245 |
245 |
|
246 // This is for dumping detailed statistics for the allocations |
|
247 // in the shared spaces. |
|
248 class DumpAllocClosure : public Metaspace::AllocRecordClosure { |
|
249 public: |
|
250 |
|
251 // Here's poor man's enum inheritance |
|
252 #define SHAREDSPACE_OBJ_TYPES_DO(f) \ |
|
253 METASPACE_OBJ_TYPES_DO(f) \ |
|
254 f(SymbolHashentry) \ |
|
255 f(SymbolBuckets) \ |
|
256 f(Other) |
|
257 |
|
258 #define SHAREDSPACE_OBJ_TYPE_DECLARE(name) name ## Type, |
|
259 #define SHAREDSPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name; |
|
260 |
|
261 enum Type { |
|
262 // Types are MetaspaceObj::ClassType, MetaspaceObj::SymbolType, etc |
|
263 SHAREDSPACE_OBJ_TYPES_DO(SHAREDSPACE_OBJ_TYPE_DECLARE) |
|
264 _number_of_types |
|
265 }; |
|
266 |
|
267 static const char * type_name(Type type) { |
|
268 switch(type) { |
|
269 SHAREDSPACE_OBJ_TYPES_DO(SHAREDSPACE_OBJ_TYPE_NAME_CASE) |
|
270 default: |
|
271 ShouldNotReachHere(); |
|
272 return NULL; |
|
273 } |
|
274 } |
|
275 |
|
276 public: |
|
277 enum { |
|
278 RO = 0, |
|
279 RW = 1 |
|
280 }; |
|
281 |
|
282 int _counts[2][_number_of_types]; |
|
283 int _bytes [2][_number_of_types]; |
|
284 int _which; |
|
285 |
|
286 DumpAllocClosure() { |
|
287 memset(_counts, 0, sizeof(_counts)); |
|
288 memset(_bytes, 0, sizeof(_bytes)); |
|
289 }; |
|
290 |
|
291 void iterate_metaspace(Metaspace* space, int which) { |
|
292 assert(which == RO || which == RW, "sanity"); |
|
293 _which = which; |
|
294 space->iterate(this); |
|
295 } |
|
296 |
|
297 virtual void doit(address ptr, MetaspaceObj::Type type, int byte_size) { |
|
298 assert(int(type) >= 0 && type < MetaspaceObj::_number_of_types, "sanity"); |
|
299 _counts[_which][type] ++; |
|
300 _bytes [_which][type] += byte_size; |
|
301 } |
|
302 |
|
303 void dump_stats(int ro_all, int rw_all, int md_all, int mc_all); |
|
304 }; |
|
305 |
|
306 void DumpAllocClosure::dump_stats(int ro_all, int rw_all, int md_all, int mc_all) { |
|
307 rw_all += (md_all + mc_all); // md and mc are all mapped Read/Write |
|
308 int other_bytes = md_all + mc_all; |
|
309 |
|
310 // Calculate size of data that was not allocated by Metaspace::allocate() |
|
311 int symbol_count = _counts[RO][MetaspaceObj::SymbolType]; |
|
312 int symhash_bytes = symbol_count * sizeof (HashtableEntry<Symbol*, mtSymbol>); |
|
313 int symbuck_count = SymbolTable::the_table()->table_size(); |
|
314 int symbuck_bytes = symbuck_count * sizeof(HashtableBucket<mtSymbol>); |
|
315 |
|
316 _counts[RW][SymbolHashentryType] = symbol_count; |
|
317 _bytes [RW][SymbolHashentryType] = symhash_bytes; |
|
318 other_bytes -= symhash_bytes; |
|
319 |
|
320 _counts[RW][SymbolBucketsType] = symbuck_count; |
|
321 _bytes [RW][SymbolBucketsType] = symbuck_bytes; |
|
322 other_bytes -= symbuck_bytes; |
|
323 |
|
324 // TODO: count things like dictionary, vtable, etc |
|
325 _bytes[RW][OtherType] = other_bytes; |
|
326 |
|
327 // prevent divide-by-zero |
|
328 if (ro_all < 1) { |
|
329 ro_all = 1; |
|
330 } |
|
331 if (rw_all < 1) { |
|
332 rw_all = 1; |
|
333 } |
|
334 |
|
335 int all_ro_count = 0; |
|
336 int all_ro_bytes = 0; |
|
337 int all_rw_count = 0; |
|
338 int all_rw_bytes = 0; |
|
339 |
|
340 const char *fmt = "%-20s: %8d %10d %5.1f | %8d %10d %5.1f | %8d %10d %5.1f"; |
|
341 const char *sep = "--------------------+---------------------------+---------------------------+--------------------------"; |
|
342 const char *hdr = " ro_cnt ro_bytes % | rw_cnt rw_bytes % | all_cnt all_bytes %"; |
|
343 |
|
344 tty->print_cr("Detailed metadata info (rw includes md and mc):"); |
|
345 tty->print_cr(hdr); |
|
346 tty->print_cr(sep); |
|
347 for (int type = 0; type < int(_number_of_types); type ++) { |
|
348 const char *name = type_name((Type)type); |
|
349 int ro_count = _counts[RO][type]; |
|
350 int ro_bytes = _bytes [RO][type]; |
|
351 int rw_count = _counts[RW][type]; |
|
352 int rw_bytes = _bytes [RW][type]; |
|
353 int count = ro_count + rw_count; |
|
354 int bytes = ro_bytes + rw_bytes; |
|
355 |
|
356 double ro_perc = 100.0 * double(ro_bytes) / double(ro_all); |
|
357 double rw_perc = 100.0 * double(rw_bytes) / double(rw_all); |
|
358 double perc = 100.0 * double(bytes) / double(ro_all + rw_all); |
|
359 |
|
360 tty->print_cr(fmt, name, |
|
361 ro_count, ro_bytes, ro_perc, |
|
362 rw_count, rw_bytes, rw_perc, |
|
363 count, bytes, perc); |
|
364 |
|
365 all_ro_count += ro_count; |
|
366 all_ro_bytes += ro_bytes; |
|
367 all_rw_count += rw_count; |
|
368 all_rw_bytes += rw_bytes; |
|
369 } |
|
370 |
|
371 int all_count = all_ro_count + all_rw_count; |
|
372 int all_bytes = all_ro_bytes + all_rw_bytes; |
|
373 |
|
374 double all_ro_perc = 100.0 * double(all_ro_bytes) / double(ro_all); |
|
375 double all_rw_perc = 100.0 * double(all_rw_bytes) / double(rw_all); |
|
376 double all_perc = 100.0 * double(all_bytes) / double(ro_all + rw_all); |
|
377 |
|
378 tty->print_cr(sep); |
|
379 tty->print_cr(fmt, "Total", |
|
380 all_ro_count, all_ro_bytes, all_ro_perc, |
|
381 all_rw_count, all_rw_bytes, all_rw_perc, |
|
382 all_count, all_bytes, all_perc); |
|
383 |
|
384 assert(all_ro_bytes == ro_all, "everything should have been counted"); |
|
385 assert(all_rw_bytes == rw_all, "everything should have been counted"); |
|
386 } |
246 |
387 |
247 // Populate the shared space. |
388 // Populate the shared space. |
248 |
389 |
249 class VM_PopulateDumpSharedSpace: public VM_Operation { |
390 class VM_PopulateDumpSharedSpace: public VM_Operation { |
250 private: |
391 private: |