Commit 74cba8c2 authored by Erik Chen's avatar Erik Chen Committed by Commit Bot

Move logic from ProfilingProcessHost into Supervisor.

This CL is a refactor and has no intended behavior change.

This CL:
  * Creates a new class Supervisor in components/heap_profiling. This class
    presents a single interface for tests and consumers of the Heap Profiling
    Service.
  * Moves end to end test logic into components/heap_profiling.
  * Leaves the emit metrics, save to file, and upload in background logic in
    ProfilingProcessHost.

This refactor is necessary in order to expose this shared logic [previously
located in chrome/] to Android WebView.

The changes in this CL are tested by the end to end tests in
ProfilingTestDriver.

Change-Id: I3fda597b210522404203ac9cf932f7bccd76cad7
Bug: 827545
Reviewed-on: https://chromium-review.googlesource.com/1008366
Commit-Queue: Erik Chen <erikchen@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551055}
parent baa47091
...@@ -848,8 +848,6 @@ chrome_shared_library("libchromefortest") { ...@@ -848,8 +848,6 @@ chrome_shared_library("libchromefortest") {
sources = [ sources = [
"../app/android/chrome_main_delegate_android_initializer.cc", "../app/android/chrome_main_delegate_android_initializer.cc",
"../browser/android/chrome_entry_point_for_test.cc", "../browser/android/chrome_entry_point_for_test.cc",
"../browser/profiling_host/profiling_test_driver.cc",
"../browser/profiling_host/profiling_test_driver.h",
"../browser/profiling_host/test_android_shim.cc", "../browser/profiling_host/test_android_shim.cc",
"../browser/profiling_host/test_android_shim.h", "../browser/profiling_host/test_android_shim.h",
] ]
...@@ -857,6 +855,7 @@ chrome_shared_library("libchromefortest") { ...@@ -857,6 +855,7 @@ chrome_shared_library("libchromefortest") {
":chrome_jni_for_test_registration($default_toolchain)", ":chrome_jni_for_test_registration($default_toolchain)",
"//base/test:test_support", "//base/test:test_support",
"//chrome/browser/profiling_host:jni_headers", "//chrome/browser/profiling_host:jni_headers",
"//components/heap_profiling:test_support",
] ]
} }
......
...@@ -29,8 +29,6 @@ if (!is_android) { ...@@ -29,8 +29,6 @@ if (!is_android) {
sources = [ sources = [
"memlog_browsertest.cc", "memlog_browsertest.cc",
"profiling_test_driver.cc",
"profiling_test_driver.h",
] ]
defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
...@@ -39,6 +37,7 @@ if (!is_android) { ...@@ -39,6 +37,7 @@ if (!is_android) {
"//base", "//base",
"//base/allocator:buildflags", "//base/allocator:buildflags",
"//chrome/test:test_support_ui", "//chrome/test:test_support_ui",
"//components/heap_profiling:test_support",
"//components/services/heap_profiling/public/cpp", "//components/services/heap_profiling/public/cpp",
"//testing/gmock", "//testing/gmock",
"//testing/gtest", "//testing/gtest",
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiling_host/profiling_process_host.h" #include "chrome/browser/profiling_host/profiling_process_host.h"
#include "components/heap_profiling/supervisor.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/common/process_type.h" #include "content/public/common/process_type.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h" #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
...@@ -119,7 +120,7 @@ void BackgroundProfilingTriggers::PerformMemoryUsageChecks() { ...@@ -119,7 +120,7 @@ void BackgroundProfilingTriggers::PerformMemoryUsageChecks() {
std::move(weak_ptr), std::move(result))); std::move(weak_ptr), std::move(result)));
}, },
weak_ptr_factory_.GetWeakPtr()); weak_ptr_factory_.GetWeakPtr());
host_->GetProfiledPids(std::move(callback)); Supervisor::GetInstance()->GetProfiledPids(std::move(callback));
} }
void BackgroundProfilingTriggers::OnReceivedMemoryDump( void BackgroundProfilingTriggers::OnReceivedMemoryDump(
......
...@@ -5,10 +5,24 @@ ...@@ -5,10 +5,24 @@
#include "chrome/browser/profiling_host/chrome_browser_main_extra_parts_profiling.h" #include "chrome/browser/profiling_host/chrome_browser_main_extra_parts_profiling.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "chrome/browser/profiling_host/chrome_client_connection_manager.h"
#include "chrome/browser/profiling_host/profiling_process_host.h" #include "chrome/browser/profiling_host/profiling_process_host.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "components/heap_profiling/supervisor.h"
#include "components/services/heap_profiling/public/cpp/settings.h" #include "components/services/heap_profiling/public/cpp/settings.h"
namespace {
std::unique_ptr<heap_profiling::ClientConnectionManager>
CreateClientConnectionManager(
base::WeakPtr<heap_profiling::Controller> controller_weak_ptr,
heap_profiling::Mode mode) {
return std::make_unique<heap_profiling::ChromeClientConnectionManager>(
controller_weak_ptr, mode);
}
} // namespace
ChromeBrowserMainExtraPartsProfiling::ChromeBrowserMainExtraPartsProfiling() = ChromeBrowserMainExtraPartsProfiling::ChromeBrowserMainExtraPartsProfiling() =
default; default;
ChromeBrowserMainExtraPartsProfiling::~ChromeBrowserMainExtraPartsProfiling() = ChromeBrowserMainExtraPartsProfiling::~ChromeBrowserMainExtraPartsProfiling() =
...@@ -16,6 +30,9 @@ ChromeBrowserMainExtraPartsProfiling::~ChromeBrowserMainExtraPartsProfiling() = ...@@ -16,6 +30,9 @@ ChromeBrowserMainExtraPartsProfiling::~ChromeBrowserMainExtraPartsProfiling() =
void ChromeBrowserMainExtraPartsProfiling::ServiceManagerConnectionStarted( void ChromeBrowserMainExtraPartsProfiling::ServiceManagerConnectionStarted(
content::ServiceManagerConnection* connection) { content::ServiceManagerConnection* connection) {
heap_profiling::Supervisor::GetInstance()
->SetClientConnectionManagerConstructor(&CreateClientConnectionManager);
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
// Memory sanitizers are using large memory shadow to keep track of memory // Memory sanitizers are using large memory shadow to keep track of memory
// state. Using memlog and memory sanitizers at the same time is slowing down // state. Using memlog and memory sanitizers at the same time is slowing down
...@@ -25,9 +42,12 @@ void ChromeBrowserMainExtraPartsProfiling::ServiceManagerConnectionStarted( ...@@ -25,9 +42,12 @@ void ChromeBrowserMainExtraPartsProfiling::ServiceManagerConnectionStarted(
#else #else
heap_profiling::Mode mode = heap_profiling::GetModeForStartup(); heap_profiling::Mode mode = heap_profiling::GetModeForStartup();
if (mode != heap_profiling::Mode::kNone) { if (mode != heap_profiling::Mode::kNone) {
heap_profiling::ProfilingProcessHost::Start( heap_profiling::Supervisor::GetInstance()->Start(
connection, mode, heap_profiling::GetStackModeForStartup(), connection,
heap_profiling::GetSamplingRateForStartup(), base::OnceClosure()); base::BindOnce(
&heap_profiling::ProfilingProcessHost::Start,
base::Unretained(
heap_profiling::ProfilingProcessHost::GetInstance())));
} }
#endif #endif
} }
...@@ -10,12 +10,12 @@ ...@@ -10,12 +10,12 @@
#include "base/trace_event/trace_log.h" #include "base/trace_event/trace_log.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/profiling_host/profiling_process_host.h" #include "chrome/browser/profiling_host/profiling_process_host.h"
#include "chrome/browser/profiling_host/profiling_test_driver.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "components/heap_profiling/test_driver.h"
#include "components/services/heap_profiling/public/cpp/settings.h" #include "components/services/heap_profiling/public/cpp/settings.h"
#include "components/services/heap_profiling/public/cpp/switches.h" #include "components/services/heap_profiling/public/cpp/switches.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
...@@ -84,8 +84,8 @@ IN_PROC_BROWSER_TEST_P(MemlogBrowserTest, EndToEnd) { ...@@ -84,8 +84,8 @@ IN_PROC_BROWSER_TEST_P(MemlogBrowserTest, EndToEnd) {
LOG(INFO) << "Started via command line flag: " LOG(INFO) << "Started via command line flag: "
<< static_cast<int>( << static_cast<int>(
GetParam().start_profiling_with_command_line_flag); GetParam().start_profiling_with_command_line_flag);
ProfilingTestDriver driver; TestDriver driver;
ProfilingTestDriver::Options options; TestDriver::Options options;
options.mode = GetParam().mode; options.mode = GetParam().mode;
options.stack_mode = GetParam().stack_mode; options.stack_mode = GetParam().stack_mode;
options.profiling_already_started = options.profiling_already_started =
......
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "chrome/browser/profiling_host/background_profiling_triggers.h" #include "chrome/browser/profiling_host/background_profiling_triggers.h"
#include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h" #include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
...@@ -20,55 +18,21 @@ namespace base { ...@@ -20,55 +18,21 @@ namespace base {
class FilePath; class FilePath;
} // namespace base } // namespace base
namespace content {
class ServiceManagerConnection;
} // namespace content
namespace service_manager {
class Connector;
} // namespace service_manager
namespace heap_profiling { namespace heap_profiling {
class ChromeClientConnectionManager;
class Controller;
enum class Mode;
// Represents the browser side of the profiling process (//chrome/profiling).
//
// The profiling process is a singleton. The profiling process infrastructure
// is implemented in the Chrome layer so doesn't depend on the content
// infrastructure for managing child processes.
//
// Not thread safe. Should be used on the browser UI thread only. // Not thread safe. Should be used on the browser UI thread only.
// //
// The profiling process host can be started normally while Chrome is running, // This class is responsible for:
// but can also start in a partial mode where the memory logging connections // * Uploading heap dumps via Slow Reports.
// are active but the Mojo control channel has not yet been connected. This is // * Saving heap dumps to disk.
// to support starting the profiling process very early in the startup // * Recording metrics.
// process (to get most memory events) before other infrastructure like the
// I/O thread has been started.
class ProfilingProcessHost { class ProfilingProcessHost {
public: public:
// Returns the mode specified by the command line or via about://flags.
Mode GetMode();
// Launches the heap profiling service and connects clients. Must be called
// from the UI thread. This requires hopping to the IO thread and back.
// |callback| will be called on the UI thread after this is finished.
static void Start(content::ServiceManagerConnection* connection,
Mode mode,
mojom::StackMode stack_mode,
uint32_t sampling_rate,
base::OnceClosure callback);
// Returns true if Start() has been called.
static bool has_started() { return has_started_; }
// Returns a pointer to the current global profiling process host. // Returns a pointer to the current global profiling process host.
static ProfilingProcessHost* GetInstance(); static ProfilingProcessHost* GetInstance();
void ConfigureBackgroundProfilingTriggers(); // Starts background profiling and metrics, if appropriate.
void Start();
// Create a trace with a heap dump at the given path. // Create a trace with a heap dump at the given path.
// This is equivalent to navigating to chrome://tracing, taking a trace with // This is equivalent to navigating to chrome://tracing, taking a trace with
...@@ -85,57 +49,14 @@ class ProfilingProcessHost { ...@@ -85,57 +49,14 @@ class ProfilingProcessHost {
// memory data to the crash server (slow-report). // memory data to the crash server (slow-report).
void RequestProcessReport(std::string trigger_name); void RequestProcessReport(std::string trigger_name);
using TraceFinishedCallback =
base::OnceCallback<void(bool success, std::string trace_json)>;
// This method must be called from the UI thread. |callback| will be called
// asynchronously on the UI thread.
//
// This function does the following:
// 1. Starts tracing with no categories enabled.
// 2. Requests and waits for memory_instrumentation service to dump to
// trace.
// 3. Stops tracing.
//
// Public for testing.
void RequestTraceWithHeapDump(TraceFinishedCallback callback,
bool anonymize);
// Returns the pids of all profiled processes. The callback is posted on the
// UI thread.
using GetProfiledPidsCallback =
base::OnceCallback<void(std::vector<base::ProcessId> pids)>;
void GetProfiledPids(GetProfiledPidsCallback callback);
// Starts profiling the process with the given id.
void StartManualProfiling(base::ProcessId pid);
// Public for testing. Controls whether the profiling service keeps small
// allocations in heap dumps.
void SetKeepSmallAllocations(bool keep_small_allocations);
private: private:
friend struct base::DefaultSingletonTraits<ProfilingProcessHost>; friend struct base::DefaultSingletonTraits<ProfilingProcessHost>;
friend class BackgroundProfilingTriggersTest; friend class BackgroundProfilingTriggersTest;
friend class MemlogBrowserTest; friend class MemlogBrowserTest;
friend class ProfilingTestDriver;
ProfilingProcessHost(); ProfilingProcessHost();
~ProfilingProcessHost(); ~ProfilingProcessHost();
// Starts the profiling process.
void StartServiceOnIOThread(
mojom::StackMode stack_mode,
uint32_t sampling_rate,
std::unique_ptr<service_manager::Connector> connector,
Mode mode,
base::OnceClosure closure);
void FinishPostServiceSetupOnUIThread(
Mode mode,
base::OnceClosure closure,
base::WeakPtr<Controller> controller_weak_ptr);
// Called on the UI thread after the heap dump has been added to the trace. // Called on the UI thread after the heap dump has been added to the trace.
void DumpProcessFinishedUIThread(); void DumpProcessFinishedUIThread();
...@@ -146,21 +67,6 @@ class ProfilingProcessHost { ...@@ -146,21 +67,6 @@ class ProfilingProcessHost {
// Reports the profiling mode. // Reports the profiling mode.
void ReportMetrics(); void ReportMetrics();
void GetProfiledPidsOnIOThread(GetProfiledPidsCallback callback);
void StartProfilingPidOnIOThread(base::ProcessId pid);
bool TakingTraceForUpload();
bool SetTakingTraceForUpload(bool new_state);
// Bound to the IO thread.
std::unique_ptr<service_manager::Connector> connector_;
// Bound to the IO thread.
std::unique_ptr<Controller> controller_;
// Bound to the UI thread.
std::unique_ptr<ChromeClientConnectionManager> client_connection_manager_;
// Handle background triggers on high memory pressure. A trigger will call // Handle background triggers on high memory pressure. A trigger will call
// |RequestProcessReport| on this instance. // |RequestProcessReport| on this instance.
BackgroundProfilingTriggers background_triggers_; BackgroundProfilingTriggers background_triggers_;
...@@ -168,19 +74,6 @@ class ProfilingProcessHost { ...@@ -168,19 +74,6 @@ class ProfilingProcessHost {
// Every 24-hours, reports the profiling mode. // Every 24-hours, reports the profiling mode.
base::RepeatingTimer metrics_timer_; base::RepeatingTimer metrics_timer_;
bool should_sample_ = false;
uint32_t sampling_rate_ = 1;
// Whether or not the profiling host is started.
static bool has_started_;
// True if the instance is attempting to take a trace to upload to the crash
// servers. Pruning of small allocations is always enabled for these traces.
bool taking_trace_for_upload_ = false;
// Guards |taking_trace_for_upload_|.
base::Lock taking_trace_for_upload_lock_;
DISALLOW_COPY_AND_ASSIGN(ProfilingProcessHost); DISALLOW_COPY_AND_ASSIGN(ProfilingProcessHost);
}; };
......
...@@ -5,8 +5,7 @@ ...@@ -5,8 +5,7 @@
#include "chrome/browser/profiling_host/test_android_shim.h" #include "chrome/browser/profiling_host/test_android_shim.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "chrome/browser/profiling_host/profiling_process_host.h" #include "components/heap_profiling/test_driver.h"
#include "chrome/browser/profiling_host/profiling_test_driver.h"
#include "components/services/heap_profiling/public/cpp/settings.h" #include "components/services/heap_profiling/public/cpp/settings.h"
#include "jni/TestAndroidShim_jni.h" #include "jni/TestAndroidShim_jni.h"
...@@ -35,8 +34,8 @@ jboolean TestAndroidShim::RunTestForMode( ...@@ -35,8 +34,8 @@ jboolean TestAndroidShim::RunTestForMode(
const base::android::JavaParamRef<jstring>& stack_mode, const base::android::JavaParamRef<jstring>& stack_mode,
jboolean should_sample, jboolean should_sample,
jboolean sample_everything) { jboolean sample_everything) {
heap_profiling::ProfilingTestDriver driver; heap_profiling::TestDriver driver;
heap_profiling::ProfilingTestDriver::Options options; heap_profiling::TestDriver::Options options;
options.mode = heap_profiling::ConvertStringToMode( options.mode = heap_profiling::ConvertStringToMode(
base::android::ConvertJavaStringToUTF8(mode)); base::android::ConvertJavaStringToUTF8(mode));
options.stack_mode = heap_profiling::ConvertStringToStackMode( options.stack_mode = heap_profiling::ConvertStringToStackMode(
......
...@@ -973,6 +973,7 @@ split_static_library("ui") { ...@@ -973,6 +973,7 @@ split_static_library("ui") {
"//components/flags_ui", "//components/flags_ui",
"//components/gcm_driver", "//components/gcm_driver",
"//components/google/core/browser", "//components/google/core/browser",
"//components/heap_profiling",
"//components/history/content/browser", "//components/history/content/browser",
"//components/history/core/browser", "//components/history/core/browser",
"//components/image_fetcher/core", "//components/image_fetcher/core",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
#include "chrome/grit/browser_resources.h" #include "chrome/grit/browser_resources.h"
#include "components/heap_profiling/supervisor.h"
#include "components/services/heap_profiling/public/cpp/settings.h" #include "components/services/heap_profiling/public/cpp/settings.h"
#include "content/public/browser/browser_child_process_host_iterator.h" #include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -49,7 +50,11 @@ namespace { ...@@ -49,7 +50,11 @@ namespace {
// Returns the string to display at the top of the page for help. // Returns the string to display at the top of the page for help.
std::string GetMessageString() { std::string GetMessageString() {
#if BUILDFLAG(USE_ALLOCATOR_SHIM) #if BUILDFLAG(USE_ALLOCATOR_SHIM)
switch (ProfilingProcessHost::GetInstance()->GetMode()) { Mode mode = Mode::kNone;
if (heap_profiling::Supervisor::GetInstance()->HasStarted()) {
mode = heap_profiling::Supervisor::GetInstance()->GetMode();
}
switch (mode) {
case Mode::kAll: case Mode::kAll:
return std::string("Memory logging is enabled for all processes."); return std::string("Memory logging is enabled for all processes.");
...@@ -249,8 +254,17 @@ void MemoryInternalsDOMHandler::HandleStartProfiling( ...@@ -249,8 +254,17 @@ void MemoryInternalsDOMHandler::HandleStartProfiling(
if (!args->is_list() || args->GetList().size() != 1) if (!args->is_list() || args->GetList().size() != 1)
return; return;
ProfilingProcessHost::GetInstance()->StartManualProfiling( base::ProcessId pid = args->GetList()[0].GetInt();
args->GetList()[0].GetInt()); heap_profiling::Supervisor* supervisor =
heap_profiling::Supervisor::GetInstance();
if (supervisor->HasStarted()) {
supervisor->StartManualProfiling(pid);
} else {
supervisor->Start(
content::ServiceManagerConnection::GetForProcess(),
base::BindOnce(&heap_profiling::Supervisor::StartManualProfiling,
base::Unretained(supervisor), pid));
}
} }
void MemoryInternalsDOMHandler::GetChildProcessesOnIOThread( void MemoryInternalsDOMHandler::GetChildProcessesOnIOThread(
...@@ -278,7 +292,17 @@ void MemoryInternalsDOMHandler::GetChildProcessesOnIOThread( ...@@ -278,7 +292,17 @@ void MemoryInternalsDOMHandler::GetChildProcessesOnIOThread(
void MemoryInternalsDOMHandler::GetProfiledPids( void MemoryInternalsDOMHandler::GetProfiledPids(
std::vector<base::Value> children) { std::vector<base::Value> children) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
ProfilingProcessHost::GetInstance()->GetProfiledPids( heap_profiling::Supervisor* supervisor =
heap_profiling::Supervisor::GetInstance();
if (!supervisor->HasStarted()) {
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::BindOnce(&MemoryInternalsDOMHandler::ReturnProcessListOnUIThread,
weak_factory_.GetWeakPtr(), std::move(children),
std::vector<base::ProcessId>()));
return;
}
supervisor->GetProfiledPids(
base::BindOnce(&MemoryInternalsDOMHandler::ReturnProcessListOnUIThread, base::BindOnce(&MemoryInternalsDOMHandler::ReturnProcessListOnUIThread,
weak_factory_.GetWeakPtr(), std::move(children))); weak_factory_.GetWeakPtr(), std::move(children)));
} }
......
...@@ -6,6 +6,8 @@ static_library("heap_profiling") { ...@@ -6,6 +6,8 @@ static_library("heap_profiling") {
sources = [ sources = [
"client_connection_manager.cc", "client_connection_manager.cc",
"client_connection_manager.h", "client_connection_manager.h",
"supervisor.cc",
"supervisor.h",
] ]
deps = [ deps = [
...@@ -15,3 +17,19 @@ static_library("heap_profiling") { ...@@ -15,3 +17,19 @@ static_library("heap_profiling") {
"//content/public/common", "//content/public/common",
] ]
} }
source_set("test_support") {
testonly = true
sources = [
"test_driver.cc",
"test_driver.h",
]
deps = [
":heap_profiling",
"//base",
"//components/services/heap_profiling/public/cpp",
"//content/public/browser",
"//content/public/common",
]
}
include_rules = [ include_rules = [
"+components/services/heap_profiling/public", "+components/services/heap_profiling/public",
"+content/public", "+content/public",
"+services/resource_coordinator/public/cpp",
"+services/service_manager/public/cpp", "+services/service_manager/public/cpp",
] ]
// 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 "components/heap_profiling/supervisor.h"
#include "base/memory/ref_counted_memory.h"
#include "base/no_destructor.h"
#include "components/heap_profiling/client_connection_manager.h"
#include "components/services/heap_profiling/public/cpp/controller.h"
#include "components/services/heap_profiling/public/cpp/settings.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/tracing_controller.h"
#include "content/public/common/service_manager_connection.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "services/service_manager/public/cpp/connector.h"
namespace heap_profiling {
namespace {
base::trace_event::TraceConfig GetBackgroundTracingConfig(bool anonymize) {
// Disable all categories other than memory-infra.
base::trace_event::TraceConfig trace_config(
"-*,disabled-by-default-memory-infra",
base::trace_event::RECORD_UNTIL_FULL);
// This flag is set by background tracing to filter out undesired events.
if (anonymize)
trace_config.EnableArgumentFilter();
return trace_config;
}
} // namespace
// static
Supervisor* Supervisor::GetInstance() {
static base::NoDestructor<Supervisor> supervisor;
return supervisor.get();
}
Supervisor::Supervisor() = default;
Supervisor::~Supervisor() {
NOTREACHED();
}
bool Supervisor::HasStarted() {
return started_;
}
void Supervisor::SetClientConnectionManagerConstructor(
ClientConnectionManagerConstructor constructor) {
DCHECK(!HasStarted());
constructor_ = constructor;
}
void Supervisor::Start(content::ServiceManagerConnection* connection,
base::OnceClosure closure) {
Start(connection, GetModeForStartup(), GetStackModeForStartup(),
GetSamplingRateForStartup(), std::move(closure));
}
void Supervisor::Start(content::ServiceManagerConnection* connection,
Mode mode,
mojom::StackMode stack_mode,
uint32_t sampling_rate,
base::OnceClosure closure) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(!started_);
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
->PostTask(FROM_HERE,
base::BindOnce(&Supervisor::StartServiceOnIOThread,
base::Unretained(this),
connection->GetConnector()->Clone(), mode,
stack_mode, sampling_rate, std::move(closure)));
}
Mode Supervisor::GetMode() {
DCHECK(HasStarted());
return client_connection_manager_->GetMode();
}
void Supervisor::StartManualProfiling(base::ProcessId pid) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(HasStarted());
client_connection_manager_->StartProfilingProcess(pid);
}
void Supervisor::SetKeepSmallAllocations(bool keep_small_allocations) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(HasStarted());
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
->PostTask(
FROM_HERE,
base::BindOnce(&Supervisor::SetKeepSmallAllocationsOnIOThread,
base::Unretained(this), keep_small_allocations));
}
void Supervisor::GetProfiledPids(GetProfiledPidsCallback callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(HasStarted());
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
->PostTask(FROM_HERE,
base::BindOnce(&Supervisor::GetProfiledPidsOnIOThread,
base::Unretained(this), std::move(callback)));
}
uint32_t Supervisor::GetSamplingRate() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(HasStarted());
return controller_->sampling_rate();
}
void Supervisor::RequestTraceWithHeapDump(TraceFinishedCallback callback,
bool anonymize) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(HasStarted());
if (content::TracingController::GetInstance()->IsTracing()) {
DLOG(ERROR) << "Requesting heap dump when tracing has already started.";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), false, std::string()));
return;
}
auto finished_dump_callback = base::BindOnce(
[](TraceFinishedCallback callback, bool success, uint64_t dump_guid) {
// Once the trace has stopped, run |callback| on the UI thread.
auto finish_sink_callback = base::Bind(
[](TraceFinishedCallback callback,
std::unique_ptr<const base::DictionaryValue> metadata,
base::RefCountedString* in) {
std::string result;
result.swap(in->data());
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::UI)
->PostTask(FROM_HERE,
base::BindOnce(std::move(callback), true,
std::move(result)));
},
base::Passed(std::move(callback)));
scoped_refptr<content::TracingController::TraceDataEndpoint> sink =
content::TracingController::CreateStringEndpoint(
std::move(finish_sink_callback));
content::TracingController::GetInstance()->StopTracing(sink);
},
std::move(callback));
memory_instrumentation::MemoryInstrumentation::GetInstance()
->RequestGlobalDumpAndAppendToTrace(
base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
base::AdaptCallbackForRepeating(std::move(finished_dump_callback)));
// The only reason this should return false is if tracing is already enabled,
// which we've already checked.
bool result = content::TracingController::GetInstance()->StartTracing(
GetBackgroundTracingConfig(anonymize), base::Closure());
DCHECK(result);
}
void Supervisor::StartServiceOnIOThread(
std::unique_ptr<service_manager::Connector> connector,
Mode mode,
mojom::StackMode stack_mode,
uint32_t sampling_rate,
base::OnceClosure closure) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
controller_.reset(
new Controller(std::move(connector), stack_mode, sampling_rate));
base::WeakPtr<Controller> controller_weak_ptr = controller_->GetWeakPtr();
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
->PostTask(FROM_HERE,
base::BindOnce(&Supervisor::FinishInitializationOnUIhread,
base::Unretained(this), mode,
std::move(closure), controller_weak_ptr));
}
void Supervisor::FinishInitializationOnUIhread(
Mode mode,
base::OnceClosure closure,
base::WeakPtr<Controller> controller_weak_ptr) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(!started_);
started_ = true;
if (constructor_) {
client_connection_manager_ = (*constructor_)(controller_weak_ptr, mode);
} else {
client_connection_manager_ =
std::make_unique<ClientConnectionManager>(controller_weak_ptr, mode);
}
client_connection_manager_->Start();
if (closure)
std::move(closure).Run();
}
void Supervisor::GetProfiledPidsOnIOThread(GetProfiledPidsCallback callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
auto post_result_to_ui_thread = base::BindOnce(
[](GetProfiledPidsCallback callback,
const std::vector<base::ProcessId>& result) {
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::UI)
->PostTask(FROM_HERE, base::BindOnce(std::move(callback), result));
},
std::move(callback));
controller_->GetProfiledPids(std::move(post_result_to_ui_thread));
}
void Supervisor::SetKeepSmallAllocationsOnIOThread(
bool keep_small_allocations) {
controller_->SetKeepSmallAllocations(keep_small_allocations);
}
} // namespace heap_profiling
// 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 COMPONENTS_HEAP_PROFILING_SUPERVISOR_H_
#define COMPONENTS_HEAP_PROFILING_SUPERVISOR_H_
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
namespace content {
class ServiceManagerConnection;
} // namespace content
namespace service_manager {
class Connector;
} // namespace service_manager
namespace heap_profiling {
class ClientConnectionManager;
class Controller;
enum class Mode;
// This class presents a single interface for both tests and embedders to use
// the HeapProfilingService. This class is intended to be used from the
// browser/privileged process of the embedder.
//
// This class must be accessed from the UI thread.
//
// Internally, this class:
// * Starts the HeapProfilingService.
// * Hooks up all the connections so that the appropriate processes get
// profiled.
class Supervisor {
public:
static Supervisor* GetInstance();
// When this returns |false|, no method other than Start() or
// SetClientConnectionManagerConstructor() can be called.
bool HasStarted();
// Embedders can use this method to force the Supervisor to instantiate a
// ClientConnectionManager subclass during Start(). The function will be
// called on the UI thread.
using ClientConnectionManagerConstructor =
std::unique_ptr<ClientConnectionManager> (*)(
base::WeakPtr<Controller> controller_weak_ptr,
Mode mode);
void SetClientConnectionManagerConstructor(
ClientConnectionManagerConstructor constructor);
// Must be called at most once.
// The first method is a convenience method that calls the second with
// default parameters.
// Start is an asynchronous operation that must hop to the IO thread and then
// back to the UI thread. |callback| will be invoked on the UI thread after
// this is finished.
//
// This is a brief period of time when this object is in a semi-initialized
// state - when Start has been called, but the thread hops haven't finished.
// We avoid this side case by:
// * Providing a |callback| for callers to use, if they need to do anything
// shortly after Start().
// * Relying on the assumption that in all other cases, the object is either
// fully initialized or not initialized. There are DCHECKs to enforce this
// assumption.
void Start(content::ServiceManagerConnection* connection,
base::OnceClosure callback);
void Start(content::ServiceManagerConnection* connection,
Mode mode,
mojom::StackMode stack_mode,
uint32_t sampling_rate,
base::OnceClosure callback);
Mode GetMode();
// Starts profiling the process with the given id.
void StartManualProfiling(base::ProcessId pid);
// Public for testing. Controls whether the profiling service keeps small
// allocations in heap dumps.
void SetKeepSmallAllocations(bool keep_small_allocations);
// Returns the pids of all profiled processes. The callback is posted on the
// UI thread.
using GetProfiledPidsCallback =
base::OnceCallback<void(std::vector<base::ProcessId> pids)>;
void GetProfiledPids(GetProfiledPidsCallback callback);
uint32_t GetSamplingRate();
using TraceFinishedCallback =
base::OnceCallback<void(bool success, std::string trace_json)>;
// This method must be called from the UI thread. |callback| will be called
// asynchronously on the UI thread.
//
// This function does the following:
// 1. Starts tracing with no categories enabled.
// 2. Requests and waits for memory_instrumentation service to dump to
// trace.
// 3. Stops tracing.
void RequestTraceWithHeapDump(TraceFinishedCallback callback, bool anonymize);
private:
friend class base::NoDestructor<Supervisor>;
Supervisor();
~Supervisor();
// Initialization stage 1: Start the Service on the IO thread.
void StartServiceOnIOThread(
std::unique_ptr<service_manager::Connector> connector,
Mode mode,
mojom::StackMode stack_mode,
uint32_t sampling_rate,
base::OnceClosure callback);
// Initialization stage 2: Start the ClientConnectManager on the UI thread.
void FinishInitializationOnUIhread(
Mode mode,
base::OnceClosure closure,
base::WeakPtr<Controller> controller_weak_ptr);
void GetProfiledPidsOnIOThread(GetProfiledPidsCallback callback);
void SetKeepSmallAllocationsOnIOThread(bool keep_small_allocations);
// Bound to the IO thread.
std::unique_ptr<Controller> controller_;
// Bound to the UI thread.
std::unique_ptr<ClientConnectionManager> client_connection_manager_;
ClientConnectionManagerConstructor constructor_ = nullptr;
bool started_ = false;
DISALLOW_COPY_AND_ASSIGN(Supervisor);
};
} // namespace heap_profiling
#endif // COMPONENTS_HEAP_PROFILING_SUPERVISOR_H_
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef CHROME_BROWSER_PROFILING_HOST_PROFILING_TEST_DRIVER_H_ #ifndef COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_
#define CHROME_BROWSER_PROFILING_HOST_PROFILING_TEST_DRIVER_H_ #define COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_
#include <vector> #include <vector>
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted_memory.h" #include "base/memory/ref_counted_memory.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "chrome/browser/profiling_host/profiling_process_host.h" #include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
namespace base { namespace base {
class Value; class Value;
...@@ -19,11 +19,15 @@ class Value; ...@@ -19,11 +19,15 @@ class Value;
namespace heap_profiling { namespace heap_profiling {
// This class runs tests for the profiling service, a cross-platform, enum class Mode;
// multi-process component. Chrome on Android does not support browser_tests. It
// does support content_browsertests, but those are not multi-process tests. On // This class runs tests for the Heap Profiling Service, a cross-platform,
// Android, processes have to be started via the Activity mechanism, and the // multi-process component.
// test infrastructure does not support this. //
// Chrome on Android does not support browser_tests. It does support
// content_browsertests, but those are not multi-process tests. On Android,
// processes have to be started via the Activity mechanism, and the test
// infrastructure does not support this.
// //
// To avoid test-code duplication, all tests are pulled into this class. // To avoid test-code duplication, all tests are pulled into this class.
// browser_tests will directly call this class. The android // browser_tests will directly call this class. The android
...@@ -37,7 +41,7 @@ namespace heap_profiling { ...@@ -37,7 +41,7 @@ namespace heap_profiling {
// //
// Note: Outputting to stderr will not have the desired effect, since that is // Note: Outputting to stderr will not have the desired effect, since that is
// not captured by logcat. // not captured by logcat.
class ProfilingTestDriver { class TestDriver {
public: public:
struct Options { struct Options {
// The profiling mode to test. // The profiling mode to test.
...@@ -60,8 +64,8 @@ class ProfilingTestDriver { ...@@ -60,8 +64,8 @@ class ProfilingTestDriver {
bool sample_everything; bool sample_everything;
}; };
ProfilingTestDriver(); TestDriver();
~ProfilingTestDriver(); ~TestDriver();
// If this is called on the content::BrowserThread::UI thread, then the // If this is called on the content::BrowserThread::UI thread, then the
// platform must support nested message loops. [This is currently not // platform must support nested message loops. [This is currently not
...@@ -72,10 +76,17 @@ class ProfilingTestDriver { ...@@ -72,10 +76,17 @@ class ProfilingTestDriver {
bool RunTest(const Options& options); bool RunTest(const Options& options);
private: private:
// Populates |has_started_| and then signals |wait_for_ui_thread_|.
void GetHasStartedOnUIThread();
// Populates |initialization_success_| with the result of // Populates |initialization_success_| with the result of
// |RunInitializationOnUIThread|, and then signals |wait_for_ui_thread_|. // |RunInitializationOnUIThread|, and then signals |wait_for_ui_thread_|.
void CheckOrStartProfilingOnUIThreadAndSignal(); void CheckOrStartProfilingOnUIThreadAndSignal();
// Calls Supervisor::SetKeepSmallAllocations() and then signals
// |wait_for_ui_thread_|.
void SetKeepSmallAllocationsOnUIThreadAndSignal();
// If profiling is expected to already be started, confirm it. // If profiling is expected to already be started, confirm it.
// Otherwise, start profiling with the given mode. // Otherwise, start profiling with the given mode.
bool CheckOrStartProfiling(); bool CheckOrStartProfiling();
...@@ -131,6 +142,9 @@ class ProfilingTestDriver { ...@@ -131,6 +142,9 @@ class ProfilingTestDriver {
// Whether the test was invoked on the ui thread. // Whether the test was invoked on the ui thread.
bool running_on_ui_thread_ = true; bool running_on_ui_thread_ = true;
// Whether the supervisor has started.
bool has_started_ = false;
// Whether an error has occurred. // Whether an error has occurred.
bool initialization_success_ = false; bool initialization_success_ = false;
...@@ -140,9 +154,9 @@ class ProfilingTestDriver { ...@@ -140,9 +154,9 @@ class ProfilingTestDriver {
base::WaitableEvent wait_for_ui_thread_; base::WaitableEvent wait_for_ui_thread_;
DISALLOW_COPY_AND_ASSIGN(ProfilingTestDriver); DISALLOW_COPY_AND_ASSIGN(TestDriver);
}; };
} // namespace heap_profiling } // namespace heap_profiling
#endif // CHROME_BROWSER_PROFILING_HOST_PROFILING_TEST_DRIVER_H_ #endif // COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_
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