skia2/tools/perf-canvaskit-puppeteer/perf-canvaskit-with-puppeteer.js

267 lines
7.7 KiB
JavaScript
Raw Normal View History

[canvaskit] Start a generic puppeteer perfing system. IMPORTANT LESSON: when bringing in node (and possibly other executables) via CIPD, add them to the path in gen_tasks_logic so the parent executable (the task driver itself) has the right PATH set. Otherwise, the subprocesses it spawns might grab the wrong version because of how golang handles environments of subprocesses. This is starting as a fork of Skottie WASM. I hope to have a more unified system for creating and running benchmarks. Overall overview: gen_tasks_logic.go creates a task in task.json that compiles CanvasKit and the task drivers and then executes our task (i.e. perf_puppeteer.go) perf_puppeteer runs a node program (perf-with-puppeteer.js) that uses puppeteer to execute benchmarking code on an html page (canvaskit-skottie-frames-load.html). I needed to update the node package so npm could be updated from 3.x to 6.14.4 so it knew about `npm ci`. This may not have been entirely necessary, given the problems of executing the correct npm (see important lesson above), but it hasn't broken things further, so more up-to-date is probably a good thing. Suggested Review Order: - canvaskit-skottie-frames-load.html (note it is similar to skottie-wasm-perf.html, but it waits for a button click to start animating and records times from the main JS thread itself) - perf-with-puppeteer.js (similar to skottie-wasm-perf.js, but has some things made optional [e.g. tracing]) - perf_puppeteer_test.go (shows the inputs/outputs of various steps) - perf_puppeteer.go - Everything else. Change-Id: I380e81b825f36682c257664d488267edaf36369e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/285783 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Eric Boren <borenet@google.com>
2020-05-01 18:16:27 +00:00
/**
* Command line application to run CanvasKit benchmarks in webpages using puppeteer. Different
* webpages can be specified to measure different aspects. The HTML page run contains the JS code
* to run the scenario and either 1) produce the perf output as a JSON object or 2) defer to
* puppeteer reading the tracing data.
*
*/
const puppeteer = require('puppeteer');
const express = require('express');
const fs = require('fs');
const commandLineArgs = require('command-line-args');
const commandLineUsage= require('command-line-usage');
const opts = [
{
name: 'bench_html',
typeLabel: '{underline file}',
description: 'An HTML file containing the bench harness.'
},
{
name: 'canvaskit_js',
typeLabel: '{underline file}',
description: '(required) The path to canvaskit.js.'
},
{
name: 'canvaskit_wasm',
typeLabel: '{underline file}',
description: '(required) The path to canvaskit.wasm.'
},
{
name: 'input_lottie',
typeLabel: '{underline file}',
description: 'The Lottie JSON file to process.'
},
{
name: 'input_skp',
typeLabel: '{underline file}',
description: 'The SKP file to process.'
},
[canvaskit] Start a generic puppeteer perfing system. IMPORTANT LESSON: when bringing in node (and possibly other executables) via CIPD, add them to the path in gen_tasks_logic so the parent executable (the task driver itself) has the right PATH set. Otherwise, the subprocesses it spawns might grab the wrong version because of how golang handles environments of subprocesses. This is starting as a fork of Skottie WASM. I hope to have a more unified system for creating and running benchmarks. Overall overview: gen_tasks_logic.go creates a task in task.json that compiles CanvasKit and the task drivers and then executes our task (i.e. perf_puppeteer.go) perf_puppeteer runs a node program (perf-with-puppeteer.js) that uses puppeteer to execute benchmarking code on an html page (canvaskit-skottie-frames-load.html). I needed to update the node package so npm could be updated from 3.x to 6.14.4 so it knew about `npm ci`. This may not have been entirely necessary, given the problems of executing the correct npm (see important lesson above), but it hasn't broken things further, so more up-to-date is probably a good thing. Suggested Review Order: - canvaskit-skottie-frames-load.html (note it is similar to skottie-wasm-perf.html, but it waits for a button click to start animating and records times from the main JS thread itself) - perf-with-puppeteer.js (similar to skottie-wasm-perf.js, but has some things made optional [e.g. tracing]) - perf_puppeteer_test.go (shows the inputs/outputs of various steps) - perf_puppeteer.go - Everything else. Change-Id: I380e81b825f36682c257664d488267edaf36369e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/285783 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Eric Boren <borenet@google.com>
2020-05-01 18:16:27 +00:00
{
name: 'assets',
typeLabel: '{underline file}',
description: 'A directory containing any assets needed by the lottie file (e.g. images/fonts).'
[canvaskit] Start a generic puppeteer perfing system. IMPORTANT LESSON: when bringing in node (and possibly other executables) via CIPD, add them to the path in gen_tasks_logic so the parent executable (the task driver itself) has the right PATH set. Otherwise, the subprocesses it spawns might grab the wrong version because of how golang handles environments of subprocesses. This is starting as a fork of Skottie WASM. I hope to have a more unified system for creating and running benchmarks. Overall overview: gen_tasks_logic.go creates a task in task.json that compiles CanvasKit and the task drivers and then executes our task (i.e. perf_puppeteer.go) perf_puppeteer runs a node program (perf-with-puppeteer.js) that uses puppeteer to execute benchmarking code on an html page (canvaskit-skottie-frames-load.html). I needed to update the node package so npm could be updated from 3.x to 6.14.4 so it knew about `npm ci`. This may not have been entirely necessary, given the problems of executing the correct npm (see important lesson above), but it hasn't broken things further, so more up-to-date is probably a good thing. Suggested Review Order: - canvaskit-skottie-frames-load.html (note it is similar to skottie-wasm-perf.html, but it waits for a button click to start animating and records times from the main JS thread itself) - perf-with-puppeteer.js (similar to skottie-wasm-perf.js, but has some things made optional [e.g. tracing]) - perf_puppeteer_test.go (shows the inputs/outputs of various steps) - perf_puppeteer.go - Everything else. Change-Id: I380e81b825f36682c257664d488267edaf36369e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/285783 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Eric Boren <borenet@google.com>
2020-05-01 18:16:27 +00:00
},
{
name: 'output',
typeLabel: '{underline file}',
description: 'The perf file to write. Defaults to perf.json',
},
{
name: 'use_gpu',
description: 'Whether we should run in non-headless mode with GPU.',
type: Boolean,
},
{
name: 'use_tracing',
description: 'If non-empty, will be interpreted as the tracing categories that should be ' +
'measured and returned in the output JSON. Example: "blink,cc,gpu"',
type: String,
},
{
name: 'port',
description: 'The port number to use, defaults to 8081.',
type: Number,
},
{
name: 'query_params',
description: 'The query params to be added to the testing page URL. Useful for passing' +
'options to the perf html page.',
type: String,
multiple: true
},
[canvaskit] Start a generic puppeteer perfing system. IMPORTANT LESSON: when bringing in node (and possibly other executables) via CIPD, add them to the path in gen_tasks_logic so the parent executable (the task driver itself) has the right PATH set. Otherwise, the subprocesses it spawns might grab the wrong version because of how golang handles environments of subprocesses. This is starting as a fork of Skottie WASM. I hope to have a more unified system for creating and running benchmarks. Overall overview: gen_tasks_logic.go creates a task in task.json that compiles CanvasKit and the task drivers and then executes our task (i.e. perf_puppeteer.go) perf_puppeteer runs a node program (perf-with-puppeteer.js) that uses puppeteer to execute benchmarking code on an html page (canvaskit-skottie-frames-load.html). I needed to update the node package so npm could be updated from 3.x to 6.14.4 so it knew about `npm ci`. This may not have been entirely necessary, given the problems of executing the correct npm (see important lesson above), but it hasn't broken things further, so more up-to-date is probably a good thing. Suggested Review Order: - canvaskit-skottie-frames-load.html (note it is similar to skottie-wasm-perf.html, but it waits for a button click to start animating and records times from the main JS thread itself) - perf-with-puppeteer.js (similar to skottie-wasm-perf.js, but has some things made optional [e.g. tracing]) - perf_puppeteer_test.go (shows the inputs/outputs of various steps) - perf_puppeteer.go - Everything else. Change-Id: I380e81b825f36682c257664d488267edaf36369e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/285783 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Eric Boren <borenet@google.com>
2020-05-01 18:16:27 +00:00
{
name: 'help',
alias: 'h',
type: Boolean,
description: 'Print this usage guide.'
},
];
const usage = [
{
header: 'Skia Web-based Performance Metrics of CanvasKit',
content: "Command line application to capture performance metrics from a browser."
},
{
header: 'Options',
optionList: opts,
},
];
// Parse and validate flags.
const options = commandLineArgs(opts);
if (!options.output) {
options.output = 'perf.json';
}
if (!options.port) {
options.port = 8081;
}
if (options.help) {
console.log(commandLineUsage(usage));
process.exit(0);
}
if (!options.bench_html) {
console.error('You must supply the bench_html file to run.');
console.log(commandLineUsage(usage));
process.exit(1);
}
const driverHTML = fs.readFileSync(options.bench_html, 'utf8');
// This express webserver will serve the HTML file running the benchmark and any additional assets
// needed to run the tests.
const app = express();
app.get('/', (req, res) => res.send(driverHTML));
if (!options.canvaskit_js) {
console.error('You must supply path to canvaskit.js.');
console.log(commandLineUsage(usage));
process.exit(1);
}
if (!options.canvaskit_wasm) {
console.error('You must supply path to canvaskit.wasm.');
console.log(commandLineUsage(usage));
process.exit(1);
}
const canvasKitJS = fs.readFileSync(options.canvaskit_js, 'utf8');
const canvasKitWASM = fs.readFileSync(options.canvaskit_wasm, 'binary');
app.get('/static/canvaskit.js', (req, res) => res.send(canvasKitJS));
app.get('/static/canvaskit.wasm', function(req, res) {
// Set the MIME type so it can be streamed efficiently.
res.type('application/wasm');
res.send(new Buffer(canvasKitWASM, 'binary'));
});
if (options.input_lottie) {
const lottieJSON = fs.readFileSync(options.input_lottie, 'utf8');
app.get('/static/lottie.json', (req, res) => res.send(lottieJSON));
}
if (options.input_skp) {
const skpBytes = fs.readFileSync(options.input_skp, 'binary');
app.get('/static/test.skp', (req, res) => {
res.send(new Buffer(skpBytes, 'binary'));
});
}
[canvaskit] Start a generic puppeteer perfing system. IMPORTANT LESSON: when bringing in node (and possibly other executables) via CIPD, add them to the path in gen_tasks_logic so the parent executable (the task driver itself) has the right PATH set. Otherwise, the subprocesses it spawns might grab the wrong version because of how golang handles environments of subprocesses. This is starting as a fork of Skottie WASM. I hope to have a more unified system for creating and running benchmarks. Overall overview: gen_tasks_logic.go creates a task in task.json that compiles CanvasKit and the task drivers and then executes our task (i.e. perf_puppeteer.go) perf_puppeteer runs a node program (perf-with-puppeteer.js) that uses puppeteer to execute benchmarking code on an html page (canvaskit-skottie-frames-load.html). I needed to update the node package so npm could be updated from 3.x to 6.14.4 so it knew about `npm ci`. This may not have been entirely necessary, given the problems of executing the correct npm (see important lesson above), but it hasn't broken things further, so more up-to-date is probably a good thing. Suggested Review Order: - canvaskit-skottie-frames-load.html (note it is similar to skottie-wasm-perf.html, but it waits for a button click to start animating and records times from the main JS thread itself) - perf-with-puppeteer.js (similar to skottie-wasm-perf.js, but has some things made optional [e.g. tracing]) - perf_puppeteer_test.go (shows the inputs/outputs of various steps) - perf_puppeteer.go - Everything else. Change-Id: I380e81b825f36682c257664d488267edaf36369e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/285783 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Eric Boren <borenet@google.com>
2020-05-01 18:16:27 +00:00
if (options.assets) {
app.use('/static/assets/', express.static(options.assets));
console.log('assets served from', options.assets);
}
app.listen(options.port, () => console.log('- Local web server started.'));
let hash = "#cpu";
if (options.use_gpu) {
hash = "#gpu";
}
let query_param_string = '?';
if (options.query_params) {
for (const string of options.query_params) {
query_param_string += string + '&';
}
}
const targetURL = `http://localhost:${options.port}/${query_param_string}${hash}`;
[canvaskit] Start a generic puppeteer perfing system. IMPORTANT LESSON: when bringing in node (and possibly other executables) via CIPD, add them to the path in gen_tasks_logic so the parent executable (the task driver itself) has the right PATH set. Otherwise, the subprocesses it spawns might grab the wrong version because of how golang handles environments of subprocesses. This is starting as a fork of Skottie WASM. I hope to have a more unified system for creating and running benchmarks. Overall overview: gen_tasks_logic.go creates a task in task.json that compiles CanvasKit and the task drivers and then executes our task (i.e. perf_puppeteer.go) perf_puppeteer runs a node program (perf-with-puppeteer.js) that uses puppeteer to execute benchmarking code on an html page (canvaskit-skottie-frames-load.html). I needed to update the node package so npm could be updated from 3.x to 6.14.4 so it knew about `npm ci`. This may not have been entirely necessary, given the problems of executing the correct npm (see important lesson above), but it hasn't broken things further, so more up-to-date is probably a good thing. Suggested Review Order: - canvaskit-skottie-frames-load.html (note it is similar to skottie-wasm-perf.html, but it waits for a button click to start animating and records times from the main JS thread itself) - perf-with-puppeteer.js (similar to skottie-wasm-perf.js, but has some things made optional [e.g. tracing]) - perf_puppeteer_test.go (shows the inputs/outputs of various steps) - perf_puppeteer.go - Everything else. Change-Id: I380e81b825f36682c257664d488267edaf36369e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/285783 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Eric Boren <borenet@google.com>
2020-05-01 18:16:27 +00:00
const viewPort = {width: 1000, height: 1000};
// Drive chrome to load the web page from the server we have running.
async function driveBrowser() {
console.log('- Launching chrome for ' + options.input);
let browser;
let page;
const headless = !options.use_gpu;
let browser_args = [
'--no-sandbox',
'--disable-setuid-sandbox',
'--window-size=' + viewPort.width + ',' + viewPort.height,
// The following two params allow Chrome to run at an unlimited fps. Note, if there is
// already a chrome instance running, these arguments will have NO EFFECT, as the existing
// Chrome instance will be used instead of puppeteer spinning up a new one.
'--disable-frame-rate-limit',
'--disable-gpu-vsync',
[canvaskit] Start a generic puppeteer perfing system. IMPORTANT LESSON: when bringing in node (and possibly other executables) via CIPD, add them to the path in gen_tasks_logic so the parent executable (the task driver itself) has the right PATH set. Otherwise, the subprocesses it spawns might grab the wrong version because of how golang handles environments of subprocesses. This is starting as a fork of Skottie WASM. I hope to have a more unified system for creating and running benchmarks. Overall overview: gen_tasks_logic.go creates a task in task.json that compiles CanvasKit and the task drivers and then executes our task (i.e. perf_puppeteer.go) perf_puppeteer runs a node program (perf-with-puppeteer.js) that uses puppeteer to execute benchmarking code on an html page (canvaskit-skottie-frames-load.html). I needed to update the node package so npm could be updated from 3.x to 6.14.4 so it knew about `npm ci`. This may not have been entirely necessary, given the problems of executing the correct npm (see important lesson above), but it hasn't broken things further, so more up-to-date is probably a good thing. Suggested Review Order: - canvaskit-skottie-frames-load.html (note it is similar to skottie-wasm-perf.html, but it waits for a button click to start animating and records times from the main JS thread itself) - perf-with-puppeteer.js (similar to skottie-wasm-perf.js, but has some things made optional [e.g. tracing]) - perf_puppeteer_test.go (shows the inputs/outputs of various steps) - perf_puppeteer.go - Everything else. Change-Id: I380e81b825f36682c257664d488267edaf36369e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/285783 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Eric Boren <borenet@google.com>
2020-05-01 18:16:27 +00:00
];
if (options.use_gpu) {
browser_args.push('--ignore-gpu-blacklist');
browser_args.push('--ignore-gpu-blocklist');
browser_args.push('--enable-gpu-rasterization');
}
console.log("Running with headless: " + headless + " args: " + browser_args);
try {
browser = await puppeteer.launch({headless: headless, args: browser_args});
page = await browser.newPage();
await page.setViewport(viewPort);
} catch (e) {
console.log('Could not open the browser.', e);
process.exit(1);
}
console.log("Loading " + targetURL);
try {
await page.goto(targetURL, {
timeout: 60000,
waitUntil: 'networkidle0'
});
// Page is mostly loaded, wait for benchmark page to report itself ready.
console.log('Waiting 15s for benchmark to be ready');
await page.waitForFunction(`(window._perfReady === true) || window._error`, {
timeout: 15000,
});
let err = await page.evaluate('window._error');
if (err) {
console.log(`ERROR: ${err}`);
process.exit(1);
}
// Start trace if requested
if (options.use_tracing) {
const categories = options.use_tracing.split(',');
console.log('Collecting tracing data for categories', categories);
await page.tracing.start({
path: options.output,
screenshots: false,
categories: categories,
});
}
// Benchmarks should have a button with id #start_bench to click (this also makes manual
// debugging easier).
await page.click('#start_bench');
console.log('Waiting 60s for run to be done');
await page.waitForFunction(`(window._perfDone === true) || window._error`, {
timeout: 60000,
});
err = await page.evaluate('window._error');
if (err) {
console.log(`ERROR: ${err}`);
process.exit(1);
}
if (options.use_tracing) {
// Stop Trace.
await page.tracing.stop();
} else {
const perfResults = await page.evaluate('window._perfData');
console.debug('Perf results: ', perfResults);
fs.writeFileSync(options.output, JSON.stringify(perfResults));
}
} catch(e) {
console.log('Timed out while loading or drawing.', e);
await browser.close();
process.exit(1);
}
await browser.close();
// Need to call exit() because the web server is still running.
process.exit(0);
}
driveBrowser();