aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarkiran Bolaria <hbolaria@google.com>2023-07-05 09:03:37 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2023-07-05 09:03:37 +0000
commit09c5009206a83f6015904b7dda8e111681ec4da9 (patch)
tree3a5fc9c682ec5f4d2633e7d401a25a110cf49c93
parent5d69a9365ef1755ec0cd393df2e41e8e5ff45385 (diff)
parente817b0258b75e3a73a90c2bd1a008c0601e97c8b (diff)
downloadperfetto-09c5009206a83f6015904b7dda8e111681ec4da9.tar.gz
Merge "[Part 1] Add slice linking to scroll jank plugin slices."
-rw-r--r--ui/src/tracks/chrome_scroll_jank/event_latency_slice.ts189
-rw-r--r--ui/src/tracks/chrome_scroll_jank/event_latency_track.ts21
-rw-r--r--ui/src/tracks/chrome_scroll_jank/index.ts47
-rw-r--r--ui/src/tracks/chrome_scroll_jank/scroll_track.ts14
-rw-r--r--ui/src/tracks/chrome_scroll_jank/top_level_jank_track.ts15
-rw-r--r--ui/src/tracks/chrome_scroll_jank/top_level_janky_event_latencies_details_panel.ts257
-rw-r--r--ui/src/tracks/chrome_scroll_jank/top_level_janky_event_latencies_track.ts53
7 files changed, 564 insertions, 32 deletions
diff --git a/ui/src/tracks/chrome_scroll_jank/event_latency_slice.ts b/ui/src/tracks/chrome_scroll_jank/event_latency_slice.ts
new file mode 100644
index 000000000..046ef23bc
--- /dev/null
+++ b/ui/src/tracks/chrome_scroll_jank/event_latency_slice.ts
@@ -0,0 +1,189 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import m from 'mithril';
+
+import {assertExists} from '../../base/logging';
+import {Actions} from '../../common/actions';
+import {EngineProxy} from '../../common/engine';
+import {LONG, NUM} from '../../common/query_result';
+import {TPDuration} from '../../common/time';
+import {Anchor} from '../../frontend/anchor';
+import {globals} from '../../frontend/globals';
+import {scrollToTrackAndTs} from '../../frontend/scroll_helper';
+import {Icons} from '../../frontend/semantic_icons';
+import {asTPTimestamp, SliceSqlId, TPTimestamp} from '../../frontend/sql_types';
+
+import {
+ EventLatencyTrack,
+} from './event_latency_track';
+import {ScrollJankPluginState} from './index';
+
+export interface EventLatencySlice {
+ // Chrome slice id for an EventLatency slice.
+ sliceId: SliceSqlId;
+ // Timestamp of the beginning of this slice in nanoseconds.
+ ts: TPTimestamp;
+ // Duration of this slice in nanoseconds.
+ dur: TPDuration;
+}
+
+export async function getEventLatencySlice(
+ engine: EngineProxy, id: number): Promise<EventLatencySlice|undefined> {
+ const eventLatencyTrack =
+ ScrollJankPluginState.getInstance().getTrack(EventLatencyTrack.kind);
+ if (eventLatencyTrack == undefined) {
+ throw new Error(`${EventLatencyTrack.kind} track is not registered.`);
+ }
+
+ const query = await engine.query(`
+ SELECT
+ id as sliceId,
+ ts,
+ dur as dur
+ FROM ${eventLatencyTrack.sqlTableName}
+ WHERE id=${id}`);
+ const it = query.iter({
+ sliceId: NUM,
+ ts: LONG,
+ dur: LONG,
+ });
+
+ const result: EventLatencySlice[] = [];
+
+ for (; it.valid(); it.next()) {
+ result.push({
+ sliceId: it.sliceId as SliceSqlId,
+ ts: asTPTimestamp(it.ts),
+ dur: it.dur,
+ });
+ }
+
+ if (result.length > 1) {
+ throw new Error(`${
+ eventLatencyTrack.sqlTableName} table has more than one row with id ${
+ id}`);
+ }
+ if (result.length === 0) {
+ return undefined;
+ }
+ return result[0];
+}
+
+export async function getEventLatencyDescendantSlice(
+ engine: EngineProxy, id: number, descendant: string|undefined):
+ Promise<EventLatencySlice|undefined> {
+ const query = await engine.query(`
+ SELECT
+ id as sliceId,
+ ts,
+ dur as dur
+ FROM descendant_slice(${id})
+ WHERE name='${descendant}'`);
+ const it = query.iter({
+ sliceId: NUM,
+ ts: LONG,
+ dur: LONG,
+ });
+
+ const result: EventLatencySlice[] = [];
+
+ for (; it.valid(); it.next()) {
+ result.push({
+ sliceId: it.sliceId as SliceSqlId,
+ ts: asTPTimestamp(it.ts),
+ dur: it.dur,
+ });
+ }
+
+ const eventLatencyTrack =
+ ScrollJankPluginState.getInstance().getTrack(EventLatencyTrack.kind);
+ if (eventLatencyTrack == undefined) {
+ throw new Error(`${EventLatencyTrack.kind} track is not registered.`);
+ }
+
+ if (result.length > 1) {
+ throw new Error(`
+ Slice table and track view ${
+ eventLatencyTrack
+ .sqlTableName} has more than one descendant of slice id ${
+ id} with name ${descendant}`);
+ }
+ if (result.length === 0) {
+ return undefined;
+ }
+ return result[0];
+}
+
+interface EventLatencySliceRefAttrs {
+ id: SliceSqlId;
+ ts: TPTimestamp;
+ // If not present, a placeholder name will be used.
+ name: string;
+ chromeSliceTrackId?: number;
+}
+
+export class EventLatencySliceRef implements
+ m.ClassComponent<EventLatencySliceRefAttrs> {
+ view(vnode: m.Vnode<EventLatencySliceRefAttrs>) {
+ return m(
+ Anchor,
+ {
+ icon: Icons.UpdateSelection,
+ onclick: () => {
+ const eventLatencyTrack =
+ ScrollJankPluginState.getInstance().getTrack(
+ EventLatencyTrack.kind);
+ if (eventLatencyTrack == undefined) {
+ throw new Error(
+ `${EventLatencyTrack.kind} track is not registered.`);
+ }
+
+ const trackIdx = vnode.attrs.chromeSliceTrackId as number;
+ assertExists(trackIdx);
+ const uiTrackId = globals.state.uiTrackIdByTraceTrackId[trackIdx];
+ if (uiTrackId === undefined) return;
+ globals.makeSelection(Actions.selectChromeSlice(
+ {id: vnode.attrs.id, trackId: uiTrackId, table: 'slice'}));
+
+ let trackId = '';
+ for (const track of Object.values(globals.state.tracks)) {
+ if (track.kind === EventLatencyTrack.kind) {
+ trackId = track.id;
+ }
+ }
+
+ if (trackId === '') {
+ throw new Error(
+ `Track id for ${EventLatencyTrack.kind} track not found.`);
+ }
+
+ scrollToTrackAndTs(trackId, vnode.attrs.ts, true);
+ },
+ },
+ vnode.attrs.name,
+ );
+ }
+}
+
+export function eventLatencySlice(
+ state: EventLatencySlice, name: string, chromeSliceTrackId?: number):
+ m.Child {
+ return m(EventLatencySliceRef, {
+ id: state.sliceId,
+ ts: state.ts,
+ name: name,
+ chromeSliceTrackId: chromeSliceTrackId,
+ });
+}
diff --git a/ui/src/tracks/chrome_scroll_jank/event_latency_track.ts b/ui/src/tracks/chrome_scroll_jank/event_latency_track.ts
index c784527fc..7250819d8 100644
--- a/ui/src/tracks/chrome_scroll_jank/event_latency_track.ts
+++ b/ui/src/tracks/chrome_scroll_jank/event_latency_track.ts
@@ -19,12 +19,14 @@ import {
generateSqlWithInternalLayout,
} from '../../common/internal_layout_utils';
import {PrimaryTrackSortKey, SCROLLING_TRACK_GROUP} from '../../common/state';
+import {ChromeSliceDetailsTab} from '../../frontend/chrome_slice_details_tab';
import {
NamedSliceTrack,
NamedSliceTrackTypes,
} from '../../frontend/named_slice_track';
import {NewTrackArgs, Track} from '../../frontend/track';
import {ScrollJankTracks as DecideTracksResult} from './index';
+import {ScrollJankPluginState} from './index';
export interface EventLatencyTrackTypes extends NamedSliceTrackTypes {
config: {baseTable: string;}
@@ -39,6 +41,23 @@ export class EventLatencyTrack extends NamedSliceTrack<EventLatencyTrackTypes> {
constructor(args: NewTrackArgs) {
super(args);
+ ScrollJankPluginState.getInstance().registerTrack({
+ kind: EventLatencyTrack.kind,
+ trackId: this.trackId,
+ tableName: this.tableName,
+ detailsPanelConfig: {
+ kind: ChromeSliceDetailsTab.kind,
+ config: {
+ title: 'Input Event Latency Slice',
+ sqlTableName: this.tableName,
+ },
+ },
+ });
+ }
+
+ onDestroy() {
+ super.onDestroy();
+ ScrollJankPluginState.getInstance().unregisterTrack(EventLatencyTrack.kind);
}
async initSqlTable(tableName: string) {
@@ -126,7 +145,7 @@ export async function addLatencyTracks(engine: Engine):
engineId: engine.id,
kind: EventLatencyTrack.kind,
trackSortKey: PrimaryTrackSortKey.NULL_TRACK,
- name: 'Chrome Input Event Latencies',
+ name: 'Chrome Scroll Input Latencies',
config: {baseTable: baseTable},
trackGroup: SCROLLING_TRACK_GROUP,
});
diff --git a/ui/src/tracks/chrome_scroll_jank/index.ts b/ui/src/tracks/chrome_scroll_jank/index.ts
index b6c816d82..c72bb698e 100644
--- a/ui/src/tracks/chrome_scroll_jank/index.ts
+++ b/ui/src/tracks/chrome_scroll_jank/index.ts
@@ -18,6 +18,8 @@ import {featureFlags} from '../../common/feature_flags';
import {
PluginContext,
} from '../../public';
+import {ObjectById} from '../../common/state';
+import {CustomSqlDetailsPanelConfig} from '../custom_sql_table_slices';
import {ChromeTasksScrollJankTrack} from './chrome_tasks_scroll_jank_track';
import {addLatencyTracks, EventLatencyTrack} from './event_latency_track';
@@ -50,6 +52,51 @@ export type ScrollJankTracks = {
tracksToAdd: AddTrackArgs[],
};
+export interface ScrollJankTrackSpec {
+ id: string;
+ sqlTableName: string;
+ detailsPanelConfig: CustomSqlDetailsPanelConfig;
+}
+
+// Global state for the scroll jank plugin.
+export class ScrollJankPluginState {
+ private static instance: ScrollJankPluginState;
+ private tracks: ObjectById<ScrollJankTrackSpec>;
+
+ private constructor() {
+ this.tracks = {};
+ }
+
+ public static getInstance(): ScrollJankPluginState {
+ if (!ScrollJankPluginState.instance) {
+ ScrollJankPluginState.instance = new ScrollJankPluginState();
+ }
+
+ return ScrollJankPluginState.instance;
+ }
+
+ public registerTrack(args: {
+ kind: string,
+ trackId: string,
+ tableName: string,
+ detailsPanelConfig: CustomSqlDetailsPanelConfig,
+ }): void {
+ this.tracks[args.kind] = {
+ id: args.trackId,
+ sqlTableName: args.tableName,
+ detailsPanelConfig: args.detailsPanelConfig,
+ };
+ }
+
+ public unregisterTrack(kind: string): void {
+ delete this.tracks[kind];
+ }
+
+ public getTrack(kind: string): ScrollJankTrackSpec|undefined {
+ return this.tracks[kind];
+ }
+}
+
export async function getScrollJankTracks(engine: Engine):
Promise<ScrollJankTracks> {
const result: ScrollJankTracks = {
diff --git a/ui/src/tracks/chrome_scroll_jank/scroll_track.ts b/ui/src/tracks/chrome_scroll_jank/scroll_track.ts
index e63dfa100..be3d6f6ad 100644
--- a/ui/src/tracks/chrome_scroll_jank/scroll_track.ts
+++ b/ui/src/tracks/chrome_scroll_jank/scroll_track.ts
@@ -30,6 +30,7 @@ import {
CustomSqlTableDefConfig,
CustomSqlTableSliceTrack,
} from '../custom_sql_table_slices';
+import {ScrollJankPluginState} from './index';
import {ScrollJankTracks as DecideTracksResult} from './index';
@@ -65,13 +66,22 @@ export class TopLevelScrollTrack extends
constructor(args: NewTrackArgs) {
super(args);
+ ScrollJankPluginState.getInstance().registerTrack({
+ kind: TopLevelScrollTrack.kind,
+ trackId: this.trackId,
+ tableName: this.tableName,
+ detailsPanelConfig: this.getDetailsPanel(),
+ });
+
this.displayColumns['id'] = {displayName: 'Scroll Id (gesture_scroll_id)'};
this.displayColumns['ts'] = {displayName: 'Start time'};
this.displayColumns['dur'] = {displayName: 'Duration'};
}
- async initSqlTable(tableName: string) {
- await super.initSqlTable(tableName);
+ onDestroy() {
+ super.onDestroy();
+ ScrollJankPluginState.getInstance().unregisterTrack(
+ TopLevelScrollTrack.kind);
}
}
diff --git a/ui/src/tracks/chrome_scroll_jank/top_level_jank_track.ts b/ui/src/tracks/chrome_scroll_jank/top_level_jank_track.ts
index 848f1d381..050f08d24 100644
--- a/ui/src/tracks/chrome_scroll_jank/top_level_jank_track.ts
+++ b/ui/src/tracks/chrome_scroll_jank/top_level_jank_track.ts
@@ -27,6 +27,7 @@ import {
CustomSqlTableDefConfig,
CustomSqlTableSliceTrack,
} from '../custom_sql_table_slices';
+import {ScrollJankPluginState} from './index';
import {ScrollJankTracks as DecideTracksResult} from './index';
@@ -46,6 +47,13 @@ export class TopLevelJankTrack extends
constructor(args: NewTrackArgs) {
super(args);
+ ScrollJankPluginState.getInstance().registerTrack({
+ kind: TopLevelJankTrack.kind,
+ trackId: this.trackId,
+ tableName: this.tableName,
+ detailsPanelConfig: this.getDetailsPanel(),
+ });
+
this.displayColumns['name'] = {};
this.displayColumns['id'] = {displayName: 'Interval ID'};
this.displayColumns['ts'] = {displayName: 'Start time'};
@@ -69,8 +77,9 @@ export class TopLevelJankTrack extends
};
}
- async initSqlTable(tableName: string) {
- await super.initSqlTable(tableName);
+ onDestroy() {
+ super.onDestroy();
+ ScrollJankPluginState.getInstance().unregisterTrack(TopLevelJankTrack.kind);
}
}
@@ -91,7 +100,7 @@ export async function addTopLevelJankTrack(engine: Engine):
FROM chrome_scrolling_intervals
UNION ALL
SELECT
- "Janky Scrolling Time" AS name,
+ "Janky Frame Visible" AS name,
ts,
dur
FROM chrome_scroll_jank_intervals_v3
diff --git a/ui/src/tracks/chrome_scroll_jank/top_level_janky_event_latencies_details_panel.ts b/ui/src/tracks/chrome_scroll_jank/top_level_janky_event_latencies_details_panel.ts
new file mode 100644
index 000000000..e6a895f19
--- /dev/null
+++ b/ui/src/tracks/chrome_scroll_jank/top_level_janky_event_latencies_details_panel.ts
@@ -0,0 +1,257 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import m from 'mithril';
+
+import {exists} from '../../base/utils';
+import {EngineProxy} from '../../common/engine';
+import {LONG, NUM, STR, STR_NULL} from '../../common/query_result';
+import {
+ TPDuration,
+ tpDurationFromSql,
+ TPTime,
+ tpTimeFromSql,
+} from '../../common/time';
+import {
+ BottomTab,
+ bottomTabRegistry,
+ NewBottomTabArgs,
+} from '../../frontend/bottom_tab';
+import {
+ GenericSliceDetailsTabConfig,
+} from '../../frontend/generic_slice_details_tab';
+import {getSlice, SliceDetails, sliceRef} from '../../frontend/sql/slice';
+import {asSliceSqlId, asTPTimestamp} from '../../frontend/sql_types';
+import {sqlValueToString} from '../../frontend/sql_utils';
+import {DetailsShell} from '../../frontend/widgets/details_shell';
+import {Duration} from '../../frontend/widgets/duration';
+import {GridLayout} from '../../frontend/widgets/grid_layout';
+import {Section} from '../../frontend/widgets/section';
+import {SqlRef} from '../../frontend/widgets/sql_ref';
+import {Timestamp} from '../../frontend/widgets/timestamp';
+import {dictToTreeNodes, Tree, TreeNode} from '../../frontend/widgets/tree';
+
+import {
+ eventLatencySlice,
+ EventLatencySlice,
+ getEventLatencyDescendantSlice,
+ getEventLatencySlice,
+} from './event_latency_slice';
+import {ScrollJankPluginState} from './index';
+import {
+ TopLevelEventLatencyTrack,
+} from './top_level_janky_event_latencies_track';
+import {raf} from '../../core/raf_scheduler';
+
+interface Data {
+ id: number;
+ // The slice display name - the cause + subcause of jank.
+ name: string;
+ // The stage of EventLatency that is the cause of jank.
+ jankCause: string;
+ // Where possible, the subcause of jank.
+ jankSubcause: string;
+ // The slice type - e.g. EventLatency
+ type: string;
+ // Timestamp of the beginning of this slice in nanoseconds.
+ ts: TPTime;
+ // Duration of this slice in nanoseconds.
+ dur: TPDuration;
+}
+
+async function getSliceDetails(
+ engine: EngineProxy, id: number): Promise<SliceDetails|undefined> {
+ return getSlice(engine, asSliceSqlId(id));
+}
+
+export class JankyEventLatenciesDetailsPanel extends
+ BottomTab<GenericSliceDetailsTabConfig> {
+ static readonly kind = 'org.perfetto.JankyEventLatenciesDetailsPanel';
+ static title = 'Chrome Scroll Jank Causes';
+ private loaded = false;
+ private sliceDetails?: SliceDetails;
+ private eventLatencySliceDetails?: EventLatencySlice;
+ private causeSliceDetails?: EventLatencySlice;
+ private subcauseSliceDetails?: EventLatencySlice;
+
+ data: Data|undefined;
+
+ static create(args: NewBottomTabArgs): JankyEventLatenciesDetailsPanel {
+ return new JankyEventLatenciesDetailsPanel(args);
+ }
+
+ constructor(args: NewBottomTabArgs) {
+ super(args);
+ this.loadData();
+ }
+
+ private async loadData() {
+ const trackDetails = ScrollJankPluginState.getInstance().getTrack(
+ TopLevelEventLatencyTrack.kind);
+
+ const queryResult = await this.engine.query(`
+ SELECT
+ id,
+ name,
+ jank_cause AS jankCause,
+ jank_subcause AS jankSubcause,
+ type,
+ ts,
+ dur
+ FROM ${trackDetails?.sqlTableName} where id = ${this.config.id}`);
+
+ const iter = queryResult.firstRow({
+ id: NUM,
+ name: STR,
+ jankCause: STR,
+ jankSubcause: STR_NULL,
+ type: STR,
+ ts: LONG,
+ dur: LONG,
+ });
+ this.data = {
+ id: iter.id,
+ name: iter.name,
+ jankCause: iter.jankCause,
+ jankSubcause: iter.jankSubcause,
+ type: iter.type,
+ ts: iter.ts,
+ dur: iter.dur,
+ } as Data;
+
+ await this.loadSlices();
+ this.loaded = true;
+
+ raf.scheduleFullRedraw();
+ }
+
+ private hasCause(): boolean {
+ if (this.data === undefined) {
+ return false;
+ }
+ return this.data.jankCause !== 'UNKNOWN';
+ }
+
+ private hasSubcause(): boolean {
+ return this.hasCause() && this.data?.jankSubcause !== undefined;
+ }
+
+ private async loadSlices() {
+ this.sliceDetails = await getSliceDetails(this.engine, this.config.id);
+ this.eventLatencySliceDetails =
+ await getEventLatencySlice(this.engine, this.config.id);
+
+ if (this.hasCause()) {
+ this.causeSliceDetails = await getEventLatencyDescendantSlice(
+ this.engine, this.config.id, this.data?.jankCause);
+ }
+
+ if (this.hasSubcause()) {
+ this.subcauseSliceDetails = await getEventLatencyDescendantSlice(
+ this.engine, this.config.id, this.data?.jankSubcause);
+ }
+ }
+
+ viewTab() {
+ if (this.data === undefined) {
+ return m('h2', 'Loading');
+ }
+
+ const detailsDict: {[key: string]: m.Child} = {
+ 'Janked Event Latency stage':
+ exists(this.sliceDetails) && exists(this.causeSliceDetails) ?
+ eventLatencySlice(
+ this.causeSliceDetails,
+ this.data.jankCause,
+ this.sliceDetails.sqlTrackId) :
+ sqlValueToString(this.data.jankCause),
+ };
+
+ if (sqlValueToString(this.data.jankSubcause) != 'NULL') {
+ detailsDict['Sub-cause of Jank'] =
+ exists(this.sliceDetails) && exists(this.subcauseSliceDetails) ?
+ eventLatencySlice(
+ this.subcauseSliceDetails,
+ this.data.jankSubcause,
+ this.sliceDetails.sqlTrackId) :
+ sqlValueToString(this.data.jankSubcause);
+ }
+
+ detailsDict['Start time'] =
+ m(Timestamp, {ts: asTPTimestamp(tpTimeFromSql(this.data.ts))});
+ detailsDict['Duration'] =
+ m(Duration, {dur: tpDurationFromSql(this.data.dur)});
+ detailsDict['Slice Type'] = sqlValueToString(this.data.type as string);
+
+ const details = dictToTreeNodes(detailsDict);
+
+ if (exists(this.sliceDetails)) {
+ details.push(m(TreeNode, {
+ left: sliceRef(this.sliceDetails, 'Original EventLatency'),
+ right: '',
+ }));
+ if (exists(this.eventLatencySliceDetails)) {
+ details.push(m(TreeNode, {
+ left: eventLatencySlice(
+ this.eventLatencySliceDetails,
+ 'Chrome Input Event Latencies',
+ this.sliceDetails.sqlTrackId),
+ right: '',
+ }));
+ }
+ }
+
+ // TODO(b/278844325): add links to the correct process/track for cause.
+
+ return m(
+ DetailsShell,
+ {
+ title: JankyEventLatenciesDetailsPanel.title,
+ },
+ m(
+ GridLayout,
+ m(
+ Section,
+ {title: 'Details'},
+ m(Tree, details),
+ ),
+ m(
+ Section,
+ {title: 'Metadata'},
+ m(Tree, [m(TreeNode, {
+ left: 'SQL ID',
+ right: m(SqlRef, {
+ table: 'chrome_janky_event_latencies_v3',
+ id: this.config.id,
+ }),
+ })]),
+ ),
+ ),
+ );
+ }
+
+ getTitle(): string {
+ return `Current Selection`;
+ }
+
+ isLoading() {
+ return this.loaded;
+ }
+
+ renderTabCanvas() {
+ return;
+ }
+}
+
+bottomTabRegistry.register(JankyEventLatenciesDetailsPanel);
diff --git a/ui/src/tracks/chrome_scroll_jank/top_level_janky_event_latencies_track.ts b/ui/src/tracks/chrome_scroll_jank/top_level_janky_event_latencies_track.ts
index 8577fd195..45bbae8e9 100644
--- a/ui/src/tracks/chrome_scroll_jank/top_level_janky_event_latencies_track.ts
+++ b/ui/src/tracks/chrome_scroll_jank/top_level_janky_event_latencies_track.ts
@@ -19,10 +19,6 @@ import {
PrimaryTrackSortKey,
SCROLLING_TRACK_GROUP,
} from '../../common/state';
-import {
- Columns,
- GenericSliceDetailsTab,
-} from '../../frontend/generic_slice_details_tab';
import {NamedSliceTrackTypes} from '../../frontend/named_slice_track';
import {NewTrackArgs, Track} from '../../frontend/track';
import {
@@ -31,12 +27,15 @@ import {
CustomSqlTableSliceTrack,
} from '../custom_sql_table_slices';
+import {ScrollJankPluginState} from './index';
import {ScrollJankTracks as DecideTracksResult} from './index';
+import {
+ JankyEventLatenciesDetailsPanel,
+} from './top_level_janky_event_latencies_details_panel';
export class TopLevelEventLatencyTrack extends
CustomSqlTableSliceTrack<NamedSliceTrackTypes> {
static readonly kind = 'org.chromium.ScrollJank.top_level_event_latencies';
- displayColumns: Columns = {};
static create(args: NewTrackArgs): Track {
return new TopLevelEventLatencyTrack(args);
@@ -44,27 +43,29 @@ export class TopLevelEventLatencyTrack extends
constructor(args: NewTrackArgs) {
super(args);
- this.displayColumns['cause_of_jank'] = {displayName: 'Cause of Jank'};
- this.displayColumns['sub_cause_of_jank'] = {
- displayName: 'Sub-cause of Jank',
- };
- this.displayColumns['id'] = {displayName: 'Slice ID'};
- this.displayColumns['ts'] = {displayName: 'Start time'};
- this.displayColumns['dur'] = {displayName: 'Duration'};
- this.displayColumns['type'] = {displayName: 'Slice Type'};
+ ScrollJankPluginState.getInstance().registerTrack({
+ kind: TopLevelEventLatencyTrack.kind,
+ trackId: this.trackId,
+ tableName: this.tableName,
+ detailsPanelConfig: this.getDetailsPanel(),
+ });
}
getSqlDataSource(): CustomSqlTableDefConfig {
return {
columns: [
- 'id',
- 'ts',
- 'dur',
- 'track_id',
- 'cause_of_jank || IIF(sub_cause_of_jank IS NOT NULL, "::" || sub_cause_of_jank, "") AS name',
- 'cause_of_jank',
- 'name AS type',
- 'sub_cause_of_jank',
+ `id`,
+ `ts`,
+ `dur`,
+ `track_id`,
+ `IIF(
+ cause_of_jank IS NOT NULL,
+ cause_of_jank || IIF(
+ sub_cause_of_jank IS NOT NULL, "::" || sub_cause_of_jank, ""
+ ), "UNKNOWN") AS name`,
+ `IFNULL(cause_of_jank, "UNKNOWN") AS jank_cause`,
+ `name AS type`,
+ `sub_cause_of_jank AS jank_subcause`,
],
sqlTableName: 'chrome_janky_event_latencies_v3',
};
@@ -72,17 +73,18 @@ export class TopLevelEventLatencyTrack extends
getDetailsPanel(): CustomSqlDetailsPanelConfig {
return {
- kind: GenericSliceDetailsTab.kind,
+ kind: JankyEventLatenciesDetailsPanel.kind,
config: {
sqlTableName: this.tableName,
title: 'Chrome Scroll Jank Event Latency: Cause',
- columns: this.displayColumns,
},
};
}
- async initSqlTable(tableName: string) {
- super.initSqlTable(tableName);
+ onDestroy() {
+ super.onDestroy();
+ ScrollJankPluginState.getInstance().unregisterTrack(
+ TopLevelEventLatencyTrack.kind);
}
}
@@ -94,7 +96,6 @@ export async function addJankyLatenciesTrack(engine: Engine):
await engine.query(`SELECT IMPORT('chrome.chrome_scroll_janks');`);
-
result.tracksToAdd.push({
id: uuidv4(),
engineId: engine.id,