Skip to content

Commit f57a6ae

Browse files
committed
feat: add pm2 profile:cpu / pm2 profile:mem
1 parent 2a01e5c commit f57a6ae

File tree

4 files changed

+79
-105
lines changed

4 files changed

+79
-105
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ yarn.lock
2121
*.tar.gz
2222
e2e_time
2323
unit_time
24+
*.heapprofile

bin/pm2

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -373,19 +373,19 @@ commander.command('scale <app_name> <number>')
373373
//
374374
// snapshot PM2
375375
//
376-
commander.command('snapshot')
377-
.description('snapshot PM2 memory')
378-
.action(function() {
379-
pm2.snapshotPM2();
376+
commander.command('profile:mem [time]')
377+
.description('Sample PM2 heap memory')
378+
.action(function(time) {
379+
pm2.profile('mem', time);
380380
});
381381

382382
//
383383
// snapshot PM2
384384
//
385-
commander.command('profile <command>')
386-
.description('profile CPU')
387-
.action(function(command) {
388-
pm2.profilePM2(command);
385+
commander.command('profile:cpu [time]')
386+
.description('Profile PM2 cpu')
387+
.action(function(time) {
388+
pm2.profile('cpu', time);
389389
});
390390

391391
//

lib/API/Extra.js

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -168,64 +168,48 @@ module.exports = function(CLI) {
168168
return cb(null, pids);
169169
})
170170
}
171+
171172
/**
172173
* Create PM2 memory snapshot
173174
* @method getVersion
174175
* @callback cb
175176
*/
176-
CLI.prototype.snapshotPM2 = function(cb) {
177+
CLI.prototype.profile = function(type, time, cb) {
177178
var that = this;
178179
var moment = require('moment');
179-
var file = path.join(process.cwd(), moment().format('dd-HH:mm:ss') + '.heapsnapshot');
180+
var cmd
181+
182+
if (type == 'cpu') {
183+
cmd = {
184+
ext: '.cpuprofile',
185+
action: 'profileCPU'
186+
}
187+
}
188+
if (type == 'mem') {
189+
cmd = {
190+
ext: '.heapprofile',
191+
action: 'profileMEM'
192+
}
193+
}
194+
195+
var file = path.join(process.cwd(), moment().format('dd-HH:mm:ss') + cmd.ext);
196+
time = time || 10000
180197

181-
that.Client.executeRemote('snapshotPM2', {
182-
pwd : file
198+
console.log(`Starting ${cmd.action} profiling for ${time}ms...`)
199+
that.Client.executeRemote(cmd.action, {
200+
pwd : file,
201+
timeout: time
183202
}, function(err) {
184203
if (err) {
185204
console.error(err);
186205
return that.exitCli(1);
187206
}
188-
console.log('Heapdump in %s', file);
207+
console.log(`Profile done in ${file}`)
189208
return cb ? cb.apply(null, arguments) : that.exitCli(cst.SUCCESS_EXIT);
190209
});
191210
};
192211

193212

194-
/**
195-
* Create PM2 memory snapshot
196-
* @method getVersion
197-
* @callback cb
198-
*/
199-
CLI.prototype.profilePM2 = function(command, cb) {
200-
var that = this;
201-
var moment = require('moment');
202-
var file = path.join(process.cwd(), moment().format('dd-HH:mm:ss') + '.cpuprofile');
203-
204-
if (command == 'start') {
205-
that.Client.executeRemote('profileStart', {
206-
}, function(err) {
207-
if (err) {
208-
console.error(err);
209-
return that.exitCli(1);
210-
}
211-
console.log('CPU profiling started, type pm2 profile stop once finished');
212-
return cb ? cb.apply(null, arguments) : that.exitCli(cst.SUCCESS_EXIT);
213-
});
214-
}
215-
else if (command == 'stop') {
216-
that.Client.executeRemote('profileStop', {
217-
pwd : file
218-
}, function(err) {
219-
if (err) {
220-
console.error(err);
221-
return that.exitCli(1);
222-
}
223-
console.log('CPU profile in %s', file);
224-
return cb ? cb.apply(null, arguments) : that.exitCli(cst.SUCCESS_EXIT);
225-
});
226-
}
227-
};
228-
229213
/**
230214
* Description
231215
* @method sendLineToStdin

lib/Daemon.js

Lines changed: 46 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -151,80 +151,69 @@ Daemon.prototype.innerStart = function(cb) {
151151
that.sendReady(cb);
152152
});
153153

154-
var profiler;
155-
156-
try {
157-
profiler = semver.satisfies(process.version, '>= 10.0.0') ? require('inspector') : null;
158-
} catch(e) {
159-
profiler = null;
160-
}
161154

162155
/**
163156
* Memory Snapshot
164157
*/
165-
function snapshotPM2(msg, cb) {
166-
if (profiler == null) {
167-
console.log('Heap snapshot is not available (node 10+)');
168-
return cb(new Error('Heap snapshot is not available (node 10+)'));
158+
function profile(type, msg, cb) {
159+
if (semver.satisfies(process.version, '< 8'))
160+
return cb(null, { error: 'Node.js is not on right version' })
161+
162+
var cmd
163+
164+
if (type === 'cpu') {
165+
cmd = {
166+
enable: 'Profiler.enable',
167+
start: 'Profiler.start',
168+
stop: 'Profiler.stop',
169+
disable: 'Profiler.disable'
170+
}
171+
}
172+
if (type == 'mem') {
173+
cmd = {
174+
enable: 'HeapProfiler.enable',
175+
start: 'HeapProfiler.startSampling',
176+
stop: 'HeapProfiler.stopSampling',
177+
disable: 'HeapProfiler.disable'
178+
}
169179
}
170180

171-
const session = new profiler.Session()
172-
session.connect()
173-
session.post('HeapProfiler.enable')
174-
175-
const chunks = []
176-
session.on('HeapProfiler.addHeapSnapshotChunk', (data) => {
177-
chunks.push(data.params.chunk)
178-
})
179-
180-
session.post('HeapProfiler.takeHeapSnapshot', {
181-
reportProgress: false
182-
}, (err, data) => {
183-
if (err) return cb(err)
184-
185-
fs.writeFile(msg.pwd, chunks.join(''), function() {
186-
session.post('Profiler.disable')
187-
session.disconnect()
181+
const inspector = require('inspector')
182+
var session = new inspector.Session()
188183

189-
return cb(null, {file : msg.pwd});
190-
});
191-
})
192-
}
184+
session.connect()
193185

194-
function startProfilingPM2(msg, cb) {
195-
if (profiler == null) {
196-
console.log('v8-profiler is not available');
197-
return cb(new Error('v8-profiler is not available'));
198-
}
186+
var timeout = msg.timeout || 5000
199187

200-
profiler.startProfiling('cpu');
188+
session.post(cmd.enable, (err, data) => {
189+
if (err) return cb(null, { error: err.message || err })
201190

202-
process.nextTick(function() {
203-
return cb(null, {msg : 'profiling started'});
204-
});
205-
}
191+
console.log(`Starting ${cmd.start}`)
192+
session.post(cmd.start, (err, data) => {
193+
if (err) return cb(null, { error: err.message || err })
206194

207-
function stopProfilingPM2(msg, cb) {
208-
if (profiler == null) {
209-
console.log('v8-profiler is not available');
210-
return cb(new Error('v8-profiler is not available'));
211-
}
195+
setTimeout(() => {
196+
session.post(cmd.stop, (err, data) => {
197+
if (err) return cb(null, { error: err.message || err })
198+
const profile = data.profile
212199

213-
var profile1 = profiler.stopProfiling('cpu');
200+
console.log(`Stopping ${cmd.stop}`)
201+
session.post(cmd.disable)
214202

215-
profile1.export()
216-
.pipe(fs.createWriteStream(msg.pwd))
217-
.on('finish', function() {
218-
profile1.delete();
219-
return cb(null, {file : msg.pwd});
220-
});
203+
fs.writeFile(msg.pwd, JSON.stringify(profile), (err) => {
204+
if (err) return cb(null, { error: err.message || err })
205+
return cb(null, { file : msg.pwd })
206+
})
207+
})
208+
}, timeout)
209+
})
210+
})
221211
}
222212

223213
server.expose({
224214
killMe : that.close.bind(this),
225-
snapshotPM2 : snapshotPM2,
226-
profileStart : startProfilingPM2,
227-
profileStop : stopProfilingPM2,
215+
profileCPU : profile.bind(this, 'cpu'),
216+
profileMEM : profile.bind(this, 'mem'),
228217
prepare : God.prepare,
229218
getMonitorData : God.getMonitorData,
230219
getSystemData : God.getSystemData,

0 commit comments

Comments
 (0)