rsnext/packages/next/build/profiler/profiler.js
2020-05-18 15:24:37 -04:00

146 lines
3.1 KiB
JavaScript

import path from 'path'
import fs from 'fs'
let inspector
try {
inspector = require('inspector')
} catch (e) {
console.log('Unable to CPU profile in < node 8.0')
}
class Profiler {
constructor(inspector) {
this.session = undefined
this.inspector = inspector
}
hasSession() {
return this.session !== undefined
}
startProfiling() {
if (this.inspector === undefined) {
return Promise.resolve()
}
try {
this.session = new inspector.Session()
this.session.connect()
} catch (_) {
this.session = undefined
return Promise.resolve()
}
return Promise.all([
this.sendCommand('Profiler.setSamplingInterval', {
interval: 100,
}),
this.sendCommand('Profiler.enable'),
this.sendCommand('Profiler.start'),
])
}
sendCommand(method, params) {
if (this.hasSession()) {
return new Promise((resolve, reject) => {
return this.session.post(method, params, (err, params) => {
if (err !== null) {
reject(err)
} else {
resolve(params)
}
})
})
} else {
return Promise.resolve()
}
}
destroy() {
if (this.hasSession()) {
this.session.disconnect()
}
return Promise.resolve()
}
stopProfiling() {
return this.sendCommand('Profiler.stop')
}
}
const { Tracer } = require('chrome-trace-event')
/**
* an object that wraps Tracer and Profiler with a counter
* @typedef {Object} Trace
* @property {Tracer} trace instance of Tracer
* @property {number} counter Counter
* @property {Profiler} profiler instance of Profiler
* @property {Function} end the end function
*/
/**
* @param {string} outputPath The location where to write the log.
* @returns {Trace} The trace object
*/
export const createTrace = (outputPath) => {
const trace = new Tracer({
noStream: true,
})
const profiler = new Profiler(inspector)
if (/\/|\\/.test(outputPath)) {
const dirPath = path.dirname(outputPath)
fs.mkdirSync(dirPath, { recursive: true })
}
const fsStream = fs.createWriteStream(outputPath)
let counter = 0
trace.pipe(fsStream)
// These are critical events that need to be inserted so that tools like
// chrome dev tools can load the profile.
trace.instantEvent({
name: 'TracingStartedInPage',
id: ++counter,
cat: ['disabled-by-default-devtools.timeline'],
args: {
data: {
sessionId: '-1',
page: '0xfff',
frames: [
{
frame: '0xfff',
url: 'webpack',
name: '',
},
],
},
},
})
trace.instantEvent({
name: 'TracingStartedInBrowser',
id: ++counter,
cat: ['disabled-by-default-devtools.timeline'],
args: {
data: {
sessionId: '-1',
},
},
})
return {
trace,
counter,
profiler,
end: (callback) => {
// Wait until the write stream finishes.
fsStream.on('finish', () => {
callback()
})
// Tear down the readable trace stream.
trace.push(null)
},
}
}