Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 6 additions & 90 deletions ui/src/plugins/org.kernel.Wattson/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import m, {Vnode} from 'mithril';

import {createAggregationTab} from '../../components/aggregation_adapter';
import {
BaseCounterTrack,
Expand All @@ -26,13 +24,7 @@ import {SLICE_TRACK_KIND} from '../../public/track_kinds';
import {TrackNode} from '../../public/workspace';
import {Engine} from '../../trace_processor/engine';
import {SourceDataset} from '../../trace_processor/dataset';
import {
LONG,
LONG_NULL,
NUM,
STR,
STR_NULL,
} from '../../trace_processor/query_result';
import {LONG, LONG_NULL, NUM, STR} from '../../trace_processor/query_result';
import {WattsonEstimateSelectionAggregator} from './estimate_aggregator';
import {WattsonPackageSelectionAggregator} from './package_aggregator';
import {WattsonProcessSelectionAggregator} from './process_aggregator';
Expand All @@ -42,7 +34,7 @@ import {
GPUSS_ESTIMATE_TRACK_KIND,
} from './track_kinds';
import SchedPlugin from '../dev.perfetto.Sched';
import {linkify} from '../../widgets/anchor';
import {createCpuWarnings, hasWattsonSufficientCPUConfigs} from './warning';

export default class implements PerfettoPlugin {
static readonly id = `org.kernel.Wattson`;
Expand All @@ -52,8 +44,10 @@ export default class implements PerfettoPlugin {
const markersSupported = await hasWattsonMarkersSupport(ctx.engine);
const cpuSupported = await hasWattsonCpuSupport(ctx.engine);
const gpuSupported = await hasWattsonGpuSupport(ctx.engine);
const missingEvents = await hasWattsonSufficientCPUConfigs(ctx.engine);
const realCpuIdleCounters = await hasCpuIdleCounters(ctx.engine);
const missingEvents = markersSupported
? await hasWattsonSufficientCPUConfigs(ctx.engine)
: [];

// Short circuit if Wattson is not supported for this Perfetto trace
if (!(markersSupported || cpuSupported || gpuSupported)) return;
Expand All @@ -64,7 +58,7 @@ export default class implements PerfettoPlugin {
if (markersSupported) {
await addWattsonMarkersElements(ctx, group);
}
if (cpuSupported) {
if (cpuSupported || markersSupported) {
await addWattsonCpuElements(
ctx,
group,
Expand Down Expand Up @@ -109,46 +103,6 @@ class WattsonSubsystemEstimateTrack extends BaseCounterTrack {
}
}

// Walk through user's Perfetto Trace Configs and check
// against bare minimum configs that makes Wattson work.
// Add the missing ones to missingEvents, display in UI.
async function hasWattsonSufficientCPUConfigs(
engine: Engine,
): Promise<string[]> {
const requiredFtraceEvents: string[] = ['power/cpu_frequency'];

const dsuDependencyQuery = await engine.query(
`
INCLUDE PERFETTO MODULE wattson.curves.utils;
SELECT count(*) AS count FROM _cpu_w_dsu_dependency;
`,
);

if (dsuDependencyQuery.firstRow({count: NUM}).count > 0) {
requiredFtraceEvents.push('devfreq/devfreq_frequency');
}

const missingEvents: string[] = [];
const query = `
SELECT str_value
FROM metadata
WHERE name = 'trace_config_pbtxt';
`;

const result = await engine.query(query);
const row = result.maybeFirstRow({str_value: STR_NULL});
const traceConfig = row?.str_value || '';

for (const event of requiredFtraceEvents) {
const eventPattern = new RegExp(`ftrace_events:\\s*"${event}"`);
if (!eventPattern.test(traceConfig)) {
missingEvents.push(event);
}
}

return missingEvents;
}

async function hasCpuIdleCounters(engine: Engine): Promise<boolean> {
const checkValue = await engine.query(`
INCLUDE PERFETTO MODULE wattson.cpu.idle;
Expand Down Expand Up @@ -236,44 +190,6 @@ async function addWattsonMarkersElements(ctx: Trace, group: TrackNode) {
group.addChildInOrder(new TrackNode({uri, name: 'Wattson markers window'}));
}

function createCpuWarnings(
missingEvents: string[],
realCpuIdleCounters: boolean,
): Vnode | undefined {
const warningMsg: Vnode[] = [];

if (missingEvents.length > 0) {
warningMsg.push(
m(
'.pf-wattson-warning',
linkify(
`See https://source.android.com/docs/core/power/wattson/how-to-wattson for more details on Wattson's required trace configuration. The following ftrace_events are necessary for Wattson to make power estimates:`,
),
m(
'.pf-wattson-warning__list',
missingEvents.map((event) => m('li', event)),
),
),
);
}

if (!realCpuIdleCounters) {
if (warningMsg.length > 0) {
warningMsg.push(m('hr'));
}
warningMsg.push(
m(
'p',
'`cpu_idle` counters are not available in this trace; deriving cpu_idle counters from the swapper thread.',
),
);
}

return warningMsg.length > 0
? m('.pf-wattson-warning', warningMsg)
: undefined;
}

async function addWattsonCpuElements(
ctx: Trace,
group: TrackNode,
Expand Down
118 changes: 118 additions & 0 deletions ui/src/plugins/org.kernel.Wattson/warning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import m, {Vnode} from 'mithril';
import {Engine} from '../../trace_processor/engine';
import {NUM, STR_NULL} from '../../trace_processor/query_result';
import {linkify} from '../../widgets/anchor';

enum FtraceEvent {
CPU_FREQUENCY = 'power/cpu_frequency',
CPU_IDLE = 'power/cpu_idle',
DEVFREQ_FREQUENCY = 'devfreq/devfreq_frequency',
CPUHP_ENTER = 'cpuhp/cpuhp_enter',
CPUHP_EXIT = 'cpuhp/cpuhp_exit',
CPUHP_MULTI_ENTER = 'cpuhp/cpuhp_multi_enter',
PRINT = 'ftrace/print',
SUSPEND_RESUME = 'power/suspend_resume',
SCHED_SWITCH = 'sched/sched_switch',
}

// Walk through user's Perfetto Trace Configs and check
// against bare minimum configs that makes Wattson work.
// Add the missing ones to missingEvents, display in UI.
export async function hasWattsonSufficientCPUConfigs(
engine: Engine,
): Promise<string[]> {
// 1. Determine required events first
const requiredEvents = new Set<FtraceEvent>([FtraceEvent.CPU_FREQUENCY]);

const dsuDependencyQuery = await engine.query(
`
INCLUDE PERFETTO MODULE wattson.curves.utils;
SELECT count(*) AS count FROM _cpu_w_dsu_dependency;
`,
);

if (dsuDependencyQuery.firstRow({count: NUM}).count > 0) {
requiredEvents.add(FtraceEvent.DEVFREQ_FREQUENCY);
}

// 2. Check configured events
const query = `
SELECT str_value
FROM metadata
WHERE name = 'trace_config_pbtxt';
`;

const result = await engine.query(query);
const row = result.maybeFirstRow({str_value: STR_NULL});
const traceConfig = row?.str_value || '';

const foundEvents = new Set<FtraceEvent>();

if (/cpufreq_period_ms:\s*\d+/.test(traceConfig)) {
foundEvents.add(FtraceEvent.CPU_FREQUENCY);
}

// below events are included in "freq" Atrace category.
if (/atrace_categories:\s*"freq"/.test(traceConfig)) {
foundEvents.add(FtraceEvent.CPU_FREQUENCY);
foundEvents.add(FtraceEvent.DEVFREQ_FREQUENCY);
foundEvents.add(FtraceEvent.SUSPEND_RESUME);
foundEvents.add(FtraceEvent.CPUHP_ENTER);
foundEvents.add(FtraceEvent.CPUHP_EXIT);
}

for (const event of Object.values(FtraceEvent)) {
const eventPattern = new RegExp(`ftrace_events:\\s*"${event}"`);
if (eventPattern.test(traceConfig)) {
foundEvents.add(event);
}
}

// 3. Compare required events with found events
const missingEvents: string[] = [];
for (const requiredEvent of requiredEvents) {
if (!foundEvents.has(requiredEvent)) {
missingEvents.push(requiredEvent);
}
}

return missingEvents;
}

export function createCpuWarnings(
missingEvents: string[],
realCpuIdleCounters: boolean,
): Vnode | undefined {
const warningMsg: Vnode[] = [];

if (missingEvents.length > 0) {
warningMsg.push(
m(
'.pf-wattson-warning',
linkify(
`See https://source.android.com/docs/core/power/wattson/how-to-wattson for more details on Wattson's required trace configuration. The following ftrace_events are necessary for Wattson to make power estimates:`,
),
m(
'.pf-wattson-warning__list',
missingEvents.map((event) => m('li', event)),
),
),
);
}

if (!realCpuIdleCounters) {
if (warningMsg.length > 0) {
warningMsg.push(m('hr'));
}
warningMsg.push(
m(
'p',
'`cpu_idle` counters are not available in this trace; deriving cpu_idle counters from the swapper thread.',
),
);
}

return warningMsg.length > 0
? m('.pf-wattson-warning', warningMsg)
: undefined;
}