blob: d7dd5ec4f42103d79d6b3eccbaae84283ef317cc [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const utils = require('./bootperf-utils');
const puppeteer = require('puppeteer');
const { performance } = require('perf_hooks');
const { runs, targetUrl, progress, port, chromeBinary, waitFor } = require('yargs')
.option('runs', {
alias: 'r',
describe: 'The number of times to run',
default: 5,
type: 'number'
})
.option('target-url', {
alias: 'u',
describe: 'The target url to test against',
default: 'https://www.google.com/'
})
.option('port', {
alias: 'p',
describe: 'The remote debugging port',
default: 9222,
type: 'number'
})
.option('chrome-binary', {
alias: 'e',
describe: 'The executable to launch',
default: process.env['CHROME_BIN']
})
.option('wait-for', {
alias: 'w',
describe: 'The selector to wait for',
default: '.elements'
})
.option('progress', {
describe: 'Show progress',
type: 'boolean',
default: true
})
.version('1.0.0')
.help()
.argv;
if (!chromeBinary) {
console.log('No Chromium binary path provided.');
process.exit(1);
}
const times = [];
const pages = [];
let exitCode = 0;
async function runBootPerf () {
try {
const browser = await puppeteer.launch({
headless: true,
executablePath: chromeBinary,
defaultViewport: {
width: 1280,
height: 720
},
args: ['--remote-debugging-port=9222']
});
// Load the target page.
const srcPage = await browser.newPage();
await srcPage.goto(targetUrl);
pages.push(srcPage);
// Now get the DevTools listings.
const devtools = await browser.newPage();
await devtools.goto(`http://localhost:${port}/json`);
pages.push(devtools);
// Find the appropriate item to inspect the target page.
const listing = await devtools.$('pre');
const json = await devtools.evaluate(listing => listing.textContent, listing);
const targets = JSON.parse(json);
const { id } = targets.find((target) => target.url === targetUrl);
for (let i = 0; i < runs; i++) {
if (progress) {
printRunProgress(`Run ${i + 1} of ${runs}`);
}
const start = performance.now();
// Connect to the DevTools frontend.
const frontEnd = await browser.newPage();
await frontEnd.goto(`http://localhost:8090/front_end/inspector.html?ws=localhost:${port}/devtools/page/${id}`);
await frontEnd.waitForSelector(waitFor);
const duration = performance.now() - start;
times.push(duration);
// Close the page.
frontEnd.close();
}
} catch (err) {
console.warn(err);
console.log(json);
exitCode = 1;
} finally {
// Shut down.
for (const page of pages) {
try {
await page.close();
} catch (err) {
console.warn('Catastrophic failure: unable to close pages');
exitCode = 1;
}
}
console.log(`Runs: ${times.length}`);
if (times.length) {
// Clear the output before showing the final figures.
if (progress) {
printRunProgress();
}
console.log(`Mean boot time: ${utils.mean(times).toFixed(2)}ms`);
console.log(`50th percentile boot time: ${utils.percentile(times, 0.5).toFixed(2)}ms`);
console.log(`90th percentile boot time: ${utils.percentile(times, 0.9).toFixed(2)}ms`);
console.log(`99th percentile boot time: ${utils.percentile(times, 0.99).toFixed(2)}ms`);
}
process.exit(exitCode);
}
}
function printRunProgress(msg = '') {
if (!process || !('stdout' in process)) {
return;
}
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write(msg);
}
runBootPerf()