Commit d911f7ff authored by Takashi SAKAMOTO's avatar Takashi SAKAMOTO Committed by Commit Bot

[2/2] Report Memory_Experimental UKM 1, 5, 10 and 15 minutes after each tab's page load

We would like to see more Memory_Experimental UKM after page load.
We are thinking that renderer memory usage will quickly grow after page load.
However, currently Memory_Experimental UKM is reported every 30 minutes, and
is not related to any page load.

ProcessMemoryMetricsEmitter's change was https://chromium-review.googlesource.com/1032150
and submitted.

Bug: 837498
Change-Id: I16eb5997879fb9a16b647969dc9e73503211065c
Reviewed-on: https://chromium-review.googlesource.com/925987
Commit-Queue: Takashi Sakamoto <tasak@google.com>
Reviewed-by: default avatarChris Hamilton <chrisha@chromium.org>
Cr-Commit-Position: refs/heads/master@{#560948}
parent 6abf93f5
...@@ -1264,6 +1264,10 @@ jumbo_split_static_library("browser") { ...@@ -1264,6 +1264,10 @@ jumbo_split_static_library("browser") {
"resource_coordinator/resource_coordinator_web_contents_observer.h", "resource_coordinator/resource_coordinator_web_contents_observer.h",
"resource_coordinator/tab_load_tracker.cc", "resource_coordinator/tab_load_tracker.cc",
"resource_coordinator/tab_load_tracker.h", "resource_coordinator/tab_load_tracker.h",
"resource_coordinator/tab_memory_metrics_reporter.cc",
"resource_coordinator/tab_memory_metrics_reporter.h",
"resource_coordinator/time.cc",
"resource_coordinator/time.h",
"resources_util.cc", "resources_util.cc",
"resources_util.h", "resources_util.h",
"safe_search_api/safe_search_url_checker.cc", "safe_search_api/safe_search_url_checker.cc",
...@@ -2691,8 +2695,6 @@ jumbo_split_static_library("browser") { ...@@ -2691,8 +2695,6 @@ jumbo_split_static_library("browser") {
"resource_coordinator/tab_manager_web_contents_data.h", "resource_coordinator/tab_manager_web_contents_data.h",
"resource_coordinator/tab_metrics_logger.cc", "resource_coordinator/tab_metrics_logger.cc",
"resource_coordinator/tab_metrics_logger.h", "resource_coordinator/tab_metrics_logger.h",
"resource_coordinator/time.cc",
"resource_coordinator/time.h",
"search/iframe_source.cc", "search/iframe_source.cc",
"search/iframe_source.h", "search/iframe_source.h",
"search/instant_service.cc", "search/instant_service.cc",
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "chrome/browser/resource_coordinator/page_signal_receiver.h" #include "chrome/browser/resource_coordinator/page_signal_receiver.h"
#include "chrome/browser/resource_coordinator/tab_load_tracker.h" #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
#include "chrome/browser/resource_coordinator/tab_manager.h" #include "chrome/browser/resource_coordinator/tab_manager.h"
#include "chrome/browser/resource_coordinator/tab_memory_metrics_reporter.h"
#include "content/public/browser/navigation_handle.h" #include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
...@@ -27,6 +28,7 @@ ...@@ -27,6 +28,7 @@
#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/connector.h"
using resource_coordinator::TabLoadTracker; using resource_coordinator::TabLoadTracker;
using resource_coordinator::TabMemoryMetricsReporter;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(ResourceCoordinatorWebContentsObserver); DEFINE_WEB_CONTENTS_USER_DATA_KEY(ResourceCoordinatorWebContentsObserver);
...@@ -59,6 +61,7 @@ ResourceCoordinatorWebContentsObserver::ResourceCoordinatorWebContentsObserver( ...@@ -59,6 +61,7 @@ ResourceCoordinatorWebContentsObserver::ResourceCoordinatorWebContentsObserver(
} }
TabLoadTracker::Get()->StartTracking(web_contents); TabLoadTracker::Get()->StartTracking(web_contents);
TabMemoryMetricsReporter::Get()->StartReporting(TabLoadTracker::Get());
} }
ResourceCoordinatorWebContentsObserver:: ResourceCoordinatorWebContentsObserver::
......
// 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/resource_coordinator/tab_memory_metrics_reporter.h"
#include <cstdint>
#include <memory>
#include "base/process/process.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/process_memory_metrics_emitter.h"
#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
namespace resource_coordinator {
// static
TabMemoryMetricsReporter* TabMemoryMetricsReporter::Get() {
static base::NoDestructor<TabMemoryMetricsReporter>
tab_memory_metrics_reporter;
return tab_memory_metrics_reporter.get();
}
TabMemoryMetricsReporter::TabMemoryMetricsReporter() = default;
TabMemoryMetricsReporter::~TabMemoryMetricsReporter() = default;
TabMemoryMetricsReporter::TabMemoryMetricsReporter(
const base::TickClock* tick_clock)
: update_timer_(tick_clock) {}
void TabMemoryMetricsReporter::StartReporting(TabLoadTracker* tracker) {
if (reporting_started_)
return;
tracker->AddObserver(this);
reporting_started_ = true;
}
void TabMemoryMetricsReporter::OnStartTracking(
content::WebContents* web_contents,
TabLoadTracker::LoadingState loading_state) {
if (loading_state != TabLoadTracker::LoadingState::LOADED)
return;
MonitorWebContents(web_contents);
}
void TabMemoryMetricsReporter::OnLoadingStateChange(
content::WebContents* web_contents,
TabLoadTracker::LoadingState loading_state) {
if (loading_state != TabLoadTracker::LoadingState::LOADED)
return;
MonitorWebContents(web_contents);
}
void TabMemoryMetricsReporter::RemoveWebContentsDataFromMonitoredListIfExists(
content::WebContents* web_contents) {
for (auto it = monitored_contents_.begin(); it != monitored_contents_.end();
++it) {
if (it->web_contents == web_contents) {
monitored_contents_.erase(it);
break;
}
}
}
void TabMemoryMetricsReporter::MonitorWebContents(
content::WebContents* web_contents) {
base::TimeTicks current_time = NowTicks();
WebContentsData data;
data.page_loaded_time = current_time;
data.next_emit_time = data.page_loaded_time + base::TimeDelta::FromMinutes(1);
data.state = NO_METRICS_EMITTED;
data.web_contents = web_contents;
RemoveWebContentsDataFromMonitoredListIfExists(web_contents);
monitored_contents_.insert(data);
if (monitored_contents_.cbegin()->web_contents != web_contents)
return;
RestartTimerIfNeeded(current_time);
}
void TabMemoryMetricsReporter::OnStopTracking(
content::WebContents* web_contents,
TabLoadTracker::LoadingState loading_state) {
bool should_update_timer =
!monitored_contents_.empty() &&
monitored_contents_.cbegin()->web_contents == web_contents;
RemoveWebContentsDataFromMonitoredListIfExists(web_contents);
if (!should_update_timer)
return;
RestartTimerIfNeeded(NowTicks());
}
void TabMemoryMetricsReporter::UpdateTimerCallback() {
base::TimeTicks current_time = NowTicks();
// A list of renderers whose memory dumps were emitted.
std::forward_list<WebContentsData> renderers_memory_dumped;
// Extract all WebContentsData whose next_emit_time have expired,
// and emit metrics for them.
std::set<WebContentsData>::iterator it = monitored_contents_.begin();
while (it != monitored_contents_.end() &&
it->next_emit_time <= current_time) {
EmitMemoryMetricsAfterPageLoaded(*it);
renderers_memory_dumped.push_front(*it);
it = monitored_contents_.erase(it);
}
// Advance the state of each item that just emitted metrics.
// If they aren't done, put them back into the monitored list
// with the time of their next event.
while (!renderers_memory_dumped.empty()) {
WebContentsData& data = renderers_memory_dumped.front();
data.state = NextStateOfEmitMemoryDumpAfterPageLoaded(
current_time - data.page_loaded_time);
if (data.state < EMITTED_ALL_METRICS) {
data.next_emit_time =
data.page_loaded_time + NextEmitTimeAfterPageLoaded(data.state);
DCHECK(data.next_emit_time > current_time);
monitored_contents_.insert(data);
}
renderers_memory_dumped.pop_front();
}
RestartTimerIfNeeded(current_time);
}
void TabMemoryMetricsReporter::RestartTimerIfNeeded(
base::TimeTicks current_time) {
update_timer_.Stop();
if (monitored_contents_.empty())
return;
base::TimeDelta timeout =
monitored_contents_.cbegin()->next_emit_time - current_time;
update_timer_.Start(FROM_HERE, timeout, this,
&TabMemoryMetricsReporter::UpdateTimerCallback);
}
void TabMemoryMetricsReporter::EmitMemoryMetricsAfterPageLoaded(
const TabMemoryMetricsReporter::WebContentsData& content_data) {
content::RenderFrameHost* render_frame_host =
content_data.web_contents->GetMainFrame();
if (!render_frame_host)
return;
// To record only this tab's process memory metrics, we will create
// ProcessMemoryMetricsEmitter with pid.
scoped_refptr<ProcessMemoryMetricsEmitter> emitter(
new ProcessMemoryMetricsEmitter(
render_frame_host->GetProcess()->GetProcess().Pid()));
emitter->FetchAndEmitProcessMemoryMetrics();
}
base::TimeDelta TabMemoryMetricsReporter::NextEmitTimeAfterPageLoaded(
TabMemoryMetricsReporter::ReportState state) {
static constexpr base::TimeDelta next_emit_time_after_page_loaded[] = {
base::TimeDelta::FromMinutes(1), base::TimeDelta::FromMinutes(5),
base::TimeDelta::FromMinutes(10), base::TimeDelta::FromMinutes(15)};
DCHECK(NO_METRICS_EMITTED <= state && state < EMITTED_ALL_METRICS);
return next_emit_time_after_page_loaded[state];
}
TabMemoryMetricsReporter::ReportState
TabMemoryMetricsReporter::NextStateOfEmitMemoryDumpAfterPageLoaded(
base::TimeDelta time_passed) {
if (time_passed >= base::TimeDelta::FromMinutes(15))
return EMITTED_ALL_METRICS;
if (time_passed >= base::TimeDelta::FromMinutes(10))
return EMITTED_10MIN_METRIC;
if (time_passed >= base::TimeDelta::FromMinutes(5))
return EMITTED_5MIN_METRIC;
if (time_passed >= base::TimeDelta::FromMinutes(1))
return EMITTED_1MIN_METRIC;
return NO_METRICS_EMITTED;
}
bool TabMemoryMetricsReporter::WebContentsDataComparator::operator()(
const WebContentsData& a,
const WebContentsData& b) {
return a.next_emit_time < b.next_emit_time;
}
} // namespace resource_coordinator
// 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_RESOURCE_COORDINATOR_TAB_MEMORY_METRICS_REPORTER_H_
#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MEMORY_METRICS_REPORTER_H_
#include "base/gtest_prod_util.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
#include "chrome/browser/resource_coordinator/time.h"
namespace content {
class WebContents;
} // namespace content
namespace resource_coordinator {
// The TabMemoryMetricsReporter reports each tab's Memory_Experimental UKM
// 1, 5, 10, 15 minutes after the tab is loaded.
class TabMemoryMetricsReporter : public TabLoadTracker::Observer {
public:
TabMemoryMetricsReporter();
~TabMemoryMetricsReporter() override;
// Returns the singleton TabMemoryMetricsReporter instance.
static TabMemoryMetricsReporter* Get();
void StartReporting(TabLoadTracker* tracker);
void OnStartTracking(content::WebContents* web_contents,
LoadingState loading_state) override;
void OnLoadingStateChange(content::WebContents* web_contents,
LoadingState loading_state) override;
void OnStopTracking(content::WebContents* web_contents,
LoadingState loading_state) override;
private:
// For unittesting.
friend class TestTabMemoryMetricsReporter;
// Constructor for TabMemoryMetricsReporterTest.
explicit TabMemoryMetricsReporter(const base::TickClock* tick_clock);
void UpdateTimerCallback();
enum ReportState {
NO_METRICS_EMITTED,
EMITTED_1MIN_METRIC,
EMITTED_5MIN_METRIC,
EMITTED_10MIN_METRIC,
EMITTED_ALL_METRICS,
CONTENT_GONE
};
struct WebContentsData {
base::TimeTicks page_loaded_time;
base::TimeTicks next_emit_time;
ReportState state;
content::WebContents* web_contents;
};
struct WebContentsDataComparator {
bool operator()(const WebContentsData& a, const WebContentsData& b);
};
void MonitorWebContents(content::WebContents* web_contents);
void RemoveWebContentsDataFromMonitoredListIfExists(
content::WebContents* web_contents);
void RestartTimerIfNeeded(base::TimeTicks current_time);
// Returns next emit time after page loaded.
static base::TimeDelta NextEmitTimeAfterPageLoaded(ReportState);
// Returns next state of process memory dump after page loaded.
static ReportState NextStateOfEmitMemoryDumpAfterPageLoaded(
base::TimeDelta time_passed);
// Emit process memory dump of the specified process.
// Make this method virtual for TabMemoryMetricsReporterTest.
virtual void EmitMemoryMetricsAfterPageLoaded(
const WebContentsData& content_data);
// true if this TabMemoryMetricsReporter has already invoked
// TabLoadTracker::AddObserver.
// TODO(tasak): clean up this up once there's a single cross-platform
// static initialization codepath in resource_coordinator.
bool reporting_started_ = false;
// Timer to periodically update the stats of the renderers.
base::OneShotTimer update_timer_;
// A list of web contents to be reported their memory usage, sorted by
// next_emit_time.
std::set<WebContentsData, WebContentsDataComparator> monitored_contents_;
DISALLOW_COPY_AND_ASSIGN(TabMemoryMetricsReporter);
};
} // namespace resource_coordinator
#endif // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MEMORY_METRICS_REPORTER_H_
...@@ -2946,6 +2946,7 @@ test("unit_tests") { ...@@ -2946,6 +2946,7 @@ test("unit_tests") {
"../browser/resource_coordinator/tab_manager_stats_collector_unittest.cc", "../browser/resource_coordinator/tab_manager_stats_collector_unittest.cc",
"../browser/resource_coordinator/tab_manager_unittest.cc", "../browser/resource_coordinator/tab_manager_unittest.cc",
"../browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc", "../browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc",
"../browser/resource_coordinator/tab_memory_metrics_reporter_unittest.cc",
"../browser/resource_coordinator/tab_metrics_logger_unittest.cc", "../browser/resource_coordinator/tab_metrics_logger_unittest.cc",
"../browser/resource_coordinator/tab_ranker/tab_score_predictor_unittest.cc", "../browser/resource_coordinator/tab_ranker/tab_score_predictor_unittest.cc",
......
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