Skip to content

Commit

Permalink
feat: per-isolate gc profiler
Browse files Browse the repository at this point in the history
PR-URL: #132
Reviewed-BY: hyj1991 <[email protected]>
  • Loading branch information
legendecas authored Feb 11, 2022
1 parent f78cd6a commit 9a931d5
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 75 deletions.
4 changes: 2 additions & 2 deletions src/commands/dump.cc
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,11 @@ void HandleAction(void *data, string notify_type) {
break;
}
case START_GC_PROFILING: {
GcProfiler::StartGCProfiling(gcprofile_filepath);
GcProfiler::StartGCProfiling(node_isolate, gcprofile_filepath);
break;
}
case STOP_GC_PROFILING: {
GcProfiler::StopGCProfiling();
GcProfiler::StopGCProfiling(node_isolate);
AfterDumpFile(gcprofile_filepath, notify_type, unique_key);
action_map.erase(START_GC_PROFILING);
action_map.erase(STOP_GC_PROFILING);
Expand Down
143 changes: 78 additions & 65 deletions src/commands/gcprofiler/gc_profiler.cc
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#include "gc_profiler.h"

#include "../../library/writer.h"
#include "../../logbypass/gc.h"
#include "../../logger.h"
#include "environment_data.h"
#include "library/writer.h"
#include "logbypass/gc.h"
#include "logger.h"
#include "nan.h"

namespace xprofiler {
Expand All @@ -15,90 +16,102 @@ using std::ofstream;
using v8::GCType;
using v8::HeapSpaceStatistics;

static string filename = "";
static ofstream outfile;
static JSONWriter *writer = nullptr;
uint64_t init = 0;

#define SPACE_DATA(tag) \
if (type == GCType::kGCTypeScavenge) { \
writer->json_keyvalue("type", "scavenge"); \
} else if (type == GCType::kGCTypeMarkSweepCompact) { \
writer->json_keyvalue("type", "marksweep"); \
} else if (type == GCType::kGCTypeIncrementalMarking) { \
writer->json_keyvalue("type", "marking"); \
} else if (type == GCType::kGCTypeProcessWeakCallbacks) { \
writer->json_keyvalue("type", "weakcallbacks"); \
} else { \
writer->json_keyvalue("type", static_cast<int>(type)); \
} \
HeapSpaceStatistics s; \
size_t number_of_heap_spaces = isolate->NumberOfHeapSpaces(); \
writer->json_arraystart(tag); \
for (size_t i = 0; i < number_of_heap_spaces; i++) { \
writer->json_start(); \
isolate->GetHeapSpaceStatistics(&s, i); \
writer->json_keyvalue("name", s.space_name()); \
writer->json_keyvalue("space_size", s.space_size()); \
writer->json_keyvalue("space_used_size", s.space_used_size()); \
writer->json_keyvalue("space_available_size", s.space_available_size()); \
writer->json_keyvalue("physical_space_size", s.physical_space_size()); \
writer->json_end(); \
} \
inline void write_space_data(v8::Isolate* isolate, GCType type,
JSONWriter* writer, const char* tag) {
if (type == GCType::kGCTypeScavenge) {
writer->json_keyvalue("type", "scavenge");
} else if (type == GCType::kGCTypeMarkSweepCompact) {
writer->json_keyvalue("type", "marksweep");
} else if (type == GCType::kGCTypeIncrementalMarking) {
writer->json_keyvalue("type", "marking");
} else if (type == GCType::kGCTypeProcessWeakCallbacks) {
writer->json_keyvalue("type", "weakcallbacks");
} else {
writer->json_keyvalue("type", static_cast<int>(type));
}
HeapSpaceStatistics s;
size_t number_of_heap_spaces = isolate->NumberOfHeapSpaces();
writer->json_arraystart(tag);
for (size_t i = 0; i < number_of_heap_spaces; i++) {
writer->json_start();
isolate->GetHeapSpaceStatistics(&s, i);
writer->json_keyvalue("name", s.space_name());
writer->json_keyvalue("space_size", s.space_size());
writer->json_keyvalue("space_used_size", s.space_used_size());
writer->json_keyvalue("space_available_size", s.space_available_size());
writer->json_keyvalue("physical_space_size", s.physical_space_size());
writer->json_end();
}
writer->json_arrayend();

GcProfiler::GcProfiler() {}
GcProfiler::~GcProfiler() {}
}

NAN_GC_CALLBACK(GCTracerPrologueCallback) {
EnvironmentData* env_data = EnvironmentData::GetCurrent(isolate);
if (env_data->gc_profiler == nullptr) {
return;
}
JSONWriter* writer = env_data->gc_profiler->writer();
writer->json_start();
writer->json_keyvalue("totalSpentfromStart", TotalGcDuration());
writer->json_keyvalue("totalTimesfromStart", TotalGcTimes());
writer->json_keyvalue("timeFromStart", GetUptime());
writer->json_keyvalue("start", static_cast<int>((uv_hrtime() - init) / 10e5));
SPACE_DATA("before");
writer->json_keyvalue("start",
(uv_hrtime() - env_data->gc_profiler->init()) / 10e5);
write_space_data(isolate, type, writer, "before");
}

NAN_GC_CALLBACK(GCTracerEpilogueCallback) {
writer->json_keyvalue("end", static_cast<int>((uv_hrtime() - init) / 10e5));
SPACE_DATA("after");
EnvironmentData* env_data = EnvironmentData::GetCurrent(isolate);
if (env_data->gc_profiler == nullptr) {
return;
}
JSONWriter* writer = env_data->gc_profiler->writer();
writer->json_keyvalue("end",
(uv_hrtime() - env_data->gc_profiler->init()) / 10e5);
write_space_data(isolate, type, writer, "after");
writer->json_end();
}

void GcProfiler::StartGCProfiling(string filename_) {
outfile.open(filename_, ios::out | ios::binary);
if (!outfile.is_open()) {
Error("gc_profiler", "open file %s failed.", filename_.c_str());
outfile.close();
void GcProfiler::StartGCProfiling(v8::Isolate* isolate, std::string filename) {
EnvironmentData* env_data = EnvironmentData::GetCurrent(isolate);
std::unique_ptr<GcProfiler> gc_profiler =
std::unique_ptr<GcProfiler>(new GcProfiler(isolate, filename));
if (!gc_profiler->is_open()) {
Error("gc_profiler", "open file %s failed.", filename.c_str());
return;
}
env_data->gc_profiler = std::move(gc_profiler);

AddGCPrologueCallback(GCTracerPrologueCallback);
AddGCEpilogueCallback(GCTracerEpilogueCallback);
filename = filename_;
writer = new JSONWriter(outfile);
init = uv_hrtime();

JSONWriter* writer = env_data->gc_profiler->writer();
writer->json_start();
writer->json_keyvalue("startTime",
static_cast<unsigned long>(uv_hrtime() / 10e8));
writer->json_keyvalue("startTime", uv_hrtime() / 10e8);
writer->json_arraystart("gc");
}

void GcProfiler::StopGCProfiling() {
void GcProfiler::StopGCProfiling(v8::Isolate* isolate) {
RemoveGCPrologueCallback(GCTracerPrologueCallback);
RemoveGCEpilogueCallback(GCTracerEpilogueCallback);
if (writer != nullptr) {
writer->json_arrayend();
writer->json_keyvalue("stopTime",
static_cast<unsigned long>(uv_hrtime() / 10e8));
writer->json_end();
delete writer;
}
if (filename != "") {
filename = "";
}
if (outfile.is_open()) {
outfile.close();
EnvironmentData* env_data = EnvironmentData::GetCurrent(isolate);
if (env_data->gc_profiler == nullptr) {
return;
}
init = 0;
JSONWriter* writer = env_data->gc_profiler->writer();
writer->json_arrayend();
writer->json_keyvalue("stopTime", uv_hrtime() / 10e8);
writer->json_end();

env_data->gc_profiler.reset();
}
} // namespace xprofiler

GcProfiler::GcProfiler(v8::Isolate* isolate, std::string filename)
: filename_(filename),
outfile_(filename, ios::out | ios::binary),
writer_(outfile_),
init_(uv_hrtime()) {}

GcProfiler::~GcProfiler() {}

} // namespace xprofiler
31 changes: 23 additions & 8 deletions src/commands/gcprofiler/gc_profiler.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
#ifndef _SRC_COMMANDS_GCPROFILER_GC_PROFILER_H
#define _SRC_COMMANDS_GCPROFILER_GC_PROFILER_H
#ifndef XPROFILER_SRC_COMMANDS_GCPROFILER_GC_PROFILER_H
#define XPROFILER_SRC_COMMANDS_GCPROFILER_GC_PROFILER_H

#include <string>

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

namespace xprofiler {
using std::string;

class GcProfiler {
public:
GcProfiler();
virtual ~GcProfiler();
static void StartGCProfiling(string filename);
static void StopGCProfiling();
static void StartGCProfiling(v8::Isolate* isolate, std::string filename);
static void StopGCProfiling(v8::Isolate* isolate);

~GcProfiler();

bool is_open() { return outfile_.is_open(); }
JSONWriter* writer() { return &writer_; }
uint64_t init() { return init_; }

private:
GcProfiler(v8::Isolate* isolate, std::string filename);

std::string filename_ = "";
std::ofstream outfile_;
JSONWriter writer_;
uint64_t init_ = 0;
};

} // namespace xprofiler
#endif

#endif /* XPROFILER_SRC_COMMANDS_GCPROFILER_GC_PROFILER_H */
3 changes: 3 additions & 0 deletions src/environment_data.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef XPROFILER_SRC_ENVIRONMENT_DATA_H
#define XPROFILER_SRC_ENVIRONMENT_DATA_H

#include "commands/gcprofiler/gc_profiler.h"
#include "logbypass/gc.h"
#include "logbypass/heap.h"
#include "logbypass/http.h"
Expand Down Expand Up @@ -30,6 +31,8 @@ class EnvironmentData {
return &uv_handle_statistics_;
}

std::unique_ptr<GcProfiler> gc_profiler;

private:
static void AtExit(void* arg);
static void CollectStatistics(uv_async_t* handle);
Expand Down

0 comments on commit 9a931d5

Please sign in to comment.