| 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
|
|
|