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 }