Chrome's screenshot functionality is extremely slow

447 views
Skip to first unread message

Andrew Stuart

unread,
Oct 13, 2022, 5:29:57 PM10/13/22
to headle...@chromium.org
Chrome's screenshot functionality is extremely slow.

Even on a 12 core machine, Chrome is able to output only one screenshot per second.

By comparison it is able to pump out 25 to 60 frames per second when displaying to video.

Even on completely static pages such as https://www.example.com Chrome is only able to do 8 screenshots per second.

Something must be extremely slow somewhere in the screenshot code.

Closely related, I'd like to request the ability to pass a filename for the screenshot to be saved to, instead of receiving it
as base64 encoded JSON. When taking alot of screenshots it is extremely computationally expensive for Chrome to convert the
screenshot to base64, only for my code to then convert it back to binary and save it to a file. It would be much more effective
if I could pass in a filename and chrome save the binary directly to the file.

CHROME VERSION:
Google Chrome 106.0.5245.0 dev

HARDWARE:
AMD Ryzen 9 5900X 12-Core
64GB RAM
NVIDIA GeForce GTX 1660

OPERATING SYSTEM:
Ubuntu 22

TEST OUTPUT:
ubuntu:~/crbug> node test.js
timing.... URL: https://www.shadertoy.com/embed/MdX3Rr?gui=true&t=10&paused=false&muted=false captured 100 screenshots , saving screenshot to file completed in: : 1:24.015 (m:ss.mmm)
(100 screenshot in 84 seconds) = approx 1 screenshot per second

ubuntu:~/crbug> node test.js
timing.... URL: https://www.shadertoy.com/embed/MdX3Rr?gui=true&t=10&paused=false&muted=false captured 100 screenshots , not saving screenshot to file completed in: : 1:25.527 (m:ss.mmm)
(100 screenshot in 84 seconds) = approx 1 screenshot per second

ubuntu:~/crbug> node test.js
timing.... URL: https://www.example.com captured 100 screenshots , saving screenshot to file completed in: : 12.972s
(100 screenshot in 12 seconds) = approx 8 screenshots per second

ubuntu:~/crbug> node test.js
timing.... URL: https://www.example.com captured 100 screenshots , not saving screenshot to file completed in: : 12.378s
(100 screenshot in 12 seconds) = approx 8 screenshots per second

ubuntu:~/crbug> node test.js
timing.... URL: https://glslsandbox.com/e#92266.0 captured 100 screenshots , saving screenshot to file completed in: : 17.034s
(100 screenshot in 12 seconds) = approx 6 screenshots per second

ubuntu:~/crbug> node test.js
timing.... URL: https://glslsandbox.com/e#92266.0 captured 100 screenshots , not saving screenshot to file completed in: : 16.478s
(100 screenshot in 12 seconds) = approx 6 screenshots per second

CHROME COMMAND LINE:
google-chrome --headless --use-gl=egl --remote-debugging-port=9222 --remote-debugging-address=0.0.0.0 --run-all-compositor-stages-before-draw

TEST CODE:

const CDP = require('chrome-remote-interface');
const file = require('fs');

const format = 'png';
const viewportWidth = 1920;
const viewportHeight = 1080;

const url = 'https://www.example.com';
//const url = 'https://www.shadertoy.com/embed/MdX3Rr?gui=true&t=10&paused=false&muted=false';
//const url = 'https://glslsandbox.com/e#92266.0';
const iterations = 100
const saveScreenshotToFile = true

// Start the Chrome Debugging Protocol
CDP(async function (client) {
// Extract used DevTools domains.
const {DOM, Emulation, Network, Page} = client;

// Enable events on domains we are interested in.
await Page.enable();
await DOM.enable();
await Network.enable();

await Page.navigate({url});

Page.loadEventFired(async () => {
const deviceMetrics = {
width: viewportWidth,
height: viewportHeight,
deviceScaleFactor: 1,
mobile: false,
fitWindow: false,
};

await Emulation.setDeviceMetricsOverride(deviceMetrics);
await Emulation.setVisibleSize({width: viewportWidth, height: viewportHeight});
await Emulation.setDefaultBackgroundColorOverride({color: {r: 0, g: 0, b: 0, a: 0}});

console.time(`timing.... URL: ${url} captured ${iterations} screenshots ${(saveScreenshotToFile) ? ', saving screenshot to file' : ', not saving screenshot to file'} completed in: `)
for (let i = 0; i < iterations; i++) {
// get the base64 screenshot.
const screenshot = await Page.captureScreenshot({format});

const buffer = new Buffer.from(screenshot.data, 'base64');
if (saveScreenshotToFile) {
// Save the base64 screenshot to binary image file
file.writeFile(`screenshot${i}.png`, buffer, 'base64', function (err) {
if (err) {
console.error(err);
} else {
//console.log('Screenshot saved');
}
});
}
}
console.timeEnd(`timing.... URL: ${url} captured ${iterations} screenshots ${(saveScreenshotToFile) ? ', saving screenshot to file' : ', not saving screenshot to file'} completed in: `)
client.close();

});
}).on('error', err => {
console.error('Cannot connect to browser:', err);
});

Thanks


Andrew Stuart
Andrew...@supercoders.com.au


Eric Seckler

unread,
Oct 14, 2022, 7:23:39 AM10/14/22
to headless-dev, Andrew Stuart, Andrey Kosyakov
+caseq for vis

Andrey Kosyakov

unread,
Oct 14, 2022, 6:18:22 PM10/14/22
to Eric Seckler, headless-dev, Andrew Stuart
Hi Andrew,

Thanks for your repro, I played with it a bit. While there are many factors why we won't be able to get anywhere near chrome frame throughput (e.g. GPU readbacks having considerable latency and the fact that unlike a lot of cases where chrome saves time by producing frames incrementally, we have to read the entire viewport), it looks like one of the larger contributing factors is PNG encoding. Here's how the profile looks on your repro:

image.png

Interestingly, JPEG is considerably faster than PNG. I think we would be able to help with this at least to some extent by tweaking PNG encoding parameters. I've been able to get about ~2x speedup on your benchmark by disabling PNG row filtering and lowering compression level down to 1, so we may implement an option to favor speed over size when producing a PNG. May I ask you to file this as a bug at https://crbug.com/?

Best regards,
Andrey.

Duke Dougal

unread,
Oct 14, 2022, 11:27:26 PM10/14/22
to headless-dev, ca...@chromium.org, headless-dev, Andrew Stuart, Eric Seckler
Reply all
Reply to author
Forward
0 new messages