File: pressure_metrics_reporter.cc

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (136 lines) | stat: -rw-r--r-- 4,765 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// 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_) {
    std::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_) {
    std::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);
}