blob: 5f26d0870a2fb2c00c38e0e2112784cdba5bb9ef [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/page_load_metrics/browser/responsiveness_metrics_normalization.h"
namespace page_load_metrics {
// Budget for each type of user interaction, including keyboard, click or tap,
// drag.
constexpr base::TimeDelta kBudgetForKeyboard = base::Milliseconds(50);
constexpr base::TimeDelta kBudgetForClickOrTap = base::Milliseconds(100);
constexpr base::TimeDelta kBudgetForDrag = base::Milliseconds(100);
namespace {
base::TimeDelta LatencyOverBudget(
const mojom::UserInteractionLatencyPtr& user_interaction) {
base::TimeDelta latency = user_interaction->interaction_latency;
switch (user_interaction->interaction_type) {
case mojom::UserInteractionType::kKeyboard:
return std::max(latency - kBudgetForKeyboard, base::Milliseconds(0));
case mojom::UserInteractionType::kTapOrClick:
return std::max(latency - kBudgetForClickOrTap, base::Milliseconds(0));
case mojom::UserInteractionType::kDrag:
return std::max(latency - kBudgetForDrag, base::Milliseconds(0));
}
NOTREACHED();
return latency;
}
} // namespace
NormalizedInteractionLatencies::NormalizedInteractionLatencies() = default;
NormalizedInteractionLatencies::~NormalizedInteractionLatencies() = default;
NormalizedResponsivenessMetrics::NormalizedResponsivenessMetrics() = default;
NormalizedResponsivenessMetrics::~NormalizedResponsivenessMetrics() = default;
ResponsivenessMetricsNormalization::ResponsivenessMetricsNormalization() =
default;
ResponsivenessMetricsNormalization::~ResponsivenessMetricsNormalization() =
default;
// static
base::TimeDelta ResponsivenessMetricsNormalization::ApproximateHighPercentile(
uint64_t num_interactions,
std::priority_queue<base::TimeDelta,
std::vector<base::TimeDelta>,
std::greater<>> worst_ten_latencies) {
DCHECK(num_interactions);
int index = std::max(0, static_cast<int>(worst_ten_latencies.size()) - 1 -
static_cast<int>(num_interactions /
kHighPercentileUpdateFrequency));
for (; index > 0; index--) {
worst_ten_latencies.pop();
}
return worst_ten_latencies.top();
}
void ResponsivenessMetricsNormalization::AddNewUserInteractionLatencies(
uint64_t num_new_interactions,
const mojom::UserInteractionLatencies& max_event_durations) {
uint64_t last_num_user_interactions =
normalized_responsiveness_metrics_.num_user_interactions;
normalized_responsiveness_metrics_.num_user_interactions +=
num_new_interactions;
DCHECK(max_event_durations.is_user_interaction_latencies() ||
max_event_durations.is_worst_interaction_latency());
// Normalize max event durations.
NormalizeUserInteractionLatencies(
max_event_durations,
normalized_responsiveness_metrics_.normalized_max_event_durations,
last_num_user_interactions,
normalized_responsiveness_metrics_.num_user_interactions);
}
void ResponsivenessMetricsNormalization::NormalizeUserInteractionLatencies(
const mojom::UserInteractionLatencies& user_interaction_latencies,
NormalizedInteractionLatencies& normalized_event_durations,
uint64_t last_num_user_interactions,
uint64_t current_num_user_interactions) {
DCHECK(user_interaction_latencies.is_user_interaction_latencies());
for (const mojom::UserInteractionLatencyPtr& user_interaction :
user_interaction_latencies.get_user_interaction_latencies()) {
normalized_event_durations.worst_latency =
std::max(normalized_event_durations.worst_latency,
user_interaction->interaction_latency);
base::TimeDelta latency_over_budget = LatencyOverBudget(user_interaction);
normalized_event_durations.worst_latency_over_budget =
std::max(normalized_event_durations.worst_latency_over_budget,
latency_over_budget);
normalized_event_durations.sum_of_latency_over_budget +=
latency_over_budget;
normalized_event_durations.worst_ten_latencies.push(
user_interaction->interaction_latency);
if (normalized_event_durations.worst_ten_latencies.size() == 11) {
normalized_event_durations.worst_ten_latencies.pop();
}
normalized_event_durations.worst_ten_latencies_over_budget.push(
latency_over_budget);
if (normalized_event_durations.worst_ten_latencies_over_budget.size() ==
11) {
normalized_event_durations.worst_ten_latencies_over_budget.pop();
}
if (latency_over_budget >=
normalized_event_durations.high_percentile_latency_over_budget) {
normalized_event_durations.high_percentile_latency_over_budget =
latency_over_budget;
}
}
}
} // namespace page_load_metrics