# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import glob, logging, os, time
from autotest_lib.client.bin import test
from autotest_lib.client.common_lib import error

# choosing a (very) conservative threshold for now to help catch
# major breakages
percent_idle_time_threshold = 20

class power_CPUIdle(test.test):
    version = 1

    def run_once(self, sleep_time=5):
        all_cpus = cpus()

        idle_time_at_start, active_time_at_start = all_cpus.idle_time()
        logging.info('idle_time_at_start: %d' % idle_time_at_start)
        logging.info('active_time_at_start: %d' % active_time_at_start)

        # sleep for some time to allow the CPUs to drop into idle states
        time.sleep(sleep_time)

        idle_time_at_end, active_time_at_end = all_cpus.idle_time()
        logging.info('idle_time_at_end: %d' % idle_time_at_end)
        logging.info('active_time_at_end: %d' % idle_time_at_end)

        idle_time_delta_ms = (idle_time_at_end - idle_time_at_start) / 1000
        logging.info('idle_time_delta_ms: %d' % idle_time_delta_ms)

        active_time_delta_ms = (active_time_at_end - active_time_at_start) \
                               / 1000
        logging.info('active_time_delta_ms: %d' % active_time_delta_ms)

        total_time_delta_ms = active_time_delta_ms + idle_time_delta_ms
        logging.info('total_time_delta_ms: %d' % total_time_delta_ms)

        percent_active_time = active_time_delta_ms * 100.0 / total_time_delta_ms
        logging.info('percent active time : %.2f' % percent_active_time)

        percent_idle_time = idle_time_delta_ms * 100.0 / total_time_delta_ms
        logging.info('percent idle time : %.2f' % percent_idle_time)

        keyvals = {}
        keyvals['ms_active_time_delta'] = active_time_delta_ms
        keyvals['ms_idle_time_delta'] = idle_time_delta_ms
        keyvals['percent_active_time'] = percent_active_time
        keyvals['percent_idle_time'] = percent_idle_time
        self.write_perf_keyval(keyvals)

        if percent_idle_time < percent_idle_time_threshold:
            raise error.TestFail('Idle percent below threshold')



class cpus(object):
    def __init__(self):
        self.__base_path = '/sys/devices/system/cpu/cpu*/cpuidle'
        self.__cpus = []

        dirs = glob.glob(self.__base_path)
        if not dirs:
            raise error.TestError('cpuidle not supported')

        for dir in dirs:
            cpu = cpuidle(dir)
            self.__cpus.append(cpu)


    def idle_time(self):
        total_idle_time = 0
        total_active_time = 0
        for cpu in self.__cpus:
            idle_time, active_time = cpu.idle_time()
            total_idle_time += idle_time
            total_active_time += active_time
        return total_idle_time, total_active_time



class cpuidle(object):
    def __init__(self, path):
        self.__base_path = path
        self.__states = []

        dirs = glob.glob(os.path.join(self.__base_path, 'state*'))
        if not dirs:
            raise error.TestError('cpuidle states missing')

        for dir in dirs:
            state = cpuidle_state(dir)
            self.__states.append(state)


    def idle_time(self):
        total_idle_time = 0
        total_active_time = 0
        for state in self.__states:
            total_idle_time += state.idle_time()
            total_active_time += state.active_time()

        return total_idle_time, total_active_time



class cpuidle_state(object):
    def __init__(self, path):
        self.__base_path = path
        self.__name = self.__read_file('name').split()[0]
        self.__latency = int(self.__read_file('latency').split()[0])


    def __read_file(self, file_name):
        path = os.path.join(self.__base_path, file_name)
        f = open(path, 'r')
        data = f.read()
        f.close()
        return data


    def __is_idle_state(self):
        if self.__latency:
            # non-zero latency indicates non-C0 state
            return True
        return False


    def idle_time(self):
        time = 0
        if self.__is_idle_state():
            time = int(self.__read_file('time'))
        logging.info('idle_time(%s): %d' % (self.__name, time))
        return time


    def active_time(self):
        time = 0
        if not self.__is_idle_state():
            time = int(self.__read_file('time'))
        logging.info('active_time(%s): %d' % (self.__name, time))
        return time