blob: c43c3be1e245012515cb28bc3cd0c9fc889f6b92 [file] [log] [blame]
// Copyright 2019 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.
#ifndef CHROME_BROWSER_MEMORY_MEMORY_PRESSURE_MONITOR_UTILS_H_
#define CHROME_BROWSER_MEMORY_MEMORY_PRESSURE_MONITOR_UTILS_H_
#include <deque>
#include <utility>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
namespace base {
class TickClock;
}
namespace memory {
namespace internal {
// An observation window consists of a series of samples. Samples in this window
// will have a maximum age (the window length), samples that exceed that age
// will be automatically trimmed when a new one is available.
//
// Concurrent calls to instances of this class aren't allowed.
template <typename T>
class ObservationWindow {
public:
explicit ObservationWindow(const base::TimeDelta window_length);
virtual ~ObservationWindow();
// Function that should be called each time a new sample is available. When a
// new sample gets added the entries that exceeds the age of this window will
// first be removed, and then the new one will be added to it.
void OnSample(const T sample);
// Returns the number of samples in this window.
size_t SampleCount() { return observations_.size(); }
protected:
using Observation = std::pair<const base::TimeTicks, const T>;
// Called each time a sample gets added to the observation window. This gets
// called before inserting the sample into the observation window.
virtual void OnSampleAdded(const T& sample) = 0;
// Called each time a sample gets removed from the observation window. This
// gets called before removing the sample from the observation window.
virtual void OnSampleRemoved(const T& sample) = 0;
const std::deque<Observation>& observations_for_testing() {
return observations_;
}
void set_clock_for_testing(const base::TickClock* clock) { clock_ = clock; }
private:
// The length of the window. Samples older than |base::TimeTicks::Now() -
// window_length_| will automatically be removed from this window when a new
// one gets added.
const base::TimeDelta window_length_;
// The observations, in order of arrival.
std::deque<Observation> observations_;
// Allow for an injectable clock for testing.
const base::TickClock* clock_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(ObservationWindow);
};
} // namespace internal
// Implementation of an observation window that can be used to track the amount
// of free physical memory over time. The user is responsible for providing the
// samples via the |OnSample| method.
class FreeMemoryObservationWindow : public internal::ObservationWindow<int> {
public:
// Configuration of the observation window. The user is responsible for
// providing some appropriate values depending on how it implements the
// memory pressure detector. The values provided below are simple reasonable
// approximations of what value could be used here, they're not based on any
// metric.
struct Config {
// The minimum number of samples to consider that the data in this window is
// meaningful.
const size_t min_sample_count = 4;
// The ratio of samples that have to be below one of the thresholds to
// consider that the amount of free memory is really below this value.
const float sample_ratio_to_be_positive = 0.75;
// Default value for the different thresholds, the users of this class will
// want to provide a more appropriate value here (based on the platform
// specs). The early limit is used to indicate that the memory is getting
// low and that more metrics should probably be tracked. The critical limit
// indicates that the system is low on memory and that performance will
// suffer.
const int low_memory_early_limit_mb = 600;
const int low_memory_critical_limit_mb = 400;
};
FreeMemoryObservationWindow(const base::TimeDelta window_length,
const Config& config);
~FreeMemoryObservationWindow() override;
// Check if the memory is under one of the limits.
bool MemoryIsUnderEarlyLimit();
bool MemoryIsUnderCriticalLimit();
private:
FRIEND_TEST_ALL_PREFIXES(ObservationWindowTest, FreeMemoryObservationWindow);
// internal::ObservationWindow:
void OnSampleAdded(const int& sample) override;
void OnSampleRemoved(const int& sample) override;
bool MemoryIsUnderLimitImpl(size_t sample_under_limit_cnt);
// The current number of samples that are below each threshold.
size_t sample_below_early_limit_count_ = 0;
size_t sample_below_critical_limit_count_ = 0;
Config config_ = {};
DISALLOW_COPY_AND_ASSIGN(FreeMemoryObservationWindow);
};
// Implementation of an observation window that can be used to track the disk
// idle time over time. The user is responsible for providing the samples via
// the |OnSample| method, these samples should represent the percentage of time
// the disk has been idle since the last observation and should have a value in
// the [0.0, 1.0] range.
class DiskIdleTimeObservationWindow
: public internal::ObservationWindow<float> {
public:
// This window computes the average disk idle time value over time, so it
// should have a relatively short length to ensure that it doesn't take too
// many new samples to move the average.
// |threshold| is the limit that will be used to determine that the disk idle
// time is low, should have a value in the [0, 1.0] range.
//
// TODO(sebmarchand): Use an exponential moving average instead of a simple
// average, the age of the sample could be used to compute its weight.
DiskIdleTimeObservationWindow(const base::TimeDelta window_length,
const float threshold);
~DiskIdleTimeObservationWindow() override;
// Check if the disk idle time was low over the observation period.
bool DiskIdleTimeIsLow();
private:
FRIEND_TEST_ALL_PREFIXES(ObservationWindowTest,
DiskIdleTimeObservationWindow);
// internal::ObservationWindow:
void OnSampleAdded(const float& sample) override;
void OnSampleRemoved(const float& sample) override;
// The current sum of all the samples.
float sum_ = 0.0;
// The threshold under which the disk idle time will be considered as low, in
// the [0, 1] range.
const float threshold_;
DISALLOW_COPY_AND_ASSIGN(DiskIdleTimeObservationWindow);
};
} // namespace memory
#include "chrome/browser/memory/memory_pressure_monitor_utils_impl.h"
#endif // CHROME_BROWSER_MEMORY_MEMORY_PRESSURE_MONITOR_UTILS_H_