8189864: Provide an ascii map to visualize metaspace fragmentation
authorstuefe
Tue, 24 Oct 2017 14:34:14 +0200
changeset 47808 57752bd5d1b4
parent 47807 fa213afbaadb
child 47809 38f816c90f8f
8189864: Provide an ascii map to visualize metaspace fragmentation Reviewed-by: goetz, coleenp
src/hotspot/share/memory/metachunk.cpp
src/hotspot/share/memory/metachunk.hpp
src/hotspot/share/memory/metaspace.cpp
src/hotspot/share/memory/metaspace.hpp
--- a/src/hotspot/share/memory/metachunk.cpp	Tue Nov 07 22:05:44 2017 -0800
+++ b/src/hotspot/share/memory/metachunk.cpp	Tue Oct 24 14:34:14 2017 +0200
@@ -55,8 +55,8 @@
     _container(container)
 {
   _top = initial_top();
+  set_is_tagged_free(false);
 #ifdef ASSERT
-  set_is_tagged_free(false);
   mangle(uninitMetaWordVal);
 #endif
 }
--- a/src/hotspot/share/memory/metachunk.hpp	Tue Nov 07 22:05:44 2017 -0800
+++ b/src/hotspot/share/memory/metachunk.hpp	Tue Oct 24 14:34:14 2017 +0200
@@ -102,7 +102,7 @@
   // Current allocation top.
   MetaWord* _top;
 
-  DEBUG_ONLY(bool _is_tagged_free;)
+  bool _is_tagged_free;
 
   MetaWord* initial_top() const { return (MetaWord*)this + overhead(); }
   MetaWord* top() const         { return _top; }
@@ -138,10 +138,8 @@
   size_t used_word_size() const;
   size_t free_word_size() const;
 
-#ifdef ASSERT
   bool is_tagged_free() { return _is_tagged_free; }
   void set_is_tagged_free(bool v) { _is_tagged_free = v; }
-#endif
 
   bool contains(const void* ptr) { return bottom() <= ptr && ptr < _top; }
 
--- a/src/hotspot/share/memory/metaspace.cpp	Tue Nov 07 22:05:44 2017 -0800
+++ b/src/hotspot/share/memory/metaspace.cpp	Tue Oct 24 14:34:14 2017 +0200
@@ -492,6 +492,7 @@
 #endif
 
   void print_on(outputStream* st) const;
+  void print_map(outputStream* st, bool is_class) const;
 };
 
 #define assert_is_aligned(value, alignment)                  \
@@ -543,6 +544,94 @@
   }
 }
 
+void VirtualSpaceNode::print_map(outputStream* st, bool is_class) const {
+
+  // Format:
+  // <ptr>
+  // <ptr>  . .. .               .  ..
+  //        SSxSSMMMMMMMMMMMMMMMMsssXX
+  //        112114444444444444444
+  // <ptr>  . .. .               .  ..
+  //        SSxSSMMMMMMMMMMMMMMMMsssXX
+  //        112114444444444444444
+
+  if (bottom() == top()) {
+    return;
+  }
+
+  // First line: dividers for every med-chunk-sized interval
+  // Second line: a dot for the start of a chunk
+  // Third line: a letter per chunk type (x,s,m,h), uppercase if in use.
+
+  const size_t spec_chunk_size = is_class ? ClassSpecializedChunk : SpecializedChunk;
+  const size_t small_chunk_size = is_class ? ClassSmallChunk : SmallChunk;
+  const size_t med_chunk_size = is_class ? ClassMediumChunk : MediumChunk;
+
+  int line_len = 100;
+  const size_t section_len = align_up(spec_chunk_size * line_len, med_chunk_size);
+  line_len = (int)(section_len / spec_chunk_size);
+
+  char* line1 = (char*)os::malloc(line_len, mtInternal);
+  char* line2 = (char*)os::malloc(line_len, mtInternal);
+  char* line3 = (char*)os::malloc(line_len, mtInternal);
+  int pos = 0;
+  const MetaWord* p = bottom();
+  const Metachunk* chunk = (const Metachunk*)p;
+  const MetaWord* chunk_end = p + chunk->word_size();
+  while (p < top()) {
+    if (pos == line_len) {
+      pos = 0;
+      st->fill_to(22);
+      st->print_raw(line1, line_len);
+      st->cr();
+      st->fill_to(22);
+      st->print_raw(line2, line_len);
+      st->cr();
+    }
+    if (pos == 0) {
+      st->print(PTR_FORMAT ":", p2i(p));
+    }
+    if (p == chunk_end) {
+      chunk = (Metachunk*)p;
+      chunk_end = p + chunk->word_size();
+    }
+    if (p == (const MetaWord*)chunk) {
+      // chunk starts.
+      line1[pos] = '.';
+    } else {
+      line1[pos] = ' ';
+    }
+    // Line 2: chunk type (x=spec, s=small, m=medium, h=humongous), uppercase if
+    // chunk is in use.
+    const bool chunk_is_free = ((Metachunk*)chunk)->is_tagged_free();
+    if (chunk->word_size() == spec_chunk_size) {
+      line2[pos] = chunk_is_free ? 'x' : 'X';
+    } else if (chunk->word_size() == small_chunk_size) {
+      line2[pos] = chunk_is_free ? 's' : 'S';
+    } else if (chunk->word_size() == med_chunk_size) {
+      line2[pos] = chunk_is_free ? 'm' : 'M';
+   } else if (chunk->word_size() > med_chunk_size) {
+      line2[pos] = chunk_is_free ? 'h' : 'H';
+    } else {
+      ShouldNotReachHere();
+    }
+    p += spec_chunk_size;
+    pos ++;
+  }
+  if (pos > 0) {
+    st->fill_to(22);
+    st->print_raw(line1, pos);
+    st->cr();
+    st->fill_to(22);
+    st->print_raw(line2, pos);
+    st->cr();
+  }
+  os::free(line1);
+  os::free(line2);
+  os::free(line3);
+}
+
+
 #ifdef ASSERT
 uintx VirtualSpaceNode::container_count_slow() {
   uintx count = 0;
@@ -649,6 +738,7 @@
   void purge(ChunkManager* chunk_manager);
 
   void print_on(outputStream* st) const;
+  void print_map(outputStream* st) const;
 
   class VirtualSpaceListIterator : public StackObj {
     VirtualSpaceNode* _virtual_spaces;
@@ -1461,6 +1551,18 @@
   }
 }
 
+void VirtualSpaceList::print_map(outputStream* st) const {
+  VirtualSpaceNode* list = virtual_space_list();
+  VirtualSpaceListIterator iter(list);
+  unsigned i = 0;
+  while (iter.repeat()) {
+    st->print_cr("Node %u:", i);
+    VirtualSpaceNode* node = iter.get_next();
+    node->print_map(st, this->is_class());
+    i ++;
+  }
+}
+
 // MetaspaceGC methods
 
 // VM_CollectForMetadataAllocation is the vm operation used to GC.
@@ -1934,11 +2036,10 @@
   // Remove it from the links to this freelist
   chunk->set_next(NULL);
   chunk->set_prev(NULL);
-#ifdef ASSERT
+
   // Chunk is no longer on any freelist. Setting to false make container_count_slow()
   // work.
   chunk->set_is_tagged_free(false);
-#endif
   chunk->container()->inc_container_count();
 
   slow_locked_verify();
@@ -2006,7 +2107,7 @@
         chunk_size_name(index), p2i(chunk), chunk->word_size());
   }
   chunk->container()->dec_container_count();
-  DEBUG_ONLY(chunk->set_is_tagged_free(true);)
+  chunk->set_is_tagged_free(true);
 
   // Chunk has been added; update counters.
   account_for_added_chunk(chunk);
@@ -2945,9 +3046,9 @@
   size_t free_bytes = free_bytes_slow(mdtype);
   size_t used_and_free = used_bytes + free_bytes +
                            free_chunks_capacity_bytes;
-  out->print_cr("  Chunk accounting: used in chunks " SIZE_FORMAT
+  out->print_cr("  Chunk accounting: (used in chunks " SIZE_FORMAT
              "K + unused in chunks " SIZE_FORMAT "K  + "
-             " capacity in free chunks " SIZE_FORMAT "K = " SIZE_FORMAT
+             " capacity in free chunks " SIZE_FORMAT "K) = " SIZE_FORMAT
              "K  capacity in allocated chunks " SIZE_FORMAT "K",
              used_bytes / K,
              free_bytes / K,
@@ -3211,6 +3312,31 @@
   print_waste(out);
 }
 
+// Prints an ASCII representation of the given space.
+void MetaspaceAux::print_metaspace_map(outputStream* out, Metaspace::MetadataType mdtype) {
+  MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
+  const bool for_class = mdtype == Metaspace::ClassType ? true : false;
+  VirtualSpaceList* const vsl = for_class ? Metaspace::class_space_list() : Metaspace::space_list();
+  if (vsl != NULL) {
+    if (for_class) {
+      if (!Metaspace::using_class_space()) {
+        out->print_cr("No Class Space.");
+        return;
+      }
+      out->print_raw("---- Metaspace Map (Class Space) ----");
+    } else {
+      out->print_raw("---- Metaspace Map (Non-Class Space) ----");
+    }
+    // Print legend:
+    out->cr();
+    out->print_cr("Chunk Types (uppercase chunks are in use): x-specialized, s-small, m-medium, h-humongous.");
+    out->cr();
+    VirtualSpaceList* const vsl = for_class ? Metaspace::class_space_list() : Metaspace::space_list();
+    vsl->print_map(out);
+    out->cr();
+  }
+}
+
 void MetaspaceAux::verify_free_chunks() {
   Metaspace::chunk_manager_metadata()->verify();
   if (Metaspace::using_class_space()) {
@@ -3849,6 +3975,7 @@
     }
     LogStream ls(log.info());
     MetaspaceAux::dump(&ls);
+    MetaspaceAux::print_metaspace_map(&ls, mdtype);
     ChunkManager::print_all_chunkmanagers(&ls);
   }
 
--- a/src/hotspot/share/memory/metaspace.hpp	Tue Nov 07 22:05:44 2017 -0800
+++ b/src/hotspot/share/memory/metaspace.hpp	Tue Oct 24 14:34:14 2017 +0200
@@ -361,6 +361,10 @@
 
   static void print_class_waste(outputStream* out);
   static void print_waste(outputStream* out);
+
+  // Prints an ASCII representation of the given space.
+  static void print_metaspace_map(outputStream* out, Metaspace::MetadataType mdtype);
+
   static void dump(outputStream* out);
   static void verify_free_chunks();
   // Checks that the values returned by allocated_capacity_bytes() and