blob: 6bba825dbee70e0bd9eec6a30d27ec900753fee8 [file] [log] [blame]
// Copyright 2017 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 "chrome/browser/memory/swap_thrashing_monitor_delegate_win.h"
#include "base/test/scoped_task_environment.h"
#include "base/timer/mock_timer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace memory {
namespace {
class MockHardFaultDeltasWindow;
class TestSwapThrashingMonitorDelegateWin
: public SwapThrashingMonitorDelegateWin {
public:
using HardFaultDeltasWindow =
SwapThrashingMonitorDelegateWin::HardFaultDeltasWindow;
TestSwapThrashingMonitorDelegateWin()
: SwapThrashingMonitorDelegateWin::SwapThrashingMonitorDelegateWin(),
observation_override_(0U) {
SetMockWindow();
}
~TestSwapThrashingMonitorDelegateWin() override {}
void SetMockWindow();
bool RecordHardFaultCountForChromeProcesses() override {
hard_fault_deltas_window_->OnObservation(observation_override_);
return true;
}
// Override the next observations that the window will receive.
void OverrideNextObservationDelta(uint64_t observation_delta) {
observation_override_ += observation_delta;
}
MockHardFaultDeltasWindow* sample_window() { return mock_window_; }
private:
uint64_t observation_override_;
MockHardFaultDeltasWindow* mock_window_;
};
// A mock for the HardFaultDeltasWindow class.
//
// Used to access some protected fields of the HardFaultDeltasWindow class.
class MockHardFaultDeltasWindow
: public TestSwapThrashingMonitorDelegateWin::HardFaultDeltasWindow {
public:
MockHardFaultDeltasWindow()
: TestSwapThrashingMonitorDelegateWin::HardFaultDeltasWindow() {}
~MockHardFaultDeltasWindow() override {}
size_t SampleCount() { return observation_deltas_.size(); }
size_t WindowLength() { return kHardFaultDeltasWindowSize; }
};
void TestSwapThrashingMonitorDelegateWin::SetMockWindow() {
std::unique_ptr<MockHardFaultDeltasWindow> mock_window =
std::make_unique<MockHardFaultDeltasWindow>();
mock_window_ = mock_window.get();
hard_fault_deltas_window_.reset(mock_window.release());
}
} // namespace
TEST(SwapThrashingMonitorDelegateWinTest, StateTransition) {
TestSwapThrashingMonitorDelegateWin monitor;
// Arbitrarily chosen high thrashing rate.
const uint64_t kHighSwappingRate = 5000;
// This state test the transitions from the SWAP_THRASHING_LEVEL_NONE state
// to the SWAP_THRASHING_LEVEL_CONFIRMED one and then ensure that the cooldown
// mechanism works.
// We expect the system to initially be in the SWAP_THRASHING_LEVEL_NONE
// state.
EXPECT_EQ(SwapThrashingLevel::SWAP_THRASHING_LEVEL_NONE,
monitor.SampleAndCalculateSwapThrashingLevel());
// Fill the sample window with 0s.
while (monitor.sample_window()->SampleCount() <
monitor.sample_window()->WindowLength()) {
monitor.OverrideNextObservationDelta(0);
EXPECT_EQ(SwapThrashingLevel::SWAP_THRASHING_LEVEL_NONE,
monitor.SampleAndCalculateSwapThrashingLevel());
}
EXPECT_EQ(SwapThrashingLevel::SWAP_THRASHING_LEVEL_NONE,
monitor.SampleAndCalculateSwapThrashingLevel());
EXPECT_EQ(monitor.sample_window()->SampleCount(),
monitor.sample_window()->WindowLength());
// Adds high samples until we reach the suspected status.
size_t high_sample_count = 0;
while (high_sample_count < monitor.sample_window()->WindowLength()) {
high_sample_count++;
monitor.OverrideNextObservationDelta(kHighSwappingRate);
if (monitor.SampleAndCalculateSwapThrashingLevel() ==
SwapThrashingLevel::SWAP_THRASHING_LEVEL_SUSPECTED) {
break;
}
}
size_t suspected_state_sample_count = high_sample_count;
EXPECT_LT(suspected_state_sample_count,
monitor.sample_window()->WindowLength());
// And now add samples until we reach the confirmed value.
while (high_sample_count < monitor.sample_window()->WindowLength()) {
high_sample_count++;
monitor.OverrideNextObservationDelta(kHighSwappingRate);
if (monitor.SampleAndCalculateSwapThrashingLevel() ==
SwapThrashingLevel::SWAP_THRASHING_LEVEL_CONFIRMED) {
break;
}
}
size_t confirmed_state_sample_count = high_sample_count;
EXPECT_LE(confirmed_state_sample_count,
monitor.sample_window()->WindowLength());
EXPECT_GT(confirmed_state_sample_count, suspected_state_sample_count);
// Finish filling the window with high values.
while (high_sample_count < monitor.sample_window()->WindowLength()) {
high_sample_count++;
monitor.OverrideNextObservationDelta(kHighSwappingRate);
EXPECT_EQ(SwapThrashingLevel::SWAP_THRASHING_LEVEL_CONFIRMED,
monitor.SampleAndCalculateSwapThrashingLevel());
}
// Add 0s to the windows, the thrashing level should slowly decrease.
while (high_sample_count > 0) {
monitor.OverrideNextObservationDelta(0);
if (high_sample_count > confirmed_state_sample_count) {
EXPECT_EQ(SwapThrashingLevel::SWAP_THRASHING_LEVEL_CONFIRMED,
monitor.SampleAndCalculateSwapThrashingLevel());
} else if (high_sample_count > suspected_state_sample_count) {
EXPECT_EQ(SwapThrashingLevel::SWAP_THRASHING_LEVEL_SUSPECTED,
monitor.SampleAndCalculateSwapThrashingLevel());
} else {
EXPECT_EQ(SwapThrashingLevel::SWAP_THRASHING_LEVEL_NONE,
monitor.SampleAndCalculateSwapThrashingLevel());
}
high_sample_count--;
}
}
} // namespace memory