File: browser_process_snapshot_controller.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 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 (137 lines) | stat: -rw-r--r-- 5,431 bytes parent folder | download | duplicates (5)
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
137
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/heap_profiling/in_process/browser_process_snapshot_controller.h"

#include <memory>
#include <utility>

#include "base/check.h"
#include "base/containers/flat_map.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/rand_util.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "components/heap_profiling/in_process/heap_profiler_controller.h"
#include "components/heap_profiling/in_process/heap_profiler_parameters.h"
#include "components/heap_profiling/in_process/mojom/snapshot_controller.mojom.h"
#include "components/sampling_profiler/process_type.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote_set.h"

namespace heap_profiling {

// static
BrowserProcessSnapshotController*
BrowserProcessSnapshotController::GetInstance() {
  const auto* controller = HeapProfilerController::GetInstance();
  return controller ? controller->GetBrowserProcessSnapshotController()
                    : nullptr;
}

BrowserProcessSnapshotController::BrowserProcessSnapshotController(
    scoped_refptr<base::SequencedTaskRunner> snapshot_task_runner)
    : snapshot_task_runner_(std::move(snapshot_task_runner)) {
  // Label this as the main sequence.
  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);

  // Initialize with all supported process types.
  using RemoteSet = mojo::RemoteSet<mojom::SnapshotController>;
  remotes_by_process_type_.emplace(sampling_profiler::ProfilerProcessType::kGpu,
                                   std::make_unique<RemoteSet>());
  remotes_by_process_type_.emplace(
      sampling_profiler::ProfilerProcessType::kNetworkService,
      std::make_unique<RemoteSet>());
  remotes_by_process_type_.emplace(
      sampling_profiler::ProfilerProcessType::kRenderer,
      std::make_unique<RemoteSet>());
  remotes_by_process_type_.emplace(
      sampling_profiler::ProfilerProcessType::kUtility,
      std::make_unique<RemoteSet>());

  // Now that `remotes_by_process_type_` is initialized all further access
  // should be on the snapshot sequence.
  DETACH_FROM_SEQUENCE(snapshot_sequence_checker_);
}

BrowserProcessSnapshotController::~BrowserProcessSnapshotController() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(snapshot_sequence_checker_);
}

base::WeakPtr<BrowserProcessSnapshotController>
BrowserProcessSnapshotController::GetWeakPtr() {
  return weak_factory_.GetWeakPtr();
}

void BrowserProcessSnapshotController::SetBindRemoteForChildProcessCallback(
    BindRemoteCallback callback) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
  bind_remote_callback_ = std::move(callback);
}

void BrowserProcessSnapshotController::BindRemoteForChildProcess(
    int child_process_id,
    sampling_profiler::ProfilerProcessType child_process_type) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
  mojo::PendingRemote<mojom::SnapshotController> remote;
  bind_remote_callback_.Run(child_process_id,
                            remote.InitWithNewPipeAndPassReceiver());
  snapshot_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(
          &BrowserProcessSnapshotController::StoreRemoteOnSnapshotSequence,
          GetWeakPtr(), std::move(remote), child_process_type));
}

void BrowserProcessSnapshotController::TakeSnapshotsOnSnapshotSequence() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(snapshot_sequence_checker_);
  for (auto& [process_type, remote_set] : remotes_by_process_type_) {
    CHECK(remote_set);
    if (remote_set->empty()) {
      // Avoid division by 0. This won't change any metrics since there are no
      // processes to measure.
      continue;
    }
    const int snapshot_probability_pct =
        GetSnapshotProbabilityForProcess(process_type);
    if (snapshot_probability_pct == 0) {
      // No need to test each process since none will be chosen.
      continue;
    }

    // Choose a random set of processes to snapshot. If randomness is
    // suppressed, choose processes by their index in the set.
    double prob_idx = 0;     // Index for simulating probability.
    size_t process_idx = 0;  // Index of chosen process.
    for (const auto& remote : *remote_set) {
      const double prob = suppress_randomness_for_testing_
                              ? (prob_idx++ / remote_set->size())
                              : base::RandDouble();
      if (prob * 100.0 < snapshot_probability_pct) {
        remote->TakeSnapshot(snapshot_probability_pct, process_idx++);
      } else {
        remote->LogMetricsWithoutSnapshot();
      }
    }
  }
}

void BrowserProcessSnapshotController::SuppressRandomnessForTesting() {
  suppress_randomness_for_testing_ = true;
}

void BrowserProcessSnapshotController::StoreRemoteOnSnapshotSequence(
    mojo::PendingRemote<mojom::SnapshotController> remote,
    sampling_profiler::ProfilerProcessType process_type) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(snapshot_sequence_checker_);
  // at() will CHECK if `process_type` wasn't added in the constructor.
  remotes_by_process_type_.at(process_type)
      ->Add(std::move(remote), snapshot_task_runner_);
}

}  // namespace heap_profiling