/* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, SAP and/or its affiliates. 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 "precompiled.hpp" #include "memory/metachunk.hpp" #include "memory/metaspace/metaspaceCommon.hpp" #include "memory/metaspace/metaspaceStatistics.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" namespace metaspace { namespace internals { // FreeChunksStatistics methods FreeChunksStatistics::FreeChunksStatistics() : _num(0), _cap(0) {} void FreeChunksStatistics::reset() { _num = 0; _cap = 0; } void FreeChunksStatistics::add(uintx n, size_t s) { _num += n; _cap += s; } void FreeChunksStatistics::add(const FreeChunksStatistics& other) { _num += other._num; _cap += other._cap; } void FreeChunksStatistics::print_on(outputStream* st, size_t scale) const { st->print(UINTX_FORMAT, _num); st->print(" chunks, total capacity "); print_scaled_words(st, _cap, scale); } // ChunkManagerStatistics methods void ChunkManagerStatistics::reset() { for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { _chunk_stats[i].reset(); } } size_t ChunkManagerStatistics::total_capacity() const { return _chunk_stats[SpecializedIndex].cap() + _chunk_stats[SmallIndex].cap() + _chunk_stats[MediumIndex].cap() + _chunk_stats[HumongousIndex].cap(); } void ChunkManagerStatistics::print_on(outputStream* st, size_t scale) const { FreeChunksStatistics totals; for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { st->cr(); st->print("%12s chunks: ", chunk_size_name(i)); if (_chunk_stats[i].num() > 0) { st->print(UINTX_FORMAT_W(4) ", capacity ", _chunk_stats[i].num()); print_scaled_words(st, _chunk_stats[i].cap(), scale); } else { st->print("(none)"); } totals.add(_chunk_stats[i]); } st->cr(); st->print("%19s: " UINTX_FORMAT_W(4) ", capacity=", "Total", totals.num()); print_scaled_words(st, totals.cap(), scale); st->cr(); } // UsedChunksStatistics methods UsedChunksStatistics::UsedChunksStatistics() : _num(0), _cap(0), _used(0), _free(0), _waste(0), _overhead(0) {} void UsedChunksStatistics::reset() { _num = 0; _cap = _overhead = _used = _free = _waste = 0; } void UsedChunksStatistics::add(const UsedChunksStatistics& other) { _num += other._num; _cap += other._cap; _used += other._used; _free += other._free; _waste += other._waste; _overhead += other._overhead; DEBUG_ONLY(check_sanity()); } void UsedChunksStatistics::print_on(outputStream* st, size_t scale) const { int col = st->position(); st->print(UINTX_FORMAT_W(4) " chunk%s, ", _num, _num != 1 ? "s" : ""); if (_num > 0) { col += 14; st->fill_to(col); print_scaled_words(st, _cap, scale, 5); st->print(" capacity, "); col += 18; st->fill_to(col); print_scaled_words_and_percentage(st, _used, _cap, scale, 5); st->print(" used, "); col += 20; st->fill_to(col); print_scaled_words_and_percentage(st, _free, _cap, scale, 5); st->print(" free, "); col += 20; st->fill_to(col); print_scaled_words_and_percentage(st, _waste, _cap, scale, 5); st->print(" waste, "); col += 20; st->fill_to(col); print_scaled_words_and_percentage(st, _overhead, _cap, scale, 5); st->print(" overhead"); } DEBUG_ONLY(check_sanity()); } #ifdef ASSERT void UsedChunksStatistics::check_sanity() const { assert(_overhead == (Metachunk::overhead() * _num), "Sanity: Overhead."); assert(_cap == _used + _free + _waste + _overhead, "Sanity: Capacity."); } #endif // SpaceManagerStatistics methods SpaceManagerStatistics::SpaceManagerStatistics() { reset(); } void SpaceManagerStatistics::reset() { for (int i = 0; i < NumberOfInUseLists; i ++) { _chunk_stats[i].reset(); _free_blocks_num = 0; _free_blocks_cap_words = 0; } } void SpaceManagerStatistics::add_free_blocks_info(uintx num, size_t cap) { _free_blocks_num += num; _free_blocks_cap_words += cap; } void SpaceManagerStatistics::add(const SpaceManagerStatistics& other) { for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { _chunk_stats[i].add(other._chunk_stats[i]); } _free_blocks_num += other._free_blocks_num; _free_blocks_cap_words += other._free_blocks_cap_words; } // Returns total chunk statistics over all chunk types. UsedChunksStatistics SpaceManagerStatistics::totals() const { UsedChunksStatistics stat; for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { stat.add(_chunk_stats[i]); } return stat; } void SpaceManagerStatistics::print_on(outputStream* st, size_t scale, bool detailed) const { streamIndentor sti(st); if (detailed) { st->cr_indent(); st->print("Usage by chunk type:"); { streamIndentor sti2(st); for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { st->cr_indent(); st->print("%15s: ", chunk_size_name(i)); if (_chunk_stats[i].num() == 0) { st->print(" (none)"); } else { _chunk_stats[i].print_on(st, scale); } } st->cr_indent(); st->print("%15s: ", "-total-"); totals().print_on(st, scale); } if (_free_blocks_num > 0) { st->cr_indent(); st->print("deallocated: " UINTX_FORMAT " blocks with ", _free_blocks_num); print_scaled_words(st, _free_blocks_cap_words, scale); } } else { totals().print_on(st, scale); st->print(", "); st->print("deallocated: " UINTX_FORMAT " blocks with ", _free_blocks_num); print_scaled_words(st, _free_blocks_cap_words, scale); } } // ClassLoaderMetaspaceStatistics methods ClassLoaderMetaspaceStatistics::ClassLoaderMetaspaceStatistics() { reset(); } void ClassLoaderMetaspaceStatistics::reset() { nonclass_sm_stats().reset(); if (Metaspace::using_class_space()) { class_sm_stats().reset(); } } // Returns total space manager statistics for both class and non-class metaspace SpaceManagerStatistics ClassLoaderMetaspaceStatistics::totals() const { SpaceManagerStatistics stats; stats.add(nonclass_sm_stats()); if (Metaspace::using_class_space()) { stats.add(class_sm_stats()); } return stats; } void ClassLoaderMetaspaceStatistics::add(const ClassLoaderMetaspaceStatistics& other) { nonclass_sm_stats().add(other.nonclass_sm_stats()); if (Metaspace::using_class_space()) { class_sm_stats().add(other.class_sm_stats()); } } void ClassLoaderMetaspaceStatistics::print_on(outputStream* st, size_t scale, bool detailed) const { streamIndentor sti(st); st->cr_indent(); if (Metaspace::using_class_space()) { st->print("Non-Class: "); } nonclass_sm_stats().print_on(st, scale, detailed); if (detailed) { st->cr(); } if (Metaspace::using_class_space()) { st->cr_indent(); st->print(" Class: "); class_sm_stats().print_on(st, scale, detailed); if (detailed) { st->cr(); } st->cr_indent(); st->print(" Both: "); totals().print_on(st, scale, detailed); if (detailed) { st->cr(); } } st->cr(); } } // end namespace internals } // end namespace metaspace