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/mutexLocker.hpp" 35 #include "runtime/vmThread.hpp" 36 #include "services/heapObjectStatistics.hpp" 37 #include "utilities/copy.hpp" 38 #include "utilities/globalDefinitions.hpp" 39 #include "utilities/ostream.hpp" 40 41 HeapObjectStatistics* HeapObjectStatistics::_instance = NULL; 42 43 class HeapObjectStatsObjectClosure : public ObjectClosure { 44 private: 45 HeapObjectStatistics* const _stats; 46 public: 47 HeapObjectStatsObjectClosure() : _stats(HeapObjectStatistics::instance()) {} 48 void do_object(oop obj) { 49 _stats->visit_object(obj); 50 } 51 }; 52 53 class VM_HeapObjectStatistics : public VM_Operation { 54 public: 55 VMOp_Type type() const { return VMOp_HeapObjectStatistics; } 56 bool doit_prologue() { 57 Heap_lock->lock(); 58 return true; 59 } 60 61 void doit_epilogue() { 62 Heap_lock->unlock(); 63 } 64 65 void doit() { 66 assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped"); 67 assert(Heap_lock->is_locked(), "should have the Heap_lock"); 68 69 CollectedHeap* heap = Universe::heap(); 70 heap->ensure_parsability(false); 71 72 HeapObjectStatistics* stats = HeapObjectStatistics::instance(); 73 stats->begin_sample(); 74 75 HeapObjectStatsObjectClosure cl; 76 heap->object_iterate(&cl); 77 } 78 }; 79 80 HeapObjectStatisticsTask::HeapObjectStatisticsTask() : PeriodicTask(HeapObjectStatsSamplingInterval) {} 81 82 void HeapObjectStatisticsTask::task() { 83 VM_HeapObjectStatistics vmop; 84 VMThread::execute(&vmop); 85 } 86 87 void HeapObjectStatistics::initialize() { 88 assert(_instance == NULL, "Don't init twice"); 89 if (HeapObjectStats) { 90 _instance = new HeapObjectStatistics(); 91 _instance->start(); 92 } 93 } 94 95 void HeapObjectStatistics::shutdown() { 96 if (HeapObjectStats) { 97 assert(_instance != NULL, "Must be initialized"); 98 LogTarget(Info, heap, stats) lt; 99 if (lt.is_enabled()) { 100 LogStream ls(lt); 101 ResourceMark rm; 102 _instance->print(&ls); 103 } 104 _instance->stop(); 105 delete _instance; 106 _instance = NULL; 107 } 108 } 109 110 HeapObjectStatistics* HeapObjectStatistics::instance() { 111 assert(_instance != NULL, "Must be initialized"); 112 return _instance; 113 } 114 115 void HeapObjectStatistics::increase_counter(uint64_t& counter, uint64_t val) { 116 uint64_t oldval = counter; 117 uint64_t newval = counter + val; 118 if (newval < oldval) { 119 log_warning(heap, stats)("HeapObjectStats counter overflow: resulting statistics will be useless"); 120 } 121 counter = newval; 122 } 123 124 HeapObjectStatistics::HeapObjectStatistics() : 125 _task(), _num_samples(0), _num_objects(0), _num_ihashed(0), _num_locked(0), _lds(0) { } 126 127 void HeapObjectStatistics::start() { 128 _task.enroll(); 129 } 130 131 void HeapObjectStatistics::stop() { 132 _task.disenroll(); 133 } 134 135 void HeapObjectStatistics::begin_sample() { 136 _num_samples++; 137 } 138 139 void HeapObjectStatistics::visit_object(oop obj) { 140 increase_counter(_num_objects); 141 markWord mark = obj->mark(); 142 if (!mark.has_no_hash()) { 143 increase_counter(_num_ihashed); 144 if (mark.age() > 0) { 145 increase_counter(_num_ihashed_moved); 146 } 147 } 148 if (mark.is_locked()) { 149 increase_counter(_num_locked); 150 } 151 #ifdef ASSERT 152 #ifdef _LP64 153 if (!mark.has_displaced_mark_helper()) { 154 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())); 155 } 156 #endif 157 #endif 158 increase_counter(_lds, obj->size()); 159 } 160 161 void HeapObjectStatistics::print(outputStream* out) const { 162 if (!HeapObjectStats) { 163 return; 164 } 165 if (_num_samples == 0 || _num_objects == 0) { 166 return; 167 } 168 169 out->print_cr("Number of samples: " UINT64_FORMAT, _num_samples); 170 out->print_cr("Average number of objects: " UINT64_FORMAT, _num_objects / _num_samples); 171 out->print_cr("Average object size: " UINT64_FORMAT " bytes, %.1f words", (_lds * HeapWordSize) / _num_objects, (float) _lds / _num_objects); 172 out->print_cr("Average number of hashed objects: " UINT64_FORMAT " (%.2f%%)", _num_ihashed / _num_samples, (float) (_num_ihashed * 100.0) / _num_objects); 173 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); 174 out->print_cr("Average number of locked objects: " UINT64_FORMAT " (%.2f%%)", _num_locked / _num_samples, (float) (_num_locked * 100) / _num_objects); 175 out->print_cr("Average LDS: " UINT64_FORMAT " bytes", _lds * HeapWordSize / _num_samples); 176 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); 177 }