aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/skpbench/_hardware_pixel.py
blob: aa75c5f63f4e5235739836da6f9ce699c9ea4c79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# Copyright 2017 Google Inc.
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from _hardware import HardwareException, Expectation
from _hardware_android import HardwareAndroid
from collections import namedtuple
import itertools

CPU_CLOCK_RATE = 1670400
GPU_CLOCK_RATE = 510000000

DEVFREQ_DIRNAME = '/sys/class/devfreq'
DEVFREQ_THROTTLE = 0.74
DEVFREQ_BLACKLIST = ('b00000.qcom,kgsl-3d0', 'soc:qcom,kgsl-busmon',
                     'soc:qcom,m4m')
DevfreqKnobs = namedtuple('knobs',
                          ('available_governors', 'available_frequencies',
                           'governor', 'min_freq', 'max_freq', 'cur_freq'))

class HardwarePixel(HardwareAndroid):
  def __init__(self, adb):
    HardwareAndroid.__init__(self, adb)
    self._discover_devfreqs()

  def __enter__(self):
    HardwareAndroid.__enter__(self)
    self._lock_clocks()
    return self

  def __exit__(self, exception_type, exception_value, exception_traceback):
    # pixel struggles waking up; just pull a hard reboot.
    self._adb.reboot()

  def _lock_clocks(self):
    if not self._adb.is_root():
      return

    self._adb.shell('\n'.join(['''\
      stop thermal-engine
      stop thermald
      stop perfd
      stop mpdecision''',

      # enable and lock the two fast cores.
      '''
      for N in 3 2; do
        echo 1 > /sys/devices/system/cpu/cpu$N/online
        echo userspace > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_governor
        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_max_freq
        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_min_freq
        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_setspeed
      done''' % tuple(CPU_CLOCK_RATE for _ in range(3)),

      # turn off the two slow cores
      '''
      for N in 1 0; do
        echo 0 > /sys/devices/system/cpu/cpu$N/online
      done''',

      # gpu perf commands from
      # https://developer.qualcomm.com/qfile/28823/lm80-p0436-11_adb_commands.pdf
      '''
      echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split
      echo 1 > /sys/class/kgsl/kgsl-3d0/force_bus_on
      echo 1 > /sys/class/kgsl/kgsl-3d0/force_rail_on
      echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on
      echo 1000000 > /sys/class/kgsl/kgsl-3d0/idle_timer
      echo userspace > /sys/class/kgsl/kgsl-3d0/devfreq/governor
      echo 2 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel
      echo 2 > /sys/class/kgsl/kgsl-3d0/min_pwrlevel
      echo 2 > /sys/class/kgsl/kgsl-3d0/thermal_pwrlevel
      echo %i > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
      echo %i > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq
      echo %i > /sys/class/kgsl/kgsl-3d0/max_gpuclk
      echo %i > /sys/class/kgsl/kgsl-3d0/gpuclk''' %
      tuple(GPU_CLOCK_RATE for _ in range(4))] + \

      self._devfreq_lock_cmds))

  def _unlock_clocks(self):
    if not self._adb.is_root():
      return

    self._adb.shell('\n'.join(
      self._devfreq_unlock_cmds + [

      # restore gpu settings to default.
      '''
      echo 133000000 > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq
      echo 600000000 > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
      echo 0 > /sys/class/kgsl/kgsl-3d0/gpuclk
      echo msm-adreno-tz > /sys/class/kgsl/kgsl-3d0/devfreq/governor
      echo 6 > /sys/class/kgsl/kgsl-3d0/min_pwrlevel
      echo 0 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel
      echo 1 > /sys/class/kgsl/kgsl-3d0/thermal_pwrlevel
      echo 0 > /sys/class/kgsl/kgsl-3d0/idle_timer
      echo 0 > /sys/class/kgsl/kgsl-3d0/force_clk_on
      echo 0 > /sys/class/kgsl/kgsl-3d0/force_rail_on
      echo 0 > /sys/class/kgsl/kgsl-3d0/force_bus_on
      echo 1 > /sys/class/kgsl/kgsl-3d0/bus_split''',

      # turn the disabled cores back on.
      '''
      for N in 0 1; do
        echo 1 > /sys/devices/system/cpu/cpu$N/online
      done''',

      # unlock the 2 enabled big cores.
      '''
      for N in 2 3; do
        echo 307200 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_min_freq
        echo 2150400 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_max_freq
        echo 0 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_setspeed
        echo sched > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_governor
      done''',

      '''
      start mpdecision
      start perfd
      start thermald
      start thermal-engine''']))

  def sanity_check(self):
    HardwareAndroid.sanity_check(self)

    if not self._adb.is_root():
      return

    result = self._adb.check(' '.join(
      ['cat',
       '/sys/class/power_supply/battery/capacity',
       '/sys/devices/system/cpu/online'] + \
      ['/sys/devices/system/cpu/cpu%i/cpufreq/scaling_cur_freq' % i
       for i in range(2, 4)] + \
      ['/sys/class/kgsl/kgsl-3d0/thermal_pwrlevel',
       '/sys/kernel/debug/clk/gpu_gx_gfx3d_clk/measure',
       '/sys/kernel/debug/clk/bimc_clk/measure',
       '/sys/class/thermal/thermal_zone22/temp',
       '/sys/class/thermal/thermal_zone23/temp'] + \
      self._devfreq_sanity_knobs))

    expectations = \
      [Expectation(int, min_value=30, name='battery', sleeptime=30*60),
       Expectation(str, exact_value='2-3', name='online cpus')] + \
      [Expectation(int, exact_value=CPU_CLOCK_RATE, name='cpu_%i clock rate' %i)
       for i in range(2, 4)] + \
      [Expectation(int, exact_value=2, name='gpu thermal power level'),
       Expectation(long, min_value=(GPU_CLOCK_RATE - 5000),
                   max_value=(GPU_CLOCK_RATE + 5000),
                   name='measured gpu clock'),
       Expectation(long, min_value=902390000, max_value=902409999,
                   name='measured ddr clock', sleeptime=10),
       Expectation(int, max_value=41000, name='pm8994_tz temperature'),
       Expectation(int, max_value=40, name='msm_therm temperature')] + \
      self._devfreq_sanity_expectations

    Expectation.check_all(expectations, result.splitlines())

  def _discover_devfreqs(self):
    self._devfreq_lock_cmds = list()
    self._devfreq_unlock_cmds = list()
    self._devfreq_sanity_knobs = list()
    self._devfreq_sanity_expectations = list()

    results = iter(self._adb.check('''\
      KNOBS='%s'
      for DEVICE in %s/*; do
        if cd $DEVICE && ls $KNOBS >/dev/null; then
          basename $DEVICE
          cat $KNOBS
        fi
      done 2>/dev/null''' %
      (' '.join(DevfreqKnobs._fields), DEVFREQ_DIRNAME)).splitlines())

    while True:
      batch = tuple(itertools.islice(results, 1 + len(DevfreqKnobs._fields)))
      if not batch:
        break

      devfreq = batch[0]
      if devfreq in DEVFREQ_BLACKLIST:
        continue

      path = '%s/%s' % (DEVFREQ_DIRNAME, devfreq)

      knobs = DevfreqKnobs(*batch[1:])
      if not 'performance' in knobs.available_governors.split():
        print('WARNING: devfreq %s does not have performance governor' % path)
        continue

      self._devfreq_lock_cmds.append('echo performance > %s/governor' % path)
      self._devfreq_unlock_cmds.append('echo %s > %s/governor' %
                                       (knobs.governor, path))

      frequencies = map(int, knobs.available_frequencies.split())
      if frequencies:
        # choose the lowest frequency that is >= DEVFREQ_THROTTLE * max.
        frequencies.sort()
        target = DEVFREQ_THROTTLE * frequencies[-1]
        idx = len(frequencies) - 1
        while idx > 0 and frequencies[idx - 1] >= target:
          idx -= 1
        bench_frequency = frequencies[idx]
        self._devfreq_lock_cmds.append('echo %i > %s/min_freq' %
                                      (bench_frequency, path))
        self._devfreq_lock_cmds.append('echo %i > %s/max_freq' %
                                      (bench_frequency, path))
        self._devfreq_unlock_cmds.append('echo %s > %s/min_freq' %
                                        (knobs.min_freq, path))
        self._devfreq_unlock_cmds.append('echo %s > %s/max_freq' %
                                        (knobs.max_freq, path))
        self._devfreq_sanity_knobs.append('%s/cur_freq' % path)
        self._devfreq_sanity_expectations.append(
          Expectation(int, exact_value=bench_frequency,
                      name='%s/cur_freq' % path))