12e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
22e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang# Use of this source code is governed by a BSD-style license that can be
32e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang# found in the LICENSE file.
42e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
52e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spangimport hashlib, logging, multiprocessing, os, re, time
62e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spangfrom autotest_lib.client.bin import test, utils
72e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spangfrom autotest_lib.client.common_lib import error
82e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spangfrom autotest_lib.client.cros import sys_power
92e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
102e6ecda978a5d086c76ca014531ea781fd3d75aeMichael SpangSUSPEND_BURN_SECONDS = 10
112e6ecda978a5d086c76ca014531ea781fd3d75aeMichael SpangRESUME_BURN_SECONDS = 5
122e6ecda978a5d086c76ca014531ea781fd3d75aeMichael SpangMIN_CPU_USAGE = .95
132e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
142e6ecda978a5d086c76ca014531ea781fd3d75aeMichael SpangPROC_STAT_CPU_FIELDS = ['user', 'nice', 'system', 'idle', 'iowait', 'irq',
152e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang                        'softirq', 'steal', 'guest', 'guest_nice']
162e6ecda978a5d086c76ca014531ea781fd3d75aeMichael SpangPROC_STAT_CPU_IDLE_FIELDS = ['idle', 'iowait']
172e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
18ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny ChiuSYSFS_CPUQUIET_ENABLE = '/sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable'
192e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
202e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spangdef cpu_stress():
212e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    sha512_hash = open('/dev/urandom', 'r').read(64)
222e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    while True:
232e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        sha512_hash = hashlib.sha512(sha512_hash).digest()
242e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
252e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
262e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spangdef get_system_times():
272e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    proc_stat = utils.read_file('/proc/stat')
282e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    for line in proc_stat.split('\n'):
292e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        if line.startswith('cpu '):
302e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            times = line[4:].strip().split(' ')
312e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            times = [int(jiffies) for jiffies in times]
322e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            return dict(zip(PROC_STAT_CPU_FIELDS, times))
332e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
342e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
352e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spangdef get_avg_cpu_usage(pre_times, post_times):
362e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    diff_times = {}
372e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
382e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    for field in PROC_STAT_CPU_FIELDS:
392e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        diff_times[field] = post_times[field] - pre_times[field]
402e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
412e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    idle_time = sum(diff_times[field] for field in PROC_STAT_CPU_IDLE_FIELDS)
422e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    total_time = sum(diff_times[field] for field in PROC_STAT_CPU_FIELDS)
432e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
442e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    return float(total_time - idle_time) / total_time
452e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
462e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
472e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spangdef sleep_and_measure_cpu(sleep_seconds):
482e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    pre_times = get_system_times()
492e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    time.sleep(sleep_seconds)
502e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    post_times = get_system_times()
512e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
522e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    avg_cpu_usage = get_avg_cpu_usage(pre_times, post_times)
532e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    logging.info('average CPU utilization, last %ds: %s%%',
542e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang                 sleep_seconds, avg_cpu_usage * 100.)
552e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    return avg_cpu_usage
562e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
572e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
582e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spangclass power_HotCPUSuspend(test.test):
592e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    """Suspend the system with 100% CPU usage."""
602e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
612e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    version = 1
622e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
63ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu    def initialize(self):
64ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu        # Store the setting if the system has CPUQuiet feature
65ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu        if os.path.exists(SYSFS_CPUQUIET_ENABLE):
66ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu            self.is_cpuquiet_enabled = utils.read_file(SYSFS_CPUQUIET_ENABLE)
67ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu            utils.write_one_line(SYSFS_CPUQUIET_ENABLE, '0')
68ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu
692e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang    def run_once(self):
702e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        # create processs pool with enough workers to spin all CPUs
712e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        cpus = multiprocessing.cpu_count()
722e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        logging.info('found %d cpus', cpus)
732e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        workers = max(16, cpus * 2)
742e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        pool = multiprocessing.Pool(workers)
752e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
762e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        try:
772e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            # fill all CPUs with a spinning task
782e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            logging.info('starting %d workers', workers)
792e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            results = [pool.apply_async(cpu_stress) for _ in xrange(workers)]
802e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
812e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            # wait for things to settle
822e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            logging.info('spinning for %d seconds', SUSPEND_BURN_SECONDS)
832e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            if sleep_and_measure_cpu(SUSPEND_BURN_SECONDS) < MIN_CPU_USAGE:
842e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang                # There should be no idle time accounted while we're spinning.
852e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang                raise error.TestError('unexpected CPU idle time while spinning')
862e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
872e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            # go to suspend
880537d52c7b85e9454336449f2bc9efae5a4983a4Julius Werner            sys_power.kernel_suspend(10)
892e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
902e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            # keep spinning after userland resumes
912e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            logging.info('spinning for %d more seconds', RESUME_BURN_SECONDS)
922e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            if sleep_and_measure_cpu(RESUME_BURN_SECONDS) < MIN_CPU_USAGE:
932e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang                # There should be no idle time accounted while we're spinning.
942e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang                raise error.TestError('unexpected CPU idle time after resume')
952e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
962e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            # check workers: if computation completed, something is wrong
972e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            for result in results:
982e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang                if result.ready():
992e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang                    logging.error('worker finished: %s', result.get())
1002e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang                    raise error.TestError('worker terminated!')
1012e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang
1022e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang        finally:
1032e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            # kill off the workers
1042e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            logging.info('killing %d workers', workers)
1052e6ecda978a5d086c76ca014531ea781fd3d75aeMichael Spang            pool.terminate()
106ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu
107ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu    def cleanup(self):
108ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu        # Restore the original setting if system has CPUQuiet feature
109ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu        if os.path.exists(SYSFS_CPUQUIET_ENABLE):
110ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu            utils.open_write_close(
111ffd6a4b3f6c934f04392a53b53d5595a23b658dbPenny Chiu                SYSFS_CPUQUIET_ENABLE, self.is_cpuquiet_enabled)
112