• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2024 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 {Trace} from '../../public/trace';
16import {PerfettoPlugin} from '../../public/plugin';
17import {CounterOptions} from '../../components/tracks/base_counter_track';
18import {TrackNode} from '../../public/workspace';
19import {createQueryCounterTrack} from '../../components/tracks/query_counter_track';
20import StandardGroupsPlugin from '../dev.perfetto.StandardGroups';
21import {NUM, STR} from '../../trace_processor/query_result';
22
23export default class implements PerfettoPlugin {
24  static readonly id = 'dev.perfetto.CpuidleTimeInState';
25  static readonly dependencies = [StandardGroupsPlugin];
26
27  private async addCounterTrack(
28    ctx: Trace,
29    name: string,
30    query: string,
31    group: TrackNode,
32    options?: Partial<CounterOptions>,
33  ) {
34    const uri = `/cpuidle_time_in_state_${name}`;
35    const track = await createQueryCounterTrack({
36      trace: ctx,
37      uri,
38      data: {
39        sqlSource: query,
40        columns: ['ts', 'value'],
41      },
42      columns: {ts: 'ts', value: 'value'},
43      options,
44    });
45    ctx.tracks.registerTrack({
46      uri,
47      title: name,
48      track,
49    });
50    const node = new TrackNode({uri, title: name});
51    group.addChildInOrder(node);
52  }
53
54  async addIdleStateTrack(
55    ctx: Trace,
56    state: string,
57    group: TrackNode,
58  ): Promise<void> {
59    await this.addCounterTrack(
60      ctx,
61      `cpuidle.${state}`,
62      `
63        select
64          ts,
65          idle_percentage as value
66        from linux_cpu_idle_time_in_state_counters
67        where state = '${state}'
68      `,
69      group,
70      {unit: 'percent', yOverrideMaximum: 100, yOverrideMinimum: 0},
71    );
72  }
73
74  async addPerCpuIdleStateTrack(
75    ctx: Trace,
76    state: string,
77    cpu: number,
78    group: TrackNode,
79  ): Promise<void> {
80    await this.addCounterTrack(
81      ctx,
82      `cpuidle.cpu${cpu}.${state} Residency`,
83      `
84        select
85          ts,
86          idle_percentage as value
87        from linux_per_cpu_idle_time_in_state_counters
88        where state = '${state}' AND cpu = ${cpu}
89      `,
90      group,
91      {unit: 'percent', yOverrideMaximum: 100, yOverrideMinimum: 0},
92    );
93  }
94
95  async onTraceLoad(ctx: Trace): Promise<void> {
96    const group = new TrackNode({
97      title: 'CPU Idle Time In State',
98      isSummary: true,
99    });
100
101    const e = ctx.engine;
102    await e.query(`INCLUDE PERFETTO MODULE linux.cpu.idle_time_in_state;`);
103    const states = await e.query(
104      `select distinct state from linux_cpu_idle_time_in_state_counters`,
105    );
106    const it = states.iter({state: STR});
107    for (; it.valid(); it.next()) {
108      await this.addIdleStateTrack(ctx, it.state, group);
109    }
110
111    if (group.hasChildren) {
112      const cpuGroup = ctx.plugins
113        .getPlugin(StandardGroupsPlugin)
114        .getOrCreateStandardGroup(ctx.workspace, 'CPU');
115      cpuGroup.addChildInOrder(group);
116    }
117
118    const perCpuGroup = new TrackNode({
119      title: 'CPU Idle Per Cpu Time In State',
120      isSummary: true,
121    });
122
123    const perCpuStates = await e.query(
124      `select distinct state, cpu from linux_per_cpu_idle_time_in_state_counters`,
125    );
126    const pIt = perCpuStates.iter({state: STR, cpu: NUM});
127
128    for (; pIt.valid(); pIt.next()) {
129      await this.addPerCpuIdleStateTrack(ctx, pIt.state, pIt.cpu, perCpuGroup);
130    }
131
132    if (perCpuGroup.hasChildren) {
133      const cpuGroup = ctx.plugins
134        .getPlugin(StandardGroupsPlugin)
135        .getOrCreateStandardGroup(ctx.workspace, 'CPU');
136      cpuGroup.addChildInOrder(perCpuGroup);
137    }
138  }
139}
140