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 190 void ArenaStats::verify() const { 191 size_t total_used = 0; 192 for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { 193 _stats[l].verify(); 194 total_used += _stats[l]._used_words; 195 } 196 // Deallocated allocations still count as used 197 assert(total_used >= _free_blocks_word_size, 198 "Sanity"); 199 } 200 #endif 201 202 // Returns total arena statistics for both class and non-class metaspace 203 ArenaStats ClmsStats::totals() const { 204 ArenaStats out; 205 out.add(_arena_stats_nonclass); 206 out.add(_arena_stats_class); 207 return out; 208 } 209 210 void ClmsStats::print_on(outputStream* st, size_t scale, bool detailed) const { 211 streamIndentor sti(st); 212 st->cr_indent(); 213 if (Metaspace::using_class_space()) { 214 st->print("Non-Class: "); 215 } 216 _arena_stats_nonclass.print_on(st, scale, detailed); 217 if (detailed) { 218 st->cr(); 219 } 220 if (Metaspace::using_class_space()) { 221 st->cr_indent(); 222 st->print(" Class: "); 223 _arena_stats_class.print_on(st, scale, detailed); 224 if (detailed) { 225 st->cr(); 226 } 227 st->cr_indent(); 228 st->print(" Both: "); 229 totals().print_on(st, scale, detailed); 230 if (detailed) { 231 st->cr(); 232 } 233 } 234 st->cr(); 235 } 236 237 #ifdef ASSERT 238 void ClmsStats::verify() const { 239 _arena_stats_nonclass.verify(); 240 _arena_stats_class.verify(); 241 } 242 #endif 243 244 } // end namespace metaspace 245