xref: /aosp_15_r20/external/perfetto/tools/export_power_profiles.py (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6dbdd20aSAndroid Build Coastguard Worker# Copyright 2020 The Chromium Authors. All rights reserved.
3*6dbdd20aSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
4*6dbdd20aSAndroid Build Coastguard Worker# found in the LICENSE file.
5*6dbdd20aSAndroid Build Coastguard Worker
6*6dbdd20aSAndroid Build Coastguard Workerimport argparse
7*6dbdd20aSAndroid Build Coastguard Workerimport os
8*6dbdd20aSAndroid Build Coastguard Workerimport sys
9*6dbdd20aSAndroid Build Coastguard Workerimport xml.etree.ElementTree as ET
10*6dbdd20aSAndroid Build Coastguard Worker
11*6dbdd20aSAndroid Build Coastguard Worker
12*6dbdd20aSAndroid Build Coastguard Workerdef ExtractValues(xml_path, correction):
13*6dbdd20aSAndroid Build Coastguard Worker  root = ET.parse(xml_path).getroot()
14*6dbdd20aSAndroid Build Coastguard Worker
15*6dbdd20aSAndroid Build Coastguard Worker  speeds = []
16*6dbdd20aSAndroid Build Coastguard Worker  power = []
17*6dbdd20aSAndroid Build Coastguard Worker  clusters = []
18*6dbdd20aSAndroid Build Coastguard Worker  for array in root.iter('array'):
19*6dbdd20aSAndroid Build Coastguard Worker    if array.get('name') == 'cpu.clusters.cores':
20*6dbdd20aSAndroid Build Coastguard Worker      clusters = [int(value.text) for value in array.iter('value')]
21*6dbdd20aSAndroid Build Coastguard Worker    if array.get('name').startswith('cpu.core_speeds.'):
22*6dbdd20aSAndroid Build Coastguard Worker      speeds.append([int(value.text) for value in array.iter('value')])
23*6dbdd20aSAndroid Build Coastguard Worker    if array.get('name').startswith('cpu.core_power.'):
24*6dbdd20aSAndroid Build Coastguard Worker      power.append([float(value.text) for value in array.iter('value')])
25*6dbdd20aSAndroid Build Coastguard Worker
26*6dbdd20aSAndroid Build Coastguard Worker  values = []
27*6dbdd20aSAndroid Build Coastguard Worker  cpu = 0
28*6dbdd20aSAndroid Build Coastguard Worker  for cluster, n_cpus in enumerate(clusters):
29*6dbdd20aSAndroid Build Coastguard Worker    for _ in range(n_cpus):
30*6dbdd20aSAndroid Build Coastguard Worker      for freq, drain in zip(speeds[cluster], power[cluster]):
31*6dbdd20aSAndroid Build Coastguard Worker        if correction:
32*6dbdd20aSAndroid Build Coastguard Worker          drain /= n_cpus
33*6dbdd20aSAndroid Build Coastguard Worker        values.append((cpu, cluster, freq, drain))
34*6dbdd20aSAndroid Build Coastguard Worker      cpu += 1
35*6dbdd20aSAndroid Build Coastguard Worker
36*6dbdd20aSAndroid Build Coastguard Worker  return values
37*6dbdd20aSAndroid Build Coastguard Worker
38*6dbdd20aSAndroid Build Coastguard Worker
39*6dbdd20aSAndroid Build Coastguard Workerdef ExportProfiles(device_xmls, sql_path):
40*6dbdd20aSAndroid Build Coastguard Worker  sql_values = []
41*6dbdd20aSAndroid Build Coastguard Worker  for device, xml_path, correction in device_xmls:
42*6dbdd20aSAndroid Build Coastguard Worker    sql_values += [
43*6dbdd20aSAndroid Build Coastguard Worker        '("%s", %s, %s, %s, %s)' % ((device,) + v)
44*6dbdd20aSAndroid Build Coastguard Worker        for v in ExtractValues(xml_path, correction == 'yes')
45*6dbdd20aSAndroid Build Coastguard Worker    ]
46*6dbdd20aSAndroid Build Coastguard Worker
47*6dbdd20aSAndroid Build Coastguard Worker  with open(sql_path, 'w') as sql_file:
48*6dbdd20aSAndroid Build Coastguard Worker    sql_file.write('INSERT OR REPLACE INTO power_profile VALUES\n')
49*6dbdd20aSAndroid Build Coastguard Worker    sql_file.write(',\n'.join(sql_values))
50*6dbdd20aSAndroid Build Coastguard Worker    sql_file.write(';\n')
51*6dbdd20aSAndroid Build Coastguard Worker
52*6dbdd20aSAndroid Build Coastguard Worker
53*6dbdd20aSAndroid Build Coastguard Workerdef main(args):
54*6dbdd20aSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(
55*6dbdd20aSAndroid Build Coastguard Worker      description='Export XML power profile as a SQL INSERT query.',
56*6dbdd20aSAndroid Build Coastguard Worker      epilog='Example usage:\n'
57*6dbdd20aSAndroid Build Coastguard Worker      'python export_power_profiles.py '
58*6dbdd20aSAndroid Build Coastguard Worker      '--device-xml sailfish sailfish/power_profile.xml no '
59*6dbdd20aSAndroid Build Coastguard Worker      '--device-xml sargo sargo/power_profile.xml yes '
60*6dbdd20aSAndroid Build Coastguard Worker      '--output power_profile_data.sql')
61*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument(
62*6dbdd20aSAndroid Build Coastguard Worker      '--device-xml',
63*6dbdd20aSAndroid Build Coastguard Worker      nargs=3,
64*6dbdd20aSAndroid Build Coastguard Worker      metavar=('DEVICE', 'XML_FILE', 'CORRECTION'),
65*6dbdd20aSAndroid Build Coastguard Worker      action='append',
66*6dbdd20aSAndroid Build Coastguard Worker      help='First argument: device name; second argument: path to the XML '
67*6dbdd20aSAndroid Build Coastguard Worker      'file with the device power profile; third argument(yes|no): '
68*6dbdd20aSAndroid Build Coastguard Worker      'whether correction is necessary. Can be used multiple times.')
69*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument(
70*6dbdd20aSAndroid Build Coastguard Worker      '--output', metavar='SQL_FILE', help='Path to the output file.')
71*6dbdd20aSAndroid Build Coastguard Worker
72*6dbdd20aSAndroid Build Coastguard Worker  args = parser.parse_args(args)
73*6dbdd20aSAndroid Build Coastguard Worker
74*6dbdd20aSAndroid Build Coastguard Worker  sql_path = 'result.sql'
75*6dbdd20aSAndroid Build Coastguard Worker  ExportProfiles(args.device_xml, args.output)
76*6dbdd20aSAndroid Build Coastguard Worker
77*6dbdd20aSAndroid Build Coastguard Worker
78*6dbdd20aSAndroid Build Coastguard Workerif __name__ == '__main__':
79*6dbdd20aSAndroid Build Coastguard Worker  sys.exit(main(sys.argv[1:]))
80