File: tab_footprint_aggregator.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 (184 lines) | stat: -rw-r--r-- 7,113 bytes parent folder | download | duplicates (7)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Copyright 2018 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/tab_footprint_aggregator.h"

#include <limits>
#include <numeric>
#include <utility>

#include "base/containers/contains.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"

using PageId = TabFootprintAggregator::PageId;
using ukm::builders::Memory_TabFootprint;

namespace {

static const uint64_t kInvalidAmount = std::numeric_limits<uint64_t>::max();

// Unfortunately, there's no way to read attributes from |UkmEntryBuilderBase|
// instances so we can't build up counts in-place. We'll use |TabStats| for
// building the counts and copy the results to a |Memory_TabFootprint| to
// report them. See the |Memory_TabFootprint| event definition in ukm.xml for a
// description of each metric; they correspond to the getters of this class.
// Note that this class expects and reports values in terms of kilobytes while
// the ukm event uses megabytes.
class TabStats {
 public:
  uint64_t GetMainFramePmf() const { return main_frame_pmf_; }
  void SetMainFramePmf(uint64_t pmf_kb) { main_frame_pmf_ = pmf_kb; }

  uint64_t GetSubFramePmf() const { return sub_frame_pmf_; }
  void AddSubFramePmf(uint64_t pmf_kb) {
    sub_frame_pmf_ += pmf_kb;
    ++sub_frames_included_;
  }
  void IgnoreSubFrame() { ++sub_frames_excluded_; }

  uint64_t GetSubFramesIncluded() const { return sub_frames_included_; }
  uint64_t GetSubFramesExcluded() const { return sub_frames_excluded_; }

  uint64_t GetTabPmf() const {
    if (sub_frames_excluded_ != 0) {
      return kInvalidAmount;
    }
    if (main_frame_pmf_ == kInvalidAmount) {
      return kInvalidAmount;
    }

    return main_frame_pmf_ + sub_frame_pmf_;
  }

 private:
  uint64_t main_frame_pmf_ = kInvalidAmount;
  uint64_t sub_frame_pmf_ = 0u;
  uint64_t sub_frames_included_ = 0u;
  uint64_t sub_frames_excluded_ = 0u;
};

}  // namespace

TabFootprintAggregator::TabFootprintAggregator() = default;
TabFootprintAggregator::~TabFootprintAggregator() = default;

void TabFootprintAggregator::AssociateMainFrame(ukm::SourceId sid,
                                                base::ProcessId pid,
                                                PageId page_id,
                                                uint64_t pmf_kb) {
  bool did_insert =
      page_to_main_frame_process_.insert(std::make_pair(page_id, pid)).second;
  DCHECK(did_insert) << "there shouldn't be more than one main frame per page.";

  AssociateFrame(sid, pid, page_id, pmf_kb);
}

void TabFootprintAggregator::AssociateSubFrame(ukm::SourceId sid,
                                               base::ProcessId pid,
                                               PageId page_id,
                                               uint64_t pmf_kb) {
  AssociateFrame(sid, pid, page_id, pmf_kb);
}

void TabFootprintAggregator::AssociateFrame(ukm::SourceId sid,
                                            base::ProcessId pid,
                                            PageId page_id,
                                            uint64_t pmf_kb) {
  std::map<PageId, ukm::SourceId>::iterator insert_position;
  bool did_insert;
  std::tie(insert_position, did_insert) =
      page_to_source_id_.insert(std::make_pair(page_id, sid));
  // If there was already a |SourceId| associated to the |PageId|, make sure
  // it's the same |SourceId| as |sid|. This guards against attempts to
  // associate more than one top-level-navigation to a single tab.
  DCHECK(did_insert || insert_position->second == sid)
      << "Can't associate multiple SourceIds to a single PageId.";

  std::vector<PageId>& pages = process_to_pages_[pid];
  DCHECK(!base::Contains(pages, page_id))
      << "Can't duplicate associations between a process and a page.";
  pages.push_back(page_id);

  std::vector<base::ProcessId>& processes = page_to_processes_[page_id];
  DCHECK(!base::Contains(processes, pid))
      << "Can't duplicate associations between a page and a process.";
  processes.push_back(pid);

  process_to_pmf_.insert(std::make_pair(pid, pmf_kb));
}

void TabFootprintAggregator::RecordPmfs(ukm::UkmRecorder* ukm_recorder) const {
  // A map from page identifier (1:1 with tab) to a collection of stats for
  // that page's memory usage. Note that, if a component of a particular
  // TabStats::tab_pmf is invalid, the whole tab_pmf is invalid.
  std::map<PageId, TabStats> page_stats;

  for (const auto& page_procs : page_to_processes_) {
    PageId page_id = page_procs.first;

    TabStats& sink = page_stats[page_id];

    // Set |main_frame_process| to the id of the process that hosts the main
    // frame for |page_id|.
    base::ProcessId main_frame_process = base::kNullProcessId;
    auto page_to_main_frame_process_iterator =
        page_to_main_frame_process_.find(page_id);
    if (page_to_main_frame_process_iterator !=
        page_to_main_frame_process_.end()) {
      main_frame_process = page_to_main_frame_process_iterator->second;
    }

    for (const auto& proc : page_procs.second) {
      if (proc == main_frame_process) {
        // Determine if the process hosting the main frame for |page_id| is only
        // concerned with frames in that tab. If the process hosts frames from
        // any other tab, we can't use the MainFrameProcessPMF.
        const auto& all_tabs_for_proc = process_to_pages_.at(proc);
        if (all_tabs_for_proc.size() == 1) {
          DCHECK_EQ(sink.GetMainFramePmf(), kInvalidAmount)
              << "there can't be more than one process hosting a particular "
                 "frame.";
          sink.SetMainFramePmf(process_to_pmf_.at(proc));
        }
      } else {
        // The SubFrameProcessPMF is viable iff |proc| is associated to
        // |page_id| only.
        const auto& pages = process_to_pages_.at(proc);
        if (pages.size() == 1) {
          DCHECK_EQ(pages.front(), page_id);
          sink.AddSubFramePmf(process_to_pmf_.at(proc));
        } else {
          sink.IgnoreSubFrame();
        }
      }
    }
  }

  for (const auto& page_stat : page_stats) {
    // Note: fields in |Memory_TabFootprint| use MB while our accumulators use
    // KB.
    Memory_TabFootprint sink(page_to_source_id_.at(page_stat.first));

    // If MainFrameProcessPMF has been marked invalid it should be skipped.
    uint64_t main_frame_pmf = page_stat.second.GetMainFramePmf();
    if (main_frame_pmf != kInvalidAmount) {
      sink.SetMainFrameProcessPMF(main_frame_pmf / 1024);
    }

    sink.SetSubFrameProcessPMF_Total(page_stat.second.GetSubFramePmf() / 1024);
    sink.SetSubFrameProcessPMF_Included(
        page_stat.second.GetSubFramesIncluded());
    sink.SetSubFrameProcessPMF_Excluded(
        page_stat.second.GetSubFramesExcluded());

    // If TabPMF has been marked invalid it should be skipped.
    uint64_t tab_pmf = page_stat.second.GetTabPmf();
    if (tab_pmf != kInvalidAmount) {
      sink.SetTabPMF(tab_pmf / 1024);
    }

    sink.Record(ukm_recorder);
  }
}