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
|
// 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/memory_pressure/unnecessary_discard_monitor.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
namespace memory_pressure {
namespace {
// Don't expect any unnecessary discard values above 10.
constexpr size_t kUnnecessaryDiscardsExclusiveMax = 11;
} // namespace
UnnecessaryDiscardMonitor::UnnecessaryDiscardMonitor() = default;
UnnecessaryDiscardMonitor::~UnnecessaryDiscardMonitor() = default;
void UnnecessaryDiscardMonitor::OnReclaimTargetBegin(
ReclaimTarget reclaim_target) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Simply ignore if there is no timestamp for the reclaim target.
if (!reclaim_target.origin_time) {
return;
}
base::UmaHistogramMediumTimes(
"Discarding.ReclaimTargetAge",
base::TimeTicks::Now() - *reclaim_target.origin_time);
// If the new reclaim event is younger than the most recent kill event, it
// will have no unnecessary kills and the previous kill events list can be
// cleared.
if (!previous_kill_events_.empty() &&
*reclaim_target.origin_time > previous_kill_events_.back().kill_time) {
previous_kill_events_.clear();
}
// Store the reclaim target for use in identifiying unnecessary kills.
current_reclaim_event_ = reclaim_target;
}
ReclaimTarget UnnecessaryDiscardMonitor::CorrectReclaimTarget(
ReclaimTarget target) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Iterate through all previous kills to identify ones that were finished
// after this reclaim target was created.
for (const auto& kill_event : previous_kill_events_) {
if (target.target_kb == 0) {
break;
}
// If this kill happened after the current reclaim event was calculated,
// the reclaim target should be adjusted.
if (kill_event.kill_time >= target.origin_time) {
if (kill_event.kill_size_kb >= target.target_kb) {
target.target_kb = 0;
} else {
target.target_kb -= kill_event.kill_size_kb;
}
}
}
return target;
}
void UnnecessaryDiscardMonitor::OnReclaimTargetEnd() {
// The end of a reclaim target means that any unnecessary discards from this
// reclaim event can be calculated.
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!current_reclaim_event_) {
return;
}
int64_t adjusted_target_kb =
CorrectReclaimTarget(*current_reclaim_event_).target_kb;
// Now that the reclaim target has been adjusted by any kills that occurred
// after it was calculated, we can check if any of its resultant kills were
// unnecessary.
size_t i = 0;
for (; i < current_reclaim_event_kills_.size() && adjusted_target_kb > 0;
i++) {
adjusted_target_kb -= current_reclaim_event_kills_[i].kill_size_kb;
}
ReportUnnecessaryDiscards(current_reclaim_event_kills_.size() - i);
// Now that the current reclaim event is finished, move its kills onto the
// previous kills list.
previous_kill_events_.reserve(previous_kill_events_.size() +
current_reclaim_event_kills_.size());
std::move(std::begin(current_reclaim_event_kills_),
std::end(current_reclaim_event_kills_),
std::back_inserter(previous_kill_events_));
current_reclaim_event_kills_.clear();
current_reclaim_event_.reset();
}
void UnnecessaryDiscardMonitor::OnDiscard(
uint64_t memory_freed_kb,
base::TimeTicks discard_complete_time) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (current_reclaim_event_) {
// Cache this kill event along with the time it took place.
current_reclaim_event_kills_.emplace_back(memory_freed_kb,
discard_complete_time);
}
}
void UnnecessaryDiscardMonitor::ReportUnnecessaryDiscards(size_t count) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::UmaHistogramExactLinear("Discarding.DiscardsDrivenByStaleSignal", count,
kUnnecessaryDiscardsExclusiveMax);
}
} // namespace memory_pressure
|