Commit 8ceca0e5 authored by bcwhite's avatar bcwhite Committed by Commit bot

Added MemoryMonitor for Linux (with test).

Extraction of common code also means some changes to the
Windows memory-monitor.

BUG=644397

Review-Url: https://codereview.chromium.org/2310193002
Cr-Commit-Position: refs/heads/master@{#417607}
parent 26cabf35
...@@ -8,7 +8,10 @@ component("browser") { ...@@ -8,7 +8,10 @@ component("browser") {
sources = [ sources = [
"memory_coordinator.cc", "memory_coordinator.cc",
"memory_coordinator.h", "memory_coordinator.h",
"memory_monitor.cc",
"memory_monitor.h", "memory_monitor.h",
"memory_monitor_linux.cc",
"memory_monitor_linux.h",
"memory_monitor_win.cc", "memory_monitor_win.cc",
"memory_monitor_win.h", "memory_monitor_win.h",
] ]
...@@ -30,7 +33,10 @@ source_set("unit_tests") { ...@@ -30,7 +33,10 @@ source_set("unit_tests") {
sources = [ sources = [
"memory_coordinator_unittest.cc", "memory_coordinator_unittest.cc",
"memory_monitor_linux_unittest.cc",
"memory_monitor_win_unittest.cc", "memory_monitor_win_unittest.cc",
"test_memory_monitor.cc",
"test_memory_monitor.h",
] ]
deps = [ deps = [
......
// Copyright (c) 2016 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/memory_coordinator/browser/memory_monitor.h"
#include "base/process/process_metrics.h"
namespace memory_coordinator {
MemoryMonitorDelegate::~MemoryMonitorDelegate() {}
void MemoryMonitorDelegate::GetSystemMemoryInfo(
base::SystemMemoryInfoKB* mem_info) {
base::GetSystemMemoryInfo(mem_info);
}
} // namespace memory_coordinator
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#include "base/macros.h" #include "base/macros.h"
#include "components/memory_coordinator/common/memory_coordinator_export.h" #include "components/memory_coordinator/common/memory_coordinator_export.h"
namespace base {
struct SystemMemoryInfoKB;
}
namespace memory_coordinator { namespace memory_coordinator {
// A simple class that monitors the amount of free memory available on a system. // A simple class that monitors the amount of free memory available on a system.
...@@ -33,6 +37,22 @@ class MEMORY_COORDINATOR_EXPORT MemoryMonitor { ...@@ -33,6 +37,22 @@ class MEMORY_COORDINATOR_EXPORT MemoryMonitor {
// Factory function for creating a monitor for the current platform. // Factory function for creating a monitor for the current platform.
MEMORY_COORDINATOR_EXPORT std::unique_ptr<MemoryMonitor> CreateMemoryMonitor(); MEMORY_COORDINATOR_EXPORT std::unique_ptr<MemoryMonitor> CreateMemoryMonitor();
// A class for fetching system information used by a memory monitor. This can
// be subclassed for testing or if a particular MemoryMonitor implementation
// needs additional functionality.
class MEMORY_COORDINATOR_EXPORT MemoryMonitorDelegate {
public:
MemoryMonitorDelegate() {}
virtual ~MemoryMonitorDelegate();
// Returns system memory information.
virtual void GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info);
private:
DISALLOW_COPY_AND_ASSIGN(MemoryMonitorDelegate);
};
} // namespace memory_coordinator } // namespace memory_coordinator
#endif // COMPONENTS_MEMORY_COORDINATOR_BROWSER_MEMORY_MONITOR_H_ #endif // COMPONENTS_MEMORY_COORDINATOR_BROWSER_MEMORY_MONITOR_H_
// Copyright (c) 2016 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/memory_coordinator/browser/memory_monitor_linux.h"
#include "base/memory/ptr_util.h"
#include "base/process/process_metrics.h"
namespace memory_coordinator {
namespace {
// A global static instance of the default delegate. Used by default by
// MemoryMonitorLinux.
MemoryMonitorDelegate g_memory_monitor_delegate;
// The number of bits to shift to convert KiB to MiB.
const int kShiftKiBtoMiB = 10;
} // namespace
MemoryMonitorLinux::MemoryMonitorLinux(MemoryMonitorDelegate* delegate)
: delegate_(delegate) {}
int MemoryMonitorLinux::GetFreeMemoryUntilCriticalMB() {
base::SystemMemoryInfoKB mem_info = {};
delegate_->GetSystemMemoryInfo(&mem_info);
// According to kernel commit 34e431b0ae398fc54ea69ff85ec700722c9da773,
// "available" is the "amount of memory that is available for a new workload
// without pushing the system into swap"; return that value if it is valid.
// Old linux kernels (before 3.14) don't support "available" and show zero
// instead.
if (mem_info.available > 0)
return mem_info.available >> kShiftKiBtoMiB;
// If there is no "available" value, guess at it based on free memory and
// what the OS can easily discard.
return (mem_info.free + mem_info.buffers + mem_info.cached) >> kShiftKiBtoMiB;
}
// static
std::unique_ptr<MemoryMonitorLinux> MemoryMonitorLinux::Create(
MemoryMonitorDelegate* delegate) {
return base::MakeUnique<MemoryMonitorLinux>(delegate);
}
// Implementation of factory function defined in memory_monitor.h.
std::unique_ptr<MemoryMonitor> CreateMemoryMonitor() {
return MemoryMonitorLinux::Create(&g_memory_monitor_delegate);
}
} // namespace memory_coordinator
// Copyright (c) 2016 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 COMPONENTS_MEMORY_COORDINATOR_BROWSER_MEMORY_MONITOR_LINUX_H_
#define COMPONENTS_MEMORY_COORDINATOR_BROWSER_MEMORY_MONITOR_LINUX_H_
#include "components/memory_coordinator/browser/memory_monitor.h"
#include "components/memory_coordinator/common/memory_coordinator_export.h"
namespace base {
struct SystemMemoryInfoKB;
} // namespace base
namespace memory_coordinator {
// A memory monitor for the Linux platform.
class MEMORY_COORDINATOR_EXPORT MemoryMonitorLinux : public MemoryMonitor {
public:
MemoryMonitorLinux(MemoryMonitorDelegate* delegate);
~MemoryMonitorLinux() override {}
// MemoryMonitor:
int GetFreeMemoryUntilCriticalMB() override;
// Factory function to create an instance of this class.
static std::unique_ptr<MemoryMonitorLinux> Create(
MemoryMonitorDelegate* delegate);
private:
// The delegate to be used for retrieving system memory information. Used as a
// testing seam.
MemoryMonitorDelegate* delegate_;
};
} // namespace memory_coordinator
#endif // COMPONENTS_MEMORY_COORDINATOR_BROWSER_MEMORY_MONITOR_LINUX_H_
// Copyright (c) 2016 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/memory_coordinator/browser/memory_monitor_linux.h"
#include "components/memory_coordinator/browser/test_memory_monitor.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace memory_coordinator {
namespace {
// A delegate that allows mocking the various inputs to MemoryMonitorLinux.
class TestMemoryMonitorLinuxDelegate : public TestMemoryMonitorDelegate {
public:
TestMemoryMonitorLinuxDelegate() {}
void SetAvailableMemoryKB(int available_memory_kb) {
// If this is set, other "free" values are ignored.
mem_info_.available = available_memory_kb;
}
void SetFreeMemoryKB(int free_kb, int cached_kb, int buffers_kb) {
mem_info_.free = free_kb;
mem_info_.cached = cached_kb;
mem_info_.buffers = buffers_kb;
// Only if this is zero will the above values be used.
mem_info_.available = 0;
}
private:
DISALLOW_COPY_AND_ASSIGN(TestMemoryMonitorLinuxDelegate);
};
class TestMemoryMonitorLinux : public MemoryMonitorLinux {};
static const int kKBperMB = 1024;
} // namespace
class MemoryMonitorLinuxTest : public testing::Test {
public:
TestMemoryMonitorLinuxDelegate delegate_;
std::unique_ptr<MemoryMonitorLinux> monitor_;
};
TEST_F(MemoryMonitorLinuxTest, Create) {
delegate_.SetTotalMemoryKB(100000 * kKBperMB);
monitor_ = MemoryMonitorLinux::Create(&delegate_);
EXPECT_EQ(0U, delegate_.calls());
}
TEST_F(MemoryMonitorLinuxTest, GetFreeMemoryUntilCriticalMB) {
delegate_.SetTotalMemoryKB(1000 * kKBperMB);
monitor_.reset(new MemoryMonitorLinux(&delegate_));
EXPECT_EQ(0u, delegate_.calls());
delegate_.SetAvailableMemoryKB(200 * kKBperMB);
EXPECT_EQ(200, monitor_->GetFreeMemoryUntilCriticalMB());
EXPECT_EQ(1U, delegate_.calls());
delegate_.ResetCalls();
delegate_.SetFreeMemoryKB(64 * kKBperMB, 32 * kKBperMB, 16 * kKBperMB);
EXPECT_EQ(112, monitor_->GetFreeMemoryUntilCriticalMB());
EXPECT_EQ(1U, delegate_.calls());
delegate_.ResetCalls();
delegate_.SetFreeMemoryKB(0, 0, 0);
EXPECT_EQ(0, monitor_->GetFreeMemoryUntilCriticalMB());
EXPECT_EQ(1U, delegate_.calls());
delegate_.ResetCalls();
}
} // namespace memory_coordinator
...@@ -15,25 +15,9 @@ namespace { ...@@ -15,25 +15,9 @@ namespace {
const int kKBperMB = 1024; const int kKBperMB = 1024;
// A default implementation of MemoryMonitorWinDelegate. Used by default by
// MemoryMonitorWin.
class MemoryMonitorWinDelegateImpl : public MemoryMonitorWinDelegate {
public:
MemoryMonitorWinDelegateImpl() {}
~MemoryMonitorWinDelegateImpl() override {}
// GetSystemMemoryInfoDelegate:
void GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) override {
base::GetSystemMemoryInfo(mem_info);
}
private:
DISALLOW_COPY_AND_ASSIGN(MemoryMonitorWinDelegateImpl);
};
// A global static instance of the default delegate. Used by default by // A global static instance of the default delegate. Used by default by
// MemoryMonitorWin. // MemoryMonitorWin.
MemoryMonitorWinDelegateImpl g_memory_monitor_win_delegate; MemoryMonitorDelegate g_memory_monitor_win_delegate;
} // namespace } // namespace
...@@ -53,10 +37,9 @@ const int MemoryMonitorWin::kSmallMemoryTargetFreeMB = 200; ...@@ -53,10 +37,9 @@ const int MemoryMonitorWin::kSmallMemoryTargetFreeMB = 200;
// available memory, paging until that is the case. // available memory, paging until that is the case.
const int MemoryMonitorWin::kLargeMemoryTargetFreeMB = 400; const int MemoryMonitorWin::kLargeMemoryTargetFreeMB = 400;
MemoryMonitorWin::MemoryMonitorWin(MemoryMonitorWinDelegate* delegate, MemoryMonitorWin::MemoryMonitorWin(MemoryMonitorDelegate* delegate,
int target_free_mb) int target_free_mb)
: delegate_(delegate), target_free_mb_(target_free_mb) { : delegate_(delegate), target_free_mb_(target_free_mb) {}
}
int MemoryMonitorWin::GetFreeMemoryUntilCriticalMB() { int MemoryMonitorWin::GetFreeMemoryUntilCriticalMB() {
base::SystemMemoryInfoKB mem_info = {}; base::SystemMemoryInfoKB mem_info = {};
...@@ -68,13 +51,13 @@ int MemoryMonitorWin::GetFreeMemoryUntilCriticalMB() { ...@@ -68,13 +51,13 @@ int MemoryMonitorWin::GetFreeMemoryUntilCriticalMB() {
// static // static
std::unique_ptr<MemoryMonitorWin> MemoryMonitorWin::Create( std::unique_ptr<MemoryMonitorWin> MemoryMonitorWin::Create(
MemoryMonitorWinDelegate* delegate) { MemoryMonitorDelegate* delegate) {
return std::unique_ptr<MemoryMonitorWin>(new MemoryMonitorWin( return std::unique_ptr<MemoryMonitorWin>(new MemoryMonitorWin(
delegate, GetTargetFreeMB(delegate))); delegate, GetTargetFreeMB(delegate)));
} }
// static // static
bool MemoryMonitorWin::IsLargeMemory(MemoryMonitorWinDelegate* delegate) { bool MemoryMonitorWin::IsLargeMemory(MemoryMonitorDelegate* delegate) {
base::SystemMemoryInfoKB mem_info = {}; base::SystemMemoryInfoKB mem_info = {};
delegate->GetSystemMemoryInfo(&mem_info); delegate->GetSystemMemoryInfo(&mem_info);
return (mem_info.total / kKBperMB) >= return (mem_info.total / kKBperMB) >=
...@@ -82,7 +65,7 @@ bool MemoryMonitorWin::IsLargeMemory(MemoryMonitorWinDelegate* delegate) { ...@@ -82,7 +65,7 @@ bool MemoryMonitorWin::IsLargeMemory(MemoryMonitorWinDelegate* delegate) {
} }
// static // static
int MemoryMonitorWin::GetTargetFreeMB(MemoryMonitorWinDelegate* delegate) { int MemoryMonitorWin::GetTargetFreeMB(MemoryMonitorDelegate* delegate) {
if (IsLargeMemory(delegate)) if (IsLargeMemory(delegate))
return MemoryMonitorWin::kLargeMemoryTargetFreeMB; return MemoryMonitorWin::kLargeMemoryTargetFreeMB;
return MemoryMonitorWin::kSmallMemoryTargetFreeMB; return MemoryMonitorWin::kSmallMemoryTargetFreeMB;
......
...@@ -14,8 +14,6 @@ struct SystemMemoryInfoKB; ...@@ -14,8 +14,6 @@ struct SystemMemoryInfoKB;
namespace memory_coordinator { namespace memory_coordinator {
class MemoryMonitorWinDelegate;
// A memory monitor for the Windows platform. After much experimentation this // A memory monitor for the Windows platform. After much experimentation this
// class uses a very simple heuristic to anticipate paging (critical memory // class uses a very simple heuristic to anticipate paging (critical memory
// pressure). When the amount of memory available dips below a provided // pressure). When the amount of memory available dips below a provided
...@@ -28,7 +26,7 @@ class MEMORY_COORDINATOR_EXPORT MemoryMonitorWin : public MemoryMonitor { ...@@ -28,7 +26,7 @@ class MEMORY_COORDINATOR_EXPORT MemoryMonitorWin : public MemoryMonitor {
static const int kSmallMemoryTargetFreeMB; static const int kSmallMemoryTargetFreeMB;
static const int kLargeMemoryTargetFreeMB; static const int kLargeMemoryTargetFreeMB;
MemoryMonitorWin(MemoryMonitorWinDelegate* delegate, int target_free_mb); MemoryMonitorWin(MemoryMonitorDelegate* delegate, int target_free_mb);
~MemoryMonitorWin() override {} ~MemoryMonitorWin() override {}
// MemoryMonitor: // MemoryMonitor:
...@@ -40,21 +38,21 @@ class MEMORY_COORDINATOR_EXPORT MemoryMonitorWin : public MemoryMonitor { ...@@ -40,21 +38,21 @@ class MEMORY_COORDINATOR_EXPORT MemoryMonitorWin : public MemoryMonitor {
// Factory function. Automatically sizes |target_free_mb| based on the // Factory function. Automatically sizes |target_free_mb| based on the
// system. // system.
static std::unique_ptr<MemoryMonitorWin> Create( static std::unique_ptr<MemoryMonitorWin> Create(
MemoryMonitorWinDelegate* delegate); MemoryMonitorDelegate* delegate);
protected: protected:
// Determines if the system is in large memory mode. Exposed so that this // Determines if the system is in large memory mode. Exposed so that this
// function can be tested. // function can be tested.
static bool IsLargeMemory(MemoryMonitorWinDelegate* delegate); static bool IsLargeMemory(MemoryMonitorDelegate* delegate);
// Determines the default target free MB value. Exposed so that this function // Determines the default target free MB value. Exposed so that this function
// can be tested. // can be tested.
static int GetTargetFreeMB(MemoryMonitorWinDelegate* delegate); static int GetTargetFreeMB(MemoryMonitorDelegate* delegate);
private: private:
// The delegate to be used for retrieving system memory information. Used as a // The delegate to be used for retrieving system memory information. Used as a
// testing seam. // testing seam.
MemoryMonitorWinDelegate* delegate_; MemoryMonitorDelegate* delegate_;
// The amount of memory that the memory manager (MM) attempts to keep in a // The amount of memory that the memory manager (MM) attempts to keep in a
// free state. When less than this amount of physical memory is free, it is // free state. When less than this amount of physical memory is free, it is
...@@ -62,20 +60,6 @@ class MEMORY_COORDINATOR_EXPORT MemoryMonitorWin : public MemoryMonitor { ...@@ -62,20 +60,6 @@ class MEMORY_COORDINATOR_EXPORT MemoryMonitorWin : public MemoryMonitor {
int target_free_mb_; int target_free_mb_;
}; };
// A delegate that wraps functions used by MemoryMonitorWin. Used as a testing
// seam.
class MEMORY_COORDINATOR_EXPORT MemoryMonitorWinDelegate {
public:
MemoryMonitorWinDelegate() {}
virtual ~MemoryMonitorWinDelegate() {}
// Returns system memory information.
virtual void GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(MemoryMonitorWinDelegate);
};
} // namespace memory_coordinator } // namespace memory_coordinator
#endif // COMPONENTS_MEMORY_COORDINATOR_BROWSER_MEMORY_MONITOR_WIN_H_ #endif // COMPONENTS_MEMORY_COORDINATOR_BROWSER_MEMORY_MONITOR_WIN_H_
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "components/memory_coordinator/browser/memory_monitor_win.h" #include "components/memory_coordinator/browser/memory_monitor_win.h"
#include "base/process/process_metrics.h" #include "components/memory_coordinator/browser/test_memory_monitor.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace memory_coordinator { namespace memory_coordinator {
...@@ -12,35 +12,15 @@ namespace memory_coordinator { ...@@ -12,35 +12,15 @@ namespace memory_coordinator {
namespace { namespace {
// A delegate that allows mocking the various inputs to MemoryMonitorWin. // A delegate that allows mocking the various inputs to MemoryMonitorWin.
class TestMemoryMonitorWinDelegate : public MemoryMonitorWinDelegate { class TestMemoryMonitorWinDelegate : public TestMemoryMonitorDelegate {
public: public:
TestMemoryMonitorWinDelegate() : calls_(0) { TestMemoryMonitorWinDelegate() {}
mem_info_ = {};
}
~TestMemoryMonitorWinDelegate() override {}
// GetSystemMemoryInfoDelegate:
void GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) override {
*mem_info = mem_info_;
++calls_;
}
size_t calls() const { return calls_; }
void ResetCalls() { calls_ = 0; }
void SetTotalMemoryKB(int total_memory_kb) {
mem_info_.total = total_memory_kb;
}
void SetFreeMemoryKB(int free_memory_kb) { void SetFreeMemoryKB(int free_memory_kb) {
mem_info_.free = free_memory_kb; mem_info_.free = free_memory_kb;
} }
private: private:
size_t calls_;
base::SystemMemoryInfoKB mem_info_;
DISALLOW_COPY_AND_ASSIGN(TestMemoryMonitorWinDelegate); DISALLOW_COPY_AND_ASSIGN(TestMemoryMonitorWinDelegate);
}; };
......
// Copyright (c) 2016 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/memory_coordinator/browser/test_memory_monitor.h"
namespace memory_coordinator {
TestMemoryMonitorDelegate::~TestMemoryMonitorDelegate() {}
void TestMemoryMonitorDelegate::GetSystemMemoryInfo(
base::SystemMemoryInfoKB* mem_info) {
*mem_info = mem_info_;
++calls_;
}
} // namespace memory_coordinator
// Copyright (c) 2016 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/memory_coordinator/browser/memory_monitor.h"
#include "base/process/process_metrics.h"
namespace memory_coordinator {
// A delegate that allows mocking the various inputs to MemoryMonitor.
class TestMemoryMonitorDelegate : public MemoryMonitorDelegate {
public:
TestMemoryMonitorDelegate() : calls_(0) { mem_info_ = {}; }
~TestMemoryMonitorDelegate() override;
void GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) override;
size_t calls() const { return calls_; }
void ResetCalls() { calls_ = 0; }
void SetTotalMemoryKB(int total_memory_kb) {
mem_info_.total = total_memory_kb;
}
protected:
// Because the fields of SystemMemoryInfoKB vary depending on the operating
// system, specific derived classes will have to provide methods to load
// values into |mem_info_|;
base::SystemMemoryInfoKB mem_info_;
private:
size_t calls_;
DISALLOW_COPY_AND_ASSIGN(TestMemoryMonitorDelegate);
};
} // namespace memory_coordinator
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment