Commit 79b69b21 authored by Brett Wilson's avatar Brett Wilson Committed by Commit Bot

Add profiling process control channel.

This new Mojo channel connects the profiling process and the browser process. It should be run only when the enable_oop_heap_profiling is enabled, and when run with --memlog.

Fixes a bug on Posix memlog streams because sendmsg is not atomic for large messages.

Various refactoring of the profiling process. The separate IO thread has been removed and the main thread is now the IO thread.

NOPRESUBMIT=true (seems to crash presubmit checks, bug filed)

Change-Id: I93909bb95bfbd10348c0c7d51c80aa44cb26f7aa
Reviewed-on: https://chromium-review.googlesource.com/564157
Commit-Queue: Brett Wilson <brettw@chromium.org>
Reviewed-by: default avatarAlbert J. Wong <ajwong@chromium.org>
Cr-Commit-Position: refs/heads/master@{#486140}
parent b78e818b
......@@ -9,7 +9,6 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/app/chrome_main_delegate.h"
#include "chrome/browser/profiling_host/profiling_process_host.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/features.h"
#include "content/public/app/content_main.h"
......@@ -18,6 +17,7 @@
#include "ui/gfx/switches.h"
#if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING)
#include "chrome/browser/profiling_host/profiling_process_host.h"
#include "chrome/common/profiling/memlog_sender.h"
#include "chrome/profiling/profiling_main.h"
#endif
......
......@@ -69,7 +69,6 @@
#include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/browser/profiling_host/profiling_process_host.h"
#include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
......@@ -389,6 +388,10 @@
#include "chrome/browser/media/cast_remoting_connector.h"
#endif
#if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING)
#include "chrome/browser/profiling_host/profiling_process_host.h"
#endif
#if BUILDFLAG(ENABLE_PRINTING)
#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
#endif
......@@ -1655,7 +1658,9 @@ void ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
command_line->CopySwitchesFrom(browser_command_line, kCommonSwitchNames,
arraysize(kCommonSwitchNames));
#if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING)
profiling::ProfilingProcessHost::AddSwitchesToChildCmdLine(command_line);
if (process_type != switches::kZygoteProcess) {
profiling::ProfilingProcessHost::AddSwitchesToChildCmdLine(command_line);
}
#endif
static const char* const kDinosaurEasterEggSwitches[] = {
......
include_rules = [
"+mojo/edk/embedder",
]
......@@ -8,9 +8,14 @@
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/profiling/memlog_sender.h"
#include "chrome/common/profiling/profiling_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "mojo/edk/embedder/outgoing_broker_client_invitation.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
#if defined(OS_LINUX)
#include <fcntl.h>
......@@ -68,6 +73,7 @@ base::CommandLine MakeProfilingCommandLine(const std::string& pipe_id) {
ProfilingProcessHost::ProfilingProcessHost() {
pph_singleton = this;
Launch();
}
ProfilingProcessHost::~ProfilingProcessHost() {
......@@ -77,8 +83,6 @@ ProfilingProcessHost::~ProfilingProcessHost() {
// static
ProfilingProcessHost* ProfilingProcessHost::EnsureStarted() {
static ProfilingProcessHost host;
if (!host.process_.IsValid())
host.Launch();
return &host;
}
......@@ -90,52 +94,95 @@ ProfilingProcessHost* ProfilingProcessHost::Get() {
// static
void ProfilingProcessHost::AddSwitchesToChildCmdLine(
base::CommandLine* child_cmd_line) {
// Watch out: will be called on different threads.
ProfilingProcessHost* pph = ProfilingProcessHost::Get();
if (!pph)
return;
pph->EnsureControlChannelExists();
// TODO(brettw) this isn't correct for Posix. Redo when we can shave over
// Mojo
child_cmd_line->AppendSwitchASCII(switches::kMemlogPipe, pph->pipe_id_);
}
#if defined(OS_WIN)
void ProfilingProcessHost::Launch() {
base::Process process = base::Process::Current();
base::LaunchOptions options;
mojo::edk::PlatformChannelPair control_channel;
mojo::edk::HandlePassingInformation handle_passing_info;
pipe_id_ = base::IntToString(static_cast<int>(process.Pid()));
base::CommandLine profiling_cmd = MakeProfilingCommandLine(pipe_id_);
// TODO(brettw) most of this logic can be replaced with PlatformChannelPair.
process_ = base::LaunchProcess(profiling_cmd, options);
StartMemlogSender(pipe_id_);
}
#elif defined(OS_POSIX)
#if defined(OS_WIN)
base::Process process = base::Process::Current();
pipe_id_ = base::IntToString(static_cast<int>(process.Pid()));
#else
void ProfilingProcessHost::Launch() {
// Create the socketpair.
// Create the socketpair for the low level memlog pipe.
// TODO(ajwong): Should this use base/posix/unix_domain_socket_linux.h?
int fds[2];
PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0);
PCHECK(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0);
int memlog_fds[2];
PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, memlog_fds) == 0);
PCHECK(fcntl(memlog_fds[0], F_SETFL, O_NONBLOCK) == 0);
PCHECK(fcntl(memlog_fds[1], F_SETFL, O_NONBLOCK) == 0);
// Store one end for our message sender to use.
pipe_id_ = base::IntToString(fds[0]);
base::ScopedFD child_end(fds[1]);
base::ScopedFD child_end(memlog_fds[1]);
// TODO(brettw) need to get rid of pipe_id when we can share over Mojo.
pipe_id_ = base::IntToString(memlog_fds[0]);
handle_passing_info.emplace_back(child_end.get(), child_end.get());
#endif
base::CommandLine profiling_cmd =
MakeProfilingCommandLine(base::IntToString(child_end.get()));
// This is a new process forked from us. No need to remap.
base::FileHandleMappingVector fd_map;
fd_map.emplace_back(std::pair<int, int>(child_end.get(), child_end.get()));
// Keep the server handle, pass the client handle to the child.
pending_control_connection_ = control_channel.PassServerHandle();
control_channel.PrepareToPassClientHandleToChildProcess(&profiling_cmd,
&handle_passing_info);
base::LaunchOptions options;
options.fds_to_remap = &fd_map;
#if defined(OS_WIN)
options.handles_to_inherit = &handle_passing_info;
#elif defined(OS_POSIX)
options.fds_to_remap = &handle_passing_info;
options.kill_on_parent_death = true;
#else
#error Unsupported OS.
#endif
base::CommandLine profiling_cmd =
MakeProfilingCommandLine(base::IntToString(child_end.get()));
process_ = base::LaunchProcess(profiling_cmd, options);
StartMemlogSender(pipe_id_);
}
#else
#error Unsupported OS.
#endif
void ProfilingProcessHost::EnsureControlChannelExists() {
// 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::EnsureControlChannelExists,
base::Unretained(this)));
return;
}
if (pending_control_connection_.is_valid())
ConnectControlChannelOnIO();
}
// This must be called before the client attempts to connect to the control
// pipe.
void ProfilingProcessHost::ConnectControlChannelOnIO() {
mojo::edk::OutgoingBrokerClientInvitation invitation;
mojo::ScopedMessagePipeHandle control_pipe =
invitation.AttachMessagePipe(kProfilingControlPipeName);
invitation.Send(
process_.Handle(),
mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy,
std::move(pending_control_connection_)));
profiling_control_.Bind(
mojom::ProfilingControlPtrInfo(std::move(control_pipe), 0));
StartProfilingMojo();
}
} // namespace profiling
......@@ -7,6 +7,15 @@
#include "base/macros.h"
#include "base/process/process.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/profiling/profiling_control.mojom.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
// The .mojom include above may not be generated unless OOP heap profiling is
// enabled.
#if !BUILDFLAG(ENABLE_OOP_HEAP_PROFILING)
#error profiling_process_host.h should only be included with OOP heap profiling
#endif
namespace base {
class CommandLine;
......@@ -48,10 +57,25 @@ class ProfilingProcessHost {
void Launch();
void EnsureControlChannelExists();
void ConnectControlChannelOnIO();
// Use process_.IsValid() to determine if the child process has been launched.
base::Process process_;
std::string pipe_id_;
// IO thread only -----------------------------------------------------------
//
// Once the constructor is finished, the following variables must only be
// accessed on the IO thread.
// Holds the pending server handle for the Mojo control channel during
// the period between the profiling process launching and the Mojo channel
// being created. Will be invalid otherwise.
mojo::edk::ScopedPlatformHandle pending_control_connection_;
mojom::ProfilingControlPtr profiling_control_;
DISALLOW_COPY_AND_ASSIGN(ProfilingProcessHost);
};
......
......@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//chrome/common/features.gni")
import("//mojo/public/tools/bindings/mojom.gni")
if (enable_oop_heap_profiling) {
static_library("profiling") {
......@@ -18,14 +19,23 @@ if (enable_oop_heap_profiling) {
"memlog_sender_pipe_win.h",
"memlog_stream.cc",
"memlog_stream.h",
"profiling_constants.cc",
"profiling_constants.h",
]
deps = [
":interfaces",
"//base",
"//base:debugging_flags",
"//chrome/common:constants",
]
}
mojom("interfaces") {
sources = [
"profiling_control.mojom",
]
}
} else {
# Dummy group so this target can be unconditionally depended on.
group("profiling") {
......
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
......@@ -13,6 +13,10 @@
#include "build/build_config.h"
#include "chrome/common/profiling/memlog_stream.h"
#if defined(OS_POSIX)
#include <limits.h>
#endif
namespace profiling {
namespace {
......@@ -25,14 +29,20 @@ MemlogSenderPipe* g_sender_pipe = nullptr;
// to raise this to avoid truncation. This matches the current value in the
// in-process heap profiler (heap_profiler_allocation_context.h) so the two
// systems performance and memory overhead can be compared consistently.
const int kMaxStackEntries = 48;
constexpr int kMaxStackEntries = 48;
#if defined(OS_WIN)
// Matches the native buffer size on the pipe.
const int kSendBufferSize = 65536;
constexpr int kSendBufferSize = 65536;
#else
// Writes on Posix greater than PIPE_BUF are not guaranteed to be atomic so
// our buffers can't be larger than that.
constexpr int kSendBufferSize = PIPE_BUF;
#endif
// Prime since this is used like a hash table. Numbers of this magnitude seemed
// to provide sufficient parallelism to avoid lock overhead in ad-hoc testing.
const int kNumSendBuffers = 17;
constexpr int kNumSendBuffers = 17;
class SendBuffer {
public:
......
......@@ -12,6 +12,14 @@
namespace profiling {
namespace {
// TODO(brettw) this is a hack to allow StartProfilingMojo to work. Figure out
// how to get the lifetime of this that allows that function call to work.
MemlogSenderPipe* memlog_sender_pipe = nullptr;
} // namespace
void InitMemlogSenderIfNecessary(const base::CommandLine& cmdline) {
std::string pipe_id = cmdline.GetSwitchValueASCII(switches::kMemlogPipe);
if (!pipe_id.empty())
......@@ -21,13 +29,24 @@ void InitMemlogSenderIfNecessary(const base::CommandLine& cmdline) {
void StartMemlogSender(const std::string& pipe_id) {
static MemlogSenderPipe pipe(pipe_id);
pipe.Connect();
memlog_sender_pipe = &pipe;
StreamHeader header;
header.signature = kStreamSignature;
pipe.Send(&header, sizeof(StreamHeader));
InitAllocatorShim(&pipe);
}
void StartProfilingMojo() {
static bool started_mojo = false;
if (!started_mojo) {
started_mojo = true;
StartMojoControlPacket start_mojo_message;
start_mojo_message.op = kStartMojoControlPacketType;
memlog_sender_pipe->Send(&start_mojo_message, sizeof(start_mojo_message));
}
}
} // namespace profiling
......@@ -15,10 +15,18 @@ class CommandLine;
namespace profiling {
// Starts the memlog sender pipe if the command line has requested it. The pipe
// ID will be extracted from the command line argument.
void InitMemlogSenderIfNecessary(const base::CommandLine& cmdline);
// Starts the memlog sender pipe with the given ID.
void StartMemlogSender(const std::string& pipe_id);
// Tells the profiling process to try to connect to the profiling control
// channel. This must be done after the browser is ready to accept such a
// connection.
void StartProfilingMojo();
} // namespace profiling
#endif // CHROME_COMMON_PROFILING_MEMLOG_SENDER_H_
......@@ -10,7 +10,7 @@
namespace profiling {
MemlogSenderPipe::MemlogSenderPipe(const base::string& pipe_id)
MemlogSenderPipe::MemlogSenderPipe(const std::string& pipe_id)
: pipe_id_(base::UTF8ToUTF16(pipe_id)), handle_(INVALID_HANDLE_VALUE) {}
MemlogSenderPipe::~MemlogSenderPipe() {
......@@ -28,9 +28,13 @@ bool MemlogSenderPipe::Connect() {
ULONGLONG timeout_ticks = ::GetTickCount64() + kMaxWaitMS;
do {
if (!::WaitNamedPipe(pipe_name.c_str(), kMaxWaitMS)) {
// Since it will wait "forever", the only time WaitNamedPipe should fail
// is if the pipe doesn't exist.
return false;
// This code will race with the creation of the pipe in the profiling
// process. If the pipe doesn't exist yet, wait briefly and try again.
// TODO(brettw) check for GetLastError() and only do this if the pipe
// doesn't exist (other errors should bail).
::Sleep(10);
continue;
}
// This is a single-direction pipe so we don't specify GENERIC_READ, but
// MSDN says we need FILE_READ_ATTRIBUTES.
......
......@@ -7,6 +7,8 @@
#include <windows.h>
#include <string>
#include "base/macros.h"
#include "base/strings/string16.h"
......@@ -14,7 +16,7 @@ namespace profiling {
class MemlogSenderPipe {
public:
explicit MemlogSenderPipe(const base::string& pipe_id);
explicit MemlogSenderPipe(const std::string& pipe_id);
~MemlogSenderPipe();
bool Connect();
......
......@@ -11,16 +11,22 @@
namespace profiling {
static const uint32_t kStreamSignature = 0xF6103B71;
constexpr uint32_t kStreamSignature = 0xF6103B71;
static const uint32_t kAllocPacketType = 0xA1A1A1A1;
static const uint32_t kFreePacketType = 0xFEFEFEFE;
constexpr uint32_t kStartMojoControlPacketType = 0x77777777;
constexpr uint32_t kAllocPacketType = 0xA1A1A1A1;
constexpr uint32_t kFreePacketType = 0xFEFEFEFE;
#pragma pack(push, 1)
struct StreamHeader {
// TODO(brettw) consider using C++11 default initialization for the types.
uint32_t signature; // kStreamSignature
};
struct StartMojoControlPacket {
uint32_t op; // = kStartMojoControlPacketType
};
struct AllocPacket {
uint32_t op; // = kAllocPacketType
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/profiling/profiling_constants.h"
namespace profiling {
const char kProfilingControlPipeName[] = "memlog_control";
} // namespace profiling
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_COMMON_PROFILING_PROFILING_CONSTANTS_H_
#define CHROME_COMMON_PROFILING_PROFILING_CONSTANTS_H_
namespace profiling {
// Name of the profiling control Mojo service.
extern const char kProfilingControlPipeName[];
} // namespace profiling
#endif // CHROME_COMMON_PROFILING_PROFILING_CONSTANTS_H_
// Copyright 2017 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.
module profiling.mojom;
interface ProfilingControl {
// Adds a new platform-specific pipe to read memlog trace data from.
// In normal usage, each child process launch will have a corresponding call
// to this.
AddNewSender(handle sender_pipe, int32 sender_pid);
};
......@@ -33,6 +33,8 @@ if (enable_oop_heap_profiling) {
"profiling_globals.h",
"profiling_main.cc",
"profiling_main.h",
"profiling_process.cc",
"profiling_process.h",
]
deps = [
......
......@@ -22,7 +22,11 @@ struct MemlogConnectionManager::Connection {
pipe(p),
tracker(std::move(complete_cb)) {}
~Connection() {}
~Connection() {
// The parser may outlive this class because it's refcounted, make sure no
// callbacks are issued.
parser->DisconnectReceivers();
}
base::Thread thread;
......@@ -47,6 +51,14 @@ void MemlogConnectionManager::StartConnections(const std::string& pipe_id) {
server_->Start();
}
void MemlogConnectionManager::OnStartMojoControl() {
ProfilingGlobals::Get()->GetIORunner()->PostTask(
FROM_HERE,
base::Bind(
&ProfilingProcess::EnsureMojoStarted,
base::Unretained(ProfilingGlobals::Get()->GetProfilingProcess())));
}
void MemlogConnectionManager::OnNewConnection(
scoped_refptr<MemlogReceiverPipe> new_pipe) {
int remote_process = new_pipe->GetRemoteProcessID();
......@@ -62,7 +74,7 @@ void MemlogConnectionManager::OnNewConnection(
std::move(complete_cb), remote_process, new_pipe);
connection->thread.Start();
connection->parser = new MemlogStreamParser(&connection->tracker);
connection->parser = new MemlogStreamParser(this, &connection->tracker);
new_pipe->SetReceiver(connection->thread.task_runner(), connection->parser);
connections_[remote_process] = std::move(connection);
......
......@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "build/build_config.h"
#include "chrome/profiling/backtrace_storage.h"
#include "chrome/profiling/memlog_control_receiver.h"
#include "chrome/profiling/memlog_receiver_pipe_server.h"
namespace base {
......@@ -21,10 +22,10 @@ namespace profiling {
// Manages all connections and logging for each process. Pipes are supplied by
// the pipe server and this class will connect them to a parser and logger.
class MemlogConnectionManager {
class MemlogConnectionManager : public MemlogControlReceiver {
public:
MemlogConnectionManager();
~MemlogConnectionManager();
~MemlogConnectionManager() override;
// Starts listening for connections.
void StartConnections(const std::string& pipe_id);
......@@ -32,6 +33,9 @@ class MemlogConnectionManager {
private:
struct Connection;
// MemlogControlReceiver implementation.
void OnStartMojoControl() override;
// Called by the pipe server when a new pipe is created.
void OnNewConnection(scoped_refptr<MemlogReceiverPipe> new_pipe);
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_PROFILING_MEMLOG_CONTROL_RECEIVER_H_
#define CHROME_PROFILING_MEMLOG_CONTROL_RECEIVER_H_
namespace profiling {
class MemlogControlReceiver {
public:
virtual ~MemlogControlReceiver() {}
virtual void OnStartMojoControl() = 0;
};
} // namespace profiling
#endif // CHROME_PROFILING_MEMLOG_CONTROL_RECEIVER_H_
......@@ -26,19 +26,30 @@ MemlogStreamParser::Block::Block(std::unique_ptr<char[]> d, size_t s)
MemlogStreamParser::Block::~Block() {}
MemlogStreamParser::MemlogStreamParser(MemlogReceiver* receiver)
: receiver_(receiver) {}
MemlogStreamParser::MemlogStreamParser(MemlogControlReceiver* control_receiver,
MemlogReceiver* receiver)
: control_receiver_(control_receiver), receiver_(receiver) {}
MemlogStreamParser::~MemlogStreamParser() {}
void MemlogStreamParser::DisconnectReceivers() {
receiver_ = nullptr;
control_receiver_ = nullptr;
}
void MemlogStreamParser::OnStreamData(std::unique_ptr<char[]> data, size_t sz) {
if (!receiver_)
return; // When no receiver is connected, do nothing with incoming data.
blocks_.emplace_back(std::move(data), sz);
if (!received_header_) {
received_header_ = true;
ReadStatus status = ParseHeader();
if (status != READ_OK)
return; // TODO(brettw) signal error.
if (status != READ_OK) {
LOG(ERROR) << "Memlog header read error.";
return;
}
}
while (true) {
......@@ -54,16 +65,26 @@ void MemlogStreamParser::OnStreamData(std::unique_ptr<char[]> data, size_t sz) {
case kFreePacketType:
status = ParseFree();
break;
case kStartMojoControlPacketType:
ConsumeBytes(sizeof(StartMojoControlPacket));
if (control_receiver_)
control_receiver_->OnStartMojoControl();
status = READ_OK;
break;
default:
return; // TODO(brettw) signal error.
LOG(ERROR) << "Error reading memlog message stream" << msg_type;
return;
}
if (status != READ_OK) {
LOG_IF(ERROR, status == READ_ERROR) << "Memlog read error";
return;
}
if (status != READ_OK)
return; // TODO(brettw) signal error.
}
}
void MemlogStreamParser::OnStreamComplete() {
receiver_->OnComplete();
if (receiver_)
receiver_->OnComplete();
}
bool MemlogStreamParser::AreBytesAvailable(size_t count) const {
......
......@@ -8,6 +8,7 @@
#include <deque>
#include "base/macros.h"
#include "chrome/profiling/memlog_control_receiver.h"
#include "chrome/profiling/memlog_receiver.h"
#include "chrome/profiling/memlog_stream_receiver.h"
......@@ -16,8 +17,13 @@ namespace profiling {
// Parses a memory stream. Refcounted via StreamReceiver.
class MemlogStreamParser : public MemlogStreamReceiver {
public:
// Receiver must outlive this class.
explicit MemlogStreamParser(MemlogReceiver* receiver);
// Both receivers must either outlive this class or live until
// DisconnectReceivers is called.
explicit MemlogStreamParser(MemlogControlReceiver* control_receiver,
MemlogReceiver* receiver);
// For tear-down, resets both receivers so they will not be called.
void DisconnectReceivers();
// StreamReceiver implementation.
void OnStreamData(std::unique_ptr<char[]> data, size_t sz) override;
......@@ -53,7 +59,9 @@ class MemlogStreamParser : public MemlogStreamReceiver {
ReadStatus ParseAlloc();
ReadStatus ParseFree();
MemlogReceiver* receiver_; // Not owned by this class.
// Not owned by this class.
MemlogControlReceiver* control_receiver_;
MemlogReceiver* receiver_;
std::deque<Block> blocks_;
......
......@@ -10,26 +10,23 @@
namespace profiling {
ProfilingGlobals::ProfilingGlobals()
: io_thread_("IO thread") {
#if defined(OS_WIN)
io_thread_.init_com_with_mta(true);
#endif
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO;
io_thread_.StartWithOptions(options);
}
ProfilingGlobals* ProfilingGlobals::singleton_ = nullptr;
ProfilingGlobals::~ProfilingGlobals() {}
ProfilingGlobals::ProfilingGlobals() {
DCHECK(!singleton_);
singleton_ = this;
}
// static
ProfilingGlobals* ProfilingGlobals::Get() {
static ProfilingGlobals singleton;
return &singleton;
ProfilingGlobals::~ProfilingGlobals() {
singleton_ = nullptr;
}
base::TaskRunner* ProfilingGlobals::GetIORunner() {
return io_thread_.task_runner().get();
return message_loop_.task_runner().get();
}
ProfilingProcess* ProfilingGlobals::GetProfilingProcess() {
return &process_;
}
MemlogConnectionManager* ProfilingGlobals::GetMemlogConnectionManager() {
......@@ -40,28 +37,13 @@ BacktraceStorage* ProfilingGlobals::GetBacktraceStorage() {
return &backtrace_storage_;
}
scoped_refptr<base::SingleThreadTaskRunner> ProfilingGlobals::GetMainThread()
const {
CHECK(base::MessageLoop::current() == main_message_loop_);
return main_message_loop_->task_runner();
}
void ProfilingGlobals::RunMainMessageLoop() {
// TODO(brettw) if we never add anything interesting on the main thread here,
// we can change this so the main thread *is* the I/O thread. This will save
// some resources.
base::MessageLoopForUI message_loop;
DCHECK(!main_message_loop_);
main_message_loop_ = &message_loop;
base::RunLoop run_loop;
run_loop.Run();
main_message_loop_ = nullptr;
}
void ProfilingGlobals::QuitWhenIdle() {
main_message_loop_->QuitWhenIdle();
message_loop_.QuitWhenIdle();
}
} // namespace profiling
......@@ -9,13 +9,12 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread.h"
#include "base/message_loop/message_loop.h"
#include "chrome/profiling/backtrace_storage.h"
#include "chrome/profiling/memlog_connection_manager.h"
#include "chrome/profiling/profiling_process.h"
namespace base {
class MessageLoopForUI;
class SingleThreadTaskRunner;
class TaskRunner;
} // namespace base
......@@ -23,27 +22,26 @@ namespace profiling {
class ProfilingGlobals {
public:
static ProfilingGlobals* Get();
ProfilingGlobals();
~ProfilingGlobals();
static inline ProfilingGlobals* Get() { return singleton_; }
base::TaskRunner* GetIORunner();
ProfilingProcess* GetProfilingProcess();
MemlogConnectionManager* GetMemlogConnectionManager();
BacktraceStorage* GetBacktraceStorage();
// Returns non-null when inside RunMainMessageLoop. Call only on the
// main thread (otherwise there's a shutdown race).
scoped_refptr<base::SingleThreadTaskRunner> GetMainThread() const;
void RunMainMessageLoop();
void QuitWhenIdle();
private:
ProfilingGlobals();
~ProfilingGlobals();
static ProfilingGlobals* singleton_;
// Non-null inside RunMainMessageLoop.
base::MessageLoopForUI* main_message_loop_ = nullptr;
base::MessageLoopForIO message_loop_;
base::Thread io_thread_;
ProfilingProcess process_;
MemlogConnectionManager memlog_connection_manager_;
BacktraceStorage backtrace_storage_;
......
......@@ -7,9 +7,13 @@
#include "base/command_line.h"
#include "build/build_config.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/profiling/profiling_constants.h"
#include "chrome/profiling/profiling_globals.h"
#include "chrome/profiling/profiling_process.h"
#include "mojo/edk/embedder/embedder.h"
#include "mojo/edk/embedder/incoming_broker_client_invitation.h"
#include "mojo/edk/embedder/scoped_ipc_support.h"
#include "mojo/edk/embedder/transport_protocol.h"
#if defined(OS_WIN)
#include "base/win/win_util.h"
......@@ -18,17 +22,17 @@
namespace profiling {
int ProfilingMain(const base::CommandLine& cmdline) {
ProfilingGlobals* globals = ProfilingGlobals::Get();
ProfilingGlobals globals;
mojo::edk::Init();
mojo::edk::ScopedIPCSupport ipc_support(
globals->GetIORunner(),
globals.GetIORunner(),
mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
std::string pipe_id = cmdline.GetSwitchValueASCII(switches::kMemlogPipe);
globals->GetMemlogConnectionManager()->StartConnections(pipe_id);
globals.GetMemlogConnectionManager()->StartConnections(pipe_id);
ProfilingGlobals::Get()->RunMainMessageLoop();
globals.RunMainMessageLoop();
#if defined(OS_WIN)
base::win::SetShouldCrashOnProcessDetach(false);
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/profiling/profiling_process.h"
#include "base/bind.h"
#include "chrome/common/profiling/profiling_constants.h"
#include "chrome/profiling/profiling_globals.h"
namespace profiling {
ProfilingProcess::ProfilingProcess() : binding_(this) {}
ProfilingProcess::~ProfilingProcess() {}
void ProfilingProcess::EnsureMojoStarted() {
if (started_mojo_)
return;
started_mojo_ = true;
control_invitation_ =
mojo::edk::IncomingBrokerClientInvitation::AcceptFromCommandLine(
mojo::edk::TransportProtocol::kLegacy);
binding_.Bind(mojom::ProfilingControlRequest(
control_invitation_->ExtractMessagePipe(kProfilingControlPipeName)));
}
void ProfilingProcess::AddNewSender(mojo::ScopedHandle sender_pipe,
int32_t sender_pid) {}
} // namespace profiling
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_PROFILING_PROFILING_PROCESS_H_
#define CHROME_PROFILING_PROFILING_PROCESS_H_
#include "base/macros.h"
#include "chrome/common/profiling/profiling_control.mojom.h"
#include "mojo/edk/embedder/incoming_broker_client_invitation.h"
#include "mojo/public/cpp/bindings/binding.h"
namespace profiling {
// Represents the profiling process side of the profiling <-> browser
// connection. This class is not thread safe and must onle be called on the IO
// thread (which is the main thread in the profiling process).
class ProfilingProcess : public mojom::ProfilingControl {
public:
ProfilingProcess();
~ProfilingProcess() override;
void EnsureMojoStarted();
// ProfilingControl implementation.
void AddNewSender(mojo::ScopedHandle sender_pipe,
int32_t sender_pid) override;
private:
bool started_mojo_ = false;
std::unique_ptr<mojo::edk::IncomingBrokerClientInvitation>
control_invitation_;
mojo::Binding<mojom::ProfilingControl> binding_;
DISALLOW_COPY_AND_ASSIGN(ProfilingProcess);
};
} // namespace profiling
#endif // CHROME_PROFILING_PROFILING_PROCESS_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