Skip to content

Commit b7af8c7

Browse files
Adriana IxbaDevtools-frontend LUCI CQ
authored andcommitted
[RPP] Adds entity to network and main chart tooltips
network tooltip: https://screenshot.googleplex.com/BQ62tG765YonHZL main track tooltip: https://screenshot.googleplex.com/67SnHs453rQvNGv Bug:370805066 Change-Id: I2faebdae3bda8e0a50954027d93cac323428a9db Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6216980 Reviewed-by: Paul Irish <[email protected]> Commit-Queue: Paul Irish <[email protected]>
1 parent 87f2450 commit b7af8c7

23 files changed

+202
-66
lines changed

front_end/models/trace/handlers/helpers.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import * as Types from '../types/types.js';
88

99
import type {ParsedTrace} from './types.js';
1010

11-
export type Entity = typeof ThirdPartyWeb.ThirdPartyWeb.entities[number];
11+
export type Entity = typeof ThirdPartyWeb.ThirdPartyWeb.entities[number]&{
12+
isUnrecognized?: boolean,
13+
};
1214

1315
export interface EntityMappings {
1416
createdEntityCache: Map<string, Entity>;

front_end/panels/timeline/CompatibilityTracksAppender.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ export class CompatibilityTracksAppender {
202202
#layoutShiftsTrackAppender: LayoutShiftsTrackAppender;
203203
#threadAppenders: ThreadAppender[] = [];
204204
#serverTimingsTrackAppender: ServerTimingsTrackAppender;
205+
#entityMapper: TimelineUtils.EntityMapper.EntityMapper|null;
205206

206207
/**
207208
* @param flameChartData the data used by the flame chart renderer on
@@ -215,12 +216,15 @@ export class CompatibilityTracksAppender {
215216
* is needed only for compatibility with the legacy flamechart
216217
* architecture and should be removed once all tracks use the new
217218
* system.
219+
* @param entityMapper 3P entity data for the trace.
218220
*/
219221
constructor(
220222
flameChartData: PerfUI.FlameChart.FlameChartTimelineData, parsedTrace: Trace.Handlers.Types.ParsedTrace,
221-
entryData: Trace.Types.Events.Event[], legacyEntryTypeByLevel: EntryType[]) {
223+
entryData: Trace.Types.Events.Event[], legacyEntryTypeByLevel: EntryType[],
224+
entityMapper: TimelineUtils.EntityMapper.EntityMapper|null) {
222225
this.#flameChartData = flameChartData;
223226
this.#parsedTrace = parsedTrace;
227+
this.#entityMapper = entityMapper;
224228
this.#entryData = entryData;
225229
this.#colorGenerator = new Common.Color.Generator(
226230
/* hueSpace= */ {min: 30, max: 55, count: undefined},
@@ -659,13 +663,14 @@ export class CompatibilityTracksAppender {
659663
'');
660664
if (url) {
661665
const MAX_PATH_LENGTH = 45;
662-
const MAX_ORIGIN_LENGTH = 30;
663666
const path = Platform.StringUtilities.trimMiddle(url.href.replace(url.origin, ''), MAX_PATH_LENGTH);
664-
const origin =
665-
Platform.StringUtilities.trimEndWithMaxLength(url.origin.replace('https://', ''), MAX_ORIGIN_LENGTH);
666667
const urlElems = document.createElement('div');
667668
urlElems.createChild('span', 'popoverinfo-url-path').textContent = path;
668-
urlElems.createChild('span', 'popoverinfo-url-origin').textContent = `(${origin})`;
669+
const entity = this.#entityMapper ? this.#entityMapper.entityForEvent(event) : null;
670+
// Include entity with origin if it's non made-up entity, otherwise there'd be
671+
// repetition with the origin.
672+
const originWithEntity = TimelineUtils.Helpers.formatOriginWithEntity(url, entity);
673+
urlElems.createChild('span', 'popoverinfo-url-origin').textContent = `(${originWithEntity})`;
669674
info.additionalElements.push(urlElems);
670675
}
671676

front_end/panels/timeline/TimelineFlameChartDataProvider.test.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
1818
it('returns the correct events for tree views given a flame chart group', async function() {
1919
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
2020
const {parsedTrace} = await TraceLoader.traceEngine(this, 'sync-like-timings.json.gz');
21-
dataProvider.setModel(parsedTrace);
21+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
22+
dataProvider.setModel(parsedTrace, entityMapper);
2223
const timingsTrackGroup = dataProvider.timelineData().groups.find(g => g.name === 'Timings');
2324
if (!timingsTrackGroup) {
2425
assert.fail('Could not find Timings track flame chart group');
@@ -36,7 +37,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
3637
it('filters out async events if they cannot be added to the tree', async function() {
3738
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
3839
const {parsedTrace} = await TraceLoader.traceEngine(this, 'timings-track.json.gz');
39-
dataProvider.setModel(parsedTrace);
40+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
41+
dataProvider.setModel(parsedTrace, entityMapper);
4042
const timingsTrackGroup = dataProvider.timelineData().groups.find(g => g.name === 'Timings');
4143
if (!timingsTrackGroup) {
4244
assert.fail('Could not find Timings track flame chart group');
@@ -52,7 +54,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
5254
setupIgnoreListManagerEnvironment();
5355
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
5456
const {parsedTrace} = await TraceLoader.traceEngine(this, 'one-second-interaction.json.gz');
55-
dataProvider.setModel(parsedTrace);
57+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
58+
dataProvider.setModel(parsedTrace, entityMapper);
5659

5760
// Need to use an index that is not a frame, so jump past the frames.
5861
const event = dataProvider.eventByIndex(100);
@@ -63,7 +66,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
6366
setupIgnoreListManagerEnvironment();
6467
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
6568
const {parsedTrace} = await TraceLoader.traceEngine(this, 'extension-tracks-and-marks.json.gz');
66-
dataProvider.setModel(parsedTrace);
69+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
70+
dataProvider.setModel(parsedTrace, entityMapper);
6771
const groupNames = dataProvider.timelineData().groups.map(g => g.name);
6872
assert.deepEqual(
6973
groupNames,
@@ -89,7 +93,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
8993
setupIgnoreListManagerEnvironment();
9094
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
9195
const {parsedTrace} = await TraceLoader.traceEngine(this, 'one-second-interaction.json.gz');
92-
dataProvider.setModel(parsedTrace);
96+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
97+
dataProvider.setModel(parsedTrace, entityMapper);
9398
// Force the track appenders to run and populate the chart data.
9499
dataProvider.timelineData();
95100

@@ -105,7 +110,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
105110
setupIgnoreListManagerEnvironment();
106111
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
107112
const {parsedTrace} = await TraceLoader.traceEngine(this, 'one-second-interaction.json.gz');
108-
dataProvider.setModel(parsedTrace);
113+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
114+
dataProvider.setModel(parsedTrace, entityMapper);
109115
dataProvider.timelineData();
110116

111117
const {entryDecorations} = dataProvider.timelineData();
@@ -137,7 +143,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
137143
it('populates the frames track with frames and screenshots', async function() {
138144
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
139145
const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz');
140-
dataProvider.setModel(parsedTrace);
146+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
147+
dataProvider.setModel(parsedTrace, entityMapper);
141148
const framesTrack = dataProvider.timelineData().groups.find(g => {
142149
return g.name.includes('Frames');
143150
});
@@ -164,14 +171,15 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
164171

165172
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
166173
const {parsedTrace} = await TraceLoader.traceEngine(this, 'react-hello-world.json.gz');
167-
dataProvider.setModel(parsedTrace);
174+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
175+
dataProvider.setModel(parsedTrace, entityMapper);
168176

169177
const eventCountBeforeIgnoreList = dataProvider.timelineData().entryStartTimes.length;
170178

171179
const SCRIPT_TO_IGNORE = urlString`https://unpkg.com/[email protected]/umd/react.development.js`;
172180
// Clear the data provider cache and add the React script to the ignore list.
173181
dataProvider.reset();
174-
dataProvider.setModel(parsedTrace);
182+
dataProvider.setModel(parsedTrace, entityMapper);
175183
ignoreListManager.ignoreListURL(SCRIPT_TO_IGNORE);
176184

177185
const eventCountAfterIgnoreList = dataProvider.timelineData().entryStartTimes.length;
@@ -181,7 +189,7 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
181189

182190
// Clear the data provider cache and unignore the script again
183191
dataProvider.reset();
184-
dataProvider.setModel(parsedTrace);
192+
dataProvider.setModel(parsedTrace, entityMapper);
185193
ignoreListManager.unIgnoreListURL(SCRIPT_TO_IGNORE);
186194
// Ensure that now we have un-ignored the URL that we get the full set of events again.
187195
assert.strictEqual(dataProvider.timelineData().entryStartTimes.length, eventCountBeforeIgnoreList);
@@ -191,8 +199,9 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
191199
it('filters navigations to only return those that happen on the main frame', async function() {
192200
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
193201
const {parsedTrace} = await TraceLoader.traceEngine(this, 'multiple-navigations-with-iframes.json.gz');
202+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
194203

195-
dataProvider.setModel(parsedTrace);
204+
dataProvider.setModel(parsedTrace, entityMapper);
196205

197206
const mainFrameID = parsedTrace.Meta.mainFrameId;
198207
const navigationEvents = dataProvider.mainFrameNavigationStartEvents();
@@ -205,7 +214,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
205214
it('can search for entries within a given time-range', async function() {
206215
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
207216
const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev-with-commit.json.gz');
208-
dataProvider.setModel(parsedTrace);
217+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
218+
dataProvider.setModel(parsedTrace, entityMapper);
209219

210220
const bounds = parsedTrace.Meta.traceBounds;
211221
const filter = new Timeline.TimelineFilters.TimelineRegExp(/Evaluate script/);
@@ -217,7 +227,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
217227
it('delete annotations associated with an event', async function() {
218228
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
219229
const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev-with-commit.json.gz');
220-
dataProvider.setModel(parsedTrace);
230+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
231+
dataProvider.setModel(parsedTrace, entityMapper);
221232
const entryIndex = 0;
222233
const eventToFindAssociatedEntriesFor = dataProvider.eventByIndex(entryIndex);
223234
const event = dataProvider.eventByIndex(1);
@@ -245,7 +256,8 @@ describeWithEnvironment('TimelineFlameChartDataProvider', function() {
245256
it('correctly identifies if an event has annotations', async function() {
246257
const dataProvider = new Timeline.TimelineFlameChartDataProvider.TimelineFlameChartDataProvider();
247258
const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev-with-commit.json.gz');
248-
dataProvider.setModel(parsedTrace);
259+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
260+
dataProvider.setModel(parsedTrace, entityMapper);
249261
const eventIndex = 0;
250262
const event = dataProvider.eventByIndex(eventIndex);
251263
assert.exists(event);

front_end/panels/timeline/TimelineFlameChartDataProvider.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
138138
private lastSelection: Selection|null = null;
139139
readonly #font = `${PerfUI.Font.DEFAULT_FONT_SIZE} ${PerfUI.Font.getFontFamilyForCanvas()}`;
140140
#eventIndexByEvent: WeakMap<Trace.Types.Events.Event, number|null> = new WeakMap();
141+
#entityMapper: Utils.EntityMapper.EntityMapper|null = null;
141142

142143
constructor() {
143144
super();
@@ -399,14 +400,15 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
399400
return Object.assign(defaultGroupStyle, extra);
400401
}
401402

402-
setModel(parsedTrace: Trace.Handlers.Types.ParsedTrace): void {
403+
setModel(parsedTrace: Trace.Handlers.Types.ParsedTrace, entityMapper: Utils.EntityMapper.EntityMapper): void {
403404
this.reset();
404405
this.parsedTrace = parsedTrace;
405406
const {traceBounds} = parsedTrace.Meta;
406407
const minTime = Trace.Helpers.Timing.microToMilli(traceBounds.min);
407408
const maxTime = Trace.Helpers.Timing.microToMilli(traceBounds.max);
408409
this.#minimumBoundary = minTime;
409410
this.timeSpan = minTime === maxTime ? 1000 : maxTime - this.#minimumBoundary;
411+
this.#entityMapper = entityMapper;
410412
}
411413

412414
/**
@@ -424,7 +426,7 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
424426
}
425427
this.timelineDataInternal = this.#instantiateTimelineData();
426428
this.compatibilityTracksAppender = new CompatibilityTracksAppender(
427-
this.timelineDataInternal, this.parsedTrace, this.entryData, this.entryTypeByLevel);
429+
this.timelineDataInternal, this.parsedTrace, this.entryData, this.entryTypeByLevel, this.#entityMapper);
428430
}
429431
return this.compatibilityTracksAppender;
430432
}
@@ -540,6 +542,7 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
540542
this.compatibilityTracksAppender = null;
541543
this.timelineDataInternal = null;
542544
this.parsedTrace = null;
545+
this.#entityMapper = null;
543546
}
544547

545548
maxStackDepth(): number {

front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.test.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ describeWithEnvironment('TimelineFlameChartNetworkDataProvider', function() {
1212
it('renders the network track correctly', async function() {
1313
const dataProvider = new Timeline.TimelineFlameChartNetworkDataProvider.TimelineFlameChartNetworkDataProvider();
1414
const {parsedTrace} = await TraceLoader.traceEngine(this, 'load-simple.json.gz');
15+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
1516

1617
const minTime = Trace.Helpers.Timing.microToMilli(parsedTrace.Meta.traceBounds.min);
1718
const maxTime = Trace.Helpers.Timing.microToMilli(parsedTrace.Meta.traceBounds.max);
1819

19-
dataProvider.setModel(parsedTrace);
20+
dataProvider.setModel(parsedTrace, entityMapper);
2021
dataProvider.setWindowTimes(minTime, maxTime);
2122

2223
// TimelineFlameChartNetworkDataProvider only has network track, so should always be one track group.
@@ -57,7 +58,8 @@ describeWithEnvironment('TimelineFlameChartNetworkDataProvider', function() {
5758
it('can return the group for a given entryIndex', async function() {
5859
const dataProvider = new Timeline.TimelineFlameChartNetworkDataProvider.TimelineFlameChartNetworkDataProvider();
5960
const {parsedTrace} = await TraceLoader.traceEngine(this, 'load-simple.json.gz');
60-
dataProvider.setModel(parsedTrace);
61+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
62+
dataProvider.setModel(parsedTrace, entityMapper);
6163
dataProvider.timelineData();
6264

6365
assert.strictEqual(
@@ -69,11 +71,12 @@ describeWithEnvironment('TimelineFlameChartNetworkDataProvider', function() {
6971
it('filters navigations to only return those that happen on the main frame', async function() {
7072
const dataProvider = new Timeline.TimelineFlameChartNetworkDataProvider.TimelineFlameChartNetworkDataProvider();
7173
const {parsedTrace} = await TraceLoader.traceEngine(this, 'multiple-navigations-with-iframes.json.gz');
74+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
7275

7376
const minTime = Trace.Helpers.Timing.microToMilli(parsedTrace.Meta.traceBounds.min);
7477
const maxTime = Trace.Helpers.Timing.microToMilli(parsedTrace.Meta.traceBounds.max);
7578

76-
dataProvider.setModel(parsedTrace);
79+
dataProvider.setModel(parsedTrace, entityMapper);
7780
dataProvider.setWindowTimes(minTime, maxTime);
7881

7982
const mainFrameID = parsedTrace.Meta.mainFrameId;
@@ -87,7 +90,8 @@ describeWithEnvironment('TimelineFlameChartNetworkDataProvider', function() {
8790
it('can provide the index for an event and the event for a given index', async function() {
8891
const dataProvider = new Timeline.TimelineFlameChartNetworkDataProvider.TimelineFlameChartNetworkDataProvider();
8992
const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz');
90-
dataProvider.setModel(parsedTrace);
93+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
94+
dataProvider.setModel(parsedTrace, entityMapper);
9195

9296
const event = dataProvider.eventByIndex(0);
9397
assert.isOk(event);
@@ -97,11 +101,12 @@ describeWithEnvironment('TimelineFlameChartNetworkDataProvider', function() {
97101
it('does not render the network track if there is no network requests', async function() {
98102
const dataProvider = new Timeline.TimelineFlameChartNetworkDataProvider.TimelineFlameChartNetworkDataProvider();
99103
const {parsedTrace} = await TraceLoader.traceEngine(this, 'basic.json.gz');
104+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
100105

101106
const minTime = Trace.Helpers.Timing.microToMilli(parsedTrace.Meta.traceBounds.min);
102107
const maxTime = Trace.Helpers.Timing.microToMilli(parsedTrace.Meta.traceBounds.max);
103108

104-
dataProvider.setModel(parsedTrace);
109+
dataProvider.setModel(parsedTrace, entityMapper);
105110
dataProvider.setWindowTimes(minTime, maxTime);
106111

107112
// Network track appender won't append the network track if there is no network requests.
@@ -178,7 +183,8 @@ describeWithEnvironment('TimelineFlameChartNetworkDataProvider', function() {
178183
it('can search for entries within a given time-range', async function() {
179184
const dataProvider = new Timeline.TimelineFlameChartNetworkDataProvider.TimelineFlameChartNetworkDataProvider();
180185
const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev-with-commit.json.gz');
181-
dataProvider.setModel(parsedTrace);
186+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
187+
dataProvider.setModel(parsedTrace, entityMapper);
182188
const boundsMs = Trace.Helpers.Timing.traceWindowMilliSeconds(parsedTrace.Meta.traceBounds);
183189
dataProvider.setWindowTimes(boundsMs.min, boundsMs.max);
184190

@@ -191,7 +197,8 @@ describeWithEnvironment('TimelineFlameChartNetworkDataProvider', function() {
191197
it('delete annotations associated with an event', async function() {
192198
const dataProvider = new Timeline.TimelineFlameChartNetworkDataProvider.TimelineFlameChartNetworkDataProvider();
193199
const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev-with-commit.json.gz');
194-
dataProvider.setModel(parsedTrace);
200+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
201+
dataProvider.setModel(parsedTrace, entityMapper);
195202
const entryIndex = 0;
196203
const eventToFindAssociatedEntriesFor = dataProvider.eventByIndex(entryIndex);
197204
const event = dataProvider.eventByIndex(1);
@@ -220,7 +227,8 @@ describeWithEnvironment('TimelineFlameChartNetworkDataProvider', function() {
220227
it('correctly identifies if an event has annotations', async function() {
221228
const dataProvider = new Timeline.TimelineFlameChartNetworkDataProvider.TimelineFlameChartNetworkDataProvider();
222229
const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev-with-commit.json.gz');
223-
dataProvider.setModel(parsedTrace);
230+
const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace);
231+
dataProvider.setModel(parsedTrace, entityMapper);
224232
const eventIndex = 0;
225233
const event = dataProvider.eventByIndex(eventIndex);
226234
const event2 = dataProvider.eventByIndex(1);

0 commit comments

Comments
 (0)