Optionally read from stdin via cli (#99)
Test Plan: - `./cli.js` opens speedscope in browser with no file selected - `./cli.js sample/profiles/Chrome/65/simple-timeline.json` opens profile - `cat sample/profiles/Chrome/65/simple-timeline.json | ./cli.js -` opens profile - `node --prof-process --preprocess -j sample/profiles/node/8.5.0/isolate-0x102802600-v8.log | ./cli.js -` opens profile Fixes #95
This commit is contained in:
@@ -37,14 +37,10 @@ If you record profiling information like so:
|
||||
|
||||
node --prof /path/to/my/script.js
|
||||
|
||||
Then this will generate a bunch of `isolate*.log` files. Process one of them
|
||||
into usable JSON like so:
|
||||
Then this will generate one or more `isolate*.log` files. You can open
|
||||
the resulting profile in speedscope by running the following command:
|
||||
|
||||
node --prof-process -preprocess -j isolate*.log > profile.v8log.json
|
||||
|
||||
Then drop the resulting `profile.v8log.json` file into speedscope, or run
|
||||
|
||||
speedscope profile.v8log.json
|
||||
node --prof-process --preprocess -j isolate*.log | speedscope -
|
||||
|
||||
### Instruments.app
|
||||
|
||||
|
||||
@@ -2,73 +2,102 @@
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const os = require('os')
|
||||
const stream = require('stream')
|
||||
|
||||
const opn = require('opn')
|
||||
|
||||
const helpString = `
|
||||
Usage: speedscope [filepath]
|
||||
const helpString = `Usage: speedscope [filepath]
|
||||
|
||||
If invoked with no arguments, will open a local copy of speedscope in your default browser.
|
||||
Once open, you can browse for a profile to import.
|
||||
|
||||
If - is used as the filepath, will read from stdin instead.
|
||||
|
||||
cat /path/to/profile | speedscope -
|
||||
`
|
||||
|
||||
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
||||
console.log(helpString)
|
||||
process.exit(0)
|
||||
function getProfileStream(relPath) {
|
||||
const absPath = path.resolve(process.cwd(), relPath)
|
||||
if (relPath === '-') {
|
||||
// Read from stdin
|
||||
return process.stdin
|
||||
} else {
|
||||
return fs.createReadStream(absPath)
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
||||
console.log('v' + require('./package.json').version)
|
||||
process.exit(0)
|
||||
function getProfileBuffer(relPath) {
|
||||
const profileStream = getProfileStream(relPath)
|
||||
const chunks = []
|
||||
return new Promise((resolve, reject) => {
|
||||
profileStream.pipe(
|
||||
stream.Writable({
|
||||
write(chunk, encoding, callback) {
|
||||
chunks.push(chunk)
|
||||
callback()
|
||||
},
|
||||
final() {
|
||||
resolve(Buffer.concat(chunks))
|
||||
},
|
||||
}),
|
||||
)
|
||||
profileStream.on('error', ev => reject(ev))
|
||||
})
|
||||
}
|
||||
|
||||
if (process.argv.length > 3) {
|
||||
console.log('At most one argument expected')
|
||||
console.log(helpString)
|
||||
process.exit(1)
|
||||
async function main() {
|
||||
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
||||
console.log(helpString)
|
||||
return
|
||||
}
|
||||
|
||||
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
||||
console.log('v' + require('./package.json').version)
|
||||
return
|
||||
}
|
||||
|
||||
if (process.argv.length > 3) {
|
||||
throw new Error('At most one argument expected')
|
||||
}
|
||||
|
||||
let urlToOpen = 'file://' + path.resolve(__dirname, './dist/release/index.html')
|
||||
|
||||
if (process.argv.length === 3) {
|
||||
const relPath = process.argv[2]
|
||||
const sourceBuffer = await getProfileBuffer(relPath)
|
||||
const filename = path.basename(relPath)
|
||||
const sourceBase64 = sourceBuffer.toString('base64')
|
||||
const jsSource = `speedscope.loadFileFromBase64(${JSON.stringify(filename)}, ${JSON.stringify(
|
||||
sourceBase64,
|
||||
)})`
|
||||
|
||||
const filePrefix = `speedscope-${+new Date()}-${process.pid}`
|
||||
const jsPath = path.join(os.tmpdir(), `${filePrefix}.js`)
|
||||
console.log(`Creating temp file ${jsPath}`)
|
||||
fs.writeFileSync(jsPath, jsSource)
|
||||
urlToOpen += `#localProfilePath=${jsPath}`
|
||||
|
||||
// For some silly reason, the OS X open command ignores any query parameters or hash parameters
|
||||
// passed as part of the URL. To get around this weird issue, we'll create a local HTML file
|
||||
// that just redirects.
|
||||
const htmlPath = path.join(os.tmpdir(), `${filePrefix}.html`)
|
||||
console.log(`Creating temp file ${htmlPath}`)
|
||||
fs.writeFileSync(htmlPath, `<script>window.location=${JSON.stringify(urlToOpen)}</script>`)
|
||||
|
||||
urlToOpen = `file://${htmlPath}`
|
||||
}
|
||||
|
||||
console.log('Opening', urlToOpen, 'in your default browser')
|
||||
|
||||
await opn(urlToOpen, {wait: false})
|
||||
}
|
||||
|
||||
let urlToOpen = 'file://' + path.resolve(__dirname, './dist/release/index.html')
|
||||
|
||||
if (process.argv.length === 3) {
|
||||
const absPath = path.resolve(process.cwd(), process.argv[2])
|
||||
let sourceBuffer
|
||||
try {
|
||||
sourceBuffer = fs.readFileSync(absPath)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
main()
|
||||
.then(() => {
|
||||
process.exit(0)
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e.stack + '\n')
|
||||
console.log(helpString)
|
||||
process.exit(1)
|
||||
}
|
||||
const filename = path.basename(absPath)
|
||||
const sourceBase64 = sourceBuffer.toString('base64')
|
||||
const jsSource = `speedscope.loadFileFromBase64(${JSON.stringify(filename)}, ${JSON.stringify(
|
||||
sourceBase64,
|
||||
)})`
|
||||
|
||||
const filePrefix = `speedscope-${+new Date()}-${process.pid}`
|
||||
const jsPath = path.join(os.tmpdir(), `${filePrefix}.js`)
|
||||
console.log(`Creating temp file ${jsPath}`)
|
||||
fs.writeFileSync(jsPath, jsSource)
|
||||
urlToOpen += `#localProfilePath=${jsPath}`
|
||||
|
||||
// For some silly reason, the OS X open command ignores any query parameters or hash parameters
|
||||
// passed as part of the URL. To get around this weird issue, we'll create a local HTML file
|
||||
// that just redirects.
|
||||
const htmlPath = path.join(os.tmpdir(), `${filePrefix}.html`)
|
||||
console.log(`Creating temp file ${htmlPath}`)
|
||||
fs.writeFileSync(htmlPath, `<script>window.location=${JSON.stringify(urlToOpen)}</script>`)
|
||||
|
||||
urlToOpen = `file://${htmlPath}`
|
||||
}
|
||||
|
||||
console.log('Opening', urlToOpen, 'in your default browser')
|
||||
|
||||
opn(urlToOpen, {wait: false}).then(
|
||||
() => {
|
||||
process.exit(0)
|
||||
},
|
||||
err => {
|
||||
console.error(err)
|
||||
console.exit(1)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user