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, AreaSelectionAggregator} from '../../public/selection'; 18import {CPU_SLICE_TRACK_KIND} from '../../public/track_kinds'; 19import {Engine} from '../../trace_processor/engine'; 20 21export class WattsonProcessSelectionAggregator 22 implements AreaSelectionAggregator 23{ 24 readonly id = 'wattson_process_aggregation'; 25 26 async createAggregateView(engine: Engine, area: AreaSelection) { 27 await engine.query(`drop view if exists ${this.id};`); 28 29 const selectedCpus: number[] = []; 30 for (const trackInfo of area.tracks) { 31 trackInfo?.tags?.kind === CPU_SLICE_TRACK_KIND && 32 exists(trackInfo.tags.cpu) && 33 selectedCpus.push(trackInfo.tags.cpu); 34 } 35 if (selectedCpus.length === 0) return false; 36 37 const cpusCsv = `(` + selectedCpus.join() + `)`; 38 const duration = area.end - area.start; 39 40 // Prerequisite tables are already generated by Wattson thread aggregation, 41 // which is run prior to execution of this module 42 engine.query(` 43 INCLUDE PERFETTO MODULE wattson.curves.idle_attribution; 44 INCLUDE PERFETTO MODULE wattson.curves.estimates; 45 46 -- Only get idle attribution in user defined window and filter by selected 47 -- CPUs and GROUP BY process 48 CREATE OR REPLACE PERFETTO TABLE _per_process_idle_attribution AS 49 SELECT 50 ROUND(SUM(idle_cost_mws), 2) as idle_cost_mws, 51 upid 52 FROM _filter_idle_attribution(${area.start}, ${duration}) 53 WHERE cpu in ${cpusCsv} 54 GROUP BY upid; 55 56 -- Grouped by UPID and made CPU agnostic 57 CREATE VIEW ${this.id} AS 58 SELECT 59 ROUND(SUM(total_pws) / ${duration}, 2) as active_mw, 60 ROUND(SUM(total_pws) / 1000000000, 2) as active_mws, 61 COALESCE(idle_cost_mws, 0) as idle_cost_mws, 62 ROUND( 63 COALESCE(idle_cost_mws, 0) + SUM(total_pws) / 1000000000, 64 2 65 ) as total_mws, 66 pid, 67 process_name 68 FROM _unioned_per_cpu_total 69 LEFT JOIN _per_process_idle_attribution USING (upid) 70 GROUP BY upid; 71 `); 72 73 return true; 74 } 75 76 getColumnDefinitions(): ColumnDef[] { 77 return [ 78 { 79 title: 'Process Name', 80 kind: 'STRING', 81 columnConstructor: Uint16Array, 82 columnId: 'process_name', 83 }, 84 { 85 title: 'PID', 86 kind: 'NUMBER', 87 columnConstructor: Uint16Array, 88 columnId: 'pid', 89 }, 90 { 91 title: 'Active power (estimated mW)', 92 kind: 'NUMBER', 93 columnConstructor: Float64Array, 94 columnId: 'active_mw', 95 sum: true, 96 }, 97 { 98 title: 'Active energy (estimated mWs)', 99 kind: 'NUMBER', 100 columnConstructor: Float64Array, 101 columnId: 'active_mws', 102 sum: true, 103 }, 104 { 105 title: 'Idle transitions overhead (estimated mWs)', 106 kind: 'NUMBER', 107 columnConstructor: Float64Array, 108 columnId: 'idle_cost_mws', 109 sum: true, 110 }, 111 { 112 title: 'Total energy (estimated mWs)', 113 kind: 'NUMBER', 114 columnConstructor: Float64Array, 115 columnId: 'total_mws', 116 sum: true, 117 }, 118 ]; 119 } 120 121 async getExtra() {} 122 123 getTabName() { 124 return 'Wattson by process'; 125 } 126 127 getDefaultSorting(): Sorting { 128 return {column: 'active_mws', direction: 'DESC'}; 129 } 130} 131