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