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