Skip to content
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

core: support traces with TracingStartedInBrowser event #5271

Merged
merged 5 commits into from
Jun 4, 2018

Conversation

a1ph
Copy link
Contributor

@a1ph a1ph commented May 19, 2018

Since version 67 Chrome uses a new schema to describe page frame tree.
The tree is encoded within TracingStartedInBrowser trace event.
The patch makes lighthouse to support the new event.
Legacy TracingStartedInPage event is going to the removed soon.

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the PR!

@@ -45,18 +45,30 @@ class TraceOfTab extends ComputedArtifact {
.filter(e => {
return e.cat.includes('blink.user_timing') ||
e.cat.includes('loading') ||
e.cat.includes('devtools.timeline') ||
e.name === 'TracingStartedInPage';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think you don't want to filter this out to support the legacy case? Or in the fallback case need to search for the first TracingStartedInPage in the original trace.traceEvents

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, does the filter now need to let through e.name === 'TracingStartedInBrowser' events?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both TracingStartedInPage and TracingStartedInBrowser are in devtools.timeline category which is already allowed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like it was in toplevel once upon a time based on the fixture change below?

my traces from ~December have it in disabled-by-default-devtools.timeline so I guess it's a question of how far back we want to go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT TracingStartedInPage was introduced 4 years ago with devtools.timeline category. See https://codereview.chromium.org/254613002/diff/90001/Source/core/inspector/InspectorTracingAgent.cpp
I wonder where the traces with it being in toplevel come from?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, no clue then 🤷‍♂️ 4 years is plenty good enough for me 😆

// Find out the inspected page frame.
let startedInPageEvt;
const startedInBrowserEvt = keyEvents.find(e => e.name === 'TracingStartedInBrowser');
if (startedInBrowserEvt && startedInBrowserEvt.args.data.persistentIds) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the significance of persistentIds? doesn't appear to be used anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used to have a TracingStartedInBrowser event before, but with no frames information. persistentIds is a marker that frames are provided.

const startedInBrowserEvt = keyEvents.find(e => e.name === 'TracingStartedInBrowser');
if (startedInBrowserEvt && startedInBrowserEvt.args.data.persistentIds) {
const mainFrame = (startedInBrowserEvt.args.data.frames || []).find(frame => !frame.parent);
const mainFrameId = mainFrame && mainFrame.frame || '';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the use of the fallback '' value here if there's no mainFrame or mainFrameId found? Seems like we need those and should just throw if not found

(or could set startedInPageEvt to undefined and let the legacy fallback below try to find a backup TracingStartedInPage event)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

// Beware: the tracingStartedInPage event can appear slightly after a navigationStart
startedInPageEvt = keyEvents.find(e => e.name === 'TracingStartedInPage');
if (!startedInPageEvt) throw new LHError(LHError.errors.NO_TRACING_STARTED);
// @ts-ignore - property chain exists for 'TracingStartedInPage' event.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two lines above should be pulled out of the conditional (throw if no startedInPageEvt found, // @ts-ignore comment is for the const frameId = line below)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't really matter as when we didn't enter the if block the startedInPageEvt is already there. Anyway, I will move it.

@a1ph a1ph changed the title core: Support traces with TracingStartedInBrowser event core: support traces with TracingStartedInBrowser event May 23, 2018
@a1ph a1ph force-pushed the master branch 2 times, most recently from 6840233 to 678d4aa Compare May 23, 2018 23:27
@@ -16,6 +16,8 @@ const preactTrace = require('../../fixtures/traces/preactjs.com_ts_of_undefined.
const noFMPtrace = require('../../fixtures/traces/no_fmp_event.json');
const noFCPtrace = require('../../fixtures/traces/airhorner_no_fcp');
const backgroundTabTrace = require('../../fixtures/traces/backgrounded-tab-missing-paints');
const tracingStartedInBrowserTrace =
require('../../fixtures/traces/tracing-started-in-browser.json');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this whole fixture is just to exercise that one event right?

could we use a reduced trace or even just a fake array of events for this? 6k lines for the 1 relevant event is a lot :)

@@ -45,18 +45,30 @@ class TraceOfTab extends ComputedArtifact {
.filter(e => {
return e.cat.includes('blink.user_timing') ||
e.cat.includes('loading') ||
e.cat.includes('devtools.timeline') ||
e.name === 'TracingStartedInPage';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like it was in toplevel once upon a time based on the fixture change below?

my traces from ~December have it in disabled-by-default-devtools.timeline so I guess it's a question of how far back we want to go

@@ -106,12 +121,13 @@ class TraceOfTab extends ComputedArtifact {
// stable-sort events to keep them correctly nested.
/** @type Array<LH.TraceEvent> */
const processEvents = trace.traceEvents
// @ts-ignore - property chain exists for 'TracingStartedInPage' event.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm, we shouldn't need the ts-ignore for .pid, what was the error you're suppressing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error TS2532: Object is possibly 'undefined'.

Copy link
Collaborator

@patrickhulce patrickhulce May 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh because startedInPageEvt is LH.TraceEvent|undefined and we're accessing inside a closure :/

seems like we just need progress on microsoft/TypeScript#11498, mind replacing the ts-ignore explanation with that link or casting instead? /** @type {LH.TraceEvent} */ (startedInPageEvt).pid (same for .tid below)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can annotate. I surprised the compiler hasn't noticed if (!startedInPageEvt) throw

Copy link
Collaborator

@patrickhulce patrickhulce May 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It knows, it's just that there's no mechanism for telling if the callback will be invoked asynchronously or just once synchronously.

const filtered = []
for (const e of events) if (e.pid === startedInPageEvt.pid) filtered.push(e)

works fine

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, they still do a lot simpler CFG work than closure, focusing almost entirely locally, so things like this still trip them up even while being more sophisticated in other ways :)

@a1ph a1ph force-pushed the master branch 2 times, most recently from 26c4539 to 9f252e3 Compare May 24, 2018 18:19
// The first TracingStartedInPage in the trace is definitely our renderer thread of interest
// Beware: the tracingStartedInPage event can appear slightly after a navigationStart
startedInPageEvt = keyEvents.find(e => e.name === 'TracingStartedInPage');
}
if (!startedInPageEvt) throw new LHError(LHError.errors.NO_TRACING_STARTED);
// @ts-ignore - property chain exists for 'TracingStartedInPage' event.
const frameId = startedInPageEvt.args.data.page;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the casts are annoying, could also do something like

 /** @type {LH.TraceEvent|undefined} */
let possibleStartedInPageEvt;
...

above, and then here

const startedInPageEvt = possibleStartedInPageEvt;

because the compiler will know that possibleStartedInPageEvt is definitely defined at this point, the type for startedInPageEvt will be inferred correctly as LH.TraceEvent, and then it won't need any casts below this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered that, but I didn't want to introduce more code to workaround compiler issues. I'm fine with casts.

Copy link
Collaborator

@patrickhulce patrickhulce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! thanks for helping us out here @a1ph! 👍

'args': {'name': 'CrRendererMain'},
}]};
const trace = await traceOfTab.compute_(tracingStartedInBrowserTrace);
assert.equal(trace.startedInPageEvt.ts, 2193564729582);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

want to assert the navStart is found and in the trace.mainThreadEvents since I assume that's what the thread_name addition was for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Since version 67 Chrome uses a new schema to describe page frame tree.
The tree is encoded within TracingStartedInBrowser trace event.
The patch makes lighthouse to support the new event.
Legacy TracingStartedInPage event is going to the removed soon.
@patrickhulce
Copy link
Collaborator

@brendankenny does this look good to go to you?

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a few style nits, but otherwise LGTM! Thanks for making the change

.filter(e => {
return e.cat.includes('blink.user_timing') ||
.filter(e =>
e.cat.includes('blink.user_timing') ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally for multi-line arrow function we keep the curly braces/return for clarity. Any reason to drop it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

let startedInPageEvt;
const startedInBrowserEvt = keyEvents.find(e => e.name === 'TracingStartedInBrowser');
if (startedInBrowserEvt && startedInBrowserEvt.args.data &&
startedInBrowserEvt.args.data.persistentIds) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment about why persistentIds is significant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I talked to dgozman, it was added to ensure this is a new version of the event that carries frames. I think we can just check for frames field being there.

const threadNameEvt = keyEvents.find(e => e.pid === pid && e.ph === 'M' &&
e.cat === '__metadata' && e.name === 'thread_name' &&
// @ts-ignore - property chain exists for 'thread_name' event.
e.args.name === 'CrRendererMain');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since it's just a single level into args, add name?: string to args in externs.d.ts instead of @ts-ignore here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@patrickhulce
Copy link
Collaborator

oops you got some conflicts now @a1ph! I had fixed the feedback before you pushed sorry!

Since version 67 Chrome uses a new schema to describe page frame tree.
The tree is encoded within TracingStartedInBrowser trace event.
The patch makes lighthouse to support the new event.
Legacy TracingStartedInPage event is going to the removed soon.
@patrickhulce
Copy link
Collaborator

thanks @a1ph!

@patrickhulce patrickhulce merged commit df631a0 into GoogleChrome:master Jun 4, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants