1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2018, SAP and/or its affiliates. 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 #include "memory/metachunk.hpp"
  28 #include "memory/metaspace/metaspaceCommon.hpp"
  29 #include "memory/metaspace/metaspaceStatistics.hpp"
  30 #include "utilities/debug.hpp"
  31 #include "utilities/globalDefinitions.hpp"
  32 #include "utilities/ostream.hpp"
  33 
  34 namespace metaspace {
  35 namespace internals {
  36 
  37 // FreeChunksStatistics methods
  38 
  39 FreeChunksStatistics::FreeChunksStatistics()
  40 : _num(0), _cap(0)
  41 {}
  42 
  43 void FreeChunksStatistics::reset() {
  44   _num = 0; _cap = 0;
  45 }
  46 
  47 void FreeChunksStatistics::add(uintx n, size_t s) {
  48   _num += n; _cap += s;
  49 }
  50 
  51 void FreeChunksStatistics::add(const FreeChunksStatistics& other) {
  52   _num += other._num;
  53   _cap += other._cap;
  54 }
  55 
  56 void FreeChunksStatistics::print_on(outputStream* st, size_t scale) const {
  57   st->print(UINTX_FORMAT, _num);
  58   st->print(" chunks, total capacity ");
  59   print_scaled_words(st, _cap, scale);
  60 }
  61 
  62 // ChunkManagerStatistics methods
  63 
  64 void ChunkManagerStatistics::reset() {
  65   for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
  66     _chunk_stats[i].reset();
  67   }
  68 }
  69 
  70 size_t ChunkManagerStatistics::total_capacity() const {
  71   return _chunk_stats[SpecializedIndex].cap() +
  72       _chunk_stats[SmallIndex].cap() +
  73       _chunk_stats[MediumIndex].cap() +
  74       _chunk_stats[HumongousIndex].cap();
  75 }
  76 
  77 void ChunkManagerStatistics::print_on(outputStream* st, size_t scale) const {
  78   FreeChunksStatistics totals;
  79   for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
  80     st->cr();
  81     st->print("%12s chunks: ", chunk_size_name(i));
  82     if (_chunk_stats[i].num() > 0) {
  83       st->print(UINTX_FORMAT_W(4) ", capacity ", _chunk_stats[i].num());
  84       print_scaled_words(st, _chunk_stats[i].cap(), scale);
  85     } else {
  86       st->print("(none)");
  87     }
  88     totals.add(_chunk_stats[i]);
  89   }
  90   st->cr();
  91   st->print("%19s: " UINTX_FORMAT_W(4) ", capacity=", "Total", totals.num());
  92   print_scaled_words(st, totals.cap(), scale);
  93   st->cr();
  94 }
  95 
  96 // UsedChunksStatistics methods
  97 
  98 UsedChunksStatistics::UsedChunksStatistics()
  99 : _num(0), _cap(0), _used(0), _free(0), _waste(0), _overhead(0)
 100 {}
 101 
 102 void UsedChunksStatistics::reset() {
 103   _num = 0;
 104   _cap = _overhead = _used = _free = _waste = 0;
 105 }
 106 
 107 void UsedChunksStatistics::add(const UsedChunksStatistics& other) {
 108   _num += other._num;
 109   _cap += other._cap;
 110   _used += other._used;
 111   _free += other._free;
 112   _waste += other._waste;
 113   _overhead += other._overhead;
 114   DEBUG_ONLY(check_sanity());
 115 }
 116 
 117 void UsedChunksStatistics::print_on(outputStream* st, size_t scale) const {
 118   int col = st->position();
 119   st->print(UINTX_FORMAT_W(4) " chunk%s, ", _num, _num != 1 ? "s" : "");
 120   if (_num > 0) {
 121     col += 14; st->fill_to(col);
 122 
 123     print_scaled_words(st, _cap, scale, 5);
 124     st->print(" capacity, ");
 125 
 126     col += 18; st->fill_to(col);
 127     print_scaled_words_and_percentage(st, _used, _cap, scale, 5);
 128     st->print(" used, ");
 129 
 130     col += 20; st->fill_to(col);
 131     print_scaled_words_and_percentage(st, _free, _cap, scale, 5);
 132     st->print(" free, ");
 133 
 134     col += 20; st->fill_to(col);
 135     print_scaled_words_and_percentage(st, _waste, _cap, scale, 5);
 136     st->print(" waste, ");
 137 
 138     col += 20; st->fill_to(col);
 139     print_scaled_words_and_percentage(st, _overhead, _cap, scale, 5);
 140     st->print(" overhead");
 141   }
 142   DEBUG_ONLY(check_sanity());
 143 }
 144 
 145 #ifdef ASSERT
 146 void UsedChunksStatistics::check_sanity() const {
 147   assert(_overhead == (Metachunk::overhead() * _num), "Sanity: Overhead.");
 148   assert(_cap == _used + _free + _waste + _overhead, "Sanity: Capacity.");
 149 }
 150 #endif
 151 
 152 // SpaceManagerStatistics methods
 153 
 154 SpaceManagerStatistics::SpaceManagerStatistics() { reset(); }
 155 
 156 void SpaceManagerStatistics::reset() {
 157   for (int i = 0; i < NumberOfInUseLists; i ++) {
 158     _chunk_stats[i].reset();
 159     _free_blocks_num = 0; _free_blocks_cap_words = 0;
 160   }
 161 }
 162 
 163 void SpaceManagerStatistics::add_free_blocks_info(uintx num, size_t cap) {
 164   _free_blocks_num += num;
 165   _free_blocks_cap_words += cap;
 166 }
 167 
 168 void SpaceManagerStatistics::add(const SpaceManagerStatistics& other) {
 169   for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
 170     _chunk_stats[i].add(other._chunk_stats[i]);
 171   }
 172   _free_blocks_num += other._free_blocks_num;
 173   _free_blocks_cap_words += other._free_blocks_cap_words;
 174 }
 175 
 176 // Returns total chunk statistics over all chunk types.
 177 UsedChunksStatistics SpaceManagerStatistics::totals() const {
 178   UsedChunksStatistics stat;
 179   for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
 180     stat.add(_chunk_stats[i]);
 181   }
 182   return stat;
 183 }
 184 
 185 void SpaceManagerStatistics::print_on(outputStream* st, size_t scale,  bool detailed) const {
 186   streamIndentor sti(st);
 187   if (detailed) {
 188     st->cr_indent();
 189     st->print("Usage by chunk type:");
 190     {
 191       streamIndentor sti2(st);
 192       for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
 193         st->cr_indent();
 194         st->print("%15s: ", chunk_size_name(i));
 195         if (_chunk_stats[i].num() == 0) {
 196           st->print(" (none)");
 197         } else {
 198           _chunk_stats[i].print_on(st, scale);
 199         }
 200       }
 201 
 202       st->cr_indent();
 203       st->print("%15s: ", "-total-");
 204       totals().print_on(st, scale);
 205     }
 206     if (_free_blocks_num > 0) {
 207       st->cr_indent();
 208       st->print("deallocated: " UINTX_FORMAT " blocks with ", _free_blocks_num);
 209       print_scaled_words(st, _free_blocks_cap_words, scale);
 210     }
 211   } else {
 212     totals().print_on(st, scale);
 213     st->print(", ");
 214     st->print("deallocated: " UINTX_FORMAT " blocks with ", _free_blocks_num);
 215     print_scaled_words(st, _free_blocks_cap_words, scale);
 216   }
 217 }
 218 
 219 // ClassLoaderMetaspaceStatistics methods
 220 
 221 ClassLoaderMetaspaceStatistics::ClassLoaderMetaspaceStatistics() { reset(); }
 222 
 223 void ClassLoaderMetaspaceStatistics::reset() {
 224   nonclass_sm_stats().reset();
 225   if (Metaspace::using_class_space()) {
 226     class_sm_stats().reset();
 227   }
 228 }
 229 
 230 // Returns total space manager statistics for both class and non-class metaspace
 231 SpaceManagerStatistics ClassLoaderMetaspaceStatistics::totals() const {
 232   SpaceManagerStatistics stats;
 233   stats.add(nonclass_sm_stats());
 234   if (Metaspace::using_class_space()) {
 235     stats.add(class_sm_stats());
 236   }
 237   return stats;
 238 }
 239 
 240 void ClassLoaderMetaspaceStatistics::add(const ClassLoaderMetaspaceStatistics& other) {
 241   nonclass_sm_stats().add(other.nonclass_sm_stats());
 242   if (Metaspace::using_class_space()) {
 243     class_sm_stats().add(other.class_sm_stats());
 244   }
 245 }
 246 
 247 void ClassLoaderMetaspaceStatistics::print_on(outputStream* st, size_t scale, bool detailed) const {
 248   streamIndentor sti(st);
 249   st->cr_indent();
 250   if (Metaspace::using_class_space()) {
 251     st->print("Non-Class: ");
 252   }
 253   nonclass_sm_stats().print_on(st, scale, detailed);
 254   if (detailed) {
 255     st->cr();
 256   }
 257   if (Metaspace::using_class_space()) {
 258     st->cr_indent();
 259     st->print("    Class: ");
 260     class_sm_stats().print_on(st, scale, detailed);
 261     if (detailed) {
 262       st->cr();
 263     }
 264     st->cr_indent();
 265     st->print("     Both: ");
 266     totals().print_on(st, scale, detailed);
 267     if (detailed) {
 268       st->cr();
 269     }
 270   }
 271   st->cr();
 272 }
 273 
 274 
 275 } // end namespace internals
 276 } // end namespace metaspace
 277 
 278