Index: content/browser/memory/memory_state_updater.cc |
diff --git a/content/browser/memory/memory_state_updater.cc b/content/browser/memory/memory_state_updater.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..fb75dbd2016aecfef0b80fb4da54a4826a0c76f2 |
--- /dev/null |
+++ b/content/browser/memory/memory_state_updater.cc |
@@ -0,0 +1,173 @@ |
+// Copyright 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 "content/browser/memory/memory_state_updater.h" |
+ |
+#include "base/metrics/histogram_macros.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "components/variations/variations_associated_data.h" |
+#include "content/browser/memory/memory_monitor.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+// A expected renderer size. These values come from the median of appropriate |
+// UMA stats. |
+#if defined(OS_ANDROID) || defined(OS_IOS) |
+const int kDefaultExpectedRendererSizeMB = 40; |
+#elif defined(OS_WIN) |
+const int kDefaultExpectedRendererSizeMB = 70; |
+#else // Mac, Linux, and ChromeOS |
+const int kDefaultExpectedRendererSizeMB = 120; |
+#endif |
+ |
+// Default values for parameters to determine the global state. |
+const int kDefaultNewRenderersUntilThrottled = 4; |
+const int kDefaultNewRenderersUntilSuspended = 2; |
+const int kDefaultNewRenderersBackToNormal = 5; |
+const int kDefaultNewRenderersBackToThrottled = 3; |
+const int kDefaultMinimumTransitionPeriodSeconds = 30; |
+const int kDefaultMonitoringIntervalSeconds = 5; |
+ |
+void SetIntVariationParameter(const std::map<std::string, std::string> params, |
+ const char* name, |
+ int* target) { |
+ const auto& iter = params.find(name); |
+ if (iter == params.end()) |
+ return; |
+ int value; |
+ if (!iter->second.empty() && base::StringToInt(iter->second, &value)) { |
+ DCHECK(value > 0); |
+ *target = value; |
+ } |
+} |
+ |
+void SetSecondsVariationParameter( |
+ const std::map<std::string, std::string> params, |
+ const char* name, |
+ base::TimeDelta* target) { |
+ const auto& iter = params.find(name); |
+ if (iter == params.end()) |
+ return; |
+ int value; |
+ if (!iter->second.empty() && base::StringToInt(iter->second, &value)) { |
+ DCHECK(value > 0); |
+ *target = base::TimeDelta::FromSeconds(value); |
+ } |
+} |
+ |
+} // namespace |
+ |
+MemoryStateUpdater::MemoryStateUpdater( |
+ MemoryCoordinatorImpl* coordinator, |
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
+ : coordinator_(coordinator), task_runner_(task_runner) { |
+ DCHECK(coordinator_); |
+ InitializeParameters(); |
+ DCHECK(ValidateParameters()); |
+} |
+ |
+MemoryStateUpdater::~MemoryStateUpdater() {} |
+ |
+base::MemoryState MemoryStateUpdater::CalculateNextState() { |
+ using MemoryState = base::MemoryState; |
+ |
+ int available = |
+ coordinator_->memory_monitor()->GetFreeMemoryUntilCriticalMB(); |
+ |
+ // TODO(chrisha): Move this histogram recording to a better place when |
+ // https://codereview.chromium.org/2479673002/ is landed. |
+ UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Coordinator.FreeMemoryUntilCritical", |
+ available); |
+ |
+ if (available <= 0) |
+ return MemoryState::SUSPENDED; |
+ |
+ auto current_state = coordinator_->GetGlobalMemoryState(); |
+ int expected_renderer_count = available / expected_renderer_size_; |
+ |
+ switch (current_state) { |
+ case MemoryState::NORMAL: |
+ if (expected_renderer_count <= new_renderers_until_suspended_) |
+ return MemoryState::SUSPENDED; |
+ if (expected_renderer_count <= new_renderers_until_throttled_) |
+ return MemoryState::THROTTLED; |
+ return MemoryState::NORMAL; |
+ case MemoryState::THROTTLED: |
+ if (expected_renderer_count <= new_renderers_until_suspended_) |
+ return MemoryState::SUSPENDED; |
+ if (expected_renderer_count >= new_renderers_back_to_normal_) |
+ return MemoryState::NORMAL; |
+ return MemoryState::THROTTLED; |
+ case MemoryState::SUSPENDED: |
+ if (expected_renderer_count >= new_renderers_back_to_normal_) |
+ return MemoryState::NORMAL; |
+ if (expected_renderer_count >= new_renderers_back_to_throttled_) |
+ return MemoryState::THROTTLED; |
+ return MemoryState::SUSPENDED; |
+ case MemoryState::UNKNOWN: |
+ // Fall through |
+ default: |
+ NOTREACHED(); |
+ return MemoryState::UNKNOWN; |
+ } |
+} |
+ |
+void MemoryStateUpdater::UpdateState() { |
+ auto current_state = coordinator_->GetGlobalMemoryState(); |
+ auto next_state = CalculateNextState(); |
+ if (coordinator_->ChangeStateIfNeeded(current_state, next_state)) { |
+ ScheduleUpdateState(minimum_transition_period_); |
+ } else { |
+ ScheduleUpdateState(monitoring_interval_); |
+ } |
+} |
+ |
+void MemoryStateUpdater::ScheduleUpdateState(base::TimeDelta delta) { |
+ update_state_closure_.Reset(base::Bind(&MemoryStateUpdater::UpdateState, |
+ base::Unretained(this))); |
+ task_runner_->PostDelayedTask(FROM_HERE, update_state_closure_.callback(), |
+ delta); |
+} |
+ |
+void MemoryStateUpdater::InitializeParameters() { |
+ expected_renderer_size_ = kDefaultExpectedRendererSizeMB; |
+ new_renderers_until_throttled_ = kDefaultNewRenderersUntilThrottled; |
+ new_renderers_until_suspended_ = kDefaultNewRenderersUntilSuspended; |
+ new_renderers_back_to_normal_ = kDefaultNewRenderersBackToNormal; |
+ new_renderers_back_to_throttled_ = kDefaultNewRenderersBackToThrottled; |
+ minimum_transition_period_ = |
+ base::TimeDelta::FromSeconds(kDefaultMinimumTransitionPeriodSeconds); |
+ monitoring_interval_ = |
+ base::TimeDelta::FromSeconds(kDefaultMonitoringIntervalSeconds); |
+ |
+ // Override default parameters with variations. |
+ static constexpr char kMemoryCoordinatorV0Trial[] = "MemoryCoordinatorV0"; |
+ std::map<std::string, std::string> params; |
+ variations::GetVariationParams(kMemoryCoordinatorV0Trial, ¶ms); |
+ SetIntVariationParameter(params, "expected_renderer_size", |
+ &expected_renderer_size_); |
+ SetIntVariationParameter(params, "new_renderers_until_throttled", |
+ &new_renderers_until_throttled_); |
+ SetIntVariationParameter(params, "new_renderers_until_suspended", |
+ &new_renderers_until_suspended_); |
+ SetIntVariationParameter(params, "new_renderers_back_to_normal", |
+ &new_renderers_back_to_normal_); |
+ SetIntVariationParameter(params, "new_renderers_back_to_throttled", |
+ &new_renderers_back_to_throttled_); |
+ SetSecondsVariationParameter(params, "minimum_transition_period", |
+ &minimum_transition_period_); |
+ SetSecondsVariationParameter(params, "monitoring_interval", |
+ &monitoring_interval_); |
+} |
+ |
+bool MemoryStateUpdater::ValidateParameters() { |
+ return (new_renderers_until_throttled_ > new_renderers_until_suspended_) && |
+ (new_renderers_back_to_normal_ > new_renderers_back_to_throttled_) && |
+ (new_renderers_back_to_normal_ > new_renderers_until_throttled_) && |
+ (new_renderers_back_to_throttled_ > new_renderers_until_suspended_); |
+} |
+ |
+} // namespace content |