[PM] Adding a working set trimmer policy.
As discussed this CL will add a WorkingSetTrimmer policy. The default
policy as implemented in working_set_trimmer_policy is identical to the
previous behavior on Windows in which we will always trim on frozen.
The Windows implementation uses that same default behavior but uses
PlatformSupportsWorkingSetTrim to check if it's flag enabled.
The ChromeOS implementation uses the same default plus it adds working
set trim on Moderate memory pressure. There are a number of flags used
to control this behavior.
Bug: 973963
Change-Id: I2dfd4a8e7e45497725cb905bc1254beb8fda3ae3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1706450
Commit-Queue: Brian Geffon <[email protected]>
Reviewed-by: Marc Treib <[email protected]>
Reviewed-by: Chris Hamilton <[email protected]>
Cr-Commit-Position: refs/heads/master@{#682475}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 3ad3ecf..fe481d3b 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1072,6 +1072,14 @@
"performance_manager/graph/page_node.cc",
"performance_manager/graph/page_node_impl.cc",
"performance_manager/graph/page_node_impl.h",
+ "performance_manager/graph/policies/policy_features.cc",
+ "performance_manager/graph/policies/policy_features.h",
+ "performance_manager/graph/policies/working_set_trimmer_policy.cc",
+ "performance_manager/graph/policies/working_set_trimmer_policy.h",
+ "performance_manager/graph/policies/working_set_trimmer_policy_chromeos.cc",
+ "performance_manager/graph/policies/working_set_trimmer_policy_chromeos.h",
+ "performance_manager/graph/policies/working_set_trimmer_policy_win.cc",
+ "performance_manager/graph/policies/working_set_trimmer_policy_win.h",
"performance_manager/graph/process_node.cc",
"performance_manager/graph/process_node_impl.cc",
"performance_manager/graph/process_node_impl.h",
@@ -1092,8 +1100,6 @@
"performance_manager/observers/isolation_context_metrics.h",
"performance_manager/observers/metrics_collector.cc",
"performance_manager/observers/metrics_collector.h",
- "performance_manager/observers/working_set_trimmer_observer_win.cc",
- "performance_manager/observers/working_set_trimmer_observer_win.h",
"performance_manager/performance_manager.cc",
"performance_manager/performance_manager.h",
"performance_manager/performance_manager_clock.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 8211aae..86a9fc8 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -369,6 +369,7 @@
"+chrome/browser/performance_manager/public",
"+chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.h",
"+chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.h",
+ "+chrome/browser/performance_manager/graph/policies/policy_features.h",
"+chrome/browser/performance_manager/performance_manager.h",
"+chrome/browser/performance_manager/performance_manager_tab_helper.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ce7bdba..817af2b1 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -30,6 +30,7 @@
#include "chrome/browser/browser_features.h"
#include "chrome/browser/flag_descriptions.h"
#include "chrome/browser/notifications/scheduler/public/features.h"
+#include "chrome/browser/performance_manager/graph/policies/policy_features.h"
#include "chrome/browser/predictors/loading_predictor_config.h"
#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/resource_coordinator/tab_manager_features.h"
@@ -1541,6 +1542,14 @@
{"enable-virtual-desks", flag_descriptions::kEnableVirtualDesksName,
flag_descriptions::kEnableVirtualDesksDescription, kOsCrOS,
FEATURE_VALUE_TYPE(ash::features::kVirtualDesks)},
+ {"trim-on-all-frames-frozen", flag_descriptions::kTrimOnFreezeName,
+ flag_descriptions::kTrimOnFreezeDescription, kOsCrOS,
+ FEATURE_VALUE_TYPE(
+ performance_manager::features::chromeos::kTrimOnFreeze)},
+ {"trim-on-memory-pressure", flag_descriptions::kTrimOnMemoryPressureName,
+ flag_descriptions::kTrimOnMemoryPressureDescription, kOsCrOS,
+ FEATURE_VALUE_TYPE(
+ performance_manager::features::chromeos::kTrimOnMemoryPressure)},
#endif // OS_CHROMEOS
{
"disable-accelerated-video-decode",
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 1523569..68a093d 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3082,6 +3082,16 @@
"expiry_milestone": 78
},
{
+ "name": "trim-on-all-frames-frozen",
+ "owners": [ "bgeffon", "sonnyrao" ],
+ "expiry_milestone": 81
+ },
+ {
+ "name": "trim-on-memory-pressure",
+ "owners": [ "bgeffon", "sonnyrao" ],
+ "expiry_milestone": 81
+ },
+ {
"name": "try-supported-channel-layouts",
"owners": [ "dalecurtis" ],
"expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 1807c80..4727217a 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3220,6 +3220,13 @@
const char kEnableVirtualDesksDescription[] =
"A preview of the upcoming Virtual Desks features on Chrome OS devices.";
+const char kTrimOnFreezeName[] = "Trim Working Set on freeze";
+const char kTrimOnFreezeDescription[] = "Trim Working Set on all frames frozen";
+
+const char kTrimOnMemoryPressureName[] = "Trim Working Set on memory pressure";
+const char kTrimOnMemoryPressureDescription[] =
+ "Trim Working Set periodically on memory pressure";
+
const char kEnableZeroStateSuggestionsName[] = "Enable Zero State Suggetions";
const char kEnableZeroStateSuggestionsDescription[] =
"Enable Zero State Suggestions feature in Launcher, which will show "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index e9bd0de..649fa49 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1924,6 +1924,12 @@
extern const char kEnableVirtualDesksName[];
extern const char kEnableVirtualDesksDescription[];
+extern const char kTrimOnFreezeName[];
+extern const char kTrimOnFreezeDescription[];
+
+extern const char kTrimOnMemoryPressureName[];
+extern const char kTrimOnMemoryPressureDescription[];
+
extern const char kEnableZeroStateSuggestionsName[];
extern const char kEnableZeroStateSuggestionsDescription[];
diff --git a/chrome/browser/performance_manager/graph/policies/policy_features.cc b/chrome/browser/performance_manager/graph/policies/policy_features.cc
new file mode 100644
index 0000000..00cd050
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/policy_features.cc
@@ -0,0 +1,56 @@
+// 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.
+
+#include "chrome/browser/performance_manager/graph/policies/policy_features.h"
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace performance_manager {
+namespace features {
+
+#if defined(OS_CHROMEOS)
+namespace chromeos {
+
+const base::Feature kTrimOnMemoryPressure{"TrimOnMemoryPressure",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kTrimOnFreeze{"TrimOnFreeze",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::FeatureParam<int> kGraphWalkBackoffTimeSec = {
+ &kTrimOnMemoryPressure, "GraphWalkBackoffTimeSec", 120};
+
+// Specifies the minimum amount of time a parent frame node must be invisible
+// before considering the process node for working set trim.
+const base::FeatureParam<int> kNodeInvisibileTimeSec = {
+ &kTrimOnMemoryPressure, "NodeInvisibleTimeSec", 360};
+
+// Specifies the minimum amount of time a parent frame node must be invisible
+// before considering the process node for working set trim.
+const base::FeatureParam<int> kNodeTrimBackoffTimeSec = {
+ &kTrimOnMemoryPressure, "NodeTrimBackoffTimeSec", 1200};
+
+TrimOnMemoryPressureParams::TrimOnMemoryPressureParams() = default;
+TrimOnMemoryPressureParams::TrimOnMemoryPressureParams(
+ const TrimOnMemoryPressureParams& other) = default;
+
+TrimOnMemoryPressureParams TrimOnMemoryPressureParams::GetParams() {
+ TrimOnMemoryPressureParams params;
+ params.graph_walk_backoff_time =
+ base::TimeDelta::FromSeconds(kGraphWalkBackoffTimeSec.Get());
+ params.node_invisible_time =
+ base::TimeDelta::FromSeconds(kNodeInvisibileTimeSec.Get());
+ params.node_trim_backoff_time =
+ base::TimeDelta::FromSeconds(kNodeTrimBackoffTimeSec.Get());
+ return params;
+}
+
+} // namespace chromeos
+#endif
+
+} // namespace features
+} // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/policies/policy_features.h b/chrome/browser/performance_manager/graph/policies/policy_features.h
new file mode 100644
index 0000000..9ec9eea6
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/policy_features.h
@@ -0,0 +1,60 @@
+// 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.
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_POLICIES_POLICY_FEATURES_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_POLICIES_POLICY_FEATURES_H_
+
+namespace performance_manager {
+namespace features {
+
+// TODO(bgeffon): The WorkingSetTrimmer for windows feature should also be moved
+// from resource manager to here.
+#if defined(OS_CHROMEOS)
+namespace chromeos {
+
+// The trim on Memory Pressure feature will trim a process nodes working set
+// according to the parameters below.
+extern const base::Feature kTrimOnMemoryPressure;
+
+// The trim on freeze feature will trim the working set of a process when all
+// frames are frozen.
+extern const base::Feature kTrimOnFreeze;
+
+// The graph walk backoff is the _minimum_ backoff time between graph walks
+// under moderate pressure in seconds. By default we will not walk more than
+// once every 2 minutes.
+extern const base::FeatureParam<int> kGraphWalkBackoffTimeSec;
+
+// Specifies the minimum amount of time a parent frame node must be invisible
+// before considering the process node for working set trim.
+extern const base::FeatureParam<int> kNodeInvisibileTimeSec;
+
+// Specifies the minimum amount of time a parent frame node must be invisible
+// before considering the process node for working set trim.
+extern const base::FeatureParam<int> kNodeTrimBackoffTimeSec;
+
+struct TrimOnMemoryPressureParams {
+ TrimOnMemoryPressureParams();
+ TrimOnMemoryPressureParams(const TrimOnMemoryPressureParams& other);
+
+ // GetParams will return this struct with the populated parameters below.
+ static TrimOnMemoryPressureParams GetParams();
+
+ base::TimeDelta graph_walk_backoff_time;
+ base::TimeDelta node_invisible_time;
+ base::TimeDelta node_trim_backoff_time;
+};
+
+} // namespace chromeos
+#endif
+
+} // namespace features
+} // namespace performance_manager
+
+#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_POLICIES_POLICY_FEATURES_H_
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.cc b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.cc
new file mode 100644
index 0000000..1f46588
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.cc
@@ -0,0 +1,112 @@
+// 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.
+
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h"
+
+#include "build/build_config.h"
+
+#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer.h"
+#include "chrome/browser/performance_manager/public/graph/graph.h"
+#include "chrome/browser/performance_manager/public/graph/node_attached_data.h"
+#include "chrome/browser/performance_manager/public/graph/process_node.h"
+#if defined(OS_WIN)
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_win.h"
+#elif defined(OS_CHROMEOS)
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.h"
+#endif
+
+namespace performance_manager {
+namespace policies {
+
+namespace {
+
+class WorkingSetTrimData
+ : public ExternalNodeAttachedDataImpl<WorkingSetTrimData> {
+ public:
+ explicit WorkingSetTrimData(const ProcessNode* node) {}
+ ~WorkingSetTrimData() override = default;
+
+ base::TimeTicks last_trim_;
+};
+
+} // namespace
+
+WorkingSetTrimmerPolicy::WorkingSetTrimmerPolicy() = default;
+WorkingSetTrimmerPolicy::~WorkingSetTrimmerPolicy() = default;
+
+void WorkingSetTrimmerPolicy::OnPassedToGraph(Graph* graph) {
+ RegisterObservers(graph);
+}
+
+void WorkingSetTrimmerPolicy::OnTakenFromGraph(Graph* graph) {
+ UnregisterObservers(graph);
+}
+
+void WorkingSetTrimmerPolicy::OnAllFramesInProcessFrozen(
+ const ProcessNode* process_node) {
+ TrimWorkingSet(process_node);
+}
+
+void WorkingSetTrimmerPolicy::RegisterObservers(Graph* graph) {
+ graph->AddProcessNodeObserver(this);
+}
+
+void WorkingSetTrimmerPolicy::UnregisterObservers(Graph* graph) {
+ graph->RemoveProcessNodeObserver(this);
+}
+
+base::TimeTicks WorkingSetTrimmerPolicy::GetLastTrimTime(
+ const ProcessNode* process_node) {
+ auto* data = WorkingSetTrimData::GetOrCreate(process_node);
+ return data->last_trim_;
+}
+
+void WorkingSetTrimmerPolicy::SetLastTrimTimeNow(
+ const ProcessNode* process_node) {
+ SetLastTrimTime(process_node, base::TimeTicks::Now());
+}
+
+void WorkingSetTrimmerPolicy::SetLastTrimTime(const ProcessNode* process_node,
+ base::TimeTicks time) {
+ auto* data = WorkingSetTrimData::GetOrCreate(process_node);
+ data->last_trim_ = time;
+}
+
+bool WorkingSetTrimmerPolicy::TrimWorkingSet(const ProcessNode* process_node) {
+ auto* trimmer = mechanism::WorkingSetTrimmer::GetInstance();
+ DCHECK(trimmer);
+ if (process_node->GetProcess().IsValid()) {
+ SetLastTrimTimeNow(process_node);
+ return trimmer->TrimWorkingSet(process_node);
+ }
+
+ return false;
+}
+
+// static
+bool WorkingSetTrimmerPolicy::PlatformSupportsWorkingSetTrim() {
+#if defined(OS_WIN)
+ return WorkingSetTrimmerPolicyWin::PlatformSupportsWorkingSetTrim();
+#elif defined(OS_CHROMEOS)
+ return WorkingSetTrimmerPolicyChromeOS::PlatformSupportsWorkingSetTrim();
+#else
+ return false;
+#endif
+}
+
+// static
+std::unique_ptr<WorkingSetTrimmerPolicy>
+WorkingSetTrimmerPolicy::CreatePolicyForPlatform() {
+#if defined(OS_WIN)
+ return std::make_unique<WorkingSetTrimmerPolicyWin>();
+#elif defined(OS_CHROMEOS)
+ return std::make_unique<WorkingSetTrimmerPolicyChromeOS>();
+#else
+ NOTIMPLEMENTED() << "Platform does not support WorkingSetTrim.";
+ return nullptr;
+#endif
+}
+
+} // namespace policies
+} // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h
new file mode 100644
index 0000000..ba9cfc961
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h
@@ -0,0 +1,85 @@
+// 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_PERFORMANCE_MANAGER_GRAPH_POLICIES_WORKING_SET_TRIMMER_POLICY_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_POLICIES_WORKING_SET_TRIMMER_POLICY_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "chrome/browser/performance_manager/public/graph/graph.h"
+#include "chrome/browser/performance_manager/public/graph/node_attached_data.h"
+#include "chrome/browser/performance_manager/public/graph/process_node.h"
+
+namespace performance_manager {
+namespace policies {
+
+// Empties the working set of processes in which all frames are frozen.
+//
+// Objective #1: Track working set growth rate.
+// Swap thrashing occurs when a lot of pages are accessed in a short period of
+// time. Swap thrashing can be reduced by reducing the number of pages
+// accessed by processes in which all frames are frozen. To track efforts
+// towards this goal, we empty the working set of processes when all their
+// frames become frozen and record the size of their working set after x
+// minutes.
+// TODO(fdoray): Record the working set size x minutes after emptying it.
+// https://crbug.com/885293
+//
+// Objective #2: Improve performance.
+// We hypothesize that emptying the working set of a process causes its pages
+// to be compressed and/or written to disk preemptively, which makes more
+// memory available quickly for foreground processes and improves global
+// browser performance.
+class WorkingSetTrimmerPolicy : public GraphOwned,
+ public ProcessNode::ObserverDefaultImpl {
+ public:
+ WorkingSetTrimmerPolicy();
+ ~WorkingSetTrimmerPolicy() override;
+
+ // CreatePolicyForPlatform will create a working set trimmer policy for a
+ // specific platform which should be owned by the graph, you should always
+ // check PlatformSupportsWorkingSetTrim() before creating a policy to do so as
+ // it would result in unnecessary book-keeping.
+ static std::unique_ptr<WorkingSetTrimmerPolicy> CreatePolicyForPlatform();
+
+ // Returns true if running on a platform that supports working set trimming.
+ static bool PlatformSupportsWorkingSetTrim();
+
+ // GraphOwned implementation:
+ void OnPassedToGraph(Graph* graph) override;
+ void OnTakenFromGraph(Graph* graph) override;
+
+ // ProcessNodeObserver implementation:
+ void OnAllFramesInProcessFrozen(const ProcessNode* process_node) override;
+
+ protected:
+ // (Un)registers the various node observer flavors of this object with the
+ // graph. These are invoked by OnPassedToGraph and OnTakenFromGraph, but
+ // hoisted to their own functions for testing.
+ void RegisterObservers(Graph* graph);
+ void UnregisterObservers(Graph* graph);
+
+ // Returns the time in which this process was last trimmed.
+ base::TimeTicks GetLastTrimTime(const ProcessNode* process_node);
+
+ // Sets the last trim time to TimeTicks::Now().
+ void SetLastTrimTimeNow(const ProcessNode* process_node);
+
+ // TrimWorkingSet will trim a ProcessNode's working set, it will return true
+ // on success. This is virtual for testing.
+ virtual bool TrimWorkingSet(const ProcessNode* process_node);
+
+ private:
+ friend class WorkingSetTrimmerPolicyTest;
+
+ // A helper method which sets the last trim time to the specified time.
+ void SetLastTrimTime(const ProcessNode* process_node, base::TimeTicks time);
+
+ DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmerPolicy);
+};
+
+} // namespace policies
+} // namespace performance_manager
+
+#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_POLICIES_WORKING_SET_TRIMMER_POLICY_H_
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.cc b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.cc
new file mode 100644
index 0000000..9d20a71
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.cc
@@ -0,0 +1,109 @@
+// 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.
+
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.h"
+
+#include "base/bind.h"
+#include "chrome/browser/performance_manager/graph/policies/policy_features.h"
+#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer.h"
+#include "chrome/browser/performance_manager/performance_manager.h"
+#include "chrome/browser/performance_manager/public/graph/frame_node.h"
+#include "chrome/browser/performance_manager/public/graph/graph.h"
+#include "chrome/browser/performance_manager/public/graph/page_node.h"
+#include "url/gurl.h"
+
+namespace performance_manager {
+namespace policies {
+
+WorkingSetTrimmerPolicyChromeOS::WorkingSetTrimmerPolicyChromeOS() {
+ trim_on_memory_pressure_enabled_ =
+ base::FeatureList::IsEnabled(features::chromeos::kTrimOnMemoryPressure);
+ trim_on_freeze_enabled_ =
+ base::FeatureList::IsEnabled(features::chromeos::kTrimOnFreeze);
+
+ if (trim_on_memory_pressure_enabled_) {
+ trim_on_memory_pressure_params_ =
+ features::chromeos::TrimOnMemoryPressureParams::GetParams();
+ }
+}
+
+WorkingSetTrimmerPolicyChromeOS::~WorkingSetTrimmerPolicyChromeOS() = default;
+
+// On MemoryPressure we will try to trim the working set of some renders if they
+// have been backgrounded for some period of time and have not been trimmed for
+// at least the backoff period.
+void WorkingSetTrimmerPolicyChromeOS::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level) {
+ if (level == base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE)
+ return;
+
+ // Try not to walk the graph too frequently because we can receive moderate
+ // memory pressure notifications every 10s.
+ if (base::TimeTicks::Now() - last_graph_walk_ <
+ trim_on_memory_pressure_params_.graph_walk_backoff_time) {
+ return;
+ }
+
+ TrimNodesOnGraph();
+}
+
+void WorkingSetTrimmerPolicyChromeOS::TrimNodesOnGraph() {
+ const base::TimeTicks now_ticks = base::TimeTicks::Now();
+ for (const PageNode* node : graph_->GetAllPageNodes()) {
+ if (!node->IsVisible() &&
+ node->GetTimeSinceLastVisibilityChange() >
+ trim_on_memory_pressure_params_.node_invisible_time) {
+ // Get the process node and if it has not been
+ // trimmed within the backoff period, we will do that
+ // now.
+ const ProcessNode* process_node =
+ node->GetMainFrameNode()->GetProcessNode();
+ if (process_node->GetProcess().IsValid()) {
+ base::TimeTicks last_trim = GetLastTrimTime(process_node);
+ if (now_ticks - last_trim >
+ trim_on_memory_pressure_params_.node_trim_backoff_time) {
+ TrimWorkingSet(process_node);
+ }
+ }
+ }
+ }
+ last_graph_walk_ = now_ticks;
+}
+
+void WorkingSetTrimmerPolicyChromeOS::OnTakenFromGraph(Graph* graph) {
+ memory_pressure_listener_.reset();
+ graph_ = nullptr;
+ WorkingSetTrimmerPolicy::OnTakenFromGraph(graph);
+}
+
+void WorkingSetTrimmerPolicyChromeOS::OnAllFramesInProcessFrozen(
+ const ProcessNode* process_node) {
+ if (trim_on_freeze_enabled_) {
+ WorkingSetTrimmerPolicy::OnAllFramesInProcessFrozen(process_node);
+ }
+}
+
+void WorkingSetTrimmerPolicyChromeOS::OnPassedToGraph(Graph* graph) {
+ if (trim_on_memory_pressure_enabled_) {
+ // We wait to register the memory pressure listener so we're on the
+ // right sequence.
+ trim_on_memory_pressure_params_ =
+ features::chromeos::TrimOnMemoryPressureParams::GetParams();
+ memory_pressure_listener_.emplace(
+ base::BindRepeating(&WorkingSetTrimmerPolicyChromeOS::OnMemoryPressure,
+ base::Unretained(this)));
+ }
+
+ graph_ = graph;
+ WorkingSetTrimmerPolicy::OnPassedToGraph(graph);
+}
+
+// static
+bool WorkingSetTrimmerPolicyChromeOS::PlatformSupportsWorkingSetTrim() {
+ return mechanism::WorkingSetTrimmer::GetInstance()
+ ->PlatformSupportsWorkingSetTrim();
+}
+
+} // namespace policies
+} // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.h b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.h
new file mode 100644
index 0000000..84df00ae
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.h
@@ -0,0 +1,68 @@
+// 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_PERFORMANCE_MANAGER_GRAPH_POLICIES_WORKING_SET_TRIMMER_POLICY_CHROMEOS_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_POLICIES_WORKING_SET_TRIMMER_POLICY_CHROMEOS_H_
+
+#include "base/memory/memory_pressure_listener.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "chrome/browser/performance_manager/graph/policies/policy_features.h"
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h"
+
+namespace performance_manager {
+namespace policies {
+
+class WorkingSetTrimmerPolicyChromeOSTest;
+
+// ChromeOS specific WorkingSetTrimmerPolicy which uses the default policy on
+// all frames frozen, additionally it will add working set trim under memory
+// pressure.
+class WorkingSetTrimmerPolicyChromeOS : public WorkingSetTrimmerPolicy {
+ public:
+ ~WorkingSetTrimmerPolicyChromeOS() override;
+ WorkingSetTrimmerPolicyChromeOS();
+
+ // Returns true if this platform supports working set trim, in the case of
+ // Windows this will check that the appropriate flags are set for working set
+ // trim.
+ static bool PlatformSupportsWorkingSetTrim();
+
+ // GraphOwned implementation:
+ void OnTakenFromGraph(Graph* graph) override;
+ void OnPassedToGraph(Graph* graph) override;
+
+ // ProcessNodeObserver implementation:
+ void OnAllFramesInProcessFrozen(const ProcessNode* process_node) override;
+
+ protected:
+ friend class WorkingSetTrimmerPolicyChromeOSTest;
+
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level);
+
+ void TrimNodesOnGraph();
+
+ bool trim_on_freeze_enabled_ = false;
+ bool trim_on_memory_pressure_enabled_ = false;
+
+ features::chromeos::TrimOnMemoryPressureParams
+ trim_on_memory_pressure_params_;
+
+ // Keeps track of the last time we walked the graph looking for processes
+ // to trim.
+ base::TimeTicks last_graph_walk_;
+
+ base::Optional<base::MemoryPressureListener> memory_pressure_listener_;
+
+ private:
+ Graph* graph_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmerPolicyChromeOS);
+};
+
+} // namespace policies
+} // namespace performance_manager
+
+#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_POLICIES_WORKING_SET_TRIMMER_POLICY_CHROMEOS_H_
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos_unittest.cc b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos_unittest.cc
new file mode 100644
index 0000000..158d96cb
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos_unittest.cc
@@ -0,0 +1,218 @@
+// 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.
+
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.h"
+
+#include "base/memory/memory_pressure_listener.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "chrome/browser/performance_manager/graph/graph_impl_operations.h"
+#include "chrome/browser/performance_manager/graph/graph_test_harness.h"
+#include "chrome/browser/performance_manager/graph/mock_graphs.h"
+#include "chrome/browser/performance_manager/graph/page_node_impl.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
+#include "chrome/browser/performance_manager/performance_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager {
+namespace policies {
+
+class MockWorkingSetTrimmerPolicyChromeOS
+ : public WorkingSetTrimmerPolicyChromeOS {
+ public:
+ MockWorkingSetTrimmerPolicyChromeOS() {
+ trim_on_memory_pressure_enabled_ = true;
+ trim_on_freeze_enabled_ = true;
+
+ // Setup parameters for trimming on memory pressure.
+ trim_on_memory_pressure_params_.graph_walk_backoff_time =
+ base::TimeDelta::FromSeconds(30);
+
+ trim_on_memory_pressure_params_.node_invisible_time =
+ base::TimeDelta::FromSeconds(30);
+
+ trim_on_memory_pressure_params_.node_trim_backoff_time =
+ base::TimeDelta::FromSeconds(30);
+ }
+
+ ~MockWorkingSetTrimmerPolicyChromeOS() override {}
+
+ base::MemoryPressureListener& listener() {
+ return memory_pressure_listener_.value();
+ }
+
+ base::TimeTicks get_last_graph_walk() { return last_graph_walk_; }
+
+ MOCK_METHOD1(TrimWorkingSet, bool(const ProcessNode*));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockWorkingSetTrimmerPolicyChromeOS);
+};
+
+class WorkingSetTrimmerPolicyChromeOSTest : public GraphTestHarness {
+ public:
+ WorkingSetTrimmerPolicyChromeOSTest()
+ : GraphTestHarness(
+ base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME_AND_NOW) {}
+ ~WorkingSetTrimmerPolicyChromeOSTest() override {}
+
+ void SetUp() override {
+ GraphTestHarness::SetUp();
+
+ // Add our mock policy to the graph.
+ std::unique_ptr<MockWorkingSetTrimmerPolicyChromeOS> mock_policy(
+ new MockWorkingSetTrimmerPolicyChromeOS);
+ policy_ = mock_policy.get();
+ graph()->PassToGraph(std::move(mock_policy));
+ }
+
+ void TearDown() override {
+ policy_ = nullptr;
+ GraphTestHarness::TearDown();
+ }
+
+ MockWorkingSetTrimmerPolicyChromeOS* policy() { return policy_; }
+
+ base::TimeTicks NowTicks() { return task_env().NowTicks(); }
+
+ base::TimeTicks FastForwardBy(base::TimeDelta delta) {
+ task_env().FastForwardBy(delta);
+ return NowTicks();
+ }
+
+ private:
+ MockWorkingSetTrimmerPolicyChromeOS* policy_ = nullptr; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmerPolicyChromeOSTest);
+};
+
+// Validate that we don't walk again before the backoff period has expired.
+TEST_F(WorkingSetTrimmerPolicyChromeOSTest, GraphWalkBackoffPeriod) {
+ // Since we've never walked the graph we should do so now.
+ const base::TimeTicks initial_walk_time = policy()->get_last_graph_walk();
+ ASSERT_EQ(initial_walk_time, base::TimeTicks());
+
+ policy()->listener().SimulatePressureNotification(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+
+ FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ // Since we have never walked we expect that we walked it now, we confirm by
+ // checking the last walk time against the known clock.
+ const base::TimeTicks last_walk_time = policy()->get_last_graph_walk();
+ EXPECT_LT(initial_walk_time, last_walk_time);
+
+ policy()->listener().SimulatePressureNotification(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+
+ FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ // We will not have caused a walk as the clock has not advanced beyond the
+ // backoff period.
+ EXPECT_EQ(last_walk_time, policy()->get_last_graph_walk());
+}
+
+// Validate that we will walk the graph again after the backoff period is
+// expired.
+TEST_F(WorkingSetTrimmerPolicyChromeOSTest, GraphWalkAfterBackoffPeriod) {
+ // Since we've never walked the graph we should do so now.
+ const base::TimeTicks initial_walk_time = policy()->get_last_graph_walk();
+ ASSERT_EQ(initial_walk_time, base::TimeTicks());
+
+ policy()->listener().SimulatePressureNotification(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+
+ FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ // Since we have never walked we expect that we walked it now, we confirm by
+ // checking the last walk time against the known clock.
+ const base::TimeTicks last_walk_time = policy()->get_last_graph_walk();
+ EXPECT_LT(initial_walk_time, last_walk_time);
+
+ FastForwardBy(base::TimeDelta::FromDays(1));
+
+ policy()->listener().SimulatePressureNotification(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+
+ // Finally advance the clock beyond the backoff period and it should allow it
+ // to walk again.
+ FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ const base::TimeTicks final_walk_time = policy()->get_last_graph_walk();
+ EXPECT_GT(final_walk_time, last_walk_time);
+}
+
+// This test will validate that we will NOT try to trim a node if it has not
+// been invisible for long enough.
+TEST_F(WorkingSetTrimmerPolicyChromeOSTest, DontTrimIfNotInvisibleLongEnough) {
+ // Create a simple graph
+ auto process_node = CreateNode<ProcessNodeImpl>();
+ auto page_node = CreateNode<PageNodeImpl>();
+ auto parent_frame =
+ CreateNode<FrameNodeImpl>(process_node.get(), page_node.get());
+
+ // Since we've never walked the graph we should do so now.
+ const base::TimeTicks clock_time = NowTicks();
+ const base::TimeTicks initial_walk_time = policy()->get_last_graph_walk();
+
+ // Set the PageNode to invisible but the state change time to now, since it
+ // will not have been invisible long enough it will NOT trigger a call to
+ // TrimWorkingSet.
+ page_node->SetIsVisible(true); // Reset visibility and set invisible Now.
+ page_node->SetIsVisible(false); // Uses the testing clock.
+ EXPECT_CALL(*policy(), TrimWorkingSet(testing::_)).Times(0);
+
+ // Triger memory pressure and we should observe the walk.
+ policy()->listener().SimulatePressureNotification(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+
+ FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ const base::TimeTicks current_walk_time = policy()->get_last_graph_walk();
+ EXPECT_EQ(clock_time, current_walk_time);
+ EXPECT_NE(current_walk_time, initial_walk_time);
+}
+
+// This test will validate that we WILL trim the working set if it has been
+// invisible long enough.
+TEST_F(WorkingSetTrimmerPolicyChromeOSTest, TrimIfInvisibleLongEnough) {
+ // Create a simple graph
+ auto process_node = CreateNode<ProcessNodeImpl>();
+ auto page_node = CreateNode<PageNodeImpl>();
+ auto parent_frame =
+ CreateNode<FrameNodeImpl>(process_node.get(), page_node.get());
+
+ ASSERT_EQ(1u, graph()->GetAllPageNodes().size());
+
+ // Create a Process so this process node doesn't bail on Process.IsValid();
+ const base::Process self = base::Process::Current();
+ auto duplicate = self.Duplicate();
+ ASSERT_TRUE(duplicate.IsValid());
+ process_node->SetProcess(std::move(duplicate), base::Time::Now());
+
+ // Set it invisible using the current clock, then we will advance the clock
+ // and it should result in a TrimWorkingSet since it's been invisible long
+ // enough.
+ page_node->SetIsVisible(true); // Reset visibility and then set invisible.
+ page_node->SetIsVisible(false); // Uses the testing clock.
+ const base::TimeTicks cur_time =
+ FastForwardBy(base::TimeDelta::FromDays(365));
+
+ // We will attempt to trim to corresponding ProcessNode since we've been
+ // invisible long enough.
+ EXPECT_CALL(*policy(), TrimWorkingSet(process_node.get())).Times(1);
+
+ // Triger memory pressure and we should observe the walk since we've never
+ // walked before.
+ policy()->listener().SimulatePressureNotification(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+
+ FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ // We should have triggered the walk and it should have trimmed.
+ EXPECT_EQ(cur_time, policy()->get_last_graph_walk());
+}
+
+} // namespace policies
+} // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_unittest.cc b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_unittest.cc
new file mode 100644
index 0000000..dd8d183
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_unittest.cc
@@ -0,0 +1,74 @@
+// 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.
+
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h"
+
+#include "chrome/browser/performance_manager/graph/graph_test_harness.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
+#include "chrome/browser/performance_manager/performance_manager_clock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager {
+namespace policies {
+
+class MockWorkingSetTrimmerPolicy : public WorkingSetTrimmerPolicy {
+ public:
+ MockWorkingSetTrimmerPolicy() {}
+ ~MockWorkingSetTrimmerPolicy() override {}
+
+ MOCK_METHOD1(TrimWorkingSet, bool(const ProcessNode*));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockWorkingSetTrimmerPolicy);
+};
+
+class WorkingSetTrimmerPolicyTest : public GraphTestHarness {
+ public:
+ WorkingSetTrimmerPolicyTest() {}
+ ~WorkingSetTrimmerPolicyTest() override {}
+
+ void SetUp() override { policy_.reset(new WorkingSetTrimmerPolicy); }
+
+ void SetLastTrimTime(const ProcessNode* node, base::TimeTicks time) {
+ policy_->SetLastTrimTime(node, time);
+ }
+
+ base::TimeTicks GetLastTrimTime(const ProcessNode* node) {
+ return policy_->GetLastTrimTime(node);
+ }
+
+ protected:
+ std::unique_ptr<WorkingSetTrimmerPolicy> policy_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmerPolicyTest);
+};
+
+// Validate that we can set and get the last trim time on a ProcessNode.
+TEST_F(WorkingSetTrimmerPolicyTest, SetTrimTimeOnNode) {
+ auto process_node = CreateNode<ProcessNodeImpl>();
+ ASSERT_NE(process_node.get(), nullptr);
+
+ auto now_ticks = base::TimeTicks::Now();
+ SetLastTrimTime(process_node.get(), now_ticks);
+ ASSERT_EQ(GetLastTrimTime(process_node.get()), now_ticks);
+}
+
+// Validate that when all frames in a ProcessNode are frozen we attempt to trim
+// the working set.
+TEST_F(WorkingSetTrimmerPolicyTest, TrimOnFrozen) {
+ std::unique_ptr<MockWorkingSetTrimmerPolicy> mock_policy(
+ new MockWorkingSetTrimmerPolicy);
+ auto process_node = CreateNode<ProcessNodeImpl>();
+ ASSERT_NE(process_node.get(), nullptr);
+
+ EXPECT_CALL(*mock_policy, TrimWorkingSet(process_node.get())).Times(1);
+ graph()->PassToGraph(std::move(mock_policy));
+
+ process_node->OnAllFramesInProcessFrozenForTesting();
+}
+
+} // namespace policies
+} // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_win.cc b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_win.cc
new file mode 100644
index 0000000..220d678
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_win.cc
@@ -0,0 +1,27 @@
+// 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.
+
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_win.h"
+
+#include "base/feature_list.h"
+#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer.h"
+#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
+
+namespace performance_manager {
+namespace policies {
+
+WorkingSetTrimmerPolicyWin::WorkingSetTrimmerPolicyWin() = default;
+WorkingSetTrimmerPolicyWin::~WorkingSetTrimmerPolicyWin() = default;
+
+// static
+bool WorkingSetTrimmerPolicyWin::PlatformSupportsWorkingSetTrim() {
+ bool enabled = base::FeatureList::IsEnabled(features::kEmptyWorkingSet);
+ bool supported = mechanism::WorkingSetTrimmer::GetInstance()
+ ->PlatformSupportsWorkingSetTrim();
+
+ return enabled && supported;
+}
+
+} // namespace policies
+} // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_win.h b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_win.h
new file mode 100644
index 0000000..13b1c83
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_win.h
@@ -0,0 +1,33 @@
+// 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_PERFORMANCE_MANAGER_GRAPH_POLICIES_WORKING_SET_TRIMMER_POLICY_WIN_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_POLICIES_WORKING_SET_TRIMMER_POLICY_WIN_H_
+
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h"
+
+namespace performance_manager {
+namespace policies {
+
+// The Windows WorkingSetTrimmerPolicy uses the defaults except it defines it's
+// own PlatformSupportsWorkingSetTrim() because we want to flag guard this
+// feature.
+class WorkingSetTrimmerPolicyWin : public WorkingSetTrimmerPolicy {
+ public:
+ ~WorkingSetTrimmerPolicyWin() override;
+ WorkingSetTrimmerPolicyWin();
+
+ // Returns true if this platform supports working set trim, in the case of
+ // Windows this will check that the appropriate flags are set for working set
+ // trim.
+ static bool PlatformSupportsWorkingSetTrim();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmerPolicyWin);
+};
+
+} // namespace policies
+} // namespace performance_manager
+
+#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_POLICIES_WORKING_SET_TRIMMER_POLICY_WIN_H_
diff --git a/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win_unittest.cc b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_win_unittest.cc
similarity index 93%
rename from chrome/browser/performance_manager/observers/working_set_trimmer_observer_win_unittest.cc
rename to chrome/browser/performance_manager/mechanisms/working_set_trimmer_win_unittest.cc
index 3d6113b..4deb867 100644
--- a/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win_unittest.cc
+++ b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_win_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h"
+#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer_win.h"
#include <windows.h> // Must be in front of other Windows header files.
@@ -110,7 +110,6 @@
base::Process child_process_;
TestNodeWrapper<ProcessNodeImpl> process_node_ =
CreateNode<ProcessNodeImpl>();
- WorkingSetTrimmer working_set_trimmer_;
private:
DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmerTest);
@@ -126,7 +125,12 @@
// When all frames in the process node are frozen, the working set of
// |child_process_| should be emptied.
size_t working_set_before = GetWorkingSetSizeMb(child_process_.Handle());
- working_set_trimmer_.OnAllFramesInProcessFrozen(process_node_.get());
+
+ ASSERT_TRUE(mechanism::WorkingSetTrimmer::GetInstance()
+ ->PlatformSupportsWorkingSetTrim());
+ mechanism::WorkingSetTrimmer::GetInstance()->TrimWorkingSet(
+ process_node_.get());
+
// Make sure the working set has shrunk by at least the 10mb allocation.
EXPECT_GE(working_set_before - 10U,
GetWorkingSetSizeMb(child_process_.Handle()));
diff --git a/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.cc b/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.cc
deleted file mode 100644
index 253eb0ef..0000000
--- a/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2018 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/performance_manager/observers/working_set_trimmer_observer_win.h"
-
-#include "base/logging.h"
-#include "base/process/process.h"
-#include "base/time/time.h"
-#include "chrome/browser/performance_manager/graph/node_base.h"
-#include "chrome/browser/performance_manager/graph/process_node_impl.h"
-#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer.h"
-
-namespace performance_manager {
-
-WorkingSetTrimmer::WorkingSetTrimmer() = default;
-WorkingSetTrimmer::~WorkingSetTrimmer() = default;
-
-void WorkingSetTrimmer::OnPassedToGraph(Graph* graph) {
- RegisterObservers(graph);
-}
-
-void WorkingSetTrimmer::OnTakenFromGraph(Graph* graph) {
- UnregisterObservers(graph);
-}
-
-void WorkingSetTrimmer::OnAllFramesInProcessFrozen(
- const ProcessNode* process_node) {
- auto* trimmer = mechanism::WorkingSetTrimmer::GetInstance();
-
- if (process_node->GetProcess().IsValid() &&
- trimmer->PlatformSupportsWorkingSetTrim())
- trimmer->TrimWorkingSet(process_node);
-}
-
-void WorkingSetTrimmer::RegisterObservers(Graph* graph) {
- graph->AddProcessNodeObserver(this);
-}
-
-void WorkingSetTrimmer::UnregisterObservers(Graph* graph) {
- graph->RemoveProcessNodeObserver(this);
-}
-
-} // namespace performance_manager
diff --git a/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h b/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h
deleted file mode 100644
index f333c68..0000000
--- a/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2018 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_PERFORMANCE_MANAGER_OBSERVERS_WORKING_SET_TRIMMER_OBSERVER_WIN_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_WORKING_SET_TRIMMER_OBSERVER_WIN_H_
-
-#include "base/macros.h"
-#include "chrome/browser/performance_manager/public/graph/graph.h"
-#include "chrome/browser/performance_manager/public/graph/process_node.h"
-
-namespace performance_manager {
-
-// Empties the working set of processes in which all frames are frozen.
-//
-// Objective #1: Track working set growth rate.
-// Swap trashing occurs when a lot of pages are accessed in a short period of
-// time. Swap trashing can be reduced by reducing the number of pages accessed
-// by processes in which all frames are frozen. To track efforts towards this
-// goal, we empty the working set of processes when all their frames become
-// frozen and record the size of their working set after x minutes.
-// TODO(fdoray): Record the working set size x minutes after emptying it.
-// https://crbug.com/885293
-//
-// Objective #2: Improve performance.
-// We hypothesize that emptying the working set of a process causes its pages
-// to be compressed and/or written to disk preemptively, which makes more
-// memory available quickly for foreground processes and improves global
-// browser performance.
-class WorkingSetTrimmer : public GraphOwned,
- public ProcessNode::ObserverDefaultImpl {
- public:
- WorkingSetTrimmer();
- ~WorkingSetTrimmer() override;
-
- // GraphOwned implementation:
- void OnPassedToGraph(Graph* graph) override;
- void OnTakenFromGraph(Graph* graph) override;
-
- // ProcessNodeObserver:
- void OnAllFramesInProcessFrozen(const ProcessNode* process_node) override;
-
- protected:
- // (Un)registers the various node observer flavors of this object with the
- // graph. These are invoked by OnPassedToGraph and OnTakenFromGraph, but
- // hoisted to their own functions for testing.
- void RegisterObservers(Graph* graph);
- void UnregisterObservers(Graph* graph);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmer);
-};
-
-} // namespace performance_manager
-
-#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_WORKING_SET_TRIMMER_OBSERVER_WIN_H_
diff --git a/chrome/browser/performance_manager/performance_manager.cc b/chrome/browser/performance_manager/performance_manager.cc
index 373b3974..8ba37ee 100644
--- a/chrome/browser/performance_manager/performance_manager.cc
+++ b/chrome/browser/performance_manager/performance_manager.cc
@@ -20,11 +20,11 @@
#include "chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h"
#include "chrome/browser/performance_manager/graph/frame_node_impl.h"
#include "chrome/browser/performance_manager/graph/page_node_impl.h"
+#include "chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy.h"
#include "chrome/browser/performance_manager/graph/process_node_impl.h"
#include "chrome/browser/performance_manager/graph/system_node_impl.h"
#include "chrome/browser/performance_manager/observers/isolation_context_metrics.h"
#include "chrome/browser/performance_manager/observers/metrics_collector.h"
-#include "chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h"
#include "content/public/browser/system_connector.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
@@ -322,10 +322,10 @@
graph_.PassToGraph(std::make_unique<IsolationContextMetrics>());
graph_.PassToGraph(std::make_unique<MetricsCollector>());
-#if defined(OS_WIN)
- if (base::FeatureList::IsEnabled(features::kEmptyWorkingSet))
- graph_.PassToGraph(std::make_unique<WorkingSetTrimmer>());
-#endif
+ if (policies::WorkingSetTrimmerPolicy::PlatformSupportsWorkingSetTrim()) {
+ graph_.PassToGraph(
+ policies::WorkingSetTrimmerPolicy::CreatePolicyForPlatform());
+ }
interface_registry_.AddInterface(base::BindRepeating(
&PerformanceManager::BindWebUIGraphDump, base::Unretained(this)));