Commit 0eb57d23 authored by Erik Chen's avatar Erik Chen Committed by Commit Bot

Remove the DumpProcess profiling_service mojom method.

Previously, DumpProcess would create a full trace, with metadata provided by
ProfilingProcessHost, and write the result to a file. This duplicated
functionality of DumpProcessesForTracing, which uses the Tracing service to
create a fully-fledged trace.

Bug: 
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: Ibca11524f23b7fe8d9808370e05225298a0794a5
Reviewed-on: https://chromium-review.googlesource.com/798152
Commit-Queue: Erik Chen <erikchen@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarBrett Wilson <brettw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521216}
parent 88cc1869
......@@ -314,13 +314,20 @@ std::unique_ptr<base::Value> ReadDumpFile(const base::FilePath& path) {
return base::JSONReader::Read(dump_string);
}
void QuitRunLoopAndCheckSecondParameter(base::RunLoop* run_loop, bool result) {
ASSERT_TRUE(result);
run_loop->Quit();
}
void DumpProcess(base::ProcessId pid, const base::FilePath& dumpfile_path) {
profiling::ProfilingProcessHost* pph =
profiling::ProfilingProcessHost::GetInstance();
base::RunLoop run_loop;
pph->RequestProcessDump(
pid, dumpfile_path,
base::BindOnce(&base::RunLoop::Quit, base::Unretained(&run_loop)));
pph->SaveTraceWithHeapDumpToFile(
dumpfile_path,
base::BindOnce(&QuitRunLoopAndCheckSecondParameter,
base::Unretained(&run_loop)),
true);
run_loop.Run();
}
......@@ -365,10 +372,7 @@ IN_PROC_BROWSER_TEST_P(MemlogBrowserTest, EndToEnd) {
GetParam() == switches::kMemlogModeBrowser ||
GetParam() == switches::kMemlogModeMinimal) {
ASSERT_TRUE(dump_json);
EXPECT_EQ(0, NumProcessesWithName(dump_json.get(), "Renderer"));
ValidateBrowserAllocations(dump_json.get());
} else {
ASSERT_FALSE(dump_json) << "Browser process unexpectedly profiled.";
}
}
......@@ -390,9 +394,6 @@ IN_PROC_BROWSER_TEST_P(MemlogBrowserTest, EndToEnd) {
GetParam() == switches::kMemlogModeRendererSampling) {
ASSERT_TRUE(dump_json);
ValidateRendererAllocations(dump_json.get());
EXPECT_EQ(0, NumProcessesWithName(dump_json.get(), "Browser"));
} else {
ASSERT_FALSE(dump_json) << "Renderer process unexpectedly profiled.";
}
}
......
......@@ -47,6 +47,11 @@
#include "mojo/edk/embedder/platform_channel_pair.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "third_party/zlib/zlib.h"
#if defined(OS_WIN)
#include <io.h>
#endif
namespace {
......@@ -100,8 +105,6 @@ bool ProfilingProcessHost::has_started_ = false;
namespace {
constexpr char kNoTriggerName[] = "";
// This helper class cleans up initialization boilerplate for the callers who
// need to create ProfilingClients bound to various different things.
class ProfilingClientBinder {
......@@ -440,20 +443,38 @@ void ProfilingProcessHost::ConfigureBackgroundProfilingTriggers() {
background_triggers_.StartTimer();
}
void ProfilingProcessHost::RequestProcessDump(base::ProcessId pid,
base::FilePath dest,
base::OnceClosure done) {
if (!connector_) {
void ProfilingProcessHost::SaveTraceWithHeapDumpToFile(
base::FilePath dest,
SaveTraceFinishedCallback done,
bool stop_immediately_after_heap_dump_for_tests) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (!profiling_service_.is_bound()) {
DLOG(ERROR)
<< "Requesting process dump when profiling process hasn't started.";
<< "Requesting heap dump when profiling process hasn't started.";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(done), false));
return;
}
base::PostTaskWithTraits(
FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
base::BindOnce(&ProfilingProcessHost::GetOutputFileOnBlockingThread,
base::Unretained(this), pid, std::move(dest),
kNoTriggerName, std::move(done)));
auto finish_trace_callback = base::BindOnce(
[](base::FilePath dest, SaveTraceFinishedCallback done, bool success,
std::string trace) {
if (!success) {
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::UI)
->PostTask(FROM_HERE, base::BindOnce(std::move(done), false));
return;
}
base::PostTaskWithTraits(
FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
base::BindOnce(
&ProfilingProcessHost::SaveTraceToFileOnBlockingThread,
base::Unretained(ProfilingProcessHost::GetInstance()),
std::move(dest), std::move(trace), std::move(done)));
},
std::move(dest), std::move(done));
RequestTraceWithHeapDump(std::move(finish_trace_callback),
stop_immediately_after_heap_dump_for_tests);
}
void ProfilingProcessHost::RequestProcessReport(std::string trigger_name) {
......@@ -569,74 +590,41 @@ void ProfilingProcessHost::LaunchAsService() {
}
}
void ProfilingProcessHost::GetOutputFileOnBlockingThread(
base::ProcessId pid,
void ProfilingProcessHost::SaveTraceToFileOnBlockingThread(
base::FilePath dest,
std::string trigger_name,
base::OnceClosure done) {
base::ScopedClosureRunner done_runner(std::move(done));
std::string trace,
SaveTraceFinishedCallback done) {
base::File file(dest,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&ProfilingProcessHost::HandleDumpProcessOnIOThread,
base::Unretained(this), pid, std::move(dest),
std::move(file), std::move(trigger_name),
done_runner.Release()));
}
void ProfilingProcessHost::HandleDumpProcessOnIOThread(base::ProcessId pid,
base::FilePath file_path,
base::File file,
std::string trigger_name,
base::OnceClosure done) {
mojo::ScopedHandle handle = mojo::WrapPlatformFile(file.TakePlatformFile());
profiling_service_->DumpProcess(
pid, std::move(handle), GetMetadataJSONForTrace(),
base::BindOnce(&ProfilingProcessHost::OnProcessDumpComplete,
base::Unretained(this), std::move(file_path),
std::move(trigger_name), std::move(done)));
}
void ProfilingProcessHost::OnProcessDumpComplete(base::FilePath file_path,
std::string trigger_name,
base::OnceClosure done,
bool success) {
base::ScopedClosureRunner done_runner(std::move(done));
if (!success) {
DLOG(ERROR) << "Cannot dump process.";
// On any errors, the requested trace output file is deleted.
base::PostTaskWithTraits(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
base::BindOnce(base::IgnoreResult(&base::DeleteFile), file_path,
false));
// Pass ownership of the underlying fd/HANDLE to zlib.
base::PlatformFile platform_file = file.TakePlatformFile();
#if defined(OS_WIN)
// The underlying handle |platform_file| is also closed when |fd| is closed.
int fd = _open_osfhandle(reinterpret_cast<intptr_t>(platform_file), 0);
#else
int fd = platform_file;
#endif
gzFile gz_file = gzdopen(fd, "w");
if (!gz_file) {
DLOG(ERROR) << "Cannot compress trace file";
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
->PostTask(FROM_HERE, base::BindOnce(std::move(done), false));
return;
}
size_t written_bytes = gzwrite(gz_file, trace.c_str(), trace.size());
gzclose(gz_file);
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
->PostTask(FROM_HERE, base::BindOnce(std::move(done),
written_bytes == trace.size()));
}
void ProfilingProcessHost::SetMode(Mode mode) {
mode_ = mode;
}
std::unique_ptr<base::DictionaryValue>
ProfilingProcessHost::GetMetadataJSONForTrace() {
std::unique_ptr<base::DictionaryValue> metadata_dict(
new base::DictionaryValue);
metadata_dict->SetKey(
"product-version",
base::Value(version_info::GetProductNameAndVersionForUserAgent()));
metadata_dict->SetKey("user-agent", base::Value(GetUserAgent()));
metadata_dict->SetKey("os-name",
base::Value(base::SysInfo::OperatingSystemName()));
metadata_dict->SetKey(
"command_line",
base::Value(
base::CommandLine::ForCurrentProcess()->GetCommandLineString()));
metadata_dict->SetKey(
"os-arch", base::Value(base::SysInfo::OperatingSystemArchitecture()));
return metadata_dict;
}
void ProfilingProcessHost::ReportMetrics() {
UMA_HISTOGRAM_ENUMERATION("OutOfProcessHeapProfiling.ProfilingMode", mode(),
Mode::kCount);
......
......@@ -105,11 +105,16 @@ class ProfilingProcessHost : public content::BrowserChildProcessObserver,
void ConfigureBackgroundProfilingTriggers();
// Sends a message to the profiling process to dump the given process'
// memory data to the given file.
void RequestProcessDump(base::ProcessId pid,
base::FilePath dest,
base::OnceClosure done);
// Create a trace with a heap dump at the given path.
// This is equivalent to navigating to chrome://tracing, taking a trace with
// only the memory-infra category selected, waiting 10 seconds, and saving the
// result to |dest|.
// |done| will be called on the UI thread.
using SaveTraceFinishedCallback = base::OnceCallback<void(bool success)>;
void SaveTraceWithHeapDumpToFile(
base::FilePath dest,
SaveTraceFinishedCallback done,
bool stop_immediately_after_heap_dump_for_tests);
// Sends a message to the profiling process to report all profiled processes
// memory data to the crash server (slow-report).
......@@ -181,23 +186,9 @@ class ProfilingProcessHost : public content::BrowserChildProcessObserver,
base::ProcessId pid,
profiling::mojom::ProcessType process_type);
void GetOutputFileOnBlockingThread(base::ProcessId pid,
base::FilePath dest,
std::string trigger_name,
base::OnceClosure done);
void HandleDumpProcessOnIOThread(base::ProcessId pid,
base::FilePath file_path,
base::File file,
std::string trigger_name,
base::OnceClosure done);
void OnProcessDumpComplete(base::FilePath file_path,
std::string trigger_name,
base::OnceClosure done,
bool success);
// Returns the metadata for the trace. This is the minimum amount of metadata
// needed to symbolize the trace.
std::unique_ptr<base::DictionaryValue> GetMetadataJSONForTrace();
void SaveTraceToFileOnBlockingThread(base::FilePath dest,
std::string trace,
SaveTraceFinishedCallback done);
// Reports the profiling mode.
void ReportMetrics();
......
......@@ -18,7 +18,7 @@
margin-bottom: 1em;
padding: 5px;
}
.refresh {
.commands {
padding: 5px;
}
</style>
......
......@@ -8,8 +8,8 @@ function requestProcessList() {
chrome.send('requestProcessList');
}
function dumpProcess(pid) {
chrome.send('dumpProcess', [pid]);
function saveDump() {
chrome.send('saveDump');
}
function reportProcess(pid) {
......@@ -29,6 +29,10 @@ function addListRow(table, celltype, cols) {
table.appendChild(tr);
}
function setSaveDumpMessage(data) {
$('save_dump_text').innerText = data;
}
function returnProcessList(data) {
$('message').innerText = data['message'];
......@@ -39,30 +43,34 @@ function returnProcessList(data) {
if (processes.length == 0)
return; // No processes to dump, don't make the table and refresh button.
// Add the refresh button.
let refreshDiv = document.createElement('div');
refreshDiv.className = 'refresh';
// Add the refresh and save-dump buttons.
let commandsDiv = document.createElement('div');
commandsDiv.className = 'commands';
let refreshButton = document.createElement('button');
refreshButton.innerText = '\u21ba Refresh process list';
refreshButton.onclick = () => requestProcessList();
refreshDiv.appendChild(refreshButton);
proclist.appendChild(refreshDiv);
commandsDiv.appendChild(refreshButton);
let saveDumpButton = document.createElement('button');
saveDumpButton.innerText = '\u21e9 Save dump';
saveDumpButton.onclick = () => saveDump();
commandsDiv.appendChild(saveDumpButton);
let saveDumpText = document.createElement('div');
saveDumpText.id = 'save_dump_text';
commandsDiv.appendChild(saveDumpText);
proclist.appendChild(commandsDiv);
let table = document.createElement('table');
// Heading.
addListRow(table, 'th', [
null, null, document.createTextNode('Process ID'),
document.createTextNode('Name')
null, document.createTextNode('Process ID'), document.createTextNode('Name')
]);
for (let proc of processes) {
let procId = proc[0];
let saveButton = document.createElement('button');
saveButton.innerText = '\u21e9 Save dump';
saveButton.onclick = () => dumpProcess(procId);
let reportButton = document.createElement('button');
reportButton.innerText = '\uD83D\uDC1E Report';
reportButton.onclick = () => reportProcess(procId);
......@@ -70,8 +78,7 @@ function returnProcessList(data) {
let procIdText = document.createTextNode(procId.toString());
let description = document.createTextNode(proc[1]);
addListRow(
table, 'td', [saveButton, reportButton, procIdText, description]);
addListRow(table, 'td', [reportButton, procIdText, description]);
}
proclist.appendChild(table);
......
......@@ -125,8 +125,8 @@ class MemoryInternalsDOMHandler : public content::WebUIMessageHandler,
// Callback for the "requestProcessList" message.
void HandleRequestProcessList(const base::ListValue* args);
// Callback for the "dumpProcess" message.
void HandleDumpProcess(const base::ListValue* args);
// Callback for the "saveDump" message.
void HandleSaveDump(const base::ListValue* args);
// Callback for the "reportProcess" message.
void HandleReportProcess(const base::ListValue* args);
......@@ -144,6 +144,8 @@ class MemoryInternalsDOMHandler : public content::WebUIMessageHandler,
void* params) override;
void FileSelectionCanceled(void* params) override;
void SaveTraceFinished(bool success);
scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
content::WebUI* web_ui_; // The WebUI that owns us.
......@@ -168,8 +170,8 @@ void MemoryInternalsDOMHandler::RegisterMessages() {
base::Bind(&MemoryInternalsDOMHandler::HandleRequestProcessList,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"dumpProcess",
base::BindRepeating(&MemoryInternalsDOMHandler::HandleDumpProcess,
"saveDump",
base::BindRepeating(&MemoryInternalsDOMHandler::HandleSaveDump,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"reportProcess",
......@@ -187,26 +189,27 @@ void MemoryInternalsDOMHandler::HandleRequestProcessList(
weak_factory_.GetWeakPtr()));
}
void MemoryInternalsDOMHandler::HandleDumpProcess(const base::ListValue* args) {
if (!args->is_list() || args->GetList().size() != 1)
return;
const base::Value& pid_value = args->GetList()[0];
if (!pid_value.is_int())
return;
int pid = pid_value.GetInt();
void MemoryInternalsDOMHandler::HandleSaveDump(const base::ListValue* args) {
base::FilePath default_file = base::FilePath().AppendASCII(
base::StringPrintf("memlog_%d.json.gz", pid));
base::StringPrintf("trace_with_heap_dump.json.gz"));
#if defined(OS_ANDROID)
base::Value result("Saving...");
AllowJavascript();
CallJavascriptFunction("setSaveDumpMessage", result);
// On Android write to the user data dir.
// TODO(bug 757115) Does it make sense to show the Android file picker here
// instead? Need to test what that looks like.
base::FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
base::FilePath output_path = user_data_dir.Append(default_file);
ProfilingProcessHost::GetInstance()->RequestProcessDump(
pid, std::move(output_path), base::OnceClosure());
ProfilingProcessHost::GetInstance()->SaveTraceWithHeapDumpToFile(
std::move(output_path),
base::BindOnce(&MemoryInternalsDOMHandler::SaveTraceFinished,
weak_factory_.GetWeakPtr()),
false);
(void)web_ui_; // Avoid warning about not using private web_ui_ member.
#else
if (select_file_dialog_)
......@@ -215,12 +218,10 @@ void MemoryInternalsDOMHandler::HandleDumpProcess(const base::ListValue* args) {
this,
std::make_unique<ChromeSelectFilePolicy>(web_ui_->GetWebContents()));
// Pass the PID to dump via the "params" for the callback to use.
select_file_dialog_->SelectFile(
ui::SelectFileDialog::SELECT_SAVEAS_FILE, base::string16(), default_file,
nullptr, 0, FILE_PATH_LITERAL(".json.gz"),
web_ui_->GetWebContents()->GetTopLevelNativeWindow(),
reinterpret_cast<void*>(pid));
web_ui_->GetWebContents()->GetTopLevelNativeWindow(), nullptr);
#endif
}
......@@ -301,16 +302,20 @@ void MemoryInternalsDOMHandler::ReturnProcessListOnUIThread(
AllowJavascript();
CallJavascriptFunction("returnProcessList", result);
DisallowJavascript();
}
void MemoryInternalsDOMHandler::FileSelected(const base::FilePath& path,
int index,
void* params) {
// The PID to dump was stashed in the params.
int pid = reinterpret_cast<intptr_t>(params);
ProfilingProcessHost::GetInstance()->RequestProcessDump(pid, path,
base::OnceClosure());
base::Value result("Saving...");
AllowJavascript();
CallJavascriptFunction("setSaveDumpMessage", result);
ProfilingProcessHost::GetInstance()->SaveTraceWithHeapDumpToFile(
path,
base::BindOnce(&MemoryInternalsDOMHandler::SaveTraceFinished,
weak_factory_.GetWeakPtr()),
false);
select_file_dialog_ = nullptr;
}
......@@ -318,6 +323,12 @@ void MemoryInternalsDOMHandler::FileSelectionCanceled(void* params) {
select_file_dialog_ = nullptr;
}
void MemoryInternalsDOMHandler::SaveTraceFinished(bool success) {
base::Value result(success ? "Save successful." : "Save failure.");
AllowJavascript();
CallJavascriptFunction("setSaveDumpMessage", result);
}
} // namespace
MemoryInternalsUI::MemoryInternalsUI(content::WebUI* web_ui)
......
......@@ -41,12 +41,6 @@ interface ProfilingService {
handle memlog_pipe_receiver,
ProcessType process_type);
// Dumps the memory log of the process with the given |pid| into
// |output_file|. |metadata| is a dictionary that should be added to the trace
// under the "metadata" key.
DumpProcess(mojo.common.mojom.ProcessId pid, handle output_file,
mojo.common.mojom.DictionaryValue metadata) => (bool result);
// Dumps the memory log of all profiled processes into shared buffers. The
// contents of each shared buffer is a JSON string compatible with
// TRACE_EVENT* macros. Processes that fail to dump will be omitted from
......
......@@ -90,55 +90,6 @@ const char* StringForAllocatorType(uint32_t type) {
}
}
std::string ProcessNameFromProcessType(mojom::ProcessType process_type) {
switch (process_type) {
case mojom::ProcessType::BROWSER:
return "Browser";
case mojom::ProcessType::RENDERER:
return "Renderer";
case mojom::ProcessType::GPU:
return "Gpu";
case mojom::ProcessType::OTHER:
return "Other";
}
return "Unknown";
}
std::string ProcessMainThreadNameFromProcessType(
mojom::ProcessType process_type) {
switch (process_type) {
case mojom::ProcessType::BROWSER:
return "CrBrowserMain";
case mojom::ProcessType::RENDERER:
return "CrRendererMain";
case mojom::ProcessType::GPU:
return "CrGpuMain";
case mojom::ProcessType::OTHER:
return "CrOtherMain";
}
return "CrUnknownMain";
}
// Writes a dummy process name entry given a PID. When we have more information
// on a process it can be filled in here. But for now the tracing tools expect
// this entry since everything is associated with a PID.
void WriteProcessName(int pid, const ExportParams& params, std::ostream& out) {
out << "{ \"pid\":" << pid << ", \"ph\":\"M\", \"name\":\"process_name\", "
<< "\"args\":{\"name\":\""
<< ProcessNameFromProcessType(params.process_type) << "\"}},";
// Catapult needs a thread named "CrBrowserMain" to recognize Chrome browser.
out << "{ \"pid\":" << pid << ", \"ph\":\"M\", \"name\":\"thread_name\", "
<< "\"tid\": 1,"
<< "\"args\":{\"name\":\""
<< ProcessMainThreadNameFromProcessType(params.process_type) << "\"}},";
// At least, one event must be present on the thread to avoid being pruned.
out << "{ \"name\": \"MemlogTraceEvent\", \"cat\": \"memlog\", "
<< "\"ph\": \"B\", \"ts\": 1, \"pid\": " << pid << ", "
<< "\"tid\": 1, \"args\": {}}";
}
// Writes the top-level allocators section. This section is used by the tracing
// UI to show a small summary for each allocator. It's necessary as a
// placeholder to allow the stack-viewing UI to be shown.
......@@ -197,21 +148,6 @@ void WriteAllocatorsSummary(size_t total_size[],
out << "},\n";
}
// Writes the dictionary keys to preceed a "dumps" trace argument.
void WriteDumpsHeader(int pid, std::ostream& out) {
out << "{ \"pid\":" << pid << ",";
out << "\"ph\":\"v\",";
out << "\"name\":\"periodic_interval\",";
out << "\"ts\": 1,";
out << "\"id\": \"1\",";
out << "\"args\":{";
out << "\"dumps\":";
}
void WriteDumpsFooter(std::ostream& out) {
out << "}}"; // args, event
}
// Writes the dictionary keys to preceed a "heaps_v2" trace argument inside a
// "dumps". This is "v2" heap dump format.
void WriteHeapsV2Header(std::ostream& out) {
......@@ -433,29 +369,6 @@ void WriteAllocatorNodes(const UniqueAllocationMap& allocations,
ExportParams::ExportParams() = default;
ExportParams::~ExportParams() = default;
void ExportAllocationEventSetToJSON(
int pid,
const ExportParams& params,
std::unique_ptr<base::DictionaryValue> metadata_dict,
std::ostream& out) {
out << "{ \"traceEvents\": [";
WriteProcessName(pid, params, out);
out << ",\n";
WriteDumpsHeader(pid, out);
ExportMemoryMapsAndV2StackTraceToJSON(params, out);
WriteDumpsFooter(out);
out << "]";
// Append metadata.
if (metadata_dict) {
std::string metadata;
base::JSONWriter::Write(*metadata_dict, &metadata);
out << ",\"metadata\": " << metadata;
}
out << "}\n";
}
void ExportMemoryMapsAndV2StackTraceToJSON(const ExportParams& params,
std::ostream& out) {
// Start dictionary.
......
......@@ -43,14 +43,6 @@ struct ExportParams {
bool is_argument_filtering_enabled = false;
};
// Creates a JSON-encoded string that is similar in form to traces created by
// TracingControllerImpl. Metadata can be null.
void ExportAllocationEventSetToJSON(
int pid,
const ExportParams& params,
std::unique_ptr<base::DictionaryValue> metadata,
std::ostream& out);
// Creates a JSON string representing a JSON dictionary that contains memory
// maps and v2 format stack traces.
void ExportMemoryMapsAndV2StackTraceToJSON(const ExportParams& params,
......
This diff is collapsed.
......@@ -36,17 +36,6 @@ MemlogConnectionManager::DumpArgs::DumpArgs(DumpArgs&& other) noexcept
: backtrace_storage_lock(std::move(other.backtrace_storage_lock)) {}
MemlogConnectionManager::DumpArgs::~DumpArgs() = default;
MemlogConnectionManager::DumpProcessArgs::DumpProcessArgs() = default;
MemlogConnectionManager::DumpProcessArgs::DumpProcessArgs(
DumpProcessArgs&& other) noexcept
: DumpArgs(std::move(other)),
pid(other.pid),
maps(std::move(other.maps)),
metadata(std::move(other.metadata)),
file(std::move(other.file)),
callback(std::move(other.callback)) {}
MemlogConnectionManager::DumpProcessArgs::~DumpProcessArgs() = default;
// Tracking information for DumpProcessForTracing(). This struct is
// refcounted since there will be many background thread calls (one for each
// AllocationTracker) and the callback is only issued when each has
......@@ -189,41 +178,6 @@ void MemlogConnectionManager::OnConnectionCompleteThunk(
connection_manager, pid));
}
void MemlogConnectionManager::DumpProcess(DumpProcessArgs args) {
// Schedules the given callback to execute after the given process ID has
// been synchronized. If the process ID isn't found, the callback will be
// asynchronously run with "false" as the success parameter.
args.backtrace_storage_lock = BacktraceStorage::Lock(&backtrace_storage_);
base::AutoLock lock(connections_lock_);
auto task_runner = base::MessageLoop::current()->task_runner();
auto it = connections_.find(args.pid);
if (it == connections_.end()) {
DLOG(ERROR) << "No connections found for memory dump for pid:" << args.pid;
task_runner->PostTask(
FROM_HERE,
base::BindOnce(&MemlogConnectionManager::DoDumpProcess,
weak_factory_.GetWeakPtr(), std::move(args),
mojom::ProcessType::OTHER, false, AllocationCountMap(),
AllocationTracker::ContextMap()));
return;
}
int barrier_id = next_barrier_id_++;
// Register for callback before requesting the dump so we don't race for the
// signal. The callback will be issued on the allocation tracker thread so
// need to thunk back to the I/O thread.
Connection* connection = it->second.get();
auto callback = base::BindOnce(&MemlogConnectionManager::DoDumpProcess,
weak_factory_.GetWeakPtr(), std::move(args),
connection->process_type);
connection->tracker.SnapshotOnBarrier(barrier_id, std::move(task_runner),
std::move(callback));
connection->client->FlushMemlogPipe(barrier_id);
}
void MemlogConnectionManager::DumpProcessesForTracing(
mojom::ProfilingService::DumpProcessesForTracingCallback callback,
memory_instrumentation::mojom::GlobalMemoryDumpPtr dump) {
......@@ -264,51 +218,6 @@ void MemlogConnectionManager::DumpProcessesForTracing(
}
}
void MemlogConnectionManager::DoDumpProcess(
DumpProcessArgs args,
mojom::ProcessType process_type,
bool success,
AllocationCountMap counts,
AllocationTracker::ContextMap context) {
if (!success) {
std::move(args.callback).Run(false);
return;
}
CHECK(args.backtrace_storage_lock.IsLocked());
std::ostringstream oss;
ExportParams params;
params.allocs = std::move(counts);
params.context_map = std::move(context);
params.maps = std::move(args.maps);
params.process_type = process_type;
params.min_size_threshold = kMinSizeThreshold;
params.min_count_threshold = kMinCountThreshold;
ExportAllocationEventSetToJSON(args.pid, params, std::move(args.metadata),
oss);
std::string reply = oss.str();
// Pass ownership of the underlying fd/HANDLE to zlib.
base::PlatformFile platform_file = args.file.TakePlatformFile();
#if defined(OS_WIN)
// The underlying handle |platform_file| is also closed when |fd| is closed.
int fd = _open_osfhandle(reinterpret_cast<intptr_t>(platform_file), 0);
#else
int fd = platform_file;
#endif
gzFile gz_file = gzdopen(fd, "w");
if (!gz_file) {
DLOG(ERROR) << "Cannot compress trace file";
std::move(args.callback).Run(false);
return;
}
size_t written_bytes = gzwrite(gz_file, reply.c_str(), reply.size());
gzclose(gz_file);
std::move(args.callback).Run(written_bytes == reply.size());
}
void MemlogConnectionManager::DoDumpOneProcessForTracing(
scoped_refptr<DumpProcessesForTracingTracking> tracking,
base::ProcessId pid,
......
......@@ -60,31 +60,9 @@ class MemlogConnectionManager {
DISALLOW_COPY_AND_ASSIGN(DumpArgs);
};
// Parameters to DumpProcess().
struct DumpProcessArgs : public DumpArgs {
DumpProcessArgs();
DumpProcessArgs(DumpProcessArgs&&) noexcept;
~DumpProcessArgs();
// Process ID to dump.
base::ProcessId pid;
// The memory map for the given process for the dumped process must be
// provided here since that is not tracked as part of the normal allocation
// process.
std::vector<memory_instrumentation::mojom::VmRegionPtr> maps;
std::unique_ptr<base::DictionaryValue> metadata;
// File to dump the output to.
base::File file;
mojom::ProfilingService::DumpProcessCallback callback;
};
// Dumping is asynchronous so will not be complete when this function
// returns. The dump is complete when the callback provided in the args is
// fired.
void DumpProcess(DumpProcessArgs args);
void DumpProcessesForTracing(
mojom::ProfilingService::DumpProcessesForTracingCallback callback,
memory_instrumentation::mojom::GlobalMemoryDumpPtr dump);
......@@ -99,12 +77,6 @@ class MemlogConnectionManager {
struct Connection;
struct DumpProcessesForTracingTracking;
// Actually does the dump assuming the given process has been synchronized.
void DoDumpProcess(DumpProcessArgs args,
mojom::ProcessType process_type,
bool success,
AllocationCountMap counts,
AllocationTracker::ContextMap context);
void DoDumpOneProcessForTracing(
scoped_refptr<DumpProcessesForTracingTracking> tracking,
base::ProcessId pid,
......
......@@ -69,31 +69,6 @@ void ProfilingService::AddProfilingClient(
std::move(memlog_pipe_receiver), process_type);
}
void ProfilingService::DumpProcess(
base::ProcessId pid,
mojo::ScopedHandle output_file,
std::unique_ptr<base::DictionaryValue> metadata,
DumpProcessCallback callback) {
base::PlatformFile platform_file;
MojoResult result =
UnwrapPlatformFile(std::move(output_file), &platform_file);
if (result != MOJO_RESULT_OK) {
DLOG(ERROR) << "Failed to unwrap output file " << result;
std::move(callback).Run(false);
return;
}
base::File file(platform_file);
// Need a memory map to make sense of the dump. The dump will be triggered
// in the memory map global dump callback.
// TODO(brettw) this should be a OnceCallback to avoid base::Passed.
memory_instrumentation::MemoryInstrumentation::GetInstance()
->GetVmRegionsForHeapProfiler(
base::Bind(&ProfilingService::OnGetVmRegionsCompleteForDumpProcess,
weak_factory_.GetWeakPtr(), pid, base::Passed(&metadata),
base::Passed(&file), base::Passed(&callback)));
}
void ProfilingService::DumpProcessesForTracing(
DumpProcessesForTracingCallback callback) {
// Need a memory map to make sense of the dump. The dump will be triggered
......@@ -105,44 +80,6 @@ void ProfilingService::DumpProcessesForTracing(
weak_factory_.GetWeakPtr(), base::Passed(&callback)));
}
void ProfilingService::OnGetVmRegionsCompleteForDumpProcess(
base::ProcessId pid,
std::unique_ptr<base::DictionaryValue> metadata,
base::File file,
DumpProcessCallback callback,
bool success,
memory_instrumentation::mojom::GlobalMemoryDumpPtr dump) {
if (!success) {
DLOG(ERROR) << "Global dump failed";
std::move(callback).Run(false);
return;
}
// Find the process's memory dump we want.
// TODO(bug 752621) we should be asking and getting the memory map of only
// the process we want rather than querying all processes and filtering.
memory_instrumentation::mojom::ProcessMemoryDump* process_dump = nullptr;
for (const auto& proc : dump->process_dumps) {
if (proc->pid == pid) {
process_dump = &*proc;
break;
}
}
if (!process_dump) {
DLOG(ERROR) << "Don't have a memory dump for PID " << pid;
std::move(callback).Run(false);
return;
}
MemlogConnectionManager::DumpProcessArgs args;
args.pid = pid;
args.metadata = std::move(metadata);
args.maps = std::move(process_dump->os_dump->memory_maps_for_heap_profiler);
args.file = std::move(file);
args.callback = std::move(callback);
connection_manager_.DumpProcess(std::move(args));
}
void ProfilingService::OnGetVmRegionsCompleteForDumpProcessesForTracing(
mojom::ProfilingService::DumpProcessesForTracingCallback callback,
bool success,
......
......@@ -46,10 +46,6 @@ class ProfilingService : public service_manager::Service,
mojo::ScopedHandle memlog_pipe_sender,
mojo::ScopedHandle memlog_pipe_receiver,
mojom::ProcessType process_type) override;
void DumpProcess(base::ProcessId pid,
mojo::ScopedHandle output_file,
std::unique_ptr<base::DictionaryValue> metadata,
DumpProcessCallback callback) override;
void DumpProcessesForTracing(
DumpProcessesForTracingCallback callback) override;
......@@ -63,13 +59,6 @@ class ProfilingService : public service_manager::Service,
service_manager::ServiceContextRefFactory* ref_factory,
mojom::ProfilingServiceRequest request);
void OnGetVmRegionsCompleteForDumpProcess(
base::ProcessId pid,
std::unique_ptr<base::DictionaryValue> metadata,
base::File file,
DumpProcessCallback callback,
bool success,
memory_instrumentation::mojom::GlobalMemoryDumpPtr dump);
void OnGetVmRegionsCompleteForDumpProcessesForTracing(
mojom::ProfilingService::DumpProcessesForTracingCallback callback,
bool success,
......
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