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 {ColumnDef, Sorting} from '../../public/aggregation'; 16import {Area, AreaSelection} from '../../public/selection'; 17import {Engine} from '../../trace_processor/engine'; 18import {CPUSS_ESTIMATE_TRACK_KIND} from '../../public/track_kinds'; 19import {AreaSelectionAggregator} from '../../public/selection'; 20import {exists} from '../../base/utils'; 21 22export class WattsonEstimateSelectionAggregator 23 implements AreaSelectionAggregator 24{ 25 readonly id = 'wattson_plugin_estimate_aggregation'; 26 27 async createAggregateView(engine: Engine, area: AreaSelection) { 28 await engine.query(`drop view if exists ${this.id};`); 29 30 const estimateTracks: string[] = []; 31 for (const trackInfo of area.tracks) { 32 if ( 33 trackInfo?.tags?.kind === CPUSS_ESTIMATE_TRACK_KIND && 34 exists(trackInfo.tags?.wattson) 35 ) { 36 estimateTracks.push(`${trackInfo.tags.wattson}`); 37 } 38 } 39 if (estimateTracks.length === 0) return false; 40 41 const query = this.getEstimateTracksQuery(area, estimateTracks); 42 engine.query(query); 43 44 return true; 45 } 46 47 getEstimateTracksQuery( 48 area: Area, 49 estimateTracks: ReadonlyArray<string>, 50 ): string { 51 const duration = area.end - area.start; 52 let query = ` 53 INCLUDE PERFETTO MODULE wattson.curves.estimates; 54 55 CREATE OR REPLACE PERFETTO TABLE wattson_plugin_ui_selection_window AS 56 SELECT 57 ${area.start} as ts, 58 ${duration} as dur; 59 60 DROP TABLE IF EXISTS wattson_plugin_windowed_cpuss_estimate; 61 CREATE VIRTUAL TABLE wattson_plugin_windowed_cpuss_estimate 62 USING 63 SPAN_JOIN(wattson_plugin_ui_selection_window, _system_state_mw); 64 65 CREATE PERFETTO VIEW ${this.id} AS 66 `; 67 68 // Convert average power track to total energy in UI window, then divide by 69 // duration of window to get average estimated power of the window 70 estimateTracks.forEach((estimateTrack, i) => { 71 if (i != 0) { 72 query += `UNION ALL `; 73 } 74 query += ` 75 SELECT 76 '${estimateTrack}' as name, 77 ROUND(SUM(${estimateTrack}_mw * dur) / ${duration}, 3) as power, 78 ROUND(SUM(${estimateTrack}_mw * dur) / 1000000000, 3) as energy 79 FROM wattson_plugin_windowed_cpuss_estimate 80 `; 81 }); 82 query += `;`; 83 84 return query; 85 } 86 87 getColumnDefinitions(): ColumnDef[] { 88 return [ 89 { 90 title: 'Name', 91 kind: 'STRING', 92 columnConstructor: Uint16Array, 93 columnId: 'name', 94 }, 95 { 96 title: 'Power (estimated mW)', 97 kind: 'NUMBER', 98 columnConstructor: Float64Array, 99 columnId: 'power', 100 sum: true, 101 }, 102 { 103 title: 'Energy (estimated mWs)', 104 kind: 'NUMBER', 105 columnConstructor: Float64Array, 106 columnId: 'energy', 107 sum: true, 108 }, 109 ]; 110 } 111 112 async getExtra() {} 113 114 getTabName() { 115 return 'Wattson estimates'; 116 } 117 118 getDefaultSorting(): Sorting { 119 return {column: 'name', direction: 'ASC'}; 120 } 121} 122