Skip to content

Commit

Permalink
feat: per-isolate heap profiler
Browse files Browse the repository at this point in the history
PR-URL: #133
Reviewed-BY: hyj1991 <[email protected]>
  • Loading branch information
legendecas authored Feb 11, 2022
1 parent ae6ab8d commit f78cd6a
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 91 deletions.
30 changes: 15 additions & 15 deletions src/commands/dump.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ static void AfterDumpFile(string &filepath, string notify_type,
filepath = "";
}

#define CHECK(func) \
#define CHECK_ERR(func) \
func; \
if (err.Fail()) { \
Debug(module_type, "<%s> %s error: %s", notify_type.c_str(), \
Expand Down Expand Up @@ -181,10 +181,10 @@ void HandleAction(void *data, string notify_type) {
unique_key.c_str());

// check conflict action running
CHECK(ConflictActionRunning(action, err))
CHECK_ERR(ConflictActionRunning(action, err))

// check dependent action running
CHECK(DependentActionRunning(action, err))
CHECK_ERR(DependentActionRunning(action, err))

// start run action
switch (action) {
Expand All @@ -203,18 +203,18 @@ void HandleAction(void *data, string notify_type) {
break;
}
case HEAPDUMP: {
HeapProfiler::TakeSnapshot(heapsnapshot_filepath);
HeapProfiler::TakeSnapshot(node_isolate, heapsnapshot_filepath);
AfterDumpFile(heapsnapshot_filepath, notify_type, unique_key);
action_map.erase(HEAPDUMP);
break;
}
case START_SAMPLING_HEAP_PROFILING: {
SamplingHeapProfile::StartSamplingHeapProfiling();
SamplingHeapProfiler::StartSamplingHeapProfiling(node_isolate);
break;
}
case STOP_SAMPLING_HEAP_PROFILING: {
SamplingHeapProfile::StopSamplingHeapProfiling(
sampling_heapprofile_filepath);
SamplingHeapProfiler::StopSamplingHeapProfiling(
node_isolate, sampling_heapprofile_filepath);
AfterDumpFile(sampling_heapprofile_filepath, notify_type, unique_key);
action_map.erase(START_SAMPLING_HEAP_PROFILING);
action_map.erase(STOP_SAMPLING_HEAP_PROFILING);
Expand Down Expand Up @@ -243,7 +243,7 @@ void HandleAction(void *data, string notify_type) {
}
}

#undef CHECK
#undef CHECK_ERR

static void RequestInterruptCallback(Isolate *isolate, void *data) {
HandleAction(data, "v8_request_interrupt");
Expand Down Expand Up @@ -335,8 +335,8 @@ void UnrefDumpActionAsyncHandle() {
uv_unref(reinterpret_cast<uv_handle_t *>(&async_send_callback));
}

#define CHECK(func) \
func; \
#define CHECK_ERR(func) \
func; \
if (err.Fail()) return result;

template <typename T>
Expand All @@ -345,16 +345,16 @@ static json DoDumpAction(json command, DumpAction action, string prefix,
json result;

// get traceid
CHECK(string traceid = GetJsonValue<string>(command, "traceid", err))
CHECK_ERR(string traceid = GetJsonValue<string>(command, "traceid", err))

// check action running
CHECK(ActionRunning(action, err))
CHECK_ERR(ActionRunning(action, err))

// check conflict action running
CHECK(ConflictActionRunning(action, err))
CHECK_ERR(ConflictActionRunning(action, err))

// check dependent action running
CHECK(DependentActionRunning(action, err))
CHECK_ERR(DependentActionRunning(action, err))

// set action running flag
action_map.insert(make_pair(action, true));
Expand Down Expand Up @@ -460,5 +460,5 @@ V(GetNodeReport, node_report_, NODE_REPORT, false, diagreport, diag)

#undef ACTION_HANDLE

#undef CHECK
#undef CHECK_ERR
} // namespace xprofiler
20 changes: 11 additions & 9 deletions src/commands/heapdump/heap_profiler.cc
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
#include "heap_profiler.h"

#include "heap_snapshot.h"
#include "util.h"
#include "xpf_v8.h"

namespace xprofiler {
using Nan::HandleScope;
using v8::HeapSnapshot;
using v8::Isolate;

HeapProfiler::HeapProfiler() {}
HeapProfiler::~HeapProfiler() {}
void DeleteHeapSnapshot(const v8::HeapSnapshot* snapshot) {
const_cast<v8::HeapSnapshot*>(snapshot)->Delete();
}

void HeapProfiler::TakeSnapshot(string filename) {
Isolate *isolate = Isolate::GetCurrent();
HandleScope scope;
const HeapSnapshot *snap = isolate->GetHeapProfiler()->TakeHeapSnapshot();
Snapshot::Serialize(snap, filename);
void HeapProfiler::TakeSnapshot(v8::Isolate* isolate, std::string filename) {
HandleScope scope(isolate);
HeapSnapshotPointer snap =
HeapSnapshotPointer(isolate->GetHeapProfiler()->TakeHeapSnapshot());
HeapSnapshot::Serialize(std::move(snap), filename);
}

} // namespace xprofiler
16 changes: 9 additions & 7 deletions src/commands/heapdump/heap_profiler.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
#ifndef _SRC_COMMANDS_HEAPDUMP_HEAP_PROFILER_H
#define _SRC_COMMANDS_HEAPDUMP_HEAP_PROFILER_H
#ifndef XPROFILER_SRC_COMMANDS_HEAPDUMP_HEAP_PROFILER_H
#define XPROFILER_SRC_COMMANDS_HEAPDUMP_HEAP_PROFILER_H

#include "nan.h"
#include "util.h"
#include "v8-profiler.h"

namespace xprofiler {
using std::string;
void DeleteHeapSnapshot(const v8::HeapSnapshot* snapshot);

using HeapSnapshotPointer =
DeleteFnPtr<const v8::HeapSnapshot, DeleteHeapSnapshot>;

class HeapProfiler {
public:
HeapProfiler();
virtual ~HeapProfiler();
static void TakeSnapshot(string filename);
static void TakeSnapshot(v8::Isolate* isolate, std::string filename);
};
} // namespace xprofiler

#endif // NODE_HEAP_PROFILER_H
#endif /* XPROFILER_SRC_COMMANDS_HEAPDUMP_HEAP_PROFILER_H */
41 changes: 26 additions & 15 deletions src/commands/heapdump/heap_snapshot.cc
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
#include "heap_snapshot.h"

#include "../../library/writer.h"
#include "../../logger.h"
#include "library/writer.h"
#include "logger.h"

namespace xprofiler {
using v8::OutputStream;

class FileOutputStream : public OutputStream {
class FileOutputStream final : public OutputStream {
public:
FileOutputStream(FILE *stream) : stream_(stream) {}
FileOutputStream(std::string filename) {
stream_ = fopen(filename.c_str(), "w");
}
~FileOutputStream() {
if (stream_ != nullptr) {
fclose(stream_);
}
}

// Delete copy
FileOutputStream(const FileOutputStream& other) = delete;
FileOutputStream& operator=(const FileOutputStream& other) = delete;

bool is_open() { return stream_ != nullptr; }

virtual int GetChunkSize() {
int GetChunkSize() override {
return 65536; // big chunks == faster
}

virtual void EndOfStream() {}
void EndOfStream() override {}

virtual WriteResult WriteAsciiChunk(char *data, int size) {
WriteResult WriteAsciiChunk(char* data, int size) override {
const size_t len = static_cast<size_t>(size);
size_t off = 0;

Expand All @@ -27,18 +40,16 @@ class FileOutputStream : public OutputStream {
}

private:
FILE *stream_;
FILE* stream_ = nullptr;
};

void Snapshot::Serialize(const HeapSnapshot *profile, string filename) {
FILE *fp = fopen(filename.c_str(), "w");
if (fp == NULL) {
void HeapSnapshot::Serialize(HeapSnapshotPointer profile,
std::string filename) {
FileOutputStream stream(filename);
if (!stream.is_open()) {
Error("heapdump", "open file %s failed.", filename.c_str());
return;
}
FileOutputStream stream(fp);
profile->Serialize(&stream, HeapSnapshot::kJSON);
fclose(fp);
const_cast<HeapSnapshot *>(profile)->Delete();
profile->Serialize(&stream, v8::HeapSnapshot::kJSON);
}
} // namespace xprofiler
15 changes: 7 additions & 8 deletions src/commands/heapdump/heap_snapshot.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
#ifndef _SRC_COMMANDS_HEAPDUMP_HEAP_SNAPSHOT_H
#define _SRC_COMMANDS_HEAPDUMP_HEAP_SNAPSHOT_H
#ifndef XPROFILER_SRC_COMMANDS_HEAPDUMP_HEAP_SNAPSHOT_H
#define XPROFILER_SRC_COMMANDS_HEAPDUMP_HEAP_SNAPSHOT_H

#include "heap_profiler.h"
#include "v8-profiler.h"

namespace xprofiler {
using std::string;
using v8::HeapSnapshot;

class Snapshot {
class HeapSnapshot {
public:
static void Serialize(const HeapSnapshot *profile, string filename);
static void Serialize(HeapSnapshotPointer profile, std::string filename);
};
} // namespace xprofiler
#endif // NODE_SNAPSHOT_

#endif /* XPROFILER_SRC_COMMANDS_HEAPDUMP_HEAP_SNAPSHOT_H */
50 changes: 23 additions & 27 deletions src/commands/heapprofiler/sampling_heap_profiler.cc
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
#include "sampling_heap_profiler.h"

#include "../../library/writer.h"
#include "../../logger.h"
#include "library/writer.h"
#include "logger.h"
#include "xpf_v8.h"

namespace xprofiler {
using Nan::HandleScope;
using Nan::Utf8String;
using std::ofstream;
using v8::AllocationProfile;
using v8::Isolate;

SamplingHeapProfile::SamplingHeapProfile() {}
SamplingHeapProfile::~SamplingHeapProfile() {}

void TranslateAllocationProfile(AllocationProfile::Node *node,
JSONWriter *writer) {
HandleScope scope;
void TranslateAllocationProfile(Isolate* isolate, AllocationProfile::Node* node,
JSONWriter* writer) {
HandleScope scope(isolate);
writer->json_objectstart("callFrame");
Utf8String function_name(node->name);
Utf8String url(node->script_name);
Expand All @@ -27,7 +24,7 @@ void TranslateAllocationProfile(AllocationProfile::Node *node,
writer->json_objectend();

// add self size
int selfSize = 0;
size_t selfSize = 0;
for (size_t i = 0; i < node->allocations.size(); i++) {
AllocationProfile::Allocation alloc = node->allocations[i];
selfSize += alloc.size * alloc.count;
Expand All @@ -38,38 +35,37 @@ void TranslateAllocationProfile(AllocationProfile::Node *node,
writer->json_arraystart("children");
for (size_t i = 0; i < node->children.size(); i++) {
writer->json_start();
TranslateAllocationProfile(node->children[i], writer);
TranslateAllocationProfile(isolate, node->children[i], writer);
writer->json_end();
}
writer->json_arrayend();
}

void SamplingHeapProfile::StartSamplingHeapProfiling() {
Isolate::GetCurrent()->GetHeapProfiler()->StartSamplingHeapProfiler();
void SamplingHeapProfiler::StartSamplingHeapProfiling(v8::Isolate* isolate) {
isolate->GetHeapProfiler()->StartSamplingHeapProfiler();
}

void SamplingHeapProfile::StopSamplingHeapProfiling(string filename) {
HandleScope scope;
ofstream outfile;
outfile.open(filename, std::ios::out | std::ios::binary);
void SamplingHeapProfiler::StopSamplingHeapProfiling(v8::Isolate* isolate,
std::string filename) {
ofstream outfile(filename, std::ios::out | std::ios::binary);
if (!outfile.is_open()) {
Error("sampling_heap_profiler", "open file %s failed.", filename.c_str());
outfile.close();
return;
}
HandleScope scope(isolate);
// get allocationProfile
AllocationProfile *profile =
Isolate::GetCurrent()->GetHeapProfiler()->GetAllocationProfile();
AllocationProfile::Node *root = profile->GetRootNode();
std::unique_ptr<AllocationProfile> profile =
std::unique_ptr<AllocationProfile>(
isolate->GetHeapProfiler()->GetAllocationProfile());
// stop sampling heap profile
isolate->GetHeapProfiler()->StopSamplingHeapProfiler();

AllocationProfile::Node* root = profile->GetRootNode();
JSONWriter writer(outfile);
writer.json_start();
writer.json_objectstart("head");
TranslateAllocationProfile(root, &writer);
TranslateAllocationProfile(isolate, root, &writer);
writer.json_objectend();
writer.json_end();
outfile.close();
free(profile);
// stop sampling heap profile
Isolate::GetCurrent()->GetHeapProfiler()->StopSamplingHeapProfiler();
}
} // namespace xprofiler
} // namespace xprofiler
17 changes: 7 additions & 10 deletions src/commands/heapprofiler/sampling_heap_profiler.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
#ifndef _SRC_COMMANDS_HEAPPROFILER_SAMPLING_HEAP_PROFILER_H
#define _SRC_COMMANDS_HEAPPROFILER_SAMPLING_HEAP_PROFILER_H
#ifndef XPROFILER_SRC_COMMANDS_HEAPPROFILER_SAMPLING_HEAP_PROFILER_H
#define XPROFILER_SRC_COMMANDS_HEAPPROFILER_SAMPLING_HEAP_PROFILER_H

#include "nan.h"
#include "v8-profiler.h"

namespace xprofiler {
using std::string;

class SamplingHeapProfile {
class SamplingHeapProfiler final {
public:
SamplingHeapProfile();
virtual ~SamplingHeapProfile();
static void StartSamplingHeapProfiling();
static void StopSamplingHeapProfiling(string filename);
static void StartSamplingHeapProfiling(v8::Isolate* isolate);
static void StopSamplingHeapProfiling(v8::Isolate* isolate,
std::string filename);
};

} // namespace xprofiler
#endif
#endif /* XPROFILER_SRC_COMMANDS_HEAPPROFILER_SAMPLING_HEAP_PROFILER_H */
9 changes: 9 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ constexpr size_t arraysize(const T (&)[N]) {
return N;
}

template <typename T, void (*function)(T*)>
struct FunctionDeleter {
void operator()(T* pointer) const { function(pointer); }
using Pointer = std::unique_ptr<T, FunctionDeleter>;
};

template <typename T, void (*function)(T*)>
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;

// Convenience wrapper around v8::String::NewFromOneByte
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
const char* data, int length = -1);
Expand Down

0 comments on commit f78cd6a

Please sign in to comment.