Skip to content
This repository has been archived by the owner on Apr 2, 2024. It is now read-only.

Commit

Permalink
Use uv_async for work scheduling(fix #22) and add few more fields to …
Browse files Browse the repository at this point in the history
…stats
  • Loading branch information
dainis committed Jun 19, 2017
1 parent 6a91081 commit 487ae04
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 26 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ node_js:
- "5"
- "4"
- "6"
- "8"

env:
- CXX=g++-4.8
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ This will print blobs like this whenever a GC happened:
* usedHeapSize: Number of bytes in use by application data
* total HeapExecutableSize: Number of bytes for compiled bytecode and JITed code
* heapSizeLimit: The absolute limit the heap cannot exceed
* totalPhysicalSize: Commited size (node 0.11+)
* totalPhysicalSize: Committed size (node 0.11+)
* totalAvailableSize: Available heap size(node 4+)

* pause: Nanoseconds from start to end of GC using hrtime()
* pauseMS: pause expressed in milliseconds
* gctype can have the following values([v8 source](https://github.com/nodejs/node/blob/master/deps/v8/include/v8.h#L5165-L5172)):
* gctype can have the following values([v8 source](https://github.com/nodejs/node/blob/554fa24916c5c6d052b51c5cee9556b76489b3f7/deps/v8/include/v8.h#L6137-L6144)):
* 1: Scavenge (minor GC)
* 2: Mark/Sweep/Compact (major GC)
* 4: Incremental marking
Expand Down
165 changes: 165 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
"license": "Unlicense",
"scripts": {
"install": "node-gyp rebuild",
"test": "./node_modules/mocha/bin/mocha --expose-gc ./tests"
"test": "./node_modules/mocha/bin/mocha --expose-gc ./tests",
"example" : "node --expose-gc ./example.js"
},
"dependencies": {
"bindings": "^1.2.1",
"nan": "^2.0.5"
"nan": "^2.6.2"
},
"gypfile": true,
"devDependencies": {
"mocha": "^2.3.3",
"semver": "^5.0.3",
"mocha": "^2.5.3",
"semver": "^5.3.0",
"should": "^7.1.0"
}
}
77 changes: 57 additions & 20 deletions src/gcstats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,45 +8,67 @@ struct HeapInfo {
size_t totalPhysicalSize;
size_t usedHeapSize;
size_t heapSizeLimit;
size_t totalAvailableSize;
size_t mallocedMemory;
size_t peakMallocedMemory;
};

struct HeapData {
HeapInfo* before;
HeapInfo* after;
uint64_t gcStartTime;
uint64_t gcEndTime;
HeapInfo* before;
HeapInfo* after;
uint64_t gcStartTime;
uint64_t gcEndTime;
int gctype;
};

static Nan::Callback* afterGCCallback;

static HeapStatistics beforeGCStats;
uint64_t gcStartTime;
GCType gctype;

static NAN_GC_CALLBACK(recordBeforeGC) {
//Docs say that new objects should not be created
gcStartTime = uv_hrtime();
Nan::GetHeapStatistics(&beforeGCStats);
}

static void copyHeapStats(HeapStatistics* stats, HeapInfo* info) {
info->totalHeapSize = stats->total_heap_size();
info->totalHeapExecutableSize = stats->total_heap_size_executable();
info->usedHeapSize = stats->used_heap_size();
info->heapSizeLimit = stats->heap_size_limit();

#if NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION
info->totalPhysicalSize = stats->total_physical_size();
#endif
info->usedHeapSize = stats->used_heap_size();
info->heapSizeLimit = stats->heap_size_limit();

#if NODE_MODULE_VERSION >= NODE_4_0_MODULE_VERSION
info->totalAvailableSize = stats->total_available_size();
#endif

#if NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION
info->mallocedMemory = stats->malloced_memory();
info->peakMallocedMemory = stats->peak_malloced_memory();
#endif
}

static void formatStats(Local<Object> obj, HeapInfo* info) {
Nan::Set(obj, Nan::New("totalHeapSize").ToLocalChecked(), Nan::New<Number>(info->totalHeapSize));
Nan::Set(obj, Nan::New("totalHeapExecutableSize").ToLocalChecked(), Nan::New<Number>(info->totalHeapExecutableSize));
Nan::Set(obj, Nan::New("usedHeapSize").ToLocalChecked(), Nan::New<Number>(info->usedHeapSize));
Nan::Set(obj, Nan::New("heapSizeLimit").ToLocalChecked(), Nan::New<Number>(info->heapSizeLimit));

#if NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION
Nan::Set(obj, Nan::New("totalPhysicalSize").ToLocalChecked(), Nan::New<Number>(info->totalPhysicalSize));
#endif

#if NODE_MODULE_VERSION >= NODE_4_0_MODULE_VERSION
Nan::Set(obj, Nan::New("totalAvailableSize").ToLocalChecked(), Nan::New<Number>(info->totalAvailableSize));
#endif

#if NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION
Nan::Set(obj, Nan::New("mallocedMemory").ToLocalChecked(), Nan::New<Number>(info->mallocedMemory));
Nan::Set(obj, Nan::New("peakMallocedMemory").ToLocalChecked(), Nan::New<Number>(info->peakMallocedMemory));
#endif
}

static void formatStatDiff(Local<Object> obj, HeapInfo* before, HeapInfo* after) {
Expand All @@ -58,16 +80,33 @@ static void formatStatDiff(Local<Object> obj, HeapInfo* before, HeapInfo* after)
static_cast<double>(after->usedHeapSize) - static_cast<double>(before->usedHeapSize)));
Nan::Set(obj, Nan::New("heapSizeLimit").ToLocalChecked(), Nan::New<Number>(
static_cast<double>(after->heapSizeLimit) - static_cast<double>(before->heapSizeLimit)));

#if NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION
Nan::Set(obj, Nan::New("totalPhysicalSize").ToLocalChecked(), Nan::New<Number>(
static_cast<double>(after->totalPhysicalSize) - static_cast<double>(before->totalPhysicalSize)));
#endif

#if NODE_MODULE_VERSION >= NODE_4_0_MODULE_VERSION
Nan::Set(obj, Nan::New("totalAvailableSize").ToLocalChecked(), Nan::New<Number>(
static_cast<double>(after->totalAvailableSize) - static_cast<double>(before->totalAvailableSize)));
#endif

#if NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION
Nan::Set(obj, Nan::New("mallocedMemory").ToLocalChecked(), Nan::New<Number>(
static_cast<double>(after->mallocedMemory) - static_cast<double>(before->mallocedMemory)));
Nan::Set(obj, Nan::New("peakMallocedMemory").ToLocalChecked(), Nan::New<Number>(
static_cast<double>(after->peakMallocedMemory) - static_cast<double>(before->peakMallocedMemory)));
#endif
}

static void closeCB(uv_handle_t *handle) {
delete handle;
}

static void asyncAfter(uv_work_t* work, int status) {
static void asyncCB(uv_async_t *handle) {
Nan::HandleScope scope;

HeapData* data = static_cast<HeapData*>(work->data);
HeapData* data = static_cast<HeapData*>(handle->data);

Local<Object> obj = Nan::New<Object>();
Local<Object> beforeGCStats = Nan::New<Object>();
Expand All @@ -83,7 +122,7 @@ static void asyncAfter(uv_work_t* work, int status) {
Nan::New<Number>(static_cast<double>(data->gcEndTime - data->gcStartTime)));
Nan::Set(obj, Nan::New("pauseMS").ToLocalChecked(),
Nan::New<Number>(static_cast<double>((data->gcEndTime - data->gcStartTime) / 1000000)));
Nan::Set(obj, Nan::New("gctype").ToLocalChecked(), Nan::New<Number>(gctype));
Nan::Set(obj, Nan::New("gctype").ToLocalChecked(), Nan::New<Number>(data->gctype));
Nan::Set(obj, Nan::New("before").ToLocalChecked(), beforeGCStats);
Nan::Set(obj, Nan::New("after").ToLocalChecked(), afterGCStats);
Nan::Set(obj, Nan::New("diff").ToLocalChecked(), diffStats);
Expand All @@ -95,22 +134,19 @@ static void asyncAfter(uv_work_t* work, int status) {
delete data->before;
delete data->after;
delete data;
delete work;
}

static void asyncWork(uv_work_t* work) {
//can't create V8 objects here because this is different thread?
uv_close((uv_handle_t*) handle, closeCB);
}

NAN_GC_CALLBACK(afterGC) {
uv_work_t* work = new uv_work_t;
uv_async_t *async = new uv_async_t;

HeapData* data = new HeapData;
data->before = new HeapInfo;
data->after = new HeapInfo;
gctype = type;
HeapStatistics stats;
data->gctype = type;

HeapStatistics stats;

Nan::GetHeapStatistics(&stats);

Expand All @@ -120,9 +156,10 @@ NAN_GC_CALLBACK(afterGC) {
copyHeapStats(&beforeGCStats, data->before);
copyHeapStats(&stats, data->after);

work->data = data;
async->data = data;

uv_queue_work(uv_default_loop(), work, asyncWork, asyncAfter);
uv_async_init(uv_default_loop(), async, asyncCB);
uv_async_send(async);
}

static NAN_METHOD(AfterGC) {
Expand Down

0 comments on commit 487ae04

Please sign in to comment.