blob: 17cd5ee56d1a67cffc3f4f269641abde0e5689c7 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/metrics/pressure/pressure_metrics_reporter.h"
#include <vector>
#include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h"
namespace {
// Histograms names for the pressure metrics.
const char kCPUPressureHistogramName[] = "System.Pressure.CPU";
const char kIOPressureHistogramName[] = "System.Pressure.IO";
const char kMemoryPressureHistogramName[] = "System.Pressure.Memory";
// Paths for the pressure metrics (Pressure Stall Information).
const base::FilePath::CharType kCPUPressureFilePath[] =
FILE_PATH_LITERAL("/proc/pressure/cpu");
const base::FilePath::CharType kIOPressureFilePath[] =
FILE_PATH_LITERAL("/proc/pressure/io");
const base::FilePath::CharType kMemoryPressureFilePath[] =
FILE_PATH_LITERAL("/proc/pressure/memory");
// The time to wait between UMA samples.
constexpr base::TimeDelta kDelayBetweenSamples = base::Minutes(10);
// The time to wait between trace counters.
constexpr base::TimeDelta kDelayBetweenTracingSamples = base::Seconds(1);
// Tracing caterogies to emit the memory pressure related trace events.
const char kTraceCategoryForPressureEvents[] = "resources";
} // anonymous namespace
class PressureMetricsWorker {
public:
PressureMetricsWorker();
~PressureMetricsWorker();
void OnTracingEnabled();
void OnTracingDisabled();
private:
void ReadAndEmitCounters();
void ReadAndEmitUMA();
std::vector<PressureMetrics> pressure_metrics_;
base::RepeatingTimer metrics_sampling_timer_;
base::RepeatingTimer tracing_sampling_timer_;
};
PressureMetricsWorker::PressureMetricsWorker() {
pressure_metrics_.emplace_back(kCPUPressureHistogramName,
base::FilePath(kCPUPressureFilePath));
pressure_metrics_.emplace_back(kIOPressureHistogramName,
base::FilePath(kIOPressureFilePath));
pressure_metrics_.emplace_back(kMemoryPressureHistogramName,
base::FilePath(kMemoryPressureFilePath));
// It is safe to use base::Unretained(this) since the timer is own by this
// class.
metrics_sampling_timer_.Start(
FROM_HERE, kDelayBetweenSamples,
base::BindRepeating(&PressureMetricsWorker::ReadAndEmitUMA,
base::Unretained(this)));
}
PressureMetricsWorker::~PressureMetricsWorker() = default;
void PressureMetricsWorker::OnTracingEnabled() {
const uint8_t* category_enabled = TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
kTraceCategoryForPressureEvents);
if (*category_enabled) {
// It is safe to use base::Unretained(this) since the timer is own by this
// class.
tracing_sampling_timer_.Start(
FROM_HERE, kDelayBetweenTracingSamples,
base::BindRepeating(&PressureMetricsWorker::ReadAndEmitCounters,
base::Unretained(this)));
}
}
void PressureMetricsWorker::OnTracingDisabled() {
tracing_sampling_timer_.Stop();
}
void PressureMetricsWorker::ReadAndEmitCounters() {
for (const auto& metric : pressure_metrics_) {
absl::optional<PressureMetrics::Sample> current_pressure =
metric.CollectCurrentPressure();
if (current_pressure.has_value()) {
metric.EmitCounters(current_pressure.value());
}
}
}
void PressureMetricsWorker::ReadAndEmitUMA() {
for (const auto& metric : pressure_metrics_) {
absl::optional<PressureMetrics::Sample> current_pressure =
metric.CollectCurrentPressure();
if (current_pressure.has_value()) {
metric.ReportToUMA(current_pressure.value());
}
}
}
PressureMetricsReporter::PressureMetricsReporter()
: worker_(base::ThreadPool::CreateSequencedTaskRunner(
{base::TaskPriority::BEST_EFFORT, base::MayBlock(),
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
// It is possible with startup tracing that tracing was enabled before this
// class has register its observer.
base::trace_event::TraceLog* trace_log =
base::trace_event::TraceLog::GetInstance();
if (trace_log->IsEnabled()) {
OnTraceLogEnabled();
}
}
PressureMetricsReporter::~PressureMetricsReporter() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
}
void PressureMetricsReporter::OnTraceLogEnabled() {
worker_.AsyncCall(&PressureMetricsWorker::OnTracingEnabled);
}
void PressureMetricsReporter::OnTraceLogDisabled() {
worker_.AsyncCall(&PressureMetricsWorker::OnTracingDisabled);
}