| Index: content/browser/memory/memory_coordinator_impl.cc
|
| diff --git a/content/browser/memory/memory_coordinator_impl.cc b/content/browser/memory/memory_coordinator_impl.cc
|
| index 2340b237efcc9d08cae6a8caa311b3d5cc402e0a..c5bf7f1e8afb655fbc89da76a044745565a69ae9 100644
|
| --- a/content/browser/memory/memory_coordinator_impl.cc
|
| +++ b/content/browser/memory/memory_coordinator_impl.cc
|
| @@ -5,6 +5,7 @@
|
| #include "content/browser/memory/memory_coordinator_impl.h"
|
|
|
| #include "base/metrics/histogram_macros.h"
|
| +#include "base/process/process_metrics.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| #include "base/trace_event/trace_event.h"
|
| #include "content/browser/memory/memory_monitor.h"
|
| @@ -52,6 +53,62 @@ mojom::MemoryState ToMojomMemoryState(base::MemoryState state) {
|
| }
|
| }
|
|
|
| +void RecordMetricsOnStateChange(base::MemoryState prev_state,
|
| + base::MemoryState next_state,
|
| + base::TimeDelta duration,
|
| + size_t total_private_mb) {
|
| +#define RECORD_METRICS(transition) \
|
| + UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Coordinator.TotalPrivate." transition, \
|
| + total_private_mb); \
|
| + UMA_HISTOGRAM_CUSTOM_TIMES("Memory.Coordinator.StateDuration." transition, \
|
| + duration, base::TimeDelta::FromSeconds(30), \
|
| + base::TimeDelta::FromHours(24), 50);
|
| +
|
| + if (prev_state == base::MemoryState::NORMAL) {
|
| + switch (next_state) {
|
| + case base::MemoryState::THROTTLED:
|
| + RECORD_METRICS("NormalToThrottled");
|
| + break;
|
| + case base::MemoryState::SUSPENDED:
|
| + RECORD_METRICS("NormalToSuspended");
|
| + break;
|
| + case base::MemoryState::UNKNOWN:
|
| + case base::MemoryState::NORMAL:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + } else if (prev_state == base::MemoryState::THROTTLED) {
|
| + switch (next_state) {
|
| + case base::MemoryState::NORMAL:
|
| + RECORD_METRICS("ThrottledToNormal");
|
| + break;
|
| + case base::MemoryState::SUSPENDED:
|
| + RECORD_METRICS("ThrottledToSuspended");
|
| + break;
|
| + case base::MemoryState::UNKNOWN:
|
| + case base::MemoryState::THROTTLED:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + } else if (prev_state == base::MemoryState::SUSPENDED) {
|
| + switch (next_state) {
|
| + case base::MemoryState::NORMAL:
|
| + RECORD_METRICS("SuspendedToNormal");
|
| + break;
|
| + case base::MemoryState::THROTTLED:
|
| + RECORD_METRICS("SuspendedToThrottled");
|
| + break;
|
| + case base::MemoryState::UNKNOWN:
|
| + case base::MemoryState::SUSPENDED:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| +#undef RECORD_METRICS
|
| +}
|
| +
|
| } // namespace
|
|
|
| // SingletonTraits for MemoryCoordinator. Returns MemoryCoordinatorImpl
|
| @@ -194,6 +251,7 @@ base::MemoryState MemoryCoordinatorImpl::CalculateNextState() {
|
| }
|
|
|
| void MemoryCoordinatorImpl::UpdateState() {
|
| + base::TimeTicks prev_last_state_change = last_state_change_;
|
| base::TimeTicks now = base::TimeTicks::Now();
|
| MemoryState prev_state = current_state_;
|
| MemoryState next_state = CalculateNextState();
|
| @@ -208,6 +266,7 @@ void MemoryCoordinatorImpl::UpdateState() {
|
| "prev", MemoryStateToString(prev_state),
|
| "next", MemoryStateToString(next_state));
|
|
|
| + RecordStateChange(prev_state, next_state, now - prev_last_state_change);
|
| NotifyStateToClients();
|
| NotifyStateToChildren();
|
| ScheduleUpdateState(minimum_transition_period_);
|
| @@ -229,6 +288,34 @@ void MemoryCoordinatorImpl::NotifyStateToChildren() {
|
| SetChildMemoryState(iter.first, mojo_state);
|
| }
|
|
|
| +void MemoryCoordinatorImpl::RecordStateChange(MemoryState prev_state,
|
| + MemoryState next_state,
|
| + base::TimeDelta duration) {
|
| + size_t total_private_kb = 0;
|
| +
|
| + // TODO(bashi): On MacOS we can't get process metrics for child processes and
|
| + // therefore can't calculate the total private memory.
|
| +#if !defined(OS_MACOSX)
|
| + auto browser_metrics = base::ProcessMetrics::CreateCurrentProcessMetrics();
|
| + base::WorkingSetKBytes working_set;
|
| + browser_metrics->GetWorkingSetKBytes(&working_set);
|
| + total_private_kb += working_set.priv;
|
| +
|
| + for (auto& iter : children()) {
|
| + auto* render_process_host = RenderProcessHost::FromID(iter.first);
|
| + DCHECK(render_process_host);
|
| + DCHECK(render_process_host->GetHandle() != base::kNullProcessHandle);
|
| + auto metrics = base::ProcessMetrics::CreateProcessMetrics(
|
| + render_process_host->GetHandle());
|
| + metrics->GetWorkingSetKBytes(&working_set);
|
| + total_private_kb += working_set.priv;
|
| + }
|
| +#endif
|
| +
|
| + RecordMetricsOnStateChange(prev_state, next_state, duration,
|
| + total_private_kb / 1024);
|
| +}
|
| +
|
| void MemoryCoordinatorImpl::ScheduleUpdateState(base::TimeDelta delta) {
|
| task_runner_->PostDelayedTask(FROM_HERE, update_state_callback_, delta);
|
| }
|
|
|