New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there a way to measure page performance? #309

Closed
inikulin opened this Issue Aug 16, 2017 · 20 comments

Comments

Projects
None yet
@inikulin

inikulin commented Aug 16, 2017

Is there a way to get numbers for time before DOMContentLoaded and load events? First paint time would be nice as well. I see that there is page.tracing API, but it produces Chrome trace file. For my task I need only two numbers mentioned above and in format that I can easily parse (e.g. JSON) and without necessity for disk I/O. Something like page.getMetrics() -> Promise<{DOMContentLoadedTime, loadTime}>.

@ivanvanderbyl

This comment has been minimized.

Show comment
Hide comment
@ivanvanderbyl

ivanvanderbyl Aug 16, 2017

@inikulin You could use evaluate and call window.performance.timing.

ivanvanderbyl commented Aug 16, 2017

@inikulin You could use evaluate and call window.performance.timing.

@a1ph

This comment has been minimized.

Show comment
Hide comment
@a1ph

a1ph Aug 16, 2017

Contributor

There is also Performance.getMetrics

For now it is accessible with something like:

await page._client.send('Performance.enable');
const response = await page._client.send('Performance.getMetrics');

There should be a more convenient API added later.

Contributor

a1ph commented Aug 16, 2017

There is also Performance.getMetrics

For now it is accessible with something like:

await page._client.send('Performance.enable');
const response = await page._client.send('Performance.getMetrics');

There should be a more convenient API added later.

@inikulin

This comment has been minimized.

Show comment
Hide comment
@inikulin

inikulin Aug 16, 2017

Great, thank you for replies, that works for me. I guess I can keep it open as ticket for more convenient API that others can track?

inikulin commented Aug 16, 2017

Great, thank you for replies, that works for me. I guess I can keep it open as ticket for more convenient API that others can track?

@ebidel ebidel added the question label Aug 16, 2017

@ebidel

This comment has been minimized.

Show comment
Hide comment
@ebidel

ebidel Aug 17, 2017

Member

Not sure Performance.getMetrics gives you the metrics you're after, but @ivanvanderbyl is spot on. Then add firstpaint like this:

const perf = await page.evaluate(_ => {
  return Object.assign({
    firstPaint: chrome.loadTimes().firstPaintTime * 1000 - performance.timing.navigationStart
  }, window.performance.timing); 
});
Member

ebidel commented Aug 17, 2017

Not sure Performance.getMetrics gives you the metrics you're after, but @ivanvanderbyl is spot on. Then add firstpaint like this:

const perf = await page.evaluate(_ => {
  return Object.assign({
    firstPaint: chrome.loadTimes().firstPaintTime * 1000 - performance.timing.navigationStart
  }, window.performance.timing); 
});
@pavelfeldman

This comment has been minimized.

Show comment
Hide comment
@pavelfeldman

pavelfeldman Aug 17, 2017

Contributor

@a1ph is working on delivering runtime / performance / memory stats to the puppeteer. They will be more complete and more accurate than those available via performance.timing.

Contributor

pavelfeldman commented Aug 17, 2017

@a1ph is working on delivering runtime / performance / memory stats to the puppeteer. They will be more complete and more accurate than those available via performance.timing.

@pavelfeldman pavelfeldman added feature P1 and removed question labels Aug 18, 2017

@inikulin

This comment has been minimized.

Show comment
Hide comment
@inikulin

inikulin Aug 23, 2017

Just in case if someone will encounter this problem as well: chrome object from #309 (comment) is not available in headless mode.

inikulin commented Aug 23, 2017

Just in case if someone will encounter this problem as well: chrome object from #309 (comment) is not available in headless mode.

@daliborgogic

This comment has been minimized.

Show comment
Hide comment
@daliborgogic

daliborgogic Aug 25, 2017

If you need chrome set headless to false

const browser = await headless.launch({
  headless: false
})

daliborgogic commented Aug 25, 2017

If you need chrome set headless to false

const browser = await headless.launch({
  headless: false
})

@msn0 msn0 referenced this issue Sep 13, 2017

Closed

Use puppeteer #4

@UnscientificMisaka

This comment has been minimized.

Show comment
Hide comment
@UnscientificMisaka

UnscientificMisaka Sep 21, 2017

@ebidel I cant' get window.performance in page.evaluate

await page.goto('xxx.com')  
const pref = await page.evaluate(() => {  
  return Object.assign({  
    firstPaint: chrome.loadTimes().firstPaintTime * 1000 - performance.timing.navigationStart  
  }, window.performance.timing)  
})

pref is an empty Object and when I console window, it does not have a property called performance

UnscientificMisaka commented Sep 21, 2017

@ebidel I cant' get window.performance in page.evaluate

await page.goto('xxx.com')  
const pref = await page.evaluate(() => {  
  return Object.assign({  
    firstPaint: chrome.loadTimes().firstPaintTime * 1000 - performance.timing.navigationStart  
  }, window.performance.timing)  
})

pref is an empty Object and when I console window, it does not have a property called performance

@pavelfeldman

This comment has been minimized.

Show comment
Hide comment
@pavelfeldman

pavelfeldman Sep 21, 2017

Contributor

Someone mean defined window.performance.timing as non-enumerable...

const timing = await page.evaluate(() => {
  const result = {};
  for (const key of Object.keys(window.performance.timing.__proto__))
    result[key] = window.performance.timing[key];
  return result;
});

@ak239 could you look into straightening performance.timing API the way you fixed console?

Contributor

pavelfeldman commented Sep 21, 2017

Someone mean defined window.performance.timing as non-enumerable...

const timing = await page.evaluate(() => {
  const result = {};
  for (const key of Object.keys(window.performance.timing.__proto__))
    result[key] = window.performance.timing[key];
  return result;
});

@ak239 could you look into straightening performance.timing API the way you fixed console?

@pavelfeldman

This comment has been minimized.

Show comment
Hide comment
@pavelfeldman

pavelfeldman Sep 21, 2017

Contributor

@a1ph: let's make sure chrome.loadTimes() is not required for getting this kind of perf metrics.

Contributor

pavelfeldman commented Sep 21, 2017

@a1ph: let's make sure chrome.loadTimes() is not required for getting this kind of perf metrics.

@a1ph

This comment has been minimized.

Show comment
Hide comment
@a1ph

a1ph Sep 21, 2017

Contributor

@pavelfeldman The plan is to add a wrapper into Page that invokes

await this._client.send('Performance.enable');
await this._client.send('Performance.getMetrics');
Contributor

a1ph commented Sep 21, 2017

@pavelfeldman The plan is to add a wrapper into Page that invokes

await this._client.send('Performance.enable');
await this._client.send('Performance.getMetrics');
@pavelfeldman

This comment has been minimized.

Show comment
Hide comment
@pavelfeldman

pavelfeldman Sep 21, 2017

Contributor

@a1ph: I meant that there was a clash between the chrome.loadTimes() and performance.timing apis and I was hoping we could fix it. Exposing those times via Performance.* also sounds good, but we need both.

Contributor

pavelfeldman commented Sep 21, 2017

@a1ph: I meant that there was a clash between the chrome.loadTimes() and performance.timing apis and I was hoping we could fix it. Exposing those times via Performance.* also sounds good, but we need both.

aslushnikov added a commit that referenced this issue Oct 10, 2017

feat(Page): Support Page.getMetrics and metrics event. (#939)
Provides access to the current page performance metrics.
Allows to push page metrics from the page JavaScript with console.timeStamp()

Fixes #309

ithinkihaveacat added a commit to ithinkihaveacat/puppeteer that referenced this issue Oct 31, 2017

feat(Page): Support Page.getMetrics and metrics event. (GoogleChrome#939
)

Provides access to the current page performance metrics.
Allows to push page metrics from the page JavaScript with console.timeStamp()

Fixes GoogleChrome#309
@surfmuggle

This comment has been minimized.

Show comment
Hide comment
@surfmuggle

surfmuggle Nov 24, 2017

I tried to get this script running on try-puppeteer.appspot.com but get this _error Error running your code.

  • Error: Evaluation failed: ReferenceError: chrome is not defined at _ (:3:17_).
  • after replacing chrome with browser: Error running your code. Error: Evaluation failed: ReferenceError: browser is not defined at _ (:3:17)

const browser = await puppeteer.launch();

const page = await browser.newPage();
await page._client.send('Performance.enable');
// const response = await page._client.send('Performance.getMetrics');
await page.goto('http://www.pixelpiz.de/');

// is (_ => { still the recommended syntax? 
const perf = await page.evaluate(_ => {
  return Object.assign({
    firstPaint: chrome.loadTimes().firstPaintTime * 1000 - performance.timing.navigationStart
  }, window.performance.timing); 
});
// above i replaced chrome.loadTimes with browser.loadTimes as well but this gave the same error

console.log(perf);
console.log("  --- was perf");
console.log(await page.content());
await page.screenshot({path: 'screenshot.png'});

await browser.close();

  • How can i fix the error?
  • How can i use feature #939
  • Is #939 already part of try-puppeteer v0.13.0 version?

surfmuggle commented Nov 24, 2017

I tried to get this script running on try-puppeteer.appspot.com but get this _error Error running your code.

  • Error: Evaluation failed: ReferenceError: chrome is not defined at _ (:3:17_).
  • after replacing chrome with browser: Error running your code. Error: Evaluation failed: ReferenceError: browser is not defined at _ (:3:17)

const browser = await puppeteer.launch();

const page = await browser.newPage();
await page._client.send('Performance.enable');
// const response = await page._client.send('Performance.getMetrics');
await page.goto('http://www.pixelpiz.de/');

// is (_ => { still the recommended syntax? 
const perf = await page.evaluate(_ => {
  return Object.assign({
    firstPaint: chrome.loadTimes().firstPaintTime * 1000 - performance.timing.navigationStart
  }, window.performance.timing); 
});
// above i replaced chrome.loadTimes with browser.loadTimes as well but this gave the same error

console.log(perf);
console.log("  --- was perf");
console.log(await page.content());
await page.screenshot({path: 'screenshot.png'});

await browser.close();

  • How can i fix the error?
  • How can i use feature #939
  • Is #939 already part of try-puppeteer v0.13.0 version?
@ebidel

This comment has been minimized.

Show comment
Hide comment
@ebidel

ebidel Nov 24, 2017

Member

@surfmuggle page.metrics() is the API call in 0.13.0: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagemetrics

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://www.pixelpiz.de/');
const perf = await page.metrics();
console.log(JSON.stringify(perf));
await browser.close();
``

Note: 
`chrome.loadTimes()` is being [deprecated in chrome 64](https://www.chromestatus.com/features/5637885046816768). It looks like it's not defined in headless mode.
Member

ebidel commented Nov 24, 2017

@surfmuggle page.metrics() is the API call in 0.13.0: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagemetrics

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://www.pixelpiz.de/');
const perf = await page.metrics();
console.log(JSON.stringify(perf));
await browser.close();
``

Note: 
`chrome.loadTimes()` is being [deprecated in chrome 64](https://www.chromestatus.com/features/5637885046816768). It looks like it's not defined in headless mode.
@therazor

This comment has been minimized.

Show comment
Hide comment
@therazor

therazor Dec 18, 2017

page.metrics() returns a completely different set of metrics compared to window.performance.timing though.

Are they meant to be complementary?

therazor commented Dec 18, 2017

page.metrics() returns a completely different set of metrics compared to window.performance.timing though.

Are they meant to be complementary?

@ebidel

This comment has been minimized.

Show comment
Hide comment
@ebidel

ebidel Dec 18, 2017

Member

@therazor, page.metrics() has limited data atm. You can use performance.timing for everything else. https://developers.google.com/web/updates/2017/12/chrome-loadtimes-deprecated is a new article on how to migrate from chrome.loadTimes() to performance.timing. It also covers the new paint entry types in PerformanceEntry.

Example of getting paint times:

  const paints = await page.evaluate(_ => {
    const result = {};
    performance.getEntriesByType('paint').map(entry => {
      result[entry.name] = entry.startTime;
    });
    return result;
  });

  for (const [key, val] of Object.entries(paints)) {
    console.log(`${key}: ${Math.round(val)}ms`);
  }
Member

ebidel commented Dec 18, 2017

@therazor, page.metrics() has limited data atm. You can use performance.timing for everything else. https://developers.google.com/web/updates/2017/12/chrome-loadtimes-deprecated is a new article on how to migrate from chrome.loadTimes() to performance.timing. It also covers the new paint entry types in PerformanceEntry.

Example of getting paint times:

  const paints = await page.evaluate(_ => {
    const result = {};
    performance.getEntriesByType('paint').map(entry => {
      result[entry.name] = entry.startTime;
    });
    return result;
  });

  for (const [key, val] of Object.entries(paints)) {
    console.log(`${key}: ${Math.round(val)}ms`);
  }
@twistedpair

This comment has been minimized.

Show comment
Hide comment
@twistedpair

twistedpair Mar 22, 2018

Do these metrics include information like CPU consumption for the given tab?

twistedpair commented Mar 22, 2018

Do these metrics include information like CPU consumption for the given tab?

@b4dnewz

This comment has been minimized.

Show comment
Hide comment
@b4dnewz

b4dnewz May 22, 2018

Does anyone know which is the simplest (maybe built-in) way to get DomContentLoaded and Load performance metrics?

image

Actually I've tried these two methods, the first is obtaining DomContentLoaded by sum of performance.timing values.

metrics.dnsTime = timing.domainLookupEnd - timing.domainLookupStart;
metrics.tcpTime = timing.connectEnd - timing.connectStart;
metrics.waitingTime = timing.responseStart - timing.requestStart;
metrics.contentTime = timing.responseEnd - timing.responseStart;
metrics.networkTime = (metrics.dnsTime + metrics.tcpTime + metrics.waitingTime + metrics.contentTime);

The other one is by listening at page events once and set a variable:

const start = performance.now();
const loadTime = 0;
page.once('load', () => {
    loadTime = performance.now() - start;
});
await page.goto(url, {waitUntil: 'load'});

Shouldn't this values be included in the page metrics or have an API for getting them?
Requests number, Bytes transferred, Total time to load, DOMContentLoad and Load time

b4dnewz commented May 22, 2018

Does anyone know which is the simplest (maybe built-in) way to get DomContentLoaded and Load performance metrics?

image

Actually I've tried these two methods, the first is obtaining DomContentLoaded by sum of performance.timing values.

metrics.dnsTime = timing.domainLookupEnd - timing.domainLookupStart;
metrics.tcpTime = timing.connectEnd - timing.connectStart;
metrics.waitingTime = timing.responseStart - timing.requestStart;
metrics.contentTime = timing.responseEnd - timing.responseStart;
metrics.networkTime = (metrics.dnsTime + metrics.tcpTime + metrics.waitingTime + metrics.contentTime);

The other one is by listening at page events once and set a variable:

const start = performance.now();
const loadTime = 0;
page.once('load', () => {
    loadTime = performance.now() - start;
});
await page.goto(url, {waitUntil: 'load'});

Shouldn't this values be included in the page metrics or have an API for getting them?
Requests number, Bytes transferred, Total time to load, DOMContentLoad and Load time

@liyunsheng

This comment has been minimized.

Show comment
Hide comment
@liyunsheng

liyunsheng Jul 26, 2018

@b4dnewz

const perfEntries = JSON.parse(
    await page.evaluate(() => JSON.stringify(performance.getEntries()))
);

Then you can calculate time/size.
But faild request is not in the entryList, see #417

liyunsheng commented Jul 26, 2018

@b4dnewz

const perfEntries = JSON.parse(
    await page.evaluate(() => JSON.stringify(performance.getEntries()))
);

Then you can calculate time/size.
But faild request is not in the entryList, see #417

@jeroenvermeulen

This comment has been minimized.

Show comment
Hide comment
@jeroenvermeulen

jeroenvermeulen Sep 28, 2018

This is dumping all useful info I have found:

const puppeteer = require('puppeteer');

async function run() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://www.github.com/');

  console.log("\n==== performance.getEntries() ====\n");
  console.log( await page.evaluate( () => JSON.stringify(performance.getEntries(), null, "  ") ) );

  console.log("\n==== performance.toJSON() ====\n");
  console.log( await page.evaluate( () => JSON.stringify(performance.toJSON(), null, "  ") ) );

  console.log("\n==== page.metrics() ====\n");
  const perf = await page.metrics();
  console.log( JSON.stringify(perf, null, "  ") );

  browser.close();
}

run();

jeroenvermeulen commented Sep 28, 2018

This is dumping all useful info I have found:

const puppeteer = require('puppeteer');

async function run() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://www.github.com/');

  console.log("\n==== performance.getEntries() ====\n");
  console.log( await page.evaluate( () => JSON.stringify(performance.getEntries(), null, "  ") ) );

  console.log("\n==== performance.toJSON() ====\n");
  console.log( await page.evaluate( () => JSON.stringify(performance.toJSON(), null, "  ") ) );

  console.log("\n==== page.metrics() ====\n");
  const perf = await page.metrics();
  console.log( JSON.stringify(perf, null, "  ") );

  browser.close();
}

run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment