• 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 {exists} from '../../base/utils';
16import {ColumnDef, Sorting} from '../../public/aggregation';
17import {AreaSelection} from '../../public/selection';
18import {Engine} from '../../trace_processor/engine';
19import {NUM} from '../../trace_processor/query_result';
20import {CPU_SLICE_TRACK_KIND} from '../../public/track_kinds';
21import {AreaSelectionAggregator} from '../../public/selection';
22
23export class WattsonPackageSelectionAggregator
24  implements AreaSelectionAggregator
25{
26  readonly id = 'wattson_plugin_package_aggregation';
27
28  async createAggregateView(engine: Engine, area: AreaSelection) {
29    await engine.query(`drop view if exists ${this.id};`);
30
31    const packageInfo = await engine.query(`
32      INCLUDE PERFETTO MODULE android.process_metadata;
33      SELECT COUNT(*) as isValid FROM android_process_metadata
34      WHERE package_name IS NOT NULL
35    `);
36    if (packageInfo.firstRow({isValid: NUM}).isValid === 0) return false;
37
38    const selectedCpus: number[] = [];
39    for (const trackInfo of area.tracks) {
40      if (trackInfo?.tags?.kind === CPU_SLICE_TRACK_KIND) {
41        exists(trackInfo.tags.cpu) && selectedCpus.push(trackInfo.tags.cpu);
42      }
43    }
44    if (selectedCpus.length === 0) return false;
45
46    const duration = area.end - area.start;
47
48    // Prerequisite tables are already generated by Wattson thread aggregation,
49    // which is run prior to execution of this module
50    engine.query(`
51      -- Grouped by UID and made CPU agnostic
52      CREATE PERFETTO VIEW ${this.id} AS
53      SELECT
54        ROUND(SUM(total_pws) / ${duration}, 3) as active_mw,
55        ROUND(SUM(total_pws) / 1000000000, 3) as active_mws,
56        ROUND(SUM(dur) / 1000000.0, 3) as dur_ms,
57        uid,
58        package_name
59      FROM wattson_plugin_unioned_per_cpu_total
60      GROUP BY uid;
61    `);
62
63    return true;
64  }
65
66  getColumnDefinitions(): ColumnDef[] {
67    return [
68      {
69        title: 'Package Name',
70        kind: 'STRING',
71        columnConstructor: Uint16Array,
72        columnId: 'package_name',
73      },
74      {
75        title: 'Android app UID',
76        kind: 'NUMBER',
77        columnConstructor: Uint16Array,
78        columnId: 'uid',
79      },
80      {
81        title: 'Total Duration (ms)',
82        kind: 'NUMBER',
83        columnConstructor: Float64Array,
84        columnId: 'dur_ms',
85      },
86      {
87        title: 'Active power (estimated mW)',
88        kind: 'NUMBER',
89        columnConstructor: Float64Array,
90        columnId: 'active_mw',
91        sum: true,
92      },
93      {
94        title: 'Active energy (estimated mWs)',
95        kind: 'NUMBER',
96        columnConstructor: Float64Array,
97        columnId: 'active_mws',
98        sum: true,
99      },
100    ];
101  }
102
103  async getExtra() {}
104
105  getTabName() {
106    return 'Wattson by package';
107  }
108
109  getDefaultSorting(): Sorting {
110    return {column: 'active_mws', direction: 'DESC'};
111  }
112}
113