File: loading_stats_collector.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (221 lines) | stat: -rw-r--r-- 9,397 bytes parent folder | download | duplicates (4)
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// Copyright 2017 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/predictors/loading_stats_collector.h"

#include <algorithm>
#include <set>
#include <vector>

#include "base/containers/contains.h"
#include "chrome/browser/predictors/loading_data_collector.h"
#include "chrome/browser/predictors/resource_prefetch_predictor.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source.h"

namespace predictors {

namespace {

using RedirectStatus = ResourcePrefetchPredictor::RedirectStatus;

// Returns the number of origins that were correctly predicted.
size_t CountCorrectlyPredictiedOrigins(const PreconnectPrediction& prediction,
                                       const PageRequestSummary& summary,
                                       HintOrigin hint_origin) {
  if (prediction.requests.empty() || summary.origins.empty()) {
    return 0;
  }

  const auto& actual_origins = summary.origins;

  size_t correctly_predicted_count = std::ranges::count_if(
      prediction.requests, [&actual_origins](const PreconnectRequest& request) {
        return actual_origins.find(request.origin) != actual_origins.end();
      });

  return correctly_predicted_count;
}

}  // namespace

LoadingStatsCollector::LoadingStatsCollector(
    ResourcePrefetchPredictor* predictor)
    : predictor_(predictor) {}

LoadingStatsCollector::~LoadingStatsCollector() = default;

void LoadingStatsCollector::RecordPageRequestSummary(
    const PageRequestSummary& summary,
    const std::optional<OptimizationGuidePrediction>&
        optimization_guide_prediction) {
  if (!summary.main_frame_load_complete) {
    return;
  }

  const GURL& initial_url = summary.initial_url;

  ukm::builders::LoadingPredictor builder(summary.ukm_source_id);
  bool recorded_ukm = false;
  size_t ukm_cap = 100;

  PreconnectPrediction preconnect_prediction;
  if (predictor_->PredictPreconnectOrigins(initial_url,
                                           &preconnect_prediction)) {
    size_t correctly_predicted_origins = CountCorrectlyPredictiedOrigins(
        preconnect_prediction, summary, HintOrigin::NAVIGATION);
    if (!preconnect_prediction.requests.empty()) {
      builder.SetLocalPredictionOrigins(
          std::min(ukm_cap, preconnect_prediction.requests.size()));
      builder.SetLocalPredictionCorrectlyPredictedOrigins(
          std::min(ukm_cap, correctly_predicted_origins));
      recorded_ukm = true;
    }
  }
  if (optimization_guide_prediction) {
    builder.SetOptimizationGuidePredictionDecision(
        static_cast<int64_t>(optimization_guide_prediction->decision));
    if (optimization_guide_prediction->optimization_guide_prediction_arrived) {
      builder.SetNavigationStartToOptimizationGuidePredictionArrived(
          (optimization_guide_prediction->optimization_guide_prediction_arrived
               .value() -
           summary.navigation_started)
              .InMilliseconds());
    }
    if (!optimization_guide_prediction->predicted_subresources.empty()) {
      url::Origin main_frame_origin = url::Origin::Create(summary.initial_url);
      size_t cross_origin_predicted_subresources = 0;
      size_t correctly_predicted_subresources = 0;
      size_t correctly_predicted_cross_origin_subresources = 0;
      size_t correctly_predicted_low_priority_subresources = 0;
      size_t correctly_predicted_low_priority_cross_origin_subresources = 0;

      for (const GURL& subresource_url :
           optimization_guide_prediction->predicted_subresources) {
        const bool is_cross_origin =
            !main_frame_origin.IsSameOriginWith(subresource_url);
        const bool is_correctly_predicted =
            base::Contains(summary.subresource_urls, subresource_url);
        const bool is_correctly_predicted_low_priority =
            !is_correctly_predicted &&
            base::Contains(summary.low_priority_subresource_urls,
                           subresource_url);
        if (is_cross_origin) {
          cross_origin_predicted_subresources++;
        }
        if (is_correctly_predicted) {
          correctly_predicted_subresources++;
        }
        if (is_cross_origin && is_correctly_predicted) {
          correctly_predicted_cross_origin_subresources++;
        }
        if (is_correctly_predicted_low_priority) {
          correctly_predicted_low_priority_subresources++;
        }
        if (is_cross_origin && is_correctly_predicted_low_priority) {
          correctly_predicted_low_priority_cross_origin_subresources++;
        }
      }

      builder.SetOptimizationGuidePredictionSubresources(std::min(
          ukm_cap,
          optimization_guide_prediction->predicted_subresources.size()));
      builder.SetOptimizationGuidePredictionSubresources_CrossOrigin(
          std::min(ukm_cap, cross_origin_predicted_subresources));
      builder.SetOptimizationGuidePredictionCorrectlyPredictedSubresources(
          std::min(ukm_cap, correctly_predicted_subresources));
      builder
          .SetOptimizationGuidePredictionCorrectlyPredictedSubresources_CrossOrigin(
              std::min(ukm_cap, correctly_predicted_cross_origin_subresources));
      builder
          .SetOptimizationGuidePredictionCorrectlyPredictedLowPrioritySubresources(
              std::min(ukm_cap, correctly_predicted_low_priority_subresources));
      builder
          .SetOptimizationGuidePredictionCorrectlyPredictedLowPrioritySubresources_CrossOrigin(
              std::min(
                  ukm_cap,
                  correctly_predicted_low_priority_cross_origin_subresources));

      std::set<url::Origin> predicted_origins;
      for (const auto& subresource :
           optimization_guide_prediction->predicted_subresources) {
        url::Origin subresource_origin = url::Origin::Create(subresource);
        if (subresource_origin == main_frame_origin) {
          // Do not count the main frame origin as a predicted origin.
          continue;
        }
        predicted_origins.insert(subresource_origin);
      }
      builder.SetOptimizationGuidePredictionOrigins(
          std::min(ukm_cap, predicted_origins.size()));
      size_t correctly_predicted_origins = std::ranges::count_if(
          predicted_origins, [&summary](const url::Origin& subresource_origin) {
            return base::Contains(summary.origins, subresource_origin);
          });
      builder.SetOptimizationGuidePredictionCorrectlyPredictedOrigins(
          std::min(ukm_cap, correctly_predicted_origins));
      size_t correctly_predicted_low_priority_origins = std::ranges::count_if(
          predicted_origins, [&summary](const url::Origin& subresource_origin) {
            return base::Contains(summary.low_priority_origins,
                                  subresource_origin) &&
                   !base::Contains(summary.origins, subresource_origin);
          });
      builder
          .SetOptimizationGuidePredictionCorrectlyPredictedLowPriorityOrigins(
              std::min(ukm_cap, correctly_predicted_low_priority_origins));
    }
    recorded_ukm = true;
  }
  if (!summary.preconnect_origins.empty()) {
    builder.SetSubresourceOriginPreconnectsInitiated(
        std::min(ukm_cap, summary.preconnect_origins.size()));
    const auto& actual_subresource_origins = summary.origins;
    size_t correctly_predicted_subresource_origins_initiated =
        std::ranges::count_if(
            summary.preconnect_origins,
            [&actual_subresource_origins](
                const url::Origin& subresource_origin) {
              return actual_subresource_origins.find(subresource_origin) !=
                     actual_subresource_origins.end();
            });
    builder.SetCorrectSubresourceOriginPreconnectsInitiated(
        std::min(ukm_cap, correctly_predicted_subresource_origins_initiated));
    recorded_ukm = true;
  }
  if (!summary.prefetch_urls.empty()) {
    builder.SetSubresourcePrefetchesInitiated(
        std::min(ukm_cap, summary.prefetch_urls.size()));
    const auto& actual_subresource_urls = summary.subresource_urls;
    size_t correctly_predicted_subresource_prefetches_initiated =
        std::ranges::count_if(
            summary.prefetch_urls,
            [&actual_subresource_urls](const GURL& subresource_url) {
              return actual_subresource_urls.find(subresource_url) !=
                     actual_subresource_urls.end();
            });
    builder.SetCorrectSubresourcePrefetchesInitiated(std::min(
        ukm_cap, correctly_predicted_subresource_prefetches_initiated));
    recorded_ukm = true;
  }
  if (summary.first_prefetch_initiated) {
    DCHECK(!summary.prefetch_urls.empty());
    builder.SetNavigationStartToFirstSubresourcePrefetchInitiated(
        (summary.first_prefetch_initiated.value() - summary.navigation_started)
            .InMilliseconds());
    recorded_ukm = true;
  }

  if (recorded_ukm) {
    // Only record nav start to commit if we had any predictions.
    if (summary.navigation_committed) {
      builder.SetNavigationStartToNavigationCommit(
          (summary.navigation_committed.value() - summary.navigation_started)
              .InMilliseconds());
    }
    builder.Record(ukm::UkmRecorder::Get());
  }
}

}  // namespace predictors