Skip to content

Commit

Permalink
feat: add process.getHeapSnapshot()
Browse files Browse the repository at this point in the history
  • Loading branch information
miniak committed Sep 5, 2018
1 parent 357576a commit e662710
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 0 deletions.
33 changes: 33 additions & 0 deletions atom/browser/api/atom_api_web_contents.cc
Expand Up @@ -28,6 +28,7 @@
#include "atom/browser/lib/bluetooth_chooser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/net/atom_network_delegate.h"
#include "base/threading/thread_restrictions.h"
#if defined(ENABLE_OSR)
#include "atom/browser/osr/osr_output_device.h"
#include "atom/browser/osr/osr_render_widget_host_view.h"
Expand Down Expand Up @@ -60,6 +61,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "brightray/browser/brightray_paths.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "chrome/browser/browser_process.h"
Expand Down Expand Up @@ -308,6 +310,10 @@ struct WebContents::FrameDispatchHelper {
IPC::Message* message) {
api_web_contents->OnRendererMessageSync(rfh, channel, args, message);
}

void OnCreateHeapSnapshotFile(IPC::Message* message) {
api_web_contents->OnCreateHeapSnapshotFile(rfh, message);
}
};

WebContents::WebContents(v8::Isolate* isolate,
Expand Down Expand Up @@ -1032,6 +1038,9 @@ bool WebContents::OnMessageReceived(const IPC::Message& message,
IPC_MESSAGE_HANDLER(AtomAutofillFrameHostMsg_ShowPopup, ShowAutofillPopup)
IPC_MESSAGE_HANDLER(AtomAutofillFrameHostMsg_HidePopup, HideAutofillPopup)
#endif
IPC_MESSAGE_FORWARD_DELAY_REPLY(
AtomFrameHostMsg_CreateHeapSnapshotFile, &helper,
FrameDispatchHelper::OnCreateHeapSnapshotFile)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()

Expand Down Expand Up @@ -2101,6 +2110,30 @@ void WebContents::OnRendererMessageTo(content::RenderFrameHost* frame_host,
}
}

void WebContents::OnCreateHeapSnapshotFile(content::RenderFrameHost* frame_host,
IPC::Message* message) {
base::ScopedAllowBlockingForTesting allow_blocking;

base::FilePath user_data;
PathService::Get(brightray::DIR_USER_DATA, &user_data);

const uint64_t now = uv_hrtime();
const unsigned long sec = static_cast<unsigned long>(now / 1000000);
const unsigned long usec = static_cast<unsigned long>(now % 1000000);
auto filename =
base::StringPrintf("heapdump-%lu.%lu.heapsnapshot", sec, usec);

auto file_path = user_data.AppendASCII(filename.c_str());

base::File file(file_path,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);

AtomFrameHostMsg_CreateHeapSnapshotFile::WriteReplyParams(
message, file_path, IPC::TakePlatformFileForTransit(std::move(file)));

frame_host->Send(message);
}

// static
mate::Handle<WebContents> WebContents::CreateFrom(
v8::Isolate* isolate,
Expand Down
3 changes: 3 additions & 0 deletions atom/browser/api/atom_api_web_contents.h
Expand Up @@ -431,6 +431,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
const std::string& channel,
const base::ListValue& args);

void OnCreateHeapSnapshotFile(content::RenderFrameHost* frame_host,
IPC::Message* message);

// Called when received a synchronous message from renderer to
// set temporary zoom level.
void OnSetTemporaryZoomLevel(content::RenderFrameHost* frame_host,
Expand Down
5 changes: 5 additions & 0 deletions atom/common/api/api_messages.h
Expand Up @@ -10,6 +10,7 @@
#include "content/public/common/common_param_traits.h"
#include "content/public/common/referrer.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_platform_file.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
#include "url/gurl.h"
Expand Down Expand Up @@ -76,3 +77,7 @@ IPC_SYNC_MESSAGE_ROUTED0_1(AtomFrameHostMsg_GetZoomLevel, double /* result */)
IPC_MESSAGE_ROUTED2(AtomFrameHostMsg_PDFSaveURLAs,
GURL /* url */,
content::Referrer /* referrer */)

IPC_SYNC_MESSAGE_ROUTED0_2(AtomFrameHostMsg_CreateHeapSnapshotFile,
base::FilePath /* file_path */,
IPC::PlatformFileForTransit /* file_handle */)
41 changes: 41 additions & 0 deletions atom/common/api/atom_bindings.cc
Expand Up @@ -8,16 +8,22 @@
#include <iostream>
#include <string>

#include "atom/common/api/api_messages.h"
#include "atom/common/api/file_output_stream.h"
#include "atom/common/api/locker.h"
#include "atom/common/atom_version.h"
#include "atom/common/chrome_version.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/node_includes.h"
#include "base/logging.h"
#include "base/process/process_info.h"
#include "base/process/process_metrics_iocounters.h"
#include "base/sys_info.h"
#include "content/public/renderer/render_frame.h"
#include "native_mate/dictionary.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "v8/include/v8-profiler.h"

namespace atom {

Expand Down Expand Up @@ -54,6 +60,7 @@ void AtomBindings::BindTo(v8::Isolate* isolate, v8::Local<v8::Object> process) {
dict.SetMethod("crash", &AtomBindings::Crash);
dict.SetMethod("hang", &Hang);
dict.SetMethod("log", &Log);
dict.SetMethod("getHeapSnapshot", &GetHeapSnapshot);
dict.SetMethod("getHeapStatistics", &GetHeapStatistics);
dict.SetMethod("getProcessMemoryInfo", &GetProcessMemoryInfo);
dict.SetMethod("getCreationTime", &GetCreationTime);
Expand Down Expand Up @@ -129,6 +136,40 @@ void AtomBindings::Hang() {
base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
}

// static
base::FilePath AtomBindings::GetHeapSnapshot(v8::Isolate* isolate) {
auto* frame = blink::WebLocalFrame::FrameForCurrentContext();
if (!frame)
return base::FilePath();

auto* render_frame = content::RenderFrame::FromWebFrame(frame);
if (!render_frame)
return base::FilePath();

base::FilePath file_path;
IPC::PlatformFileForTransit file_handle;
auto* message = new AtomFrameHostMsg_CreateHeapSnapshotFile(
render_frame->GetRoutingID(), &file_path, &file_handle);
if (!render_frame->Send(message))
return base::FilePath();

auto file = IPC::PlatformFileForTransitToFile(file_handle);
if (!file.IsValid())
return base::FilePath();

auto* snap = isolate->GetHeapProfiler()->TakeHeapSnapshot();

FileOutputStream stream(&file);
snap->Serialize(&stream, v8::HeapSnapshot::kJSON);

const_cast<v8::HeapSnapshot*>(snap)->Delete();

if (!stream.IsComplete())
return base::FilePath();

return file_path;
}

// static
v8::Local<v8::Value> AtomBindings::GetHeapStatistics(v8::Isolate* isolate) {
v8::HeapStatistics v8_heap_stats;
Expand Down
2 changes: 2 additions & 0 deletions atom/common/api/atom_bindings.h
Expand Up @@ -7,6 +7,7 @@

#include <list>

#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/process/process_metrics.h"
#include "base/strings/string16.h"
Expand Down Expand Up @@ -35,6 +36,7 @@ class AtomBindings {
static void Log(const base::string16& message);
static void Crash();
static void Hang();
static base::FilePath GetHeapSnapshot(v8::Isolate* isolate);
static v8::Local<v8::Value> GetHeapStatistics(v8::Isolate* isolate);
static v8::Local<v8::Value> GetProcessMemoryInfo(v8::Isolate* isolate);
static v8::Local<v8::Value> GetCreationTime(v8::Isolate* isolate);
Expand Down
29 changes: 29 additions & 0 deletions atom/common/api/file_output_stream.cc
@@ -0,0 +1,29 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/common/api/file_output_stream.h"

namespace atom {

FileOutputStream::FileOutputStream(base::File* file) : file_(file) {}

bool FileOutputStream::IsComplete() const {
return is_complete_;
}

int FileOutputStream::GetChunkSize() {
return 65536;
}

void FileOutputStream::EndOfStream() {
is_complete_ = true;
}

v8::OutputStream::WriteResult FileOutputStream::WriteAsciiChunk(char* data,
int size) {
auto bytes_written = file_->WriteAtCurrentPos(data, size);
return bytes_written == size ? kContinue : kAbort;
}

} // namespace atom
32 changes: 32 additions & 0 deletions atom/common/api/file_output_stream.h
@@ -0,0 +1,32 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#ifndef ATOM_COMMON_API_FILE_OUTPUT_STREAM_H_
#define ATOM_COMMON_API_FILE_OUTPUT_STREAM_H_

#include "base/files/file.h"
#include "base/files/file_path.h"
#include "v8/include/v8-profiler.h"

namespace atom {

class FileOutputStream : public v8::OutputStream {
public:
explicit FileOutputStream(base::File* file);

bool IsComplete() const;

// v8::OutputStream
virtual int GetChunkSize();
virtual void EndOfStream();
virtual v8::OutputStream::WriteResult WriteAsciiChunk(char* data, int size);

private:
base::File* file_ = nullptr;
bool is_complete_ = false;
};

} // namespace atom

#endif // ATOM_COMMON_API_FILE_OUTPUT_STREAM_H_
2 changes: 2 additions & 0 deletions atom/renderer/atom_sandboxed_renderer_client.cc
Expand Up @@ -6,6 +6,7 @@

#include "atom/common/api/api_messages.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/node_bindings.h"
Expand Down Expand Up @@ -152,6 +153,7 @@ void AtomSandboxedRendererClient::InitializeBindings(
b.SetMethod("getExecPath", GetExecPath);
b.SetMethod("getPid", &base::GetCurrentProcId);
b.SetMethod("getResourcesPath", &NodeBindings::GetHelperResourcesPath);
b.SetMethod("getHeapSnapshot", &AtomBindings::GetHeapSnapshot);
b.SetMethod("getHeapStatistics", &AtomBindings::GetHeapStatistics);
b.SetMethod("getProcessMemoryInfo", &AtomBindings::GetProcessMemoryInfo);
b.SetMethod("getSystemMemoryInfo", &AtomBindings::GetSystemMemoryInfo);
Expand Down
2 changes: 2 additions & 0 deletions filenames.gypi
Expand Up @@ -449,6 +449,8 @@
'atom/common/api/event_emitter_caller.cc',
'atom/common/api/event_emitter_caller.h',
'atom/common/api/features.cc',
'atom/common/api/file_output_stream.cc',
'atom/common/api/file_output_stream.h',
'atom/common/api/locker.cc',
'atom/common/api/locker.h',
'atom/common/api/object_life_monitor.cc',
Expand Down
1 change: 1 addition & 0 deletions lib/sandboxed_renderer/init.js
Expand Up @@ -48,6 +48,7 @@ require('../renderer/web-frame-init')()
const preloadProcess = new events.EventEmitter()
preloadProcess.crash = () => binding.crash()
preloadProcess.hang = () => binding.hang()
preloadProcess.getHeapSnapshot = () => binding.getHeapSnapshot()
preloadProcess.getHeapStatistics = () => binding.getHeapStatistics()
preloadProcess.getProcessMemoryInfo = () => binding.getProcessMemoryInfo()
preloadProcess.getSystemMemoryInfo = () => binding.getSystemMemoryInfo()
Expand Down

0 comments on commit e662710

Please sign in to comment.