| /* |
| * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 2018, 2020 SAP SE. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #include "memory/metaspace/metaspaceCommon.hpp" |
| #include "memory/metaspace/metaspaceStatistics.hpp" |
| #include "utilities/debug.hpp" |
| #include "utilities/globalDefinitions.hpp" |
| #include "utilities/ostream.hpp" |
| |
| namespace metaspace { |
| |
| // Returns total word size of all chunks in this manager. |
| void ChunkManagerStats::add(const ChunkManagerStats& other) { |
| for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { |
| _num_chunks[l] += other._num_chunks[l]; |
| _committed_word_size[l] += other._committed_word_size[l]; |
| } |
| } |
| |
| // Returns total word size of all chunks in this manager. |
| size_t ChunkManagerStats::total_word_size() const { |
| size_t s = 0; |
| for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { |
| s += _num_chunks[l] * chunklevel::word_size_for_level(l); |
| } |
| return s; |
| } |
| |
| // Returns total committed word size of all chunks in this manager. |
| size_t ChunkManagerStats::total_committed_word_size() const { |
| size_t s = 0; |
| for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { |
| s += _committed_word_size[l]; |
| } |
| return s; |
| } |
| |
| void ChunkManagerStats::print_on(outputStream* st, size_t scale) const { |
| // Note: used as part of MetaspaceReport so formatting matters. |
| size_t total_size = 0; |
| size_t total_committed_size = 0; |
| for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { |
| st->cr(); |
| chunklevel::print_chunk_size(st, l); |
| st->print(": "); |
| if (_num_chunks[l] > 0) { |
| const size_t word_size = _num_chunks[l] * chunklevel::word_size_for_level(l); |
| |
| st->print("%4d, capacity=", _num_chunks[l]); |
| print_scaled_words(st, word_size, scale); |
| |
| st->print(", committed="); |
| print_scaled_words_and_percentage(st, _committed_word_size[l], word_size, scale); |
| |
| total_size += word_size; |
| total_committed_size += _committed_word_size[l]; |
| } else { |
| st->print("(none)"); |
| } |
| } |
| st->cr(); |
| st->print("Total word size: "); |
| print_scaled_words(st, total_size, scale); |
| st->print(", committed: "); |
| print_scaled_words_and_percentage(st, total_committed_size, total_size, scale); |
| st->cr(); |
| } |
| |
| #ifdef ASSERT |
| void ChunkManagerStats::verify() const { |
| assert(total_committed_word_size() <= total_word_size(), |
| "Sanity"); |
| } |
| #endif |
| |
| void InUseChunkStats::print_on(outputStream* st, size_t scale) const { |
| int col = st->position(); |
| st->print("%4d chunk%s, ", _num, _num != 1 ? "s" : ""); |
| if (_num > 0) { |
| col += 14; st->fill_to(col); |
| |
| print_scaled_words(st, _word_size, scale, 5); |
| st->print(" capacity,"); |
| |
| col += 20; st->fill_to(col); |
| print_scaled_words_and_percentage(st, _committed_words, _word_size, scale, 5); |
| st->print(" committed, "); |
| |
| col += 18; st->fill_to(col); |
| print_scaled_words_and_percentage(st, _used_words, _word_size, scale, 5); |
| st->print(" used, "); |
| |
| col += 20; st->fill_to(col); |
| print_scaled_words_and_percentage(st, _free_words, _word_size, scale, 5); |
| st->print(" free, "); |
| |
| col += 20; st->fill_to(col); |
| print_scaled_words_and_percentage(st, _waste_words, _word_size, scale, 5); |
| st->print(" waste "); |
| |
| } |
| } |
| |
| #ifdef ASSERT |
| void InUseChunkStats::verify() const { |
| assert(_word_size >= _committed_words && |
| _committed_words == _used_words + _free_words + _waste_words, |
| "Sanity: cap %zu, committed %zu, used %zu, free %zu, waste %zu.", |
| _word_size, _committed_words, _used_words, _free_words, _waste_words); |
| } |
| #endif |
| |
| void ArenaStats::add(const ArenaStats& other) { |
| for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { |
| _stats[l].add(other._stats[l]); |
| } |
| _free_blocks_num += other._free_blocks_num; |
| _free_blocks_word_size += other._free_blocks_word_size; |
| } |
| |
| // Returns total chunk statistics over all chunk types. |
| InUseChunkStats ArenaStats::totals() const { |
| InUseChunkStats out; |
| for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { |
| out.add(_stats[l]); |
| } |
| return out; |
| } |
| |
| void ArenaStats::print_on(outputStream* st, size_t scale, bool detailed) const { |
| if (detailed) { |
| StreamIndentor si(st, 2); |
| st->cr(); |
| st->print("Usage by chunk level:"); |
| { |
| StreamIndentor si2(st, 2); |
| for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { |
| st->cr(); |
| chunklevel::print_chunk_size(st, l); |
| st->print(" chunks: "); |
| if (_stats[l]._num == 0) { |
| st->print(" (none)"); |
| } else { |
| _stats[l].print_on(st, scale); |
| } |
| } |
| |
| st->cr(); |
| st->print("%15s: ", "-total-"); |
| totals().print_on(st, scale); |
| } |
| if (_free_blocks_num > 0) { |
| st->cr(); |
| st->print("deallocated: %zu blocks with ", _free_blocks_num); |
| print_scaled_words(st, _free_blocks_word_size, scale); |
| } |
| } else { |
| totals().print_on(st, scale); |
| st->print(", "); |
| st->print("deallocated: %zu blocks with ", _free_blocks_num); |
| print_scaled_words(st, _free_blocks_word_size, scale); |
| } |
| } |
| |
| #ifdef ASSERT |
| void ArenaStats::verify() const { |
| size_t total_used = 0; |
| for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { |
| _stats[l].verify(); |
| total_used += _stats[l]._used_words; |
| } |
| } |
| #endif |
| |
| // Returns total arena statistics for both class and non-class metaspace |
| ArenaStats ClmsStats::totals() const { |
| ArenaStats out; |
| out.add(_arena_stats_nonclass); |
| out.add(_arena_stats_class); |
| return out; |
| } |
| |
| void ClmsStats::print_on(outputStream* st, size_t scale, bool detailed) const { |
| StreamIndentor si(st, 2); |
| st->cr(); |
| if (Metaspace::using_class_space()) { |
| st->print("Non-Class: "); |
| } |
| _arena_stats_nonclass.print_on(st, scale, detailed); |
| if (detailed) { |
| st->cr(); |
| } |
| if (Metaspace::using_class_space()) { |
| st->cr(); |
| st->print(" Class: "); |
| _arena_stats_class.print_on(st, scale, detailed); |
| if (detailed) { |
| st->cr(); |
| } |
| st->cr(); |
| st->print(" Both: "); |
| totals().print_on(st, scale, detailed); |
| if (detailed) { |
| st->cr(); |
| } |
| } |
| st->cr(); |
| } |
| |
| #ifdef ASSERT |
| void ClmsStats::verify() const { |
| _arena_stats_nonclass.verify(); |
| _arena_stats_class.verify(); |
| } |
| #endif |
| |
| } // end namespace metaspace |
| |