Skip to content

Commit 728eb56

Browse files
authored
ui: Pin per thread Wattson power tracks (#5019)
Pin the top threads by power within the window of interest (e.g. app_startup, jank window, etc.) when it's requested via the URL. This gives a more informative view of the most potentially problematic threads in the window of interest. Per SysUI team's request. Test: http://localhost:10000/#!/viewer?local_cache_key=<MY_LOCAL_KEY>#dev.perfetto.PinAndroidPerfMetrics:metrics=perfetto_wattson_markers_rails_cpu-estimated_mws-mean, http://localhost:10000/#!/viewer?local_cache_key=<MY_LOCAL_KEY>#dev.perfetto.PinAndroidPerfMetrics:metrics=perfetto_wattson_apps_rails_cuj_estimated_mws Bug: 483752560 Signed-off-by: Samuel Wu <wusamuel@google.com>
1 parent bb324c7 commit 728eb56

File tree

2 files changed

+95
-14
lines changed

2 files changed

+95
-14
lines changed

ui/src/plugins/org.kernel.Wattson/index.ts

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
import {addWattsonThreadTrack} from './wattson_thread_utils';
16+
import {App} from '../../public/app';
1517
import {createAggregationTab} from '../../components/aggregation_adapter';
1618
import {
1719
BaseCounterTrack,
@@ -25,6 +27,7 @@ import {TrackNode} from '../../public/workspace';
2527
import {Engine} from '../../trace_processor/engine';
2628
import {SourceDataset} from '../../trace_processor/dataset';
2729
import {LONG, LONG_NULL, NUM, STR} from '../../trace_processor/query_result';
30+
import {RouteArgs} from '../../public/route_schema';
2831
import {WattsonEstimateSelectionAggregator} from './estimate_aggregator';
2932
import {WattsonPackageSelectionAggregator} from './package_aggregator';
3033
import {WattsonProcessSelectionAggregator} from './process_aggregator';
@@ -36,9 +39,25 @@ import {
3639
import SchedPlugin from '../dev.perfetto.Sched';
3740
import {createCpuWarnings, missingWattsonCpuConfigs} from './warning';
3841

39-
export default class implements PerfettoPlugin {
42+
const WINDOW_MAP: Record<string, string> = {
43+
perfetto_wattson_markers: 'markers',
44+
perfetto_wattson_trace: 'trace',
45+
perfetto_wattson_apps: 'atrace_apps',
46+
perfetto_wattson_app_startup: 'app_startup',
47+
};
48+
49+
export default class Wattson implements PerfettoPlugin {
4050
static readonly id = `org.kernel.Wattson`;
4151
static readonly dependencies = [SchedPlugin];
52+
public static windowsOfInterest = new Set<string>();
53+
54+
static onActivate(_app: App, args: RouteArgs): void {
55+
const metrics: string[] = [];
56+
if (typeof args.metrics === 'string') {
57+
metrics.push(...args.metrics.split('--'));
58+
}
59+
Wattson.updateWindowsOfInterest(metrics);
60+
}
4261

4362
async onTraceLoad(ctx: Trace): Promise<void> {
4463
const markersSupported = await hasWattsonMarkersSupport(ctx.engine);
@@ -69,6 +88,60 @@ export default class implements PerfettoPlugin {
6988
if (gpuSupported) {
7089
await addWattsonGpuElements(ctx, group);
7190
}
91+
92+
if (Wattson.windowsOfInterest.size > 0) {
93+
await this.pinThreadPowerTracks(ctx);
94+
Wattson.windowsOfInterest.clear();
95+
}
96+
}
97+
98+
async pinThreadPowerTracks(ctx: Trace) {
99+
if (Wattson.windowsOfInterest.size === 0) return;
100+
101+
// Gather all utids from all windows
102+
const windowQueries = Array.from(Wattson.windowsOfInterest)
103+
.map((window) => {
104+
const suffix = WINDOW_MAP[window];
105+
if (suffix === undefined) return undefined;
106+
return `
107+
INCLUDE PERFETTO MODULE wattson.aggregation;
108+
INCLUDE PERFETTO MODULE wattson.windows;
109+
110+
SELECT utid
111+
FROM wattson_threads_aggregation!(wattson_window_${suffix})
112+
GROUP BY utid
113+
ORDER BY SUM(total_mws) DESC
114+
LIMIT 3
115+
`;
116+
})
117+
.filter((q): q is string => q !== undefined);
118+
119+
const queryResults = await Promise.all(
120+
windowQueries.map((q) => ctx.engine.query(q)),
121+
);
122+
123+
const utidsToPin = new Set<number>();
124+
for (const result of queryResults) {
125+
const it = result.iter({utid: NUM});
126+
for (; it.valid(); it.next()) {
127+
utidsToPin.add(it.utid);
128+
}
129+
}
130+
131+
// Only add tracks of unique utids
132+
for (const utid of utidsToPin) {
133+
await addWattsonThreadTrack(ctx, utid, {pin: true});
134+
}
135+
}
136+
137+
private static updateWindowsOfInterest(metrics: string[]) {
138+
for (const metric of metrics) {
139+
for (const key of Object.keys(WINDOW_MAP)) {
140+
if (metric.includes(key)) {
141+
Wattson.windowsOfInterest.add(key);
142+
}
143+
}
144+
}
72145
}
73146
}
74147

ui/src/plugins/org.kernel.Wattson/wattson_thread_utils.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,17 @@ import {WATTSON_THREAD_TRACK_KIND} from './track_kinds';
2121
export async function addWattsonThreadTrack(
2222
trace: Trace,
2323
utid: number,
24-
threadTrackUri?: string,
24+
options?: {
25+
threadTrackUri?: string;
26+
pin?: boolean;
27+
},
2528
): Promise<void> {
2629
const uri = `dev.perfetto.Sched#WattsonThreadCounter_${utid}`;
27-
if (trace.currentWorkspace.getTrackByUri(uri)) {
30+
const existingTrack = trace.currentWorkspace.getTrackByUri(uri);
31+
if (existingTrack) {
32+
if (options?.pin && !existingTrack.isPinned) {
33+
existingTrack.pin();
34+
}
2835
trace.scrollTo({track: {uri, expandGroup: true}});
2936
return;
3037
}
@@ -87,8 +94,8 @@ export async function addWattsonThreadTrack(
8794

8895
// Find the thread track and add the new track as a sibling
8996
let threadNode: TrackNode | undefined;
90-
if (threadTrackUri) {
91-
threadNode = trace.currentWorkspace.getTrackByUri(threadTrackUri);
97+
if (options?.threadTrackUri) {
98+
threadNode = trace.currentWorkspace.getTrackByUri(options.threadTrackUri);
9299
} else {
93100
const threadTrack = trace.tracks
94101
.getAllTracks()
@@ -102,20 +109,21 @@ export async function addWattsonThreadTrack(
102109
}
103110
}
104111

112+
const name = threadNode?.name ?? (utid === 0 ? 'swapper' : `utid ${utid}`);
113+
const newNode = new TrackNode({
114+
uri,
115+
name: `${name} Wattson power estimates`,
116+
});
117+
105118
if (threadNode?.parent) {
106-
const newNode = new TrackNode({
107-
uri,
108-
name: `${threadNode.name} Wattson power estimates`,
109-
});
110119
threadNode.parent.addChildBefore(newNode, threadNode);
111120
} else {
112-
const name = threadNode?.name ?? (utid === 0 ? 'swapper' : `utid ${utid}`);
113-
const newNode = new TrackNode({
114-
uri,
115-
name: `${name} Wattson power estimates`,
116-
});
117121
trace.currentWorkspace.addChildLast(newNode);
118122
}
119123

124+
if (options?.pin) {
125+
newNode.pin();
126+
}
127+
120128
trace.scrollTo({track: {uri, expandGroup: true}});
121129
}

0 commit comments

Comments
 (0)