blob: d1aab818f423808d54673a662b27cdd5002019c4 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/memory/metrics/summary.h"
#include <unordered_set>
#include <trace/event.h>
namespace memory {
const std::vector<const NameMatch> Summary::kNameMatches = {
{"blob-[0-9a-f]{1,3}", "[blobs]"},
{"thrd_t:0x.*|initial-thread|pthread_t:0x.*", "[stacks]"},
{"data:.*", "[data]"},
{"", "[unnamed]"},
{"scudo:.*", "[scudo]"},
{".*\\.so.*", "[libraries]"}};
Namer::Namer(const std::vector<const NameMatch>& name_matches)
: regex_matches_(name_matches.size()) {
for (const auto& name_match : name_matches) {
regex_matches_.push_back(RegexMatch{std::regex(name_match.regex), name_match.name});
}
}
const std::string& Namer::NameForName(const std::string& name) {
const auto& found_name = name_to_name_.find(name);
if (found_name != name_to_name_.end()) {
return found_name->second;
}
for (const auto& regex_match : regex_matches_) {
if (std::regex_match(name, regex_match.regex)) {
name_to_name_.emplace(name, regex_match.name);
return regex_match.name;
}
}
name_to_name_.emplace(name, name);
return name;
}
Summary::Summary(const Capture& capture, const std::vector<const NameMatch>& name_matches)
: time_(capture.time()), kstats_(capture.kmem()) {
Namer namer(name_matches);
std::unordered_set<zx_koid_t> empty_vmos;
Init(capture, &namer, empty_vmos);
}
Summary::Summary(const Capture& capture, Namer* namer)
: time_(capture.time()), kstats_(capture.kmem()) {
std::unordered_set<zx_koid_t> empty_vmos;
Init(capture, namer, empty_vmos);
}
Summary::Summary(const Capture& capture, Namer* namer,
const std::unordered_set<zx_koid_t>& undigested_vmos)
: time_(capture.time()), kstats_(capture.kmem()) {
Init(capture, namer, undigested_vmos);
}
void Summary::Init(const Capture& capture, Namer* namer,
const std::unordered_set<zx_koid_t>& undigested_vmos) {
TRACE_DURATION("memory_metrics", "Summary::Summary");
bool check_undigested = undigested_vmos.size() > 0;
std::unordered_map<zx_koid_t, std::unordered_set<zx_koid_t>> vmo_to_processes(
capture.koid_to_process().size() + 1);
const auto& koid_to_vmo = capture.koid_to_vmo();
for (const auto& pair : capture.koid_to_process()) {
auto process_koid = pair.first;
const auto& process = pair.second;
auto& s = process_summaries_.emplace_back(process_koid, process.name);
for (auto vmo_koid : process.vmos) {
do {
if (!check_undigested || undigested_vmos.find(vmo_koid) != undigested_vmos.end()) {
vmo_to_processes[vmo_koid].insert(process_koid);
s.vmos_.insert(vmo_koid);
}
const auto& vmo = capture.vmo_for_koid(vmo_koid);
// The parent koid could be missing.
if (!vmo.parent_koid || koid_to_vmo.find(vmo.parent_koid) == koid_to_vmo.end()) {
break;
}
vmo_koid = vmo.parent_koid;
} while (true);
}
if (s.vmos_.empty()) {
process_summaries_.pop_back();
}
}
for (auto& s : process_summaries_) {
for (const auto& v : s.vmos_) {
const auto& vmo = capture.vmo_for_koid(v);
const auto committed_bytes = vmo.committed_bytes;
const auto share_count = vmo_to_processes.at(v).size();
auto& name_sizes = s.name_to_sizes_[namer->NameForName(vmo.name)];
name_sizes.total_bytes += committed_bytes;
s.sizes_.total_bytes += committed_bytes;
if (share_count == 1) {
name_sizes.private_bytes += committed_bytes;
s.sizes_.private_bytes += committed_bytes;
name_sizes.scaled_bytes += committed_bytes;
s.sizes_.scaled_bytes += committed_bytes;
} else {
auto scaled_bytes = committed_bytes / share_count;
name_sizes.scaled_bytes += scaled_bytes;
s.sizes_.scaled_bytes += scaled_bytes;
}
}
}
uint64_t vmo_bytes = 0;
for (const auto& pair : capture.koid_to_vmo()) {
vmo_bytes += pair.second.committed_bytes;
}
process_summaries_.emplace_back(kstats_, vmo_bytes);
} // namespace memory
const zx_koid_t ProcessSummary::kKernelKoid = 1;
ProcessSummary::ProcessSummary(const zx_info_kmem_stats_t& kmem, uint64_t vmo_bytes)
: koid_(kKernelKoid), name_("kernel") {
auto kmem_vmo_bytes = kmem.vmo_bytes < vmo_bytes ? 0 : kmem.vmo_bytes - vmo_bytes;
name_to_sizes_.emplace("heap", kmem.total_heap_bytes);
name_to_sizes_.emplace("wired", kmem.wired_bytes);
name_to_sizes_.emplace("mmu", kmem.mmu_overhead_bytes);
name_to_sizes_.emplace("ipc", kmem.ipc_bytes);
name_to_sizes_.emplace("other", kmem.other_bytes);
name_to_sizes_.emplace("vmo", kmem_vmo_bytes);
sizes_.private_bytes = sizes_.scaled_bytes = sizes_.total_bytes =
kmem.wired_bytes + kmem.total_heap_bytes + kmem.mmu_overhead_bytes + kmem.ipc_bytes +
kmem.other_bytes + kmem_vmo_bytes;
}
const Sizes& ProcessSummary::GetSizes(std::string name) const { return name_to_sizes_.at(name); }
} // namespace memory