| /* |
| * 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.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(" 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); |
| } |