puppeteer icon indicating copy to clipboard operation
puppeteer copied to clipboard

[Bug]: x1.5 CPU usage increase using Puppeteer between 20.8.3 to 20.9.0+

Open mostafa-hisham opened this issue 8 months ago • 16 comments

Minimal, reproducible example

import puppeteer from 'puppeteer';
import { performance } from 'perf_hooks';
import { version } from 'process';
import { readFileSync } from 'fs';
const minimal_args = [
    '--autoplay-policy=user-gesture-required',
    '--disable-background-networking',
    '--disable-background-timer-throttling',
    '--disable-backgrounding-occluded-windows',
    '--disable-breakpad',
    '--disable-client-side-phishing-detection',
    '--disable-component-update',
    '--disable-default-apps',
    '--disable-dev-shm-usage',
    '--disable-domain-reliability',
    '--disable-extensions',
    '--disable-features=AudioServiceOutOfProcess',
    '--disable-hang-monitor',
    '--disable-ipc-flooding-protection',
    '--disable-notifications',
    '--disable-offer-store-unmasked-wallet-cards',
    '--disable-popup-blocking',
    '--disable-print-preview',
    '--disable-prompt-on-repost',
    '--disable-renderer-backgrounding',
    '--disable-setuid-sandbox',
    '--disable-speech-api',
    '--disable-sync',
    '--hide-scrollbars',
    '--ignore-gpu-blacklist',
    '--metrics-recording-only',
    '--mute-audio',
    '--no-default-browser-check',
    '--no-first-run',
    '--no-pings',
    '--no-sandbox',
    '--no-zygote',
    '--password-store=basic',
    '--use-gl=swiftshader',
    '--use-mock-keychain',
    '--disable-gpu',
    '--disable-canvas-aa',
    '--disable-2d-canvas-clip-aa',
    '--disable-gl-drawing-for-tests',
    '--disable-default-apps',
    '--disable-sync',
    '--safebrowsing-disable-auto-update',
    '--disable-accelerated-2d-canvas',
];

const getPackageVersion = (name) => {
    const fileName = `node_modules/${name}/package.json`;
    const content = readFileSync(fileName);
    const json = JSON.parse(content);
    return json.version;
};

export const task = async () => {
    const URL = 'https://google.com';
    const pptrVersion = getPackageVersion('puppeteer');

    const launchOptions = {
        headless: 'shell', // or 'old' depend on the puppeteer version
        args: minimal_args,
        pipe: true
    };

    const browser = await puppeteer.launch(launchOptions);
    const browserVersion = await browser.version();
    const allPages = await browser.pages();
    const page = (allPages.length) ? allPages[0] : await browser.newPage();
    await page.setRequestInterception(true);
    page.on('request', (req) => {
        if ('wpr-saas-no-intercept' in req.headers()){
            req.continue(); // Exception for LCP Beacon script.
        } else if ((req.resourceType() !== 'script' && req.resourceType() !== 'stylesheet' && req.resourceType() !== 'document')
            ||
            (
                req.resourceType() === 'script'
                && req.initiator().type === 'script'
            )
        ) {
            req.abort();
        } else {
            req.continue();
        }
    });
    const startTime = performance.now();
    await Promise.all([
        page.coverage.startCSSCoverage(),
        page.coverage.startJSCoverage()
    ]);
    await page.goto(URL, { waitUntil: 'load' });
    
    const elements = await page.$$('*');
    const tasks = elements.map((elem) => elem.evaluate((el) => el.className));
    await Promise.all(tasks);
    const [cssCoverage, jsCoverage] = await Promise.all([
        page.coverage.stopCSSCoverage(),
        page.coverage.stopJSCoverage(),
    ]);
    const res = {
        node: version,
        puppeteer: pptrVersion,
        browser: browserVersion,
        duration: performance.now() - startTime,
        cssCoverage,
        jsCoverage
    };

    await browser.close();

    return res;
}

Error string

No error

Bug behavior

  • [ ] Flaky
  • [ ] PDF

Background

Puppeteer is used to do a task involving query elements on the page, run CSS and JS coverage, and request interception similar to the code example above. We use one browser instance and open multiple pages then close the page after the task is done, we don't create a new browser for each task.

Problem After updating Puppeteer to v22.10.0 we noticed CPU usage has around x1.5 increase The version we originally used was pretty old so we tried to track back when the CPU usage issue started

Test We changed the puppeteer version and tested it on two servers with similar specs and did the same task on the same page URLS

The following screenshots have a graph for CPU usage on both servers, the only difference between the servers during the test is the Puppeteer version

- Green (mirror) -> used to test different Puppeteer versions
- Yellow -> is always using Puppeteer v15.5.0

if we used the same puppeteer version we always have them with CPU usage equal (up to 1 : 2%)

  • both 15.5.0 (both around 40% CPU usage) image

  • Green (mirror) -> v22.10.0 (mirror is higher 60% CPU usage) image

  • Green (mirror) -> v22.10.0 with more pages opened in the browser, (mirror is higher around 70% CPU usage) image

  • Green (mirror) -> v20.9.0 (mirror is higher 60% CPU usage) image

  • Green (mirror) -> v20.8.3 (both around 40% CPU usage) image

Conclusion The x1/.5 CPU usage increase started since Puppeteer v20.9.0 with browser version HeadlessChrome/115.0.5790.98 and we still have this CPU usage increase in v22.10.0 with browser version HeadlessChrome/125.0.6422.78

similar issue https://github.com/puppeteer/puppeteer/issues/11944

Expectation

no CPU usage increase

Reality

CPU usage has around x1.5 increase

Puppeteer configuration file (if used)

const {join} = require('path');
/**
 * @type {import("puppeteer").Configuration}
 */
module.exports = {
    // Changes the cache location for Puppeteer.
    cacheDirectory: join(__dirname,'.cache', 'puppeteer'),
};

Puppeteer version

22.10.0

Node version

18.0.0

Package manager

npm

Package manager version

8.6.0

Operating system

Linux

mostafa-hisham avatar Jun 03 '24 09:06 mostafa-hisham