blob: 36ecf9454dc23bf5aad53ade49d4695e4bba1ff7 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "partition_alloc/starscan/stats_collector.h"
#include "partition_alloc/partition_alloc_base/time/time.h"
#include "partition_alloc/starscan/logging.h"
#include "partition_alloc/starscan/stats_reporter.h"
namespace partition_alloc::internal {
StatsCollector::StatsCollector(const char* process_name,
size_t quarantine_last_size)
: process_name_(process_name),
quarantine_last_size_(quarantine_last_size) {}
StatsCollector::~StatsCollector() = default;
base::TimeDelta StatsCollector::GetOverallTime() const {
return GetTimeImpl<Context::kMutator>(mutator_trace_events_,
MutatorId::kOverall) +
GetTimeImpl<Context::kScanner>(scanner_trace_events_,
ScannerId::kOverall);
}
void StatsCollector::ReportTracesAndHists(
partition_alloc::StatsReporter& reporter) const {
ReportTracesAndHistsImpl<Context::kMutator>(reporter, mutator_trace_events_);
ReportTracesAndHistsImpl<Context::kScanner>(reporter, scanner_trace_events_);
ReportSurvivalRate(reporter);
}
template <Context context>
base::TimeDelta StatsCollector::GetTimeImpl(
const DeferredTraceEventMap<context>& event_map,
IdType<context> id) const {
base::TimeDelta overall;
for (const auto& tid_and_events : event_map.get_underlying_map_unsafe()) {
const auto& events = tid_and_events.second;
const auto& event = events[static_cast<size_t>(id)];
overall += (event.end_time - event.start_time);
}
return overall;
}
template <Context context>
void StatsCollector::ReportTracesAndHistsImpl(
partition_alloc::StatsReporter& reporter,
const DeferredTraceEventMap<context>& event_map) const {
std::array<base::TimeDelta, static_cast<size_t>(IdType<context>::kNumIds)>
accumulated_events{};
// First, report traces and accumulate each trace scope to report UMA hists.
for (const auto& tid_and_events : event_map.get_underlying_map_unsafe()) {
const internal::base::PlatformThreadId tid = tid_and_events.first;
const auto& events = tid_and_events.second;
PA_DCHECK(accumulated_events.size() == events.size());
for (size_t id = 0; id < events.size(); ++id) {
const auto& event = events[id];
if (event.start_time.is_null()) {
// If start_time is null, the event was never triggered, e.g. safepoint
// bailed out if started at the end of scanning.
PA_DCHECK(event.end_time.is_null());
continue;
}
reporter.ReportTraceEvent(static_cast<IdType<context>>(id), tid,
event.start_time.ToInternalValue(),
event.end_time.ToInternalValue());
accumulated_events[id] += (event.end_time - event.start_time);
}
}
// Report UMA if process_name is set.
if (!process_name_) {
return;
}
for (size_t id = 0; id < accumulated_events.size(); ++id) {
if (accumulated_events[id].is_zero()) {
continue;
}
reporter.ReportStats(ToUMAString(static_cast<IdType<context>>(id)).c_str(),
accumulated_events[id].InMicroseconds());
}
}
void StatsCollector::ReportSurvivalRate(
partition_alloc::StatsReporter& reporter) const {
const double survived_rate =
static_cast<double>(survived_quarantine_size()) / quarantine_last_size_;
reporter.ReportSurvivedQuarantineSize(survived_quarantine_size());
reporter.ReportSurvivedQuarantinePercent(survived_rate);
PA_PCSCAN_VLOG(2) << "quarantine size: " << quarantine_last_size_ << " -> "
<< survived_quarantine_size()
<< ", swept bytes: " << swept_size()
<< ", survival rate: " << survived_rate;
if (discarded_quarantine_size_) {
PA_PCSCAN_VLOG(2) << "discarded quarantine size: "
<< discarded_quarantine_size_;
}
}
template base::TimeDelta StatsCollector::GetTimeImpl(
const DeferredTraceEventMap<Context::kMutator>&,
IdType<Context::kMutator>) const;
template base::TimeDelta StatsCollector::GetTimeImpl(
const DeferredTraceEventMap<Context::kScanner>&,
IdType<Context::kScanner>) const;
template void StatsCollector::ReportTracesAndHistsImpl(
partition_alloc::StatsReporter& reporter,
const DeferredTraceEventMap<Context::kMutator>&) const;
template void StatsCollector::ReportTracesAndHistsImpl(
partition_alloc::StatsReporter& reporter,
const DeferredTraceEventMap<Context::kScanner>&) const;
} // namespace partition_alloc::internal