jdk/src/hotspot/os/linux/memMapPrinter_linux.cpp
2025-09-19 08:48:35 +00:00

191 lines
7.6 KiB
C++

/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates.
* 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 "nmt/memMapPrinter.hpp"
#include "procMapsParser.hpp"
#include "runtime/os.hpp"
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
#include "utilities/powerOfTwo.hpp"
#include <limits.h>
class ProcSmapsSummary {
unsigned _num_mappings;
size_t _vsize; // combined virtual size
size_t _rss; // combined resident set size
size_t _committed; // combined committed size
size_t _shared; // combined shared size
size_t _swapped_out; // combined amount of swapped-out memory
size_t _hugetlb; // combined amount of memory backed by explicit huge pages
size_t _thp; // combined amount of memory backed by THPs
public:
ProcSmapsSummary() : _num_mappings(0), _vsize(0), _rss(0), _committed(0), _shared(0),
_swapped_out(0), _hugetlb(0), _thp(0) {}
void add_mapping(const ProcSmapsInfo& info) {
_num_mappings++;
_vsize += info.vsize();
_rss += info.rss;
_committed += info.nr ? 0 : info.vsize();
_shared += info.sh ? info.vsize() : 0;
_swapped_out += info.swap;
_hugetlb += info.private_hugetlb + info.shared_hugetlb;
_thp += info.anonhugepages;
}
void print_on(const MappingPrintSession& session) const {
outputStream* st = session.out();
st->print_cr("Number of mappings: %u", _num_mappings);
st->print_cr(" vsize: %zu (" PROPERFMT ")", _vsize, PROPERFMTARGS(_vsize));
st->print_cr(" rss: %zu (" PROPERFMT ")", _rss, PROPERFMTARGS(_rss));
st->print_cr(" committed: %zu (" PROPERFMT ")", _committed, PROPERFMTARGS(_committed));
st->print_cr(" shared: %zu (" PROPERFMT ")", _shared, PROPERFMTARGS(_shared));
st->print_cr(" swapped out: %zu (" PROPERFMT ")", _swapped_out, PROPERFMTARGS(_swapped_out));
st->print_cr(" using thp: %zu (" PROPERFMT ")", _thp, PROPERFMTARGS(_thp));
st->print_cr(" hugetlb: %zu (" PROPERFMT ")", _hugetlb, PROPERFMTARGS(_hugetlb));
}
};
class ProcSmapsPrinter {
const MappingPrintSession& _session;
public:
ProcSmapsPrinter(const MappingPrintSession& session) :
_session(session)
{}
void print_single_mapping(const ProcSmapsInfo& info) const {
outputStream* st = _session.out();
#define INDENT_BY(n) \
if (st->fill_to(n) == 0) { \
st->print(" "); \
}
st->print(PTR_FORMAT "-" PTR_FORMAT, p2i(info.from), p2i(info.to));
INDENT_BY(38);
st->print("%12zu", info.vsize());
INDENT_BY(51);
st->print("%s", info.prot);
INDENT_BY(56);
st->print("%12zu", info.rss);
INDENT_BY(69);
st->print("%12zu", info.private_hugetlb);
INDENT_BY(82);
st->print(EXACTFMT, EXACTFMTARGS(info.kernelpagesize));
{
INDENT_BY(87);
int num_printed = 0;
#define PRINTIF(cond, s) \
if (cond) { \
st->print("%s%s", (num_printed > 0 ? "," : ""), s); \
num_printed++; \
}
PRINTIF(info.sh, "shrd");
PRINTIF(!info.nr, "com");
PRINTIF(info.swap > 0, "swap");
PRINTIF(info.ht, "huge");
PRINTIF(info.anonhugepages > 0, "thp");
PRINTIF(info.thpeligible, "thpel");
PRINTIF(info.hg, "thpad");
PRINTIF(info.nh, "nothp");
if (num_printed == 0) {
st->print("-");
}
#undef PRINTIF
}
INDENT_BY(104);
if (!_session.print_nmt_info_for_region(info.from, info.to)) {
st->print("-");
}
INDENT_BY(142);
st->print_raw(info.filename[0] == '\0' ? "-" : info.filename);
#undef INDENT_BY
st->cr();
}
void print_legend() const {
outputStream* st = _session.out();
st->print_cr("from, to, vsize: address range and size");
st->print_cr("prot: protection");
st->print_cr("rss: resident set size");
st->print_cr("hugetlb: size of private hugetlb pages");
st->print_cr("pgsz: page size");
st->print_cr("notes: mapping information (detail mode only)");
st->print_cr(" shrd: mapping is shared");
st->print_cr(" com: mapping committed (swap space reserved)");
st->print_cr(" swap: mapping partly or completely swapped out");
st->print_cr(" thp: mapping uses THP");
st->print_cr(" thpel: mapping is THP-eligible");
st->print_cr(" thpad: mapping is THP-madvised");
st->print_cr(" nothp: mapping is forbidden to use THP");
st->print_cr(" huge: mapping uses hugetlb pages");
st->print_cr("vm info: VM information (requires NMT)");
{
StreamIndentor si(st, 16);
_session.print_nmt_flag_legend();
}
st->print_cr("file: file mapped, if mapping is not anonymous");
}
void print_header() const {
outputStream* st = _session.out();
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
// 0x0000000414000000-0x0000000453000000 123456789012 rw-p 123456789012 123456789012 16g thp,thpadv STACK-340754-Monitor-Deflation-Thread /shared/tmp.txt
st->print_cr("from to vsize prot rss hugetlb pgsz notes info file");
st->print_cr("========================================================================================================================================================================");
}
};
void MemMapPrinter::pd_print_all_mappings(const MappingPrintSession& session) {
constexpr char filename[] = "/proc/self/smaps";
FILE* f = os::fopen(filename, "r");
if (f == nullptr) {
session.out()->print_cr("Cannot open %s", filename);
return;
}
ProcSmapsPrinter printer(session);
ProcSmapsSummary summary;
outputStream* const st = session.out();
printer.print_legend();
st->cr();
printer.print_header();
ProcSmapsInfo info;
ProcSmapsParser parser(f);
while (parser.parse_next(info)) {
printer.print_single_mapping(info);
summary.add_mapping(info);
}
st->cr();
summary.print_on(session);
st->cr();
::fclose(f);
}