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") {
sources = [
"../app/android/chrome_main_delegate_android_initializer.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.h",
]
......@@ -857,6 +855,7 @@ chrome_shared_library("libchromefortest") {
":chrome_jni_for_test_registration($default_toolchain)",
"//base/test:test_support",
"//chrome/browser/profiling_host:jni_headers",
"//components/heap_profiling:test_support",
]
}
......
......@@ -29,8 +29,6 @@ if (!is_android) {
sources = [
"memlog_browsertest.cc",
"profiling_test_driver.cc",
"profiling_test_driver.h",
]
defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
......@@ -39,6 +37,7 @@ if (!is_android) {
"//base",
"//base/allocator:buildflags",
"//chrome/test:test_support_ui",
"//components/heap_profiling:test_support",
"//components/services/heap_profiling/public/cpp",
"//testing/gmock",
"//testing/gtest",
......
......@@ -11,6 +11,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.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/common/process_type.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
......@@ -119,7 +120,7 @@ void BackgroundProfilingTriggers::PerformMemoryUsageChecks() {
std::move(weak_ptr), std::move(result)));
},
weak_ptr_factory_.GetWeakPtr());
host_->GetProfiledPids(std::move(callback));
Supervisor::GetInstance()->GetProfiledPids(std::move(callback));
}
void BackgroundProfilingTriggers::OnReceivedMemoryDump(
......
......@@ -5,10 +5,24 @@
#include "chrome/browser/profiling_host/chrome_browser_main_extra_parts_profiling.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/common/chrome_switches.h"
#include "components/heap_profiling/supervisor.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() =
default;
ChromeBrowserMainExtraPartsProfiling::~ChromeBrowserMainExtraPartsProfiling() =
......@@ -16,6 +30,9 @@ ChromeBrowserMainExtraPartsProfiling::~ChromeBrowserMainExtraPartsProfiling() =
void ChromeBrowserMainExtraPartsProfiling::ServiceManagerConnectionStarted(
content::ServiceManagerConnection* connection) {
heap_profiling::Supervisor::GetInstance()
->SetClientConnectionManagerConstructor(&CreateClientConnectionManager);
#if defined(ADDRESS_SANITIZER)
// 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
......@@ -25,9 +42,12 @@ void ChromeBrowserMainExtraPartsProfiling::ServiceManagerConnectionStarted(
#else
heap_profiling::Mode mode = heap_profiling::GetModeForStartup();
if (mode != heap_profiling::Mode::kNone) {
heap_profiling::ProfilingProcessHost::Start(
connection, mode, heap_profiling::GetStackModeForStartup(),
heap_profiling::GetSamplingRateForStartup(), base::OnceClosure());
heap_profiling::Supervisor::GetInstance()->Start(
connection,
base::BindOnce(
&heap_profiling::ProfilingProcessHost::Start,
base::Unretained(
heap_profiling::ProfilingProcessHost::GetInstance())));
}
#endif
}
......@@ -10,12 +10,12 @@
#include "base/trace_event/trace_log.h"
#include "build/build_config.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/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.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/switches.h"
#include "content/public/browser/render_frame_host.h"
......@@ -84,8 +84,8 @@ IN_PROC_BROWSER_TEST_P(MemlogBrowserTest, EndToEnd) {
LOG(INFO) << "Started via command line flag: "
<< static_cast<int>(
GetParam().start_profiling_with_command_line_flag);
ProfilingTestDriver driver;
ProfilingTestDriver::Options options;
TestDriver driver;
TestDriver::Options options;
options.mode = GetParam().mode;
options.stack_mode = GetParam().stack_mode;
options.profiling_already_started =
......
......@@ -19,15 +19,12 @@
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiling_host/chrome_client_connection_manager.h"
#include "chrome/browser/tracing/crash_service_uploader.h"
#include "components/heap_profiling/supervisor.h"
#include "components/services/heap_profiling/public/cpp/controller.h"
#include "components/services/heap_profiling/public/cpp/settings.h"
#include "components/version_info/version_info.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 "third_party/zlib/zlib.h"
#if defined(OS_WIN)
......@@ -36,25 +33,11 @@
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
namespace heap_profiling {
bool ProfilingProcessHost::has_started_ = false;
namespace {
void OnTraceUploadComplete(TraceCrashServiceUploader* uploader,
......@@ -112,31 +95,14 @@ ProfilingProcessHost::ProfilingProcessHost() : background_triggers_(this) {}
ProfilingProcessHost::~ProfilingProcessHost() = default;
Mode ProfilingProcessHost::GetMode() {
if (!client_connection_manager_)
return Mode::kNone;
return client_connection_manager_->GetMode();
}
// static
void ProfilingProcessHost::Start(content::ServiceManagerConnection* connection,
Mode mode,
mojom::StackMode stack_mode,
uint32_t sampling_rate,
base::OnceClosure closure) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
CHECK(!has_started_);
has_started_ = true;
ProfilingProcessHost* host = GetInstance();
host->connector_ = connection->GetConnector()->Clone();
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
->PostTask(
FROM_HERE,
base::BindOnce(&ProfilingProcessHost::StartServiceOnIOThread,
base::Unretained(host), stack_mode, sampling_rate,
connection->GetConnector()->Clone(), mode,
std::move(closure)));
void ProfilingProcessHost::Start() {
// Only enable automatic uploads when the Finch experiment is enabled.
// Developers can still manually upload via chrome://memory-internals.
if (IsBackgroundHeapProfilingEnabled())
background_triggers_.StartTimer();
metrics_timer_.Start(
FROM_HERE, base::TimeDelta::FromHours(24),
base::Bind(&ProfilingProcessHost::ReportMetrics, base::Unretained(this)));
}
// static
......@@ -146,13 +112,6 @@ ProfilingProcessHost* ProfilingProcessHost::GetInstance() {
base::LeakySingletonTraits<ProfilingProcessHost>>::get();
}
void ProfilingProcessHost::ConfigureBackgroundProfilingTriggers() {
// Only enable automatic uploads when the Finch experiment is enabled.
// Developers can still manually upload via chrome://memory-internals.
if (IsBackgroundHeapProfilingEnabled())
background_triggers_.StartTimer();
}
void ProfilingProcessHost::SaveTraceWithHeapDumpToFile(
base::FilePath dest,
SaveTraceFinishedCallback done,
......@@ -176,23 +135,13 @@ void ProfilingProcessHost::SaveTraceWithHeapDumpToFile(
std::move(dest), std::move(trace), std::move(done)));
},
std::move(dest), std::move(done));
RequestTraceWithHeapDump(std::move(finish_trace_callback),
false /* anonymize */);
Supervisor::GetInstance()->RequestTraceWithHeapDump(
std::move(finish_trace_callback), false /* anonymize */);
}
void ProfilingProcessHost::RequestProcessReport(std::string trigger_name) {
// https://crbug.com/753218: Add e2e tests for this code path.
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (!connector_) {
DLOG(ERROR)
<< "Requesting process dump when profiling process hasn't started.";
return;
}
// If taking_trace_for_upload_ is already true, then the setter has no effect,
// and we should early return.
if (SetTakingTraceForUpload(true))
return;
// It's safe to pass a raw pointer for ProfilingProcessHost because it's a
// singleton that's never destroyed.
......@@ -201,192 +150,15 @@ void ProfilingProcessHost::RequestProcessReport(std::string trigger_name) {
uint32_t sampling_rate, bool success, std::string trace) {
UMA_HISTOGRAM_BOOLEAN("OutOfProcessHeapProfiling.RecordTrace.Success",
success);
host->SetTakingTraceForUpload(false);
if (success) {
UploadTraceToCrashServer(std::move(trace), std::move(trigger_name),
sampling_rate);
}
},
base::Unretained(this), std::move(trigger_name),
controller_->sampling_rate());
RequestTraceWithHeapDump(std::move(finish_report_callback),
true /* anonymize */);
}
void ProfilingProcessHost::RequestTraceWithHeapDump(
TraceFinishedCallback callback,
bool anonymize) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (!connector_) {
DLOG(ERROR)
<< "Requesting heap dump when profiling process hasn't started.";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), false, std::string()));
return;
}
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 ProfilingProcessHost::GetProfiledPids(GetProfiledPidsCallback callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
->PostTask(
FROM_HERE,
base::BindOnce(&ProfilingProcessHost::GetProfiledPidsOnIOThread,
base::Unretained(this), std::move(callback)));
}
void ProfilingProcessHost::StartManualProfiling(base::ProcessId pid) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (has_started_) {
if (client_connection_manager_) {
client_connection_manager_->StartProfilingProcess(pid);
} else {
// Starting the ProfilingProcessHost requires hopping to the IO thread and
// back. That means that there's a very short period of time where
// has_started_ evaluates to true, but client_connection_manager_ has not
// yet been created. In this case, we hop to the IO thread and back.
base::OnceClosure callback = base::BindOnce(
[](ProfilingProcessHost* host, base::ProcessId pid) {
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::UI)
->PostTask(
FROM_HERE,
base::BindOnce(&ProfilingProcessHost::StartManualProfiling,
base::Unretained(host), pid));
},
base::Unretained(this), pid);
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
->PostTask(FROM_HERE, std::move(callback));
}
} else {
base::Closure callback = base::Bind(
[](base::ProcessId pid) {
ProfilingProcessHost::GetInstance()
->client_connection_manager_->StartProfilingProcess(pid);
},
pid);
ProfilingProcessHost::Start(
content::ServiceManagerConnection::GetForProcess(), Mode::kManual,
GetStackModeForStartup(), GetSamplingRateForStartup(),
std::move(callback));
}
}
void ProfilingProcessHost::GetProfiledPidsOnIOThread(
GetProfiledPidsCallback callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
if (!controller_) {
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
->PostTask(FROM_HERE, base::BindOnce(std::move(callback),
std::vector<base::ProcessId>()));
return;
}
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 ProfilingProcessHost::SetKeepSmallAllocations(
bool keep_small_allocations) {
// May get called on different threads, we need to be on the IO thread to
// work.
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) {
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
->PostTask(
FROM_HERE,
base::BindOnce(&ProfilingProcessHost::SetKeepSmallAllocations,
base::Unretained(this), keep_small_allocations));
return;
}
controller_->SetKeepSmallAllocations(keep_small_allocations);
}
void ProfilingProcessHost::StartServiceOnIOThread(
mojom::StackMode stack_mode,
uint32_t sampling_rate,
std::unique_ptr<service_manager::Connector> connector,
Mode mode,
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(
&ProfilingProcessHost::FinishPostServiceSetupOnUIThread,
base::Unretained(this), mode, std::move(closure),
controller_weak_ptr));
}
void ProfilingProcessHost::FinishPostServiceSetupOnUIThread(
Mode mode,
base::OnceClosure closure,
base::WeakPtr<Controller> controller_weak_ptr) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
client_connection_manager_.reset(
new ChromeClientConnectionManager(controller_weak_ptr, mode));
client_connection_manager_->Start();
ConfigureBackgroundProfilingTriggers();
metrics_timer_.Start(
FROM_HERE, base::TimeDelta::FromHours(24),
base::Bind(&ProfilingProcessHost::ReportMetrics, base::Unretained(this)));
if (closure)
std::move(closure).Run();
Supervisor::GetInstance()->GetSamplingRate());
Supervisor::GetInstance()->RequestTraceWithHeapDump(
std::move(finish_report_callback), true /* anonymize */);
}
void ProfilingProcessHost::SaveTraceToFileOnBlockingThread(
......@@ -422,19 +194,7 @@ void ProfilingProcessHost::SaveTraceToFileOnBlockingThread(
void ProfilingProcessHost::ReportMetrics() {
UMA_HISTOGRAM_ENUMERATION("OutOfProcessHeapProfiling.ProfilingMode",
GetMode(), Mode::kCount);
}
bool ProfilingProcessHost::TakingTraceForUpload() {
base::AutoLock lock(taking_trace_for_upload_lock_);
return taking_trace_for_upload_;
}
bool ProfilingProcessHost::SetTakingTraceForUpload(bool new_state) {
base::AutoLock lock(taking_trace_for_upload_lock_);
bool ret = taking_trace_for_upload_;
taking_trace_for_upload_ = new_state;
return ret;
Supervisor::GetInstance()->GetMode(), Mode::kCount);
}
} // namespace heap_profiling
......@@ -11,8 +11,6 @@
#include "base/macros.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 "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
......@@ -20,55 +18,21 @@ namespace base {
class FilePath;
} // namespace base
namespace content {
class ServiceManagerConnection;
} // namespace content
namespace service_manager {
class Connector;
} // namespace service_manager
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.
//
// The profiling process host can be started normally while Chrome is running,
// but can also start in a partial mode where the memory logging connections
// are active but the Mojo control channel has not yet been connected. This is
// to support starting the profiling process very early in the startup
// process (to get most memory events) before other infrastructure like the
// I/O thread has been started.
// This class is responsible for:
// * Uploading heap dumps via Slow Reports.
// * Saving heap dumps to disk.
// * Recording metrics.
class ProfilingProcessHost {
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.
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.
// This is equivalent to navigating to chrome://tracing, taking a trace with
......@@ -85,57 +49,14 @@ class ProfilingProcessHost {
// memory data to the crash server (slow-report).
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:
friend struct base::DefaultSingletonTraits<ProfilingProcessHost>;
friend class BackgroundProfilingTriggersTest;
friend class MemlogBrowserTest;
friend class ProfilingTestDriver;
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.
void DumpProcessFinishedUIThread();
......@@ -146,21 +67,6 @@ class ProfilingProcessHost {
// Reports the profiling mode.
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
// |RequestProcessReport| on this instance.
BackgroundProfilingTriggers background_triggers_;
......@@ -168,19 +74,6 @@ class ProfilingProcessHost {
// Every 24-hours, reports the profiling mode.
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);
};
......
......@@ -5,8 +5,7 @@
#include "chrome/browser/profiling_host/test_android_shim.h"
#include "base/android/jni_string.h"
#include "chrome/browser/profiling_host/profiling_process_host.h"
#include "chrome/browser/profiling_host/profiling_test_driver.h"
#include "components/heap_profiling/test_driver.h"
#include "components/services/heap_profiling/public/cpp/settings.h"
#include "jni/TestAndroidShim_jni.h"
......@@ -35,8 +34,8 @@ jboolean TestAndroidShim::RunTestForMode(
const base::android::JavaParamRef<jstring>& stack_mode,
jboolean should_sample,
jboolean sample_everything) {
heap_profiling::ProfilingTestDriver driver;
heap_profiling::ProfilingTestDriver::Options options;
heap_profiling::TestDriver driver;
heap_profiling::TestDriver::Options options;
options.mode = heap_profiling::ConvertStringToMode(
base::android::ConvertJavaStringToUTF8(mode));
options.stack_mode = heap_profiling::ConvertStringToStackMode(
......
......@@ -973,6 +973,7 @@ split_static_library("ui") {
"//components/flags_ui",
"//components/gcm_driver",
"//components/google/core/browser",
"//components/heap_profiling",
"//components/history/content/browser",
"//components/history/core/browser",
"//components/image_fetcher/core",
......
......@@ -25,6 +25,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/browser_resources.h"
#include "components/heap_profiling/supervisor.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_thread.h"
......@@ -49,7 +50,11 @@ namespace {
// Returns the string to display at the top of the page for help.
std::string GetMessageString() {
#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:
return std::string("Memory logging is enabled for all processes.");
......@@ -249,8 +254,17 @@ void MemoryInternalsDOMHandler::HandleStartProfiling(
if (!args->is_list() || args->GetList().size() != 1)
return;
ProfilingProcessHost::GetInstance()->StartManualProfiling(
args->GetList()[0].GetInt());
base::ProcessId pid = 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(
......@@ -278,7 +292,17 @@ void MemoryInternalsDOMHandler::GetChildProcessesOnIOThread(
void MemoryInternalsDOMHandler::GetProfiledPids(
std::vector<base::Value> children) {
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,
weak_factory_.GetWeakPtr(), std::move(children)));
}
......
......@@ -6,6 +6,8 @@ static_library("heap_profiling") {
sources = [
"client_connection_manager.cc",
"client_connection_manager.h",
"supervisor.cc",
"supervisor.h",
]
deps = [
......@@ -15,3 +17,19 @@ static_library("heap_profiling") {
"//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 = [
"+components/services/heap_profiling/public",
"+content/public",
"+services/resource_coordinator/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,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/profiling_host/profiling_test_driver.h"
#include "components/heap_profiling/test_driver.h"
#include <string>
......@@ -14,10 +14,11 @@
#include "base/task_scheduler/post_task.h"
#include "base/threading/platform_thread.h"
#include "base/trace_event/heap_profiler_event_filter.h"
#include "base/trace_event/trace_config_memory_test_util.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/heap_profiling/supervisor.h"
#include "components/services/heap_profiling/public/cpp/allocator_shim.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/render_process_host.h"
......@@ -527,14 +528,14 @@ bool ValidateProcessMmaps(base::Value* process_mmaps,
} // namespace
ProfilingTestDriver::ProfilingTestDriver()
TestDriver::TestDriver()
: wait_for_ui_thread_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED) {
partition_allocator_.init();
}
ProfilingTestDriver::~ProfilingTestDriver() {}
TestDriver::~TestDriver() {}
bool ProfilingTestDriver::RunTest(const Options& options) {
bool TestDriver::RunTest(const Options& options) {
options_ = options;
running_on_ui_thread_ =
......@@ -542,7 +543,16 @@ bool ProfilingTestDriver::RunTest(const Options& options) {
// The only thing to test for Mode::kNone is that profiling hasn't started.
if (options_.mode == Mode::kNone) {
if (ProfilingProcessHost::has_started()) {
if (running_on_ui_thread_) {
has_started_ = Supervisor::GetInstance()->HasStarted();
} else {
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&TestDriver::GetHasStartedOnUIThread,
base::Unretained(this)));
wait_for_ui_thread_.Wait();
}
if (has_started_) {
LOG(ERROR) << "Profiling should not have started";
return false;
}
......@@ -552,6 +562,7 @@ bool ProfilingTestDriver::RunTest(const Options& options) {
if (running_on_ui_thread_) {
if (!CheckOrStartProfiling())
return false;
Supervisor::GetInstance()->SetKeepSmallAllocations(true);
if (ShouldProfileRenderer())
WaitForProfilingToStartForAllRenderersUIThread();
if (ShouldProfileBrowser())
......@@ -560,17 +571,21 @@ bool ProfilingTestDriver::RunTest(const Options& options) {
} else {
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(
&ProfilingTestDriver::CheckOrStartProfilingOnUIThreadAndSignal,
base::Unretained(this)));
base::Bind(&TestDriver::CheckOrStartProfilingOnUIThreadAndSignal,
base::Unretained(this)));
wait_for_ui_thread_.Wait();
if (!initialization_success_)
return false;
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&TestDriver::SetKeepSmallAllocationsOnUIThreadAndSignal,
base::Unretained(this)));
wait_for_ui_thread_.Wait();
if (ShouldProfileRenderer()) {
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(
&ProfilingTestDriver::
&TestDriver::
WaitForProfilingToStartForAllRenderersUIThreadAndSignal,
base::Unretained(this)));
wait_for_ui_thread_.Wait();
......@@ -578,13 +593,11 @@ bool ProfilingTestDriver::RunTest(const Options& options) {
if (ShouldProfileBrowser()) {
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&ProfilingTestDriver::MakeTestAllocations,
base::Unretained(this)));
base::Bind(&TestDriver::MakeTestAllocations, base::Unretained(this)));
}
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&ProfilingTestDriver::CollectResults, base::Unretained(this),
false));
base::Bind(&TestDriver::CollectResults, base::Unretained(this), false));
wait_for_ui_thread_.Wait();
}
......@@ -608,7 +621,13 @@ bool ProfilingTestDriver::RunTest(const Options& options) {
return true;
}
void ProfilingTestDriver::CheckOrStartProfilingOnUIThreadAndSignal() {
void TestDriver::GetHasStartedOnUIThread() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
has_started_ = Supervisor::GetInstance()->HasStarted();
wait_for_ui_thread_.Signal();
}
void TestDriver::CheckOrStartProfilingOnUIThreadAndSignal() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
initialization_success_ = CheckOrStartProfiling();
......@@ -618,11 +637,17 @@ void ProfilingTestDriver::CheckOrStartProfilingOnUIThreadAndSignal() {
wait_for_ui_thread_.Signal();
}
bool ProfilingTestDriver::CheckOrStartProfiling() {
void TestDriver::SetKeepSmallAllocationsOnUIThreadAndSignal() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
Supervisor::GetInstance()->SetKeepSmallAllocations(true);
wait_for_ui_thread_.Signal();
}
bool TestDriver::CheckOrStartProfiling() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (options_.profiling_already_started) {
if (ProfilingProcessHost::has_started())
if (Supervisor::GetInstance()->HasStarted())
return true;
LOG(ERROR) << "Profiling should have been started, but wasn't";
return false;
......@@ -639,7 +664,10 @@ bool ProfilingTestDriver::CheckOrStartProfiling() {
// When this is not-null, initialization should wait for the QuitClosure to be
// called.
std::unique_ptr<base::RunLoop> run_loop;
base::OnceClosure start_callback;
// If we're going to profile the browser, then wait for the allocator shim to
// start. Otherwise, wait for the Supervisor to start.
if (ShouldProfileBrowser()) {
if (running_on_ui_thread_) {
run_loop.reset(new base::RunLoop);
......@@ -652,14 +680,23 @@ bool ProfilingTestDriver::CheckOrStartProfiling() {
base::Unretained(&wait_for_ui_thread_)),
base::ThreadTaskRunnerHandle::Get());
}
} else {
if (running_on_ui_thread_) {
run_loop.reset(new base::RunLoop);
start_callback = run_loop->QuitClosure();
} else {
wait_for_profiling_to_start_ = true;
start_callback = base::BindOnce(&base::WaitableEvent::Signal,
base::Unretained(&wait_for_ui_thread_));
}
}
uint32_t sampling_rate = options_.should_sample
? (options_.sample_everything ? 2 : kSampleRate)
: 1;
ProfilingProcessHost::Start(connection, options_.mode, options_.stack_mode,
sampling_rate, base::Closure());
ProfilingProcessHost::GetInstance()->SetKeepSmallAllocations(true);
Supervisor::GetInstance()->Start(connection, options_.mode,
options_.stack_mode, sampling_rate,
std::move(start_callback));
if (run_loop)
run_loop->Run();
......@@ -667,7 +704,7 @@ bool ProfilingTestDriver::CheckOrStartProfiling() {
return true;
}
void ProfilingTestDriver::MakeTestAllocations() {
void TestDriver::MakeTestAllocations() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
base::PlatformThread::SetName(kThreadName);
......@@ -720,7 +757,8 @@ void ProfilingTestDriver::MakeTestAllocations() {
// browser(), embedded_test_server()->GetURL("/french_page.html"));
}
void ProfilingTestDriver::CollectResults(bool synchronous) {
void TestDriver::CollectResults(bool synchronous) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
base::Closure finish_tracing_closure;
std::unique_ptr<base::RunLoop> run_loop;
......@@ -732,8 +770,8 @@ void ProfilingTestDriver::CollectResults(bool synchronous) {
base::Unretained(&wait_for_ui_thread_));
}
ProfilingProcessHost::GetInstance()->RequestTraceWithHeapDump(
base::Bind(&ProfilingTestDriver::TraceFinished, base::Unretained(this),
Supervisor::GetInstance()->RequestTraceWithHeapDump(
base::Bind(&TestDriver::TraceFinished, base::Unretained(this),
std::move(finish_tracing_closure)),
false /* strip_path_from_mapped_files */);
......@@ -741,14 +779,14 @@ void ProfilingTestDriver::CollectResults(bool synchronous) {
run_loop->Run();
}
void ProfilingTestDriver::TraceFinished(base::Closure closure,
bool success,
std::string trace_json) {
void TestDriver::TraceFinished(base::Closure closure,
bool success,
std::string trace_json) {
serialized_trace_.swap(trace_json);
std::move(closure).Run();
}
bool ProfilingTestDriver::ValidateBrowserAllocations(base::Value* dump_json) {
bool TestDriver::ValidateBrowserAllocations(base::Value* dump_json) {
base::Value* heaps_v2 =
FindArgDump(base::Process::Current().Pid(), dump_json, "heaps_v2");
......@@ -841,7 +879,7 @@ bool ProfilingTestDriver::ValidateBrowserAllocations(base::Value* dump_json) {
return true;
}
bool ProfilingTestDriver::ValidateRendererAllocations(base::Value* dump_json) {
bool TestDriver::ValidateRendererAllocations(base::Value* dump_json) {
std::vector<int> pids;
bool result = NumProcessesWithName(dump_json, "Renderer", &pids) >= 1;
if (!result) {
......@@ -893,35 +931,35 @@ bool ProfilingTestDriver::ValidateRendererAllocations(base::Value* dump_json) {
return true;
}
bool ProfilingTestDriver::ShouldProfileBrowser() {
bool TestDriver::ShouldProfileBrowser() {
return options_.mode == Mode::kAll || options_.mode == Mode::kBrowser ||
options_.mode == Mode::kMinimal;
}
bool ProfilingTestDriver::ShouldProfileRenderer() {
bool TestDriver::ShouldProfileRenderer() {
return options_.mode == Mode::kAll || options_.mode == Mode::kAllRenderers;
}
bool ProfilingTestDriver::ShouldIncludeNativeThreadNames() {
bool TestDriver::ShouldIncludeNativeThreadNames() {
return options_.stack_mode == mojom::StackMode::NATIVE_WITH_THREAD_NAMES;
}
bool ProfilingTestDriver::HasPseudoFrames() {
bool TestDriver::HasPseudoFrames() {
return options_.stack_mode == mojom::StackMode::PSEUDO ||
options_.stack_mode == mojom::StackMode::MIXED;
}
bool ProfilingTestDriver::HasNativeFrames() {
bool TestDriver::HasNativeFrames() {
return options_.stack_mode == mojom::StackMode::NATIVE_WITH_THREAD_NAMES ||
options_.stack_mode == mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES ||
options_.stack_mode == mojom::StackMode::MIXED;
}
bool ProfilingTestDriver::IsRecordingAllAllocations() {
bool TestDriver::IsRecordingAllAllocations() {
return !options_.should_sample || options_.sample_everything;
}
void ProfilingTestDriver::WaitForProfilingToStartForAllRenderersUIThread() {
void TestDriver::WaitForProfilingToStartForAllRenderersUIThread() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
while (true) {
std::vector<base::ProcessId> profiled_pids;
......@@ -933,7 +971,7 @@ void ProfilingTestDriver::WaitForProfilingToStartForAllRenderersUIThread() {
std::move(finished).Run();
},
&profiled_pids, run_loop.QuitClosure());
ProfilingProcessHost::GetInstance()->GetProfiledPids(std::move(callback));
Supervisor::GetInstance()->GetProfiledPids(std::move(callback));
run_loop.Run();
if (RenderersAreBeingProfiled(profiled_pids))
......@@ -941,18 +979,15 @@ void ProfilingTestDriver::WaitForProfilingToStartForAllRenderersUIThread() {
}
}
void ProfilingTestDriver::
WaitForProfilingToStartForAllRenderersUIThreadAndSignal() {
void TestDriver::WaitForProfilingToStartForAllRenderersUIThreadAndSignal() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
ProfilingProcessHost::GetInstance()->GetProfiledPids(
base::BindOnce(&ProfilingTestDriver::
WaitForProfilingToStartForAllRenderersUIThreadCallback,
base::Unretained(this)));
Supervisor::GetInstance()->GetProfiledPids(base::BindOnce(
&TestDriver::WaitForProfilingToStartForAllRenderersUIThreadCallback,
base::Unretained(this)));
}
void ProfilingTestDriver::
WaitForProfilingToStartForAllRenderersUIThreadCallback(
std::vector<base::ProcessId> results) {
void TestDriver::WaitForProfilingToStartForAllRenderersUIThreadCallback(
std::vector<base::ProcessId> results) {
if (RenderersAreBeingProfiled(results)) {
wait_for_ui_thread_.Signal();
return;
......
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PROFILING_HOST_PROFILING_TEST_DRIVER_H_
#define CHROME_BROWSER_PROFILING_HOST_PROFILING_TEST_DRIVER_H_
#ifndef COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_
#define COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_
#include <vector>
......@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted_memory.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 {
class Value;
......@@ -19,11 +19,15 @@ class Value;
namespace heap_profiling {
// This class runs tests for the profiling service, a cross-platform,
// multi-process component. 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.
enum class Mode;
// This class runs tests for the Heap Profiling Service, a cross-platform,
// multi-process component.
//
// 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.
// browser_tests will directly call this class. The android
......@@ -37,7 +41,7 @@ namespace heap_profiling {
//
// Note: Outputting to stderr will not have the desired effect, since that is
// not captured by logcat.
class ProfilingTestDriver {
class TestDriver {
public:
struct Options {
// The profiling mode to test.
......@@ -60,8 +64,8 @@ class ProfilingTestDriver {
bool sample_everything;
};
ProfilingTestDriver();
~ProfilingTestDriver();
TestDriver();
~TestDriver();
// If this is called on the content::BrowserThread::UI thread, then the
// platform must support nested message loops. [This is currently not
......@@ -72,10 +76,17 @@ class ProfilingTestDriver {
bool RunTest(const Options& options);
private:
// Populates |has_started_| and then signals |wait_for_ui_thread_|.
void GetHasStartedOnUIThread();
// Populates |initialization_success_| with the result of
// |RunInitializationOnUIThread|, and then signals |wait_for_ui_thread_|.
void CheckOrStartProfilingOnUIThreadAndSignal();
// Calls Supervisor::SetKeepSmallAllocations() and then signals
// |wait_for_ui_thread_|.
void SetKeepSmallAllocationsOnUIThreadAndSignal();
// If profiling is expected to already be started, confirm it.
// Otherwise, start profiling with the given mode.
bool CheckOrStartProfiling();
......@@ -131,6 +142,9 @@ class ProfilingTestDriver {
// Whether the test was invoked on the ui thread.
bool running_on_ui_thread_ = true;
// Whether the supervisor has started.
bool has_started_ = false;
// Whether an error has occurred.
bool initialization_success_ = false;
......@@ -140,9 +154,9 @@ class ProfilingTestDriver {
base::WaitableEvent wait_for_ui_thread_;
DISALLOW_COPY_AND_ASSIGN(ProfilingTestDriver);
DISALLOW_COPY_AND_ASSIGN(TestDriver);
};
} // 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