Skip to content

Commit 4471e62

Browse files
Fishrock123AndreasMadsen
authored andcommitted
[refactor] initial rewrite to use native async_hooks (#19)
1 parent 54b3596 commit 4471e62

16 files changed

Lines changed: 135629 additions & 57350 deletions

docs/example/dprof.json

Lines changed: 158 additions & 110 deletions
Large diffs are not rendered by default.

docs/visualizer/visualizer.build.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18531,7 +18531,7 @@ function Flatten(data) {
1853118531
var root = new Node(data.root);
1853218532

1853318533
// Construct map of all nodes
18534-
var nodes = new Map([[0, root]]);
18534+
var nodes = new Map([[1, root]]);
1853518535
var _iteratorNormalCompletion = true;
1853618536
var _didIteratorError = false;
1853718537
var _iteratorError = undefined;
@@ -18694,6 +18694,7 @@ function Node(node) {
1869418694

1869518695
// Info
1869618696
this.name = node.name;
18697+
this.uid = node.uid;
1869718698
this.stack = node.stack;
1869818699
this.initRef = node.initRef;
1869918700

@@ -18942,7 +18943,9 @@ StatsLayout.prototype.draw = function () {
1894218943
}
1894318944
wait += this._node.destroy - prevSyncTime;
1894418945

18945-
stats += '\n' + ('handle: ' + this._node.name + '\n') + ('uid: ' + this._node.uid + '\n') + ('start: ' + this._node.init.toFixed(8) + ' sec\n') + ('wait: ' + toms(wait, 11) + ' ms\n') + ('callback: ' + toms(callback, 7) + ' ms');
18946+
stats += '\n' + ('handle: ' + this._node.name + '\n') + ('uid: ' + this._node.uid + '\n') + (
18947+
// `weak (unrefed): ${this._node.unrefed}\n` +
18948+
'start: ' + this._node.init.toFixed(8) + ' sec\n') + ('wait: ' + toms(wait, 11) + ' ms\n') + ('callback: ' + toms(callback, 7) + ' ms');
1894618949

1894718950
trace += this._node.stack.map(function (site) {
1894818951
return ' at ' + site.description;

dprof.js

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

3-
const asyncHook = require('async-hook');
3+
const asyncHook = require('async_hooks');
4+
45
const chain = require('stack-chain');
56
const zlib = require('zlib');
67
const fs = require('fs');
@@ -14,9 +15,18 @@ if (process.execArgv.indexOf('--stack_trace_limit') === -1 && Error.stackTraceLi
1415
}
1516

1617
//
17-
// Define node class
18+
// Setup hooks
1819
//
20+
const hooks = asyncHook.createHook({
21+
init: asyncInit,
22+
before: asyncBefore,
23+
after: asyncAfter,
24+
destroy: asyncDestroy
25+
});
1926

27+
//
28+
// Define node class
29+
//
2030
function Site(site) {
2131
this.description = site.toString();
2232
this.filename = site.getFileName();
@@ -29,12 +39,11 @@ function timestamp() {
2939
return t[0] * 1e9 + t[1];
3040
}
3141

32-
function Node(uid, handle, stack, parent) {
42+
function Node(uid, handle, name, stack, parent) {
3343
const self = this;
34-
3544
this.parent = parent === null ? null : parent.uid;
45+
this.name = name;
3646
this.uid = uid;
37-
this.name = handle.constructor.name;
3847
this._init = timestamp();
3948
this._destroy = Infinity;
4049
this._before = [];
@@ -81,8 +90,8 @@ function getCallSites(skip) {
8190
return stack;
8291
}
8392

84-
Node.prototype.add = function (uid, handle) {
85-
const node = new Node(uid, handle, getCallSites(3), this);
93+
Node.prototype.add = function (uid, handle, type) {
94+
const node = new Node(uid, handle, type, getCallSites(3), this);
8695
this.children.push(uid);
8796
return node;
8897
};
@@ -121,63 +130,73 @@ Node.prototype.rootIntialize = function () {
121130
this._before.push(0);
122131
};
123132

124-
//
125-
// Setup hooks
126-
//
127-
asyncHook.addHooks({
128-
init: asyncInit,
129-
pre: asyncBefore,
130-
post: asyncAfter,
131-
destroy: asyncDestroy
132-
});
133-
134133
const root = new Node(
135-
0, { 'constructor': { name: 'root' } },
134+
1,
135+
{},
136+
'root',
136137
getCallSites(2),
137138
null
138139
);
139140
root.rootIntialize();
140141

141142
const nodes = new Map();
142-
const stateStack = [root];
143143

144-
function asyncInit(uid, handle, provider, parentUid) {
145-
// get parent state
146-
const topState = stateStack[stateStack.length - 1];
147-
const state = (parentUid === null ? topState : nodes.get(parentUid));
144+
// Setup the root: fake hook events
145+
hooks.disable();
146+
process.nextTick(function () {
147+
root.after();
148+
root.destroy();
149+
});
150+
hooks.enable();
151+
152+
153+
function asyncInit(uid, type, triggerId, handle) {
154+
process._rawDebug('init', {uid, type, triggerId});
155+
156+
// get initializing state
157+
let state;
158+
if (triggerId === 0 || triggerId === 1) {
159+
// 1 is always root
160+
// 0 is not root, but unknown. Use root for now.
161+
state = root;
162+
} else {
163+
state = nodes.get(triggerId);
164+
}
148165

149166
// add new state node
150-
nodes.set(uid, state.add(uid, handle));
167+
nodes.set(uid, state.add(uid, handle, type));
151168
}
152169

153170
function asyncBefore(uid) {
171+
// Ignore our nextTick for the root duration
172+
if (!nodes.has(uid)) return;
173+
process._rawDebug('before', {uid});
174+
154175
const state = nodes.get(uid);
155176

156177
state.before();
157-
stateStack.push(state);
158178
}
159179

160180
function asyncAfter(uid) {
181+
// Ignore our nextTick for the root duration
182+
if (!nodes.has(uid)) return;
183+
process._rawDebug('after', {uid});
184+
161185
const state = nodes.get(uid);
162186

163187
state.after();
164-
stateStack.pop();
165188
}
166189

167190
function asyncDestroy(uid) {
191+
// Ignore our nextTick for the root duration
192+
if (!nodes.has(uid)) return;
193+
process._rawDebug('destroy', {uid});
194+
168195
const state = nodes.get(uid);
169196

170197
state.destroy();
171198
}
172199

173-
// The root job is done when process.nextTick is called
174-
asyncHook.disable();
175-
process.nextTick(function () {
176-
root.after();
177-
root.destroy();
178-
});
179-
asyncHook.enable();
180-
181200
//
182201
// Print result
183202
//
@@ -196,9 +215,9 @@ if (process.argv.indexOf('--dprof-no-sigint') === -1 &&
196215
process.on('exit', writeDataFile);
197216

198217
function writeDataFile() {
199-
// even though zlib is sync, it still fires async_wrap events,
200-
// so disable asyncWrap just to be sure.
201-
asyncHook.disable();
218+
// even though zlib is sync, it still fires async_hook events,
219+
// so disable the hooks just to be sure.
220+
hooks.disable();
202221

203222
const data = {
204223
'total': timestamp(),

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "dprof",
33
"description": "Dynamic/structured profiling & visualization for sync and async operations",
4-
"version": "0.18.2",
4+
"version": "1.0.0",
55
"author": "Andreas Madsen <[email protected]>",
66
"main": "./dprof.js",
77
"bin": {
@@ -29,13 +29,15 @@
2929
"babelify": "^7.3.0",
3030
"babel-preset-es2015": "^6.13.2",
3131
"startpoint": "0.3.x",
32-
"async-hook": "^1.6.0",
3332
"stack-chain": "^1.3.7"
3433
},
3534
"devDependencies": {
3635
"tap": "^6.3.2",
3736
"pako": "^1.0.3",
3837
"interpreted": "0.7.x"
3938
},
40-
"license": "MIT"
39+
"license": "MIT",
40+
"engines": {
41+
"node": "^8.0"
42+
}
4143
}

0 commit comments

Comments
 (0)