1 /* 2 * Copyright (c) 2021, Red Hat, Inc. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "gc/shared/collectedHeap.hpp" 27 #include "logging/logStream.hpp" 28 #include "logging/logTag.hpp" 29 #include "memory/allocation.hpp" 30 #include "memory/iterator.hpp" 31 #include "memory/resourceArea.hpp" 32 #include "memory/universe.hpp" 33 #include "oops/oop.inline.hpp" 34 #include "runtime/vmThread.hpp" 35 #include "services/heapObjectStatistics.hpp" 36 #include "utilities/copy.hpp" 37 #include "utilities/globalDefinitions.hpp" 38 #include "utilities/ostream.hpp" 39 40 HeapObjectStatistics* HeapObjectStatistics::_instance = NULL; 41 42 class HeapObjectStatsObjectClosure : public ObjectClosure { 43 private: 44 HeapObjectStatistics* const _stats; 45 public: 46 HeapObjectStatsObjectClosure() : _stats(HeapObjectStatistics::instance()) {} 47 void do_object(oop obj) { 48 _stats->visit_object(obj); 49 } 50 }; 51 52 class VM_HeapObjectStatistics : public VM_Operation { 53 public: 54 VMOp_Type type() const { return VMOp_HeapObjectStatistics; } 55 bool doit_prologue() { 56 Heap_lock->lock(); 57 return true; 58 } 59 60 void doit_epilogue() { 61 Heap_lock->unlock(); 62 } 63 64 void doit() { 65 assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped"); 66 assert(Heap_lock->is_locked(), "should have the Heap_lock"); 67 68 CollectedHeap* heap = Universe::heap(); 69 heap->ensure_parsability(false); 70 71 HeapObjectStatistics* stats = HeapObjectStatistics::instance(); 72 stats->begin_sample(); 73 74 HeapObjectStatsObjectClosure cl; 75 heap->object_iterate(&cl); 76 } 77 }; 78 79 HeapObjectStatisticsTask::HeapObjectStatisticsTask() : PeriodicTask(HeapObjectStatsSamplingInterval) {} 80 81 void HeapObjectStatisticsTask::task() { 82 VM_HeapObjectStatistics vmop; 83 VMThread::execute(&vmop); 84 } 85 86 void HeapObjectStatistics::initialize() { 87 assert(_instance == NULL, "Don't init twice"); 88 if (HeapObjectStats) { 89 _instance = new HeapObjectStatistics(); 90 _instance->start(); 91 } 92 } 93 94 void HeapObjectStatistics::shutdown() { 95 if (HeapObjectStats) { 96 assert(_instance != NULL, "Must be initialized"); 97 LogTarget(Info, heap, stats) lt; 98 if (lt.is_enabled()) { 99 LogStream ls(lt); 100 ResourceMark rm; 101 _instance->print(&ls); 102 } 103 _instance->stop(); 104 delete _instance; 105 _instance = NULL; 106 } 107 } 108 109 HeapObjectStatistics* HeapObjectStatistics::instance() { 110 assert(_instance != NULL, "Must be initialized"); 111 return _instance; 112 } 113 114 void HeapObjectStatistics::increase_counter(uint64_t& counter, uint64_t val) { 115 uint64_t oldval = counter; 116 uint64_t newval = counter + val; 117 if (newval < oldval) { 118 log_warning(heap, stats)("HeapObjectStats counter overflow: resulting statistics will be useless"); 119 } 120 counter = newval; 121 } 122 123 HeapObjectStatistics::HeapObjectStatistics() : 124 _task(), _num_samples(0), _num_objects(0), _num_ihashed(0), _num_locked(0), _lds(0) { } 125 126 void HeapObjectStatistics::start() { 127 _task.enroll(); 128 } 129 130 void HeapObjectStatistics::stop() { 131 _task.disenroll(); 132 } 133 134 void HeapObjectStatistics::begin_sample() { 135 _num_samples++; 136 } 137 138 void HeapObjectStatistics::visit_object(oop obj) { 139 increase_counter(_num_objects); 140 markWord mark = obj->mark(); 141 if (!mark.has_no_hash()) { 142 increase_counter(_num_ihashed); 143 if (mark.age() > 0) { 144 increase_counter(_num_ihashed_moved); 145 } 146 } 147 if (mark.is_locked()) { 148 increase_counter(_num_locked); 149 } 150 #ifdef ASSERT 151 #ifdef _LP64 152 if (!mark.has_displaced_mark_helper()) { 153 assert(mark.narrow_klass() == CompressedKlassPointers::encode(obj->klass_or_null()), "upper 32 mark bits must be narrow klass: mark: " INTPTR_FORMAT ", compressed-klass: " INTPTR_FORMAT, (intptr_t)mark.narrow_klass(), (intptr_t)CompressedKlassPointers::encode(obj->klass_or_null())); 154 } 155 #endif 156 #endif 157 increase_counter(_lds, obj->size()); 158 } 159 160 void HeapObjectStatistics::print(outputStream* out) const { 161 if (!HeapObjectStats) { 162 return; 163 } 164 if (_num_samples == 0 || _num_objects == 0) { 165 return; 166 } 167 168 out->print_cr("Number of samples: " UINT64_FORMAT, _num_samples); 169 out->print_cr("Average number of objects: " UINT64_FORMAT, _num_objects / _num_samples); 170 out->print_cr("Average object size: " UINT64_FORMAT " bytes, %.1f words", (_lds * HeapWordSize) / _num_objects, (float) _lds / _num_objects); 171 out->print_cr("Average number of hashed objects: " UINT64_FORMAT " (%.2f%%)", _num_ihashed / _num_samples, (float) (_num_ihashed * 100.0) / _num_objects); 172 out->print_cr("Average number of moved hashed objects: " UINT64_FORMAT " (%.2f%%)", _num_ihashed_moved / _num_samples, (float) (_num_ihashed_moved * 100.0) / _num_objects); 173 out->print_cr("Average number of locked objects: " UINT64_FORMAT " (%.2f%%)", _num_locked / _num_samples, (float) (_num_locked * 100) / _num_objects); 174 out->print_cr("Average LDS: " UINT64_FORMAT " bytes", _lds * HeapWordSize / _num_samples); 175 out->print_cr("Avg LDS with (assumed) 64bit header: " UINT64_FORMAT " bytes (%.1f%%)", (_lds - _num_objects) * HeapWordSize / _num_samples, ((float) _lds - _num_objects) * 100.0 / _lds); 176 }