1 /*
  2  * Copyright (c) 2018, 2020, 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 "memory/metaspace/metaspaceCommon.hpp"
 28 #include "memory/metaspace/metaspaceStatistics.hpp"
 29 #include "utilities/debug.hpp"
 30 #include "utilities/globalDefinitions.hpp"
 31 #include "utilities/ostream.hpp"
 32 
 33 namespace metaspace {
 34 
 35 // Returns total word size of all chunks in this manager.
 36 void ChunkManagerStats::add(const ChunkManagerStats& other) {
 37   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
 38     _num_chunks[l] += other._num_chunks[l];
 39     _committed_word_size[l] += other._committed_word_size[l];
 40   }
 41 }
 42 
 43 // Returns total word size of all chunks in this manager.
 44 size_t ChunkManagerStats::total_word_size() const {
 45   size_t s = 0;
 46   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
 47     s += _num_chunks[l] * chunklevel::word_size_for_level(l);
 48   }
 49   return s;
 50 }
 51 
 52 // Returns total committed word size of all chunks in this manager.
 53 size_t ChunkManagerStats::total_committed_word_size() const {
 54   size_t s = 0;
 55   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
 56     s += _committed_word_size[l];
 57   }
 58   return s;
 59 }
 60 
 61 void ChunkManagerStats::print_on(outputStream* st, size_t scale) const {
 62   // Note: used as part of MetaspaceReport so formatting matters.
 63   size_t total_size = 0;
 64   size_t total_committed_size = 0;
 65   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
 66     st->cr();
 67     chunklevel::print_chunk_size(st, l);
 68     st->print(": ");
 69     if (_num_chunks[l] > 0) {
 70       const size_t word_size = _num_chunks[l] * chunklevel::word_size_for_level(l);
 71 
 72       st->print("%4d, capacity=", _num_chunks[l]);
 73       print_scaled_words(st, word_size, scale);
 74 
 75       st->print(", committed=");
 76       print_scaled_words_and_percentage(st, _committed_word_size[l], word_size, scale);
 77 
 78       total_size += word_size;
 79       total_committed_size += _committed_word_size[l];
 80     } else {
 81       st->print("(none)");
 82     }
 83   }
 84   st->cr();
 85   st->print("Total word size: ");
 86   print_scaled_words(st, total_size, scale);
 87   st->print(", committed: ");
 88   print_scaled_words_and_percentage(st, total_committed_size, total_size, scale);
 89   st->cr();
 90 }
 91 
 92 #ifdef ASSERT
 93 void ChunkManagerStats::verify() const {
 94   assert(total_committed_word_size() <= total_word_size(),
 95          "Sanity");
 96 }
 97 #endif
 98 
 99 void InUseChunkStats::print_on(outputStream* st, size_t scale) const {
100   int col = st->position();
101   st->print("%4d chunk%s, ", _num, _num != 1 ? "s" : "");
102   if (_num > 0) {
103     col += 14; st->fill_to(col);
104 
105     print_scaled_words(st, _word_size, scale, 5);
106     st->print(" capacity,");
107 
108     col += 20; st->fill_to(col);
109     print_scaled_words_and_percentage(st, _committed_words, _word_size, scale, 5);
110     st->print(" committed, ");
111 
112     col += 18; st->fill_to(col);
113     print_scaled_words_and_percentage(st, _used_words, _word_size, scale, 5);
114     st->print(" used, ");
115 
116     col += 20; st->fill_to(col);
117     print_scaled_words_and_percentage(st, _free_words, _word_size, scale, 5);
118     st->print(" free, ");
119 
120     col += 20; st->fill_to(col);
121     print_scaled_words_and_percentage(st, _waste_words, _word_size, scale, 5);
122     st->print(" waste ");
123 
124   }
125 }
126 
127 #ifdef ASSERT
128 void InUseChunkStats::verify() const {
129   assert(_word_size >= _committed_words &&
130       _committed_words == _used_words + _free_words + _waste_words,
131          "Sanity: cap " SIZE_FORMAT ", committed " SIZE_FORMAT ", used " SIZE_FORMAT ", free " SIZE_FORMAT ", waste " SIZE_FORMAT ".",
132          _word_size, _committed_words, _used_words, _free_words, _waste_words);
133 }
134 #endif
135 
136 void ArenaStats::add(const ArenaStats& other) {
137   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
138     _stats[l].add(other._stats[l]);
139   }
140   _free_blocks_num += other._free_blocks_num;
141   _free_blocks_word_size += other._free_blocks_word_size;
142 }
143 
144 // Returns total chunk statistics over all chunk types.
145 InUseChunkStats ArenaStats::totals() const {
146   InUseChunkStats out;
147   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
148     out.add(_stats[l]);
149   }
150   return out;
151 }
152 
153 void ArenaStats::print_on(outputStream* st, size_t scale,  bool detailed) const {
154   streamIndentor sti(st);
155   if (detailed) {
156     st->cr_indent();
157     st->print("Usage by chunk level:");
158     {
159       streamIndentor sti2(st);
160       for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
161         st->cr_indent();
162         chunklevel::print_chunk_size(st, l);
163         st->print(" chunks: ");
164         if (_stats[l]._num == 0) {
165           st->print(" (none)");
166         } else {
167           _stats[l].print_on(st, scale);
168         }
169       }
170 
171       st->cr_indent();
172       st->print("%15s: ", "-total-");
173       totals().print_on(st, scale);
174     }
175     if (_free_blocks_num > 0) {
176       st->cr_indent();
177       st->print("deallocated: " UINTX_FORMAT " blocks with ", _free_blocks_num);
178       print_scaled_words(st, _free_blocks_word_size, scale);
179     }
180   } else {
181     totals().print_on(st, scale);
182     st->print(", ");
183     st->print("deallocated: " UINTX_FORMAT " blocks with ", _free_blocks_num);
184     print_scaled_words(st, _free_blocks_word_size, scale);
185   }
186 }
187 
188 #ifdef ASSERT
189 void ArenaStats::verify() const {
190   size_t total_used = 0;
191   for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) {
192     _stats[l].verify();
193     total_used += _stats[l]._used_words;
194   }
195 }
196 #endif
197 
198 // Returns total arena statistics for both class and non-class metaspace
199 ArenaStats ClmsStats::totals() const {
200   ArenaStats out;
201   out.add(_arena_stats_nonclass);
202   out.add(_arena_stats_class);
203   return out;
204 }
205 
206 void ClmsStats::print_on(outputStream* st, size_t scale, bool detailed) const {
207   streamIndentor sti(st);
208   st->cr_indent();
209   if (Metaspace::using_class_space()) {
210     st->print("Non-Class: ");
211   }
212   _arena_stats_nonclass.print_on(st, scale, detailed);
213   if (detailed) {
214     st->cr();
215   }
216   if (Metaspace::using_class_space()) {
217     st->cr_indent();
218     st->print("    Class: ");
219     _arena_stats_class.print_on(st, scale, detailed);
220     if (detailed) {
221       st->cr();
222     }
223     st->cr_indent();
224     st->print("     Both: ");
225     totals().print_on(st, scale, detailed);
226     if (detailed) {
227       st->cr();
228     }
229   }
230   st->cr();
231 }
232 
233 #ifdef ASSERT
234 void ClmsStats::verify() const {
235   _arena_stats_nonclass.verify();
236   _arena_stats_class.verify();
237 }
238 #endif
239 
240 } // end namespace metaspace
241