2
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
25
#include "precompiled.hpp"
26
#include "memory/allocation.hpp"
27
#include "nmt/memTracker.hpp"
28
#include "nmt/memoryFileTracker.hpp"
29
#include "nmt/nmtCommon.hpp"
30
#include "nmt/nmtNativeCallStackStorage.hpp"
31
#include "nmt/vmatree.hpp"
32
#include "runtime/mutex.hpp"
33
#include "utilities/growableArray.hpp"
34
#include "utilities/nativeCallStack.hpp"
35
#include "utilities/ostream.hpp"
37
MemoryFileTracker* MemoryFileTracker::Instance::_tracker = nullptr;
38
PlatformMutex* MemoryFileTracker::Instance::_mutex = nullptr;
40
MemoryFileTracker::MemoryFileTracker(bool is_detailed_mode)
41
: _stack_storage(is_detailed_mode), _files() {}
43
void MemoryFileTracker::allocate_memory(MemoryFile* file, size_t offset,
44
size_t size, const NativeCallStack& stack,
46
NativeCallStackStorage::StackIndex sidx = _stack_storage.push(stack);
47
VMATree::RegionData regiondata(sidx, flag);
48
VMATree::SummaryDiff diff = file->_tree.commit_mapping(offset, size, regiondata);
49
for (int i = 0; i < mt_number_of_types; i++) {
50
VirtualMemory* summary = file->_summary.by_type(NMTUtil::index_to_flag(i));
51
summary->reserve_memory(diff.flag[i].commit);
52
summary->commit_memory(diff.flag[i].commit);
56
void MemoryFileTracker::free_memory(MemoryFile* file, size_t offset, size_t size) {
57
VMATree::SummaryDiff diff = file->_tree.release_mapping(offset, size);
58
for (int i = 0; i < mt_number_of_types; i++) {
59
VirtualMemory* summary = file->_summary.by_type(NMTUtil::index_to_flag(i));
60
summary->reserve_memory(diff.flag[i].commit);
61
summary->commit_memory(diff.flag[i].commit);
65
void MemoryFileTracker::print_report_on(const MemoryFile* file, outputStream* stream, size_t scale) {
66
assert(MemTracker::tracking_level() == NMT_detail, "must");
68
stream->print_cr("Memory map of %s", file->_descriptive_name);
70
VMATree::TreapNode* prev = nullptr;
72
VMATree::TreapNode* broken_start = nullptr;
73
VMATree::TreapNode* broken_end = nullptr;
75
file->_tree.visit_in_order([&](VMATree::TreapNode* current) {
76
if (prev == nullptr) {
77
// Must be first node.
82
if (broken_start != nullptr && prev->val().out.type() != current->val().in.type()) {
87
if (prev->val().out.type() == VMATree::StateType::Committed) {
88
const VMATree::position& start_addr = prev->key();
89
const VMATree::position& end_addr = current->key();
90
stream->print_cr("[" PTR_FORMAT " - " PTR_FORMAT "] allocated " SIZE_FORMAT "%s" " for %s from",
92
NMTUtil::amount_in_scale(end_addr - start_addr, scale),
93
NMTUtil::scale_name(scale),
94
NMTUtil::flag_to_name(prev->val().out.flag()));
96
streamIndentor si(stream, 4);
97
_stack_storage.get(prev->val().out.stack()).print_on(stream);
104
if (broken_start != nullptr) {
105
tty->print_cr("Broken tree found with first occurrence at nodes %zu, %zu",
106
broken_start->key(), broken_end->key());
107
tty->print_cr("Expected start out to have same type as end in, but was: %s, %s",
108
VMATree::statetype_to_string(broken_start->val().out.type()),
109
VMATree::statetype_to_string(broken_end->val().in.type()));
114
MemoryFileTracker::MemoryFile* MemoryFileTracker::make_file(const char* descriptive_name) {
115
MemoryFile* file_place = new MemoryFile{descriptive_name};
116
_files.push(file_place);
120
void MemoryFileTracker::free_file(MemoryFile* file) {
121
if (file == nullptr) return;
126
const GrowableArrayCHeap<MemoryFileTracker::MemoryFile*, mtNMT>& MemoryFileTracker::files() {
130
bool MemoryFileTracker::Instance::initialize(NMT_TrackingLevel tracking_level) {
131
if (tracking_level == NMT_TrackingLevel::NMT_off) return true;
132
_tracker = static_cast<MemoryFileTracker*>(os::malloc(sizeof(MemoryFileTracker), mtNMT));
133
if (_tracker == nullptr) return false;
134
new (_tracker) MemoryFileTracker(tracking_level == NMT_TrackingLevel::NMT_detail);
135
_mutex = new PlatformMutex();
139
void MemoryFileTracker::Instance::allocate_memory(MemoryFile* file, size_t offset,
140
size_t size, const NativeCallStack& stack,
142
_tracker->allocate_memory(file, offset, size, stack, flag);
145
void MemoryFileTracker::Instance::free_memory(MemoryFile* file, size_t offset, size_t size) {
146
_tracker->free_memory(file, offset, size);
149
MemoryFileTracker::MemoryFile*
150
MemoryFileTracker::Instance::make_file(const char* descriptive_name) {
151
return _tracker->make_file(descriptive_name);
154
void MemoryFileTracker::Instance::free_file(MemoryFileTracker::MemoryFile* file) {
155
return _tracker->free_file(file);
158
void MemoryFileTracker::Instance::print_report_on(const MemoryFile* file,
159
outputStream* stream, size_t scale) {
160
assert(file != nullptr, "must be");
161
assert(stream != nullptr, "must be");
162
_tracker->print_report_on(file, stream, scale);
165
void MemoryFileTracker::Instance::print_all_reports_on(outputStream* stream, size_t scale) {
166
const GrowableArrayCHeap<MemoryFileTracker::MemoryFile*, mtNMT>& files =
167
MemoryFileTracker::Instance::files();
169
stream->print_cr("Memory file details");
171
for (int i = 0; i < files.length(); i++) {
172
MemoryFileTracker::MemoryFile* file = files.at(i);
173
MemoryFileTracker::Instance::print_report_on(file, stream, scale);
177
const GrowableArrayCHeap<MemoryFileTracker::MemoryFile*, mtNMT>& MemoryFileTracker::Instance::files() {
178
return _tracker->files();
181
void MemoryFileTracker::summary_snapshot(VirtualMemorySnapshot* snapshot) const {
182
for (int d = 0; d < _files.length(); d++) {
183
const MemoryFile* file = _files.at(d);
184
for (int i = 0; i < mt_number_of_types; i++) {
185
VirtualMemory* snap = snapshot->by_type(NMTUtil::index_to_flag(i));
186
const VirtualMemory* current = file->_summary.by_type(NMTUtil::index_to_flag(i));
187
// Only account the committed memory.
188
snap->commit_memory(current->committed());
193
void MemoryFileTracker::Instance::summary_snapshot(VirtualMemorySnapshot* snapshot) {
194
_tracker->summary_snapshot(snapshot);
197
MemoryFileTracker::Instance::Locker::Locker() {
198
MemoryFileTracker::Instance::_mutex->lock();
201
MemoryFileTracker::Instance::Locker::~Locker() {
202
MemoryFileTracker::Instance::_mutex->unlock();