xref: /aosp_15_r20/external/autotest/client/site_tests/power_CPUIdle/power_CPUIdle.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Lint as: python2, python3
2# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import glob, logging, os, time
7from autotest_lib.client.bin import test
8from autotest_lib.client.common_lib import error
9
10# choosing a (very) conservative threshold for now to help catch
11# major breakages
12percent_idle_time_threshold = 20
13
14class power_CPUIdle(test.test):
15    version = 1
16
17    def run_once(self, sleep_time=5):
18        all_cpus = cpus()
19
20        idle_time_at_start, active_time_at_start = all_cpus.idle_time()
21        logging.info('idle_time_at_start: %d', idle_time_at_start)
22        logging.info('active_time_at_start: %d', active_time_at_start)
23
24        # sleep for some time to allow the CPUs to drop into idle states
25        time.sleep(sleep_time)
26
27        idle_time_at_end, active_time_at_end = all_cpus.idle_time()
28        logging.info('idle_time_at_end: %d', idle_time_at_end)
29        logging.info('active_time_at_end: %d', idle_time_at_end)
30
31        idle_time_delta_ms = (idle_time_at_end - idle_time_at_start) / 1000
32        logging.info('idle_time_delta_ms: %d', idle_time_delta_ms)
33
34        active_time_delta_ms = (active_time_at_end - active_time_at_start) \
35                               / 1000
36        logging.info('active_time_delta_ms: %d', active_time_delta_ms)
37
38        total_time_delta_ms = active_time_delta_ms + idle_time_delta_ms
39        logging.info('total_time_delta_ms: %d', total_time_delta_ms)
40
41        percent_active_time = active_time_delta_ms * 100.0 / total_time_delta_ms
42        logging.info('percent active time : %.2f', percent_active_time)
43
44        percent_idle_time = idle_time_delta_ms * 100.0 / total_time_delta_ms
45        logging.info('percent idle time : %.2f', percent_idle_time)
46
47        keyvals = {}
48        keyvals['ms_active_time_delta'] = active_time_delta_ms
49        keyvals['ms_idle_time_delta'] = idle_time_delta_ms
50        keyvals['percent_active_time'] = percent_active_time
51        keyvals['percent_idle_time'] = percent_idle_time
52        self.write_perf_keyval(keyvals)
53
54        if percent_idle_time < percent_idle_time_threshold:
55            raise error.TestFail('Idle percent below threshold')
56
57
58
59class cpus(object):
60    def __init__(self):
61        self.__base_path = '/sys/devices/system/cpu/cpu*/cpuidle'
62        self.__cpus = []
63
64        dirs = glob.glob(self.__base_path)
65        if not dirs:
66            raise error.TestError('cpuidle not supported')
67
68        for dir in dirs:
69            cpu = cpuidle(dir)
70            self.__cpus.append(cpu)
71
72
73    def idle_time(self):
74        total_idle_time = 0
75        total_active_time = 0
76        for cpu in self.__cpus:
77            idle_time, active_time = cpu.idle_time()
78            total_idle_time += idle_time
79            total_active_time += active_time
80        return total_idle_time, total_active_time
81
82
83
84class cpuidle(object):
85    def __init__(self, path):
86        self.__base_path = path
87        self.__states = []
88
89        dirs = glob.glob(os.path.join(self.__base_path, 'state*'))
90        if not dirs:
91            raise error.TestError('cpuidle states missing')
92
93        for dir in dirs:
94            state = cpuidle_state(dir)
95            self.__states.append(state)
96
97
98    def idle_time(self):
99        total_idle_time = 0
100        total_active_time = 0
101        for state in self.__states:
102            total_idle_time += state.idle_time()
103            total_active_time += state.active_time()
104
105        return total_idle_time, total_active_time
106
107
108
109class cpuidle_state(object):
110    def __init__(self, path):
111        self.__base_path = path
112        self.__name = self.__read_file('name').split()[0]
113        self.__latency = int(self.__read_file('latency').split()[0])
114
115
116    def __read_file(self, file_name):
117        path = os.path.join(self.__base_path, file_name)
118        f = open(path, 'r')
119        data = f.read()
120        f.close()
121        return data
122
123
124    def __is_idle_state(self):
125        if self.__latency:
126            # non-zero latency indicates non-C0 state
127            return True
128        return False
129
130
131    def idle_time(self):
132        time = 0
133        if self.__is_idle_state():
134            time = int(self.__read_file('time'))
135        logging.info('idle_time(%s): %d', self.__name, time)
136        return time
137
138
139    def active_time(self):
140        time = 0
141        if not self.__is_idle_state():
142            time = int(self.__read_file('time'))
143        logging.info('active_time(%s): %d', self.__name, time)
144        return time
145