1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2018 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 #include "precompiled.hpp"
  26 
  27 
  28 #include "memory/metaspace/chunkLevel.hpp"
  29 #include "memory/metaspace/metaspaceCommon.hpp"
  30 #include "memory/metaspace/metaspaceStatistics.hpp"
  31 
  32 #include "utilities/debug.hpp"
  33 #include "utilities/globalDefinitions.hpp"
  34 #include "utilities/ostream.hpp"
  35 
  36 namespace metaspace {
  37 
  38 // ChunkManagerStatistics methods
  39 
  40 ChunkManagerStatistics::ChunkManagerStatistics() {
  41   for (chklvl_t l = chklvl::LOWEST_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
  42     num_chunks[l] = 0;
  43     committed_word_size[l] = 0;
  44   }
  45 }
  46 
  47 size_t ChunkManagerStatistics::total_capacity() const {
  48   size_t cap = 0;
  49   for (chklvl_t l = chklvl::LOWEST_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
  50     cap += num_chunks[l] * chklvl::word_size_for_level(l);
  51   }
  52   return cap;
  53 }
  54 
  55 void ChunkManagerStatistics::print_on(outputStream* st, size_t scale) const {
  56   size_t total_size = 0;
  57   size_t total_committed_size = 0;
  58   for (chklvl_t l = chklvl::LOWEST_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
  59     st->cr();
  60     st->print(SIZE_FORMAT "K chunks: ", (chklvl::word_size_for_level(l) * BytesPerWord) / K);
  61     if (num_chunks[l] > 0) {
  62       const size_t word_size = num_chunks[l] * chklvl::word_size_for_level(l);
  63 
  64       st->print("%4d, capacity=", num_chunks[l]);
  65       print_scaled_words(st, word_size, scale);
  66 
  67       st->print(", committed=");
  68       print_scaled_words_and_percentage(st, committed_word_size[l], word_size, scale);
  69 
  70       total_size += word_size;
  71       total_committed_size += committed_word_size[l];
  72     } else {
  73       st->print("(none)");
  74     }
  75   }
  76   st->cr();
  77   st->print("Total capacity: ");
  78   print_scaled_words(st, total_size, scale);
  79   st->print(", committed: ");
  80   print_scaled_words_and_percentage(st, total_committed_size, total_size, scale);
  81   st->cr();
  82 }
  83 
  84 // UsedChunksStatistics methods
  85 
  86 void UsedChunksStatistics::print_on(outputStream* st, size_t scale) const {
  87   int col = st->position();
  88   st->print("%4d chunk%s, ", num, num != 1 ? "s" : "");
  89   if (num > 0) {
  90     col += 14; st->fill_to(col);
  91 
  92     print_scaled_words(st, cap, scale, 5);
  93     st->print(" capacity, ");
  94 
  95     col += 18; st->fill_to(col);
  96     print_scaled_words_and_percentage(st, used, cap, scale, 5);
  97     st->print(" used, ");
  98 
  99     col += 20; st->fill_to(col);
 100     print_scaled_words_and_percentage(st, free, cap, scale, 5);
 101     st->print(" free, ");
 102 
 103     col += 20; st->fill_to(col);
 104     print_scaled_words_and_percentage(st, waste, cap, scale, 5);
 105     st->print(" waste ");
 106 
 107   }
 108   DEBUG_ONLY(check_sanity());
 109 }
 110 
 111 #ifdef ASSERT
 112 void UsedChunksStatistics::check_sanity() const {
 113   assert(cap == used + free + waste, "Sanity: Capacity.");
 114 }
 115 #endif
 116 
 117 // SpaceManagerStatistics methods
 118 
 119 void SpaceManagerStatistics::add(const SpaceManagerStatistics& other) {
 120   for (chklvl_t l = chklvl::LOWEST_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
 121     chunk_stats[l].add(other.chunk_stats[l]);
 122   }
 123   free_blocks_num += other.free_blocks_num;
 124   free_blocks_word_size += other.free_blocks_word_size;
 125 }
 126 
 127 // Returns total chunk statistics over all chunk types.
 128 UsedChunksStatistics SpaceManagerStatistics::totals() const {
 129   UsedChunksStatistics stat;
 130   for (chklvl_t l = chklvl::LOWEST_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
 131     stat.add(chunk_stats[l]);
 132   }
 133   return stat;
 134 }
 135 
 136 void SpaceManagerStatistics::print_on(outputStream* st, size_t scale,  bool detailed) const {
 137   streamIndentor sti(st);
 138   if (detailed) {
 139     st->cr_indent();
 140     st->print("Usage by chunk level:");
 141     {
 142       streamIndentor sti2(st);
 143       for (chklvl_t l = chklvl::LOWEST_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
 144         st->cr_indent();
 145         st->print(SIZE_FORMAT "k chunks: ", (chklvl::word_size_for_level(l) * BytesPerWord) / K);
 146         if (chunk_stats[l].num == 0) {
 147           st->print(" (none)");
 148         } else {
 149           chunk_stats[l].print_on(st, scale);
 150         }
 151       }
 152 
 153       st->cr_indent();
 154       st->print("%15s: ", "-total-");
 155       totals().print_on(st, scale);
 156     }
 157     if (free_blocks_num > 0) {
 158       st->cr_indent();
 159       st->print("deallocated: " UINTX_FORMAT " blocks with ", free_blocks_num);
 160       print_scaled_words(st, free_blocks_word_size, scale);
 161     }
 162   } else {
 163     totals().print_on(st, scale);
 164     st->print(", ");
 165     st->print("deallocated: " UINTX_FORMAT " blocks with ", free_blocks_num);
 166     print_scaled_words(st, free_blocks_word_size, scale);
 167   }
 168 }
 169 
 170 // ClassLoaderMetaspaceStatistics methods
 171 
 172 // Returns total space manager statistics for both class and non-class metaspace
 173 SpaceManagerStatistics ClassLoaderMetaspaceStatistics::totals() const {
 174   SpaceManagerStatistics stats;
 175   stats.add(sm_stats[ClassType]);
 176   stats.add(sm_stats[NonClassType]);
 177   return stats;
 178 }
 179 
 180 void ClassLoaderMetaspaceStatistics::print_on(outputStream* st, size_t scale, bool detailed) const {
 181   streamIndentor sti(st);
 182   st->cr_indent();
 183   if (Metaspace::using_class_space()) {
 184     st->print("Non-Class: ");
 185   }
 186   sm_stats[NonClassType].print_on(st, scale, detailed);
 187   if (detailed) {
 188     st->cr();
 189   }
 190   if (Metaspace::using_class_space()) {
 191     st->cr_indent();
 192     st->print("    Class: ");
 193     sm_stats[ClassType].print_on(st, scale, detailed);
 194     if (detailed) {
 195       st->cr();
 196     }
 197     st->cr_indent();
 198     st->print("     Both: ");
 199     totals().print_on(st, scale, detailed);
 200     if (detailed) {
 201       st->cr();
 202     }
 203   }
 204   st->cr();
 205 }
 206 
 207 } // end namespace metaspace
 208 
 209 
 210