Home | History | Annotate | Download | only in module
      1 #    Copyright 2014-2015 ARM Limited
      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 #
     15 # pylint: disable=attribute-defined-outside-init
     16 from devlib.module import Module
     17 from devlib.utils.misc import memoized
     18 from devlib.utils.types import integer, boolean
     19 
     20 
     21 class CpuidleState(object):
     22 
     23     @property
     24     def usage(self):
     25         return integer(self.get('usage'))
     26 
     27     @property
     28     def time(self):
     29         return integer(self.get('time'))
     30 
     31     @property
     32     def is_enabled(self):
     33         return not boolean(self.get('disable'))
     34 
     35     @property
     36     def ordinal(self):
     37         i = len(self.id)
     38         while self.id[i - 1].isdigit():
     39             i -= 1
     40             if not i:
     41                 raise ValueError('invalid idle state name: "{}"'.format(self.id))
     42         return int(self.id[i:])
     43 
     44     def __init__(self, target, index, path, name, desc, power, latency, residency):
     45         self.target = target
     46         self.index = index
     47         self.path = path
     48         self.name = name
     49         self.desc = desc
     50         self.power = power
     51         self.latency = latency
     52         self.id = self.target.path.basename(self.path)
     53         self.cpu = self.target.path.basename(self.target.path.dirname(path))
     54 
     55     def enable(self):
     56         self.set('disable', 0)
     57 
     58     def disable(self):
     59         self.set('disable', 1)
     60 
     61     def get(self, prop):
     62         property_path = self.target.path.join(self.path, prop)
     63         return self.target.read_value(property_path)
     64 
     65     def set(self, prop, value):
     66         property_path = self.target.path.join(self.path, prop)
     67         self.target.write_value(property_path, value)
     68 
     69     def __eq__(self, other):
     70         if isinstance(other, CpuidleState):
     71             return (self.name == other.name) and (self.desc == other.desc)
     72         elif isinstance(other, basestring):
     73             return (self.name == other) or (self.desc == other)
     74         else:
     75             return False
     76 
     77     def __ne__(self, other):
     78         return not self.__eq__(other)
     79 
     80     def __str__(self):
     81         return 'CpuidleState({}, {})'.format(self.name, self.desc)
     82 
     83     __repr__ = __str__
     84 
     85 
     86 class Cpuidle(Module):
     87 
     88     name = 'cpuidle'
     89     root_path = '/sys/devices/system/cpu/cpuidle'
     90 
     91     @staticmethod
     92     def probe(target):
     93         return target.file_exists(Cpuidle.root_path)
     94 
     95     def __init__(self, target):
     96         super(Cpuidle, self).__init__(target)
     97         self._states = {}
     98 
     99         basepath = '/sys/devices/system/cpu/'
    100         values_tree = self.target.read_tree_values(basepath, depth=4, check_exit_code=False)
    101         i = 0
    102         cpu_id = 'cpu{}'.format(i)
    103         while cpu_id in values_tree:
    104             cpu_node = values_tree[cpu_id]
    105 
    106             if 'cpuidle' in cpu_node:
    107                 idle_node = cpu_node['cpuidle']
    108                 self._states[cpu_id] = []
    109                 j = 0
    110                 state_id = 'state{}'.format(j)
    111                 while state_id in idle_node:
    112                     state_node = idle_node[state_id]
    113                     state = CpuidleState(
    114                         self.target,
    115                         index=j,
    116                         path=self.target.path.join(basepath, cpu_id, 'cpuidle', state_id),
    117                         name=state_node['name'],
    118                         desc=state_node['desc'],
    119                         power=int(state_node['power']),
    120                         latency=int(state_node['latency']),
    121                         residency=int(state_node['residency']) if 'residency' in state_node else None,
    122                     )
    123                     msg = 'Adding {} state {}: {} {}'
    124                     self.logger.debug(msg.format(cpu_id, j, state.name, state.desc))
    125                     self._states[cpu_id].append(state)
    126                     j += 1
    127                     state_id = 'state{}'.format(j)
    128 
    129             i += 1
    130             cpu_id = 'cpu{}'.format(i)
    131 
    132     def get_states(self, cpu=0):
    133         if isinstance(cpu, int):
    134             cpu = 'cpu{}'.format(cpu)
    135         return self._states.get(cpu)
    136 
    137     def get_state(self, state, cpu=0):
    138         if isinstance(state, int):
    139             try:
    140                 return self.get_states(cpu)[state]
    141             except IndexError:
    142                 raise ValueError('Cpuidle state {} does not exist'.format(state))
    143         else:  # assume string-like
    144             for s in self.get_states(cpu):
    145                 if state in [s.id, s.name, s.desc]:
    146                     return s
    147             raise ValueError('Cpuidle state {} does not exist'.format(state))
    148 
    149     def enable(self, state, cpu=0):
    150         self.get_state(state, cpu).enable()
    151 
    152     def disable(self, state, cpu=0):
    153         self.get_state(state, cpu).disable()
    154 
    155     def enable_all(self, cpu=0):
    156         for state in self.get_states(cpu):
    157             state.enable()
    158 
    159     def disable_all(self, cpu=0):
    160         for state in self.get_states(cpu):
    161             state.disable()
    162 
    163     def perturb_cpus(self):
    164         """
    165         Momentarily wake each CPU. Ensures cpu_idle events in trace file.
    166         """
    167         output = self.target._execute_util('cpuidle_wake_all_cpus')
    168         print(output)
    169 
    170     def get_driver(self):
    171         return self.target.read_value(self.target.path.join(self.root_path, 'current_driver'))
    172 
    173     def get_governor(self):
    174         return self.target.read_value(self.target.path.join(self.root_path, 'current_governor_ro'))
    175