Sampling profiler: profile the NetworkService process
In the out-of-process case, network service runs on the IO thread of a utility process handling network-related tasks. See services/network/README.md for more details. To track the utility network service process, this CL enables sampling profiler in this process. It updates the StackSamplingConfiguration to turn on the switch of profiler in the network service process. Then when the switch is on, ChromeContentUtilityClient will create and start a profiler for the IO thread, and build a message pipe between the utility network service process and the browser process to pass the collected profile data. If the switch is on, the procedure will be: 1. In the |UtilityMain| function, which is the mainline routine of a utility process, a |ChildProcess| is created. This instance contains the delegate of the IO thread and its task runner. Then |ChromeContentUtilityClient::PostIOThreadCreated| will create and start a profiler for the IO thread. 2. A |UtilityThreadImpl| instance is created in the |UtilityMain| as well, it will be the main thread of the process. To initialize the instance, |UtilityThreadImpl::Init| function is called. This function only runs once in every utility process so, in this function, |ChromeContentUtilityClient::UtilityThreadStarted| will create a message pipe between the utility network service process and the browser process to pass the collected profile data. Note that there are some in-process utility threads run in other processes, so please check the process type before setting up the collector and pipe. 3. More specifically, it will create a |PendingReceiver| of |CallStackProfileCollector|. And the browser process will receive and handle this receiver. The path is: |ChildThread::BindHostReceiver| => |UtilityProcessHost::BindHostReceiver| => |ChromeContentBrowserClient::BindUtilityHostReceiver|. In the utility process side, |SetCollectorForChildProcess| is called to supply the Service Manager's connector; and in the browser process side, a |CallStackProfileCollector| will be created with the receiver. Bug: 931432 Change-Id: I245f864089d82aee09c30a42c1606a93cf5ea1c6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2186614 Commit-Queue: Lingqi Chi <lingqi@google.com> Reviewed-by: Matt Falkenhagen <falken@chromium.org> Reviewed-by: Ken Rockot <rockot@google.com> Reviewed-by: Takashi Toyoshima <toyoshim@chromium.org> Reviewed-by: Mike Wittman <wittman@chromium.org> Reviewed-by: Kinuko Yasuda <kinuko@chromium.org> Cr-Commit-Position: refs/heads/master@{#777632}
This commit is contained in:
chrome
browser
common
utility
components/metrics
content
browser
public
utility
@ -412,6 +412,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
|
||||
const GURL& service_worker_scope,
|
||||
mojo::PendingReceiver<blink::mojom::BadgeService> receiver) override;
|
||||
void BindGpuHostReceiver(mojo::GenericPendingReceiver receiver) override;
|
||||
void BindUtilityHostReceiver(mojo::GenericPendingReceiver receiver) override;
|
||||
void BindHostReceiverForRenderer(
|
||||
content::RenderProcessHost* render_process_host,
|
||||
mojo::GenericPendingReceiver receiver) override;
|
||||
|
@ -278,6 +278,12 @@ void ChromeContentBrowserClient::BindGpuHostReceiver(
|
||||
metrics::CallStackProfileCollector::Create(std::move(r));
|
||||
}
|
||||
|
||||
void ChromeContentBrowserClient::BindUtilityHostReceiver(
|
||||
mojo::GenericPendingReceiver receiver) {
|
||||
if (auto r = receiver.As<metrics::mojom::CallStackProfileCollector>())
|
||||
metrics::CallStackProfileCollector::Create(std::move(r));
|
||||
}
|
||||
|
||||
void ChromeContentBrowserClient::BindHostReceiverForRenderer(
|
||||
content::RenderProcessHost* render_process_host,
|
||||
mojo::GenericPendingReceiver receiver) {
|
||||
|
@ -161,3 +161,10 @@ IN_PROC_BROWSER_TEST_F(StackSamplingBrowserTest,
|
||||
metrics::RENDERER_PROCESS,
|
||||
metrics::COMPOSITOR_THREAD));
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(StackSamplingBrowserTest,
|
||||
NetworkServiceProcessIOThread) {
|
||||
EXPECT_TRUE(WaitForProfile(metrics::SampledProfile::PROCESS_STARTUP,
|
||||
metrics::NETWORK_SERVICE_PROCESS,
|
||||
metrics::IO_THREAD));
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "components/version_info/version_info.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "extensions/buildflags/buildflags.h"
|
||||
#include "services/service_manager/sandbox/sandbox.h"
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
#include "chrome/android/modules/stack_unwinder/public/module.h"
|
||||
@ -170,6 +171,11 @@ void StackSamplingConfiguration::AppendCommandLineSwitchForChildProcess(
|
||||
if (!enable)
|
||||
return;
|
||||
if (process_type == switches::kGpuProcess ||
|
||||
(process_type == switches::kUtilityProcess &&
|
||||
// The network service is the only utility process that is profiled for
|
||||
// now.
|
||||
service_manager::SandboxTypeFromCommandLine(*command_line) ==
|
||||
service_manager::SandboxType::kNetwork) ||
|
||||
(process_type == switches::kRendererProcess &&
|
||||
// Do not start the profiler for extension processes since profiling the
|
||||
// compositor thread in them is not useful.
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "content/public/common/service_names.mojom.h"
|
||||
#include "services/service_manager/embedder/switches.h"
|
||||
#include "services/service_manager/sandbox/sandbox.h"
|
||||
|
||||
#if defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
|
||||
#include "base/android/apk_assets.h"
|
||||
@ -66,8 +67,13 @@ CallStackProfileParams::Process GetProcess() {
|
||||
return CallStackProfileParams::RENDERER_PROCESS;
|
||||
if (process_type == switches::kGpuProcess)
|
||||
return CallStackProfileParams::GPU_PROCESS;
|
||||
if (process_type == switches::kUtilityProcess)
|
||||
if (process_type == switches::kUtilityProcess) {
|
||||
auto sandbox_type =
|
||||
service_manager::SandboxTypeFromCommandLine(*command_line);
|
||||
if (sandbox_type == service_manager::SandboxType::kNetwork)
|
||||
return CallStackProfileParams::NETWORK_SERVICE_PROCESS;
|
||||
return CallStackProfileParams::UTILITY_PROCESS;
|
||||
}
|
||||
if (process_type == service_manager::switches::kZygoteProcess)
|
||||
return CallStackProfileParams::ZYGOTE_PROCESS;
|
||||
if (process_type == switches::kPpapiPluginProcess)
|
||||
|
@ -11,8 +11,12 @@
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/lazy_instance.h"
|
||||
#include "chrome/common/profiler/stack_sampling_configuration.h"
|
||||
#include "chrome/common/profiler/thread_profiler.h"
|
||||
#include "chrome/utility/browser_exposed_utility_interfaces.h"
|
||||
#include "chrome/utility/services.h"
|
||||
#include "content/public/child/child_thread.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "services/service_manager/sandbox/switches.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINT_PREVIEW) && defined(OS_WIN)
|
||||
@ -71,6 +75,25 @@ void ChromeContentUtilityClient::RegisterNetworkBinders(
|
||||
std::move(g_network_binder_creation_callback.Get()).Run(registry);
|
||||
}
|
||||
|
||||
void ChromeContentUtilityClient::UtilityThreadStarted() {
|
||||
// Only builds message pipes for utility processes which enable sampling
|
||||
// profilers.
|
||||
const base::CommandLine* command_line =
|
||||
base::CommandLine::ForCurrentProcess();
|
||||
const std::string process_type =
|
||||
command_line->GetSwitchValueASCII(switches::kProcessType);
|
||||
if (process_type ==
|
||||
switches::kUtilityProcess && // An in-process utility thread may run
|
||||
// in other processes, only set up
|
||||
// collector in a utility process.
|
||||
StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess()) {
|
||||
mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> collector;
|
||||
content::ChildThread::Get()->BindHostReceiver(
|
||||
collector.InitWithNewPipeAndPassReceiver());
|
||||
ThreadProfiler::SetCollectorForChildProcess(std::move(collector));
|
||||
}
|
||||
}
|
||||
|
||||
mojo::ServiceFactory*
|
||||
ChromeContentUtilityClient::GetMainThreadServiceFactory() {
|
||||
if (utility_process_running_elevated_)
|
||||
@ -78,6 +101,13 @@ ChromeContentUtilityClient::GetMainThreadServiceFactory() {
|
||||
return ::GetMainThreadServiceFactory();
|
||||
}
|
||||
|
||||
void ChromeContentUtilityClient::PostIOThreadCreated(
|
||||
base::SingleThreadTaskRunner* io_thread_task_runner) {
|
||||
io_thread_task_runner->PostTask(
|
||||
FROM_HERE, base::BindOnce(&ThreadProfiler::StartOnChildThread,
|
||||
metrics::CallStackProfileParams::IO_THREAD));
|
||||
}
|
||||
|
||||
mojo::ServiceFactory* ChromeContentUtilityClient::GetIOThreadServiceFactory() {
|
||||
return ::GetIOThreadServiceFactory();
|
||||
}
|
||||
|
@ -28,8 +28,11 @@ class ChromeContentUtilityClient : public content::ContentUtilityClient {
|
||||
// content::ContentUtilityClient:
|
||||
void ExposeInterfacesToBrowser(mojo::BinderMap* binders) override;
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
void PostIOThreadCreated(
|
||||
base::SingleThreadTaskRunner* io_thread_task_runner) override;
|
||||
void RegisterNetworkBinders(
|
||||
service_manager::BinderRegistry* registry) override;
|
||||
void UtilityThreadStarted() override;
|
||||
mojo::ServiceFactory* GetMainThreadServiceFactory() override;
|
||||
mojo::ServiceFactory* GetIOThreadServiceFactory() override;
|
||||
|
||||
|
@ -19,6 +19,8 @@ Process ToExecutionContextProcess(CallStackProfileParams::Process process) {
|
||||
return GPU_PROCESS;
|
||||
case CallStackProfileParams::UTILITY_PROCESS:
|
||||
return UTILITY_PROCESS;
|
||||
case CallStackProfileParams::NETWORK_SERVICE_PROCESS:
|
||||
return NETWORK_SERVICE_PROCESS;
|
||||
case CallStackProfileParams::ZYGOTE_PROCESS:
|
||||
return ZYGOTE_PROCESS;
|
||||
case CallStackProfileParams::SANDBOX_HELPER_PROCESS:
|
||||
|
@ -21,7 +21,8 @@ struct CallStackProfileParams {
|
||||
ZYGOTE_PROCESS,
|
||||
SANDBOX_HELPER_PROCESS,
|
||||
PPAPI_PLUGIN_PROCESS,
|
||||
PPAPI_BROKER_PROCESS
|
||||
PPAPI_BROKER_PROCESS,
|
||||
NETWORK_SERVICE_PROCESS,
|
||||
};
|
||||
|
||||
// The thread from which the collection occurred.
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "content/browser/utility_process_host.h"
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
#include "components/services/font/public/mojom/font_service.mojom.h" // nogncheck
|
||||
@ -23,6 +25,7 @@ void UtilityProcessHost::BindHostReceiver(
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
GetContentClient()->browser()->BindUtilityHostReceiver(std::move(receiver));
|
||||
}
|
||||
|
||||
} // namespace content
|
||||
|
@ -1039,6 +1039,10 @@ class CONTENT_EXPORT ContentBrowserClient {
|
||||
// process. Called on the IO thread.
|
||||
virtual void BindGpuHostReceiver(mojo::GenericPendingReceiver receiver) {}
|
||||
|
||||
// Handles an unhandled incoming interface binding request from a Utility
|
||||
// process. Called on the IO thread.
|
||||
virtual void BindUtilityHostReceiver(mojo::GenericPendingReceiver receiver) {}
|
||||
|
||||
// Called on the main thread to handle an unhandled interface receiver binding
|
||||
// request from a render process. See |RenderThread::BindHostReceiver()|.
|
||||
virtual void BindHostReceiverForRenderer(
|
||||
|
@ -44,6 +44,10 @@ class CONTENT_EXPORT ContentUtilityClient {
|
||||
// corresponding UtilityProcessHost.
|
||||
virtual void ExposeInterfacesToBrowser(mojo::BinderMap* binders) {}
|
||||
|
||||
// Called on the main thread immediately after the IO thread is created.
|
||||
virtual void PostIOThreadCreated(
|
||||
base::SingleThreadTaskRunner* io_thread_task_runner) {}
|
||||
|
||||
// Allows the embedder to handle an incoming service request. If this is
|
||||
// called, this utility process was started for the sole purpose of running
|
||||
// the service identified by |service_name|.
|
||||
|
@ -15,9 +15,11 @@
|
||||
#include "build/build_config.h"
|
||||
#include "content/child/child_process.h"
|
||||
#include "content/common/content_switches_internal.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "content/public/common/main_function_params.h"
|
||||
#include "content/public/common/sandbox_init.h"
|
||||
#include "content/public/utility/content_utility_client.h"
|
||||
#include "content/utility/utility_thread_impl.h"
|
||||
#include "services/service_manager/sandbox/sandbox.h"
|
||||
#include "services/tracing/public/cpp/trace_startup.h"
|
||||
@ -118,6 +120,8 @@ int UtilityMain(const MainFunctionParams& parameters) {
|
||||
#endif
|
||||
|
||||
ChildProcess utility_process;
|
||||
GetContentClient()->utility()->PostIOThreadCreated(
|
||||
utility_process.io_task_runner());
|
||||
base::RunLoop run_loop;
|
||||
utility_process.set_main_thread(
|
||||
new UtilityThreadImpl(run_loop.QuitClosure()));
|
||||
|
Reference in New Issue
Block a user