• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2021 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {createAggregationToTabAdaptor} from '../../components/aggregation_adapter';
16import {
17  metricsFromTableOrSubquery,
18  QueryFlamegraph,
19} from '../../components/query_flamegraph';
20import {PerfettoPlugin} from '../../public/plugin';
21import {AreaSelection, areaSelectionsEqual} from '../../public/selection';
22import {Trace} from '../../public/trace';
23import {SLICE_TRACK_KIND} from '../../public/track_kinds';
24import {Flamegraph} from '../../widgets/flamegraph';
25import {CounterSelectionAggregator} from './counter_selection_aggregator';
26import {PivotTableTab} from './pivot_table_tab';
27import {SliceSelectionAggregator} from './slice_selection_aggregator';
28
29/**
30 * This plugin adds the generic aggregations for slice tracks and counter
31 * tracks.
32 */
33export default class implements PerfettoPlugin {
34  static readonly id = 'dev.perfetto.GenericAggregations';
35
36  async onTraceLoad(ctx: Trace): Promise<void> {
37    ctx.selection.registerAreaSelectionTab(
38      createAggregationToTabAdaptor(ctx, new CounterSelectionAggregator()),
39    );
40
41    ctx.selection.registerAreaSelectionTab(
42      createAggregationToTabAdaptor(ctx, new SliceSelectionAggregator()),
43    );
44
45    ctx.selection.registerAreaSelectionTab(new PivotTableTab(ctx));
46    ctx.selection.registerAreaSelectionTab(createSliceFlameGraphPanel(ctx));
47  }
48}
49
50function createSliceFlameGraphPanel(trace: Trace) {
51  let previousSelection: AreaSelection | undefined;
52  let sliceFlamegraph: QueryFlamegraph | undefined;
53  return {
54    id: 'slice_flamegraph_selection',
55    name: 'Slice Flamegraph',
56    render(selection: AreaSelection) {
57      const selectionChanged =
58        previousSelection === undefined ||
59        !areaSelectionsEqual(previousSelection, selection);
60      previousSelection = selection;
61      if (selectionChanged) {
62        sliceFlamegraph = computeSliceFlamegraph(trace, selection);
63      }
64
65      if (sliceFlamegraph === undefined) {
66        return undefined;
67      }
68
69      return {isLoading: false, content: sliceFlamegraph.render()};
70    },
71  };
72}
73
74function computeSliceFlamegraph(trace: Trace, currentSelection: AreaSelection) {
75  const trackIds = [];
76  for (const trackInfo of currentSelection.tracks) {
77    if (trackInfo?.tags?.kind !== SLICE_TRACK_KIND) {
78      continue;
79    }
80    if (trackInfo.tags?.trackIds === undefined) {
81      continue;
82    }
83    trackIds.push(...trackInfo.tags.trackIds);
84  }
85  if (trackIds.length === 0) {
86    return undefined;
87  }
88  const metrics = metricsFromTableOrSubquery(
89    `
90      (
91        select *
92        from _viz_slice_ancestor_agg!((
93          select s.id, s.dur
94          from slice s
95          left join slice t on t.parent_id = s.id
96          where s.ts >= ${currentSelection.start}
97            and s.ts <= ${currentSelection.end}
98            and s.track_id in (${trackIds.join(',')})
99            and t.id is null
100        ))
101      )
102    `,
103    [
104      {
105        name: 'Duration',
106        unit: 'ns',
107        columnName: 'self_dur',
108      },
109      {
110        name: 'Samples',
111        unit: '',
112        columnName: 'self_count',
113      },
114    ],
115    'include perfetto module viz.slices;',
116  );
117  return new QueryFlamegraph(trace, metrics, {
118    state: Flamegraph.createDefaultState(metrics),
119  });
120}
121