site_utils.py revision bf67617f8f4cc06f0b63fae3c60f3cc1d228c40b
1#pylint: disable-msg=C0111
2
3# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import logging, os, platform, re, signal, tempfile, time, uuid
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.common_lib import utils
10from autotest_lib.client.bin import base_utils
11
12class TimeoutError(error.TestError):
13    """Error raised when we time out when waiting on a condition."""
14    pass
15
16
17class Crossystem(object):
18    """A wrapper for the crossystem utility."""
19
20    def __init__(self, client):
21        self.cros_system_data = {}
22        self._client = client
23
24    def init(self):
25        self.cros_system_data = {}
26        (_, fname) = tempfile.mkstemp()
27        f = open(fname, 'w')
28        self._client.run('crossystem', stdout_tee=f)
29        f.close()
30        text = utils.read_file(fname)
31        for line in text.splitlines():
32            assignment_string = line.split('#')[0]
33            if not assignment_string.count('='):
34                continue
35            (name, value) = assignment_string.split('=', 1)
36            self.cros_system_data[name.strip()] = value.strip()
37        os.remove(fname)
38
39    def __getattr__(self, name):
40        """
41        Retrieve a crosssystem attribute.
42
43        The call crossystemobject.name() will return the crossystem reported
44        string.
45        """
46        return lambda : self.cros_system_data[name]
47
48
49def get_oldest_pid_by_name(name):
50    """
51    Return the oldest pid of a process whose name perfectly matches |name|.
52
53    name is an egrep expression, which will be matched against the entire name
54    of processes on the system.  For example:
55
56      get_oldest_pid_by_name('chrome')
57
58    on a system running
59      8600 ?        00:00:04 chrome
60      8601 ?        00:00:00 chrome
61      8602 ?        00:00:00 chrome-sandbox
62
63    would return 8600, as that's the oldest process that matches.
64    chrome-sandbox would not be matched.
65
66    Arguments:
67      name: egrep expression to match.  Will be anchored at the beginning and
68            end of the match string.
69
70    Returns:
71      pid as an integer, or None if one cannot be found.
72
73    Raises:
74      ValueError if pgrep returns something odd.
75    """
76    str_pid = utils.system_output(
77        'pgrep -o ^%s$' % name, ignore_status=True).rstrip()
78    if str_pid:
79        return int(str_pid)
80
81
82def get_oldest_by_name(name):
83    """Return pid and command line of oldest process whose name matches |name|.
84
85    @param name: egrep expression to match desired process name.
86    @return: A tuple of (pid, command_line) of the oldest process whose name
87             matches |name|.
88
89    """
90    pid = get_oldest_pid_by_name(name)
91    if pid:
92        command_line = utils.system_output('ps -p %i -o command=' % pid,
93                                           ignore_status=True).rstrip()
94        return (pid, command_line)
95
96
97def get_chrome_remote_debugging_port():
98    """Returns remote debugging port for Chrome.
99
100    Parse chrome process's command line argument to get the remote debugging
101    port.
102    """
103    pid, command = get_oldest_by_name('chrome')
104    matches = re.search('--remote-debugging-port=([0-9]+)', command)
105    if matches:
106        return int(matches.group(1))
107
108
109def get_process_list(name, command_line=None):
110    """
111    Return the list of pid for matching process |name command_line|.
112
113    on a system running
114      31475 ?    0:06 /opt/google/chrome/chrome --allow-webui-compositing -
115      31478 ?    0:00 /opt/google/chrome/chrome-sandbox /opt/google/chrome/
116      31485 ?    0:00 /opt/google/chrome/chrome --type=zygote --log-level=1
117      31532 ?    1:05 /opt/google/chrome/chrome --type=renderer
118
119    get_process_list('chrome')
120    would return ['31475', '31485', '31532']
121
122    get_process_list('chrome', '--type=renderer')
123    would return ['31532']
124
125    Arguments:
126      name: process name to search for. If command_line is provided, name is
127            matched against full command line. If command_line is not provided,
128            name is only matched against the process name.
129      command line: when command line is passed, the full process command line
130                    is used for matching.
131
132    Returns:
133      list of PIDs of the matching processes.
134
135    """
136    # TODO(rohitbm) crbug.com/268861
137    flag = '-x' if not command_line else '-f'
138    name = '\'%s.*%s\'' % (name, command_line) if command_line else name
139    str_pid = utils.system_output(
140            'pgrep %s %s' % (flag, name), ignore_status=True).rstrip()
141    return str_pid
142
143
144def nuke_process_by_name(name, with_prejudice=False):
145    try:
146        pid = get_oldest_pid_by_name(name)
147    except Exception as e:
148        logging.error(e)
149        return
150    if pid is None:
151        raise error.AutoservPidAlreadyDeadError(
152            'No process matching %s.' % name)
153    if with_prejudice:
154        utils.nuke_pid(pid, [signal.SIGKILL])
155    else:
156        utils.nuke_pid(pid)
157
158
159def poll_for_condition(
160    condition, exception=None, timeout=10, sleep_interval=0.1, desc=None):
161    """Poll until a condition becomes true.
162
163    Arguments:
164      condition: function taking no args and returning bool
165      exception: exception to throw if condition doesn't become true
166      timeout: maximum number of seconds to wait
167      sleep_interval: time to sleep between polls
168      desc: description of default TimeoutError used if 'exception' is None
169
170    Returns:
171      The true value that caused the poll loop to terminate.
172
173    Raises:
174        'exception' arg if supplied; site_utils.TimeoutError otherwise
175    """
176    start_time = time.time()
177    while True:
178        value = condition()
179        if value:
180            return value
181        if time.time() + sleep_interval - start_time > timeout:
182            if exception:
183                logging.error(exception)
184                raise exception
185
186            if desc:
187                desc = 'Timed out waiting for condition: %s' % desc
188            else:
189                desc = 'Timed out waiting for unnamed condition'
190            logging.error(desc)
191            raise TimeoutError, desc
192
193        time.sleep(sleep_interval)
194
195
196def save_vm_state(checkpoint):
197    """Saves the current state of the virtual machine.
198
199    This function is a NOOP if the test is not running under a virtual machine
200    with the USB serial port redirected.
201
202    Arguments:
203      checkpoint - Name used to identify this state
204
205    Returns:
206      None
207    """
208    # The QEMU monitor has been redirected to the guest serial port located at
209    # /dev/ttyUSB0. To save the state of the VM, we just send the 'savevm'
210    # command to the serial port.
211    proc = platform.processor()
212    if 'QEMU' in proc and os.path.exists('/dev/ttyUSB0'):
213        logging.info('Saving VM state "%s"', checkpoint)
214        serial = open('/dev/ttyUSB0', 'w')
215        serial.write("savevm %s\r\n" % checkpoint)
216        logging.info('Done saving VM state "%s"', checkpoint)
217
218
219def check_raw_dmesg(dmesg, message_level, whitelist):
220    """Checks dmesg for unexpected warnings.
221
222    This function parses dmesg for message with message_level <= message_level
223    which do not appear in the whitelist.
224
225    Arguments:
226      dmesg - string containing raw dmesg buffer
227      message_level - minimum message priority to check
228      whitelist - messages to ignore
229
230    Returns:
231      List of unexpected warnings
232    """
233    whitelist_re = re.compile(r'(%s)' % '|'.join(whitelist))
234    unexpected = []
235    for line in dmesg.splitlines():
236        if int(line[1]) <= message_level:
237            stripped_line = line.split('] ', 1)[1]
238            if whitelist_re.search(stripped_line):
239                continue
240            unexpected.append(stripped_line)
241    return unexpected
242
243def verify_mesg_set(mesg, regex, whitelist):
244    """Verifies that the exact set of messages are present in a text.
245
246    This function finds all strings in the text matching a certain regex, and
247    then verifies that all expected strings are present in the set, and no
248    unexpected strings are there.
249
250    Arguments:
251      mesg - the mutiline text to be scanned
252      regex - regular expression to match
253      whitelist - messages to find in the output, a list of strings
254          (potentially regexes) to look for in the filtered output. All these
255          strings must be there, and no other strings should be present in the
256          filtered output.
257
258    Returns:
259      string of inconsistent findings (i.e. an empty string on success).
260    """
261
262    rv = []
263
264    missing_strings = []
265    present_strings = []
266    for line in mesg.splitlines():
267        if not re.search(r'%s' % regex, line):
268            continue
269        present_strings.append(line.split('] ', 1)[1])
270
271    for string in whitelist:
272        for present_string in list(present_strings):
273            if re.search(r'^%s$' % string, present_string):
274                present_strings.remove(present_string)
275                break
276        else:
277            missing_strings.append(string)
278
279    if present_strings:
280        rv.append('unexpected strings:')
281        rv.extend(present_strings)
282    if missing_strings:
283        rv.append('missing strings:')
284        rv.extend(missing_strings)
285
286    return '\n'.join(rv)
287
288
289def target_is_pie():
290    """Returns whether the toolchain produces a PIE (position independent
291    executable) by default.
292
293    Arguments:
294      None
295
296    Returns:
297      True if the target toolchain produces a PIE by default.
298      False otherwise.
299    """
300
301
302    command = 'echo | ${CC} -E -dD -P - | grep -i pie'
303    result = utils.system_output(command, retain_output=True,
304                                 ignore_status=True)
305    if re.search('#define __PIE__', result):
306        return True
307    else:
308        return False
309
310def target_is_x86():
311    """Returns whether the toolchain produces an x86 object
312
313    Arguments:
314      None
315
316    Returns:
317      True if the target toolchain produces an x86 object
318      False otherwise.
319    """
320
321
322    command = 'echo | ${CC} -E -dD -P - | grep -i 86'
323    result = utils.system_output(command, retain_output=True,
324                                 ignore_status=True)
325    if re.search('__i386__', result) or re.search('__x86_64__', result):
326        return True
327    else:
328        return False
329
330def mounts():
331    ret = []
332    for line in file('/proc/mounts'):
333        m = re.match(r'(?P<src>\S+) (?P<dest>\S+) (?P<type>\S+) (?P<opts>\S+).*', line)
334        if m:
335            ret.append(m.groupdict())
336    return ret
337
338def is_mountpoint(path):
339    return path in [ m['dest'] for m in mounts() ]
340
341def require_mountpoint(path):
342    """
343    Raises an exception if path is not a mountpoint.
344    """
345    if not is_mountpoint(path):
346        raise error.TestFail('Path not mounted: "%s"' % path)
347
348def random_username():
349    return str(uuid.uuid4()) + '@example.com'
350
351
352def parse_cmd_output(command, run_method=utils.run):
353    """Runs a command on a host object to retrieve host attributes.
354
355    The command should output to stdout in the format of:
356    <key> = <value> # <optional_comment>
357
358
359    @param command: Command to execute on the host.
360    @param run_method: Function to use to execute the command. Defaults to
361                       utils.run so that the command will be executed locally.
362                       Can be replace with a host.run call so that it will
363                       execute on a DUT or external machine. Method must accept
364                       a command argument, stdout_tee and stderr_tee args and
365                       return a result object with a string attribute stdout
366                       which will be parsed.
367
368    @returns a dictionary mapping host attributes to their values.
369    """
370    result = {}
371    # Suppresses stdout so that the files are not printed to the logs.
372    cmd_result = run_method(command, stdout_tee=None, stderr_tee=None)
373    for line in cmd_result.stdout.splitlines():
374        # Lines are of the format "<key>     = <value>      # <comment>"
375        key_value = re.match('^\s*(?P<key>[^ ]+)\s*=\s*(?P<value>[^ ]+)'
376                             '(?:\s*#.*)?$', line)
377        if key_value:
378            result[key_value.group('key')] = key_value.group('value')
379    return result
380
381
382def set_from_keyval_output(out, delimiter=' '):
383    """Parse delimiter-separated key-val output into a set of tuples.
384
385    Output is expected to be multiline text output from a command.
386    Stuffs the key-vals into tuples in a set to be later compared.
387
388    e.g.  deactivated 0
389          disableForceClear 0
390          ==>  set(('deactivated', '0'), ('disableForceClear', '0'))
391
392    @param out: multiple lines of space-separated key-val pairs.
393    @param delimiter: character that separates key from val. Usually a
394                      space but may be '=' or something else.
395    @return set of key-val tuples.
396    """
397    results = set()
398    kv_match_re = re.compile('([^ ]+)%s(.*)' % delimiter)
399    for linecr in out.splitlines():
400        match = kv_match_re.match(linecr.strip())
401        if match:
402            results.add((match.group(1), match.group(2)))
403    return results
404
405
406def get_cpu_usage():
407    """Returns machine's CPU usage.
408
409    This function uses /proc/stat to identify CPU usage.
410    Returns:
411        A dictionary with 'user', 'nice', 'system' and 'idle' values.
412        Sample dictionary:
413        {
414            'user': 254544,
415            'nice': 9,
416            'system': 254768,
417            'idle': 2859878,
418        }
419    """
420    proc_stat = open('/proc/stat')
421    cpu_usage_str = proc_stat.readline().split()
422    proc_stat.close()
423    return {
424        'user': int(cpu_usage_str[1]),
425        'nice': int(cpu_usage_str[2]),
426        'system': int(cpu_usage_str[3]),
427        'idle': int(cpu_usage_str[4])
428    }
429
430
431def compute_active_cpu_time(cpu_usage_start, cpu_usage_end):
432    """Computes the fraction of CPU time spent non-idling.
433
434    This function should be invoked using before/after values from calls to
435    get_cpu_usage().
436    """
437    time_active_end = (cpu_usage_end['user'] + cpu_usage_end['nice'] +
438                                                  cpu_usage_end['system'])
439    time_active_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
440                                                      cpu_usage_start['system'])
441    total_time_end = (cpu_usage_end['user'] + cpu_usage_end['nice'] +
442                      cpu_usage_end['system'] + cpu_usage_end['idle'])
443    total_time_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
444                        cpu_usage_start['system'] + cpu_usage_start['idle'])
445    return ((float(time_active_end) - time_active_start) /
446                    (total_time_end - total_time_start))
447
448
449def is_pgo_mode():
450    return 'USE_PGO' in os.environ
451
452
453def wait_for_idle_cpu(timeout, utilization):
454    """Waits for the CPU to become idle (< utilization).
455
456    Args:
457        timeout: The longest time in seconds to wait before throwing an error.
458        utilization: The CPU usage below which the system should be considered
459                idle (between 0 and 1.0 independent of cores/hyperthreads).
460    """
461    time_passed = 0.0
462    fraction_active_time = 1.0
463    sleep_time = 1
464    logging.info('Starting to wait up to %.1fs for idle CPU...', timeout)
465    while fraction_active_time >= utilization:
466        cpu_usage_start = get_cpu_usage()
467        # Split timeout interval into not too many chunks to limit log spew.
468        # Start at 1 second, increase exponentially
469        time.sleep(sleep_time)
470        time_passed += sleep_time
471        sleep_time = min(16.0, 2.0 * sleep_time)
472        cpu_usage_end = get_cpu_usage()
473        fraction_active_time = \
474                compute_active_cpu_time(cpu_usage_start, cpu_usage_end)
475        logging.info('After waiting %.1fs CPU utilization is %.3f.',
476                     time_passed, fraction_active_time)
477        if time_passed > timeout:
478            logging.warning('CPU did not become idle.')
479            log_process_activity()
480            # crosbug.com/37389
481            if is_pgo_mode():
482                logging.info('Still continuing because we are in PGO mode.')
483                return True
484
485            return False
486    logging.info('Wait for idle CPU took %.1fs (utilization = %.3f).',
487                              time_passed, fraction_active_time)
488    return True
489
490
491def log_process_activity():
492    """Logs the output of top.
493
494    Useful to debug performance tests and to find runaway processes.
495    """
496    logging.info('Logging current process activity using top.')
497    cmd = 'top -b -n1 -c'
498    output = utils.run(cmd)
499    logging.info(output)
500
501
502def wait_for_cool_machine():
503    # TODO(ihf): Implement this. The concept of a cool machine is very
504    # architecture specific. We either need a good heuristic or a table of
505    # board specific temperatures.
506    time.sleep(1.0)
507    return True
508
509
510# System paths for machine performance state.
511_CPUINFO = '/proc/cpuinfo'
512_KERNEL_MAX = '/sys/devices/system/cpu/kernel_max'
513_MEMINFO = '/proc/meminfo'
514_TEMP_SENSOR_RE = 'Reading temperature...([0-9]*)'
515
516
517def _get_line_from_file(path, line):
518    """
519    line can be an integer or
520    line can be a string that matches the beginning of the line
521    """
522    f = open(path)
523    if (isinstance(line, int)):
524        l = f.readline()
525        for _ in range(0, line):
526            l = f.readline()
527        return l
528    else:
529        for l in f:
530            if l.startswith(line):
531                return l
532    return None
533
534
535def _get_match_from_file(path, line, prefix, postfix):
536    """
537    Matches line in path and returns string between first prefix and postfix.
538    """
539    match = _get_line_from_file(path, line)
540    # Strip everything from front of line including prefix.
541    if prefix:
542        match = re.split(prefix, match)[1]
543    # Strip everything from back of string including first occurence of postfix.
544    if postfix:
545        match = re.split(postfix, match)[0]
546    return match
547
548
549def _get_float_from_file(path, line, prefix, postfix):
550    match = _get_match_from_file(path, line, prefix, postfix)
551    return float(match)
552
553
554def _get_int_from_file(path, line, prefix, postfix):
555    match = _get_match_from_file(path, line, prefix, postfix)
556    return int(match)
557
558
559def _get_hex_from_file(path, line, prefix, postfix):
560    match = _get_match_from_file(path, line, prefix, postfix)
561    return int(match, 16)
562
563
564def _get_hwmon_paths(file_pattern):
565    """
566    Returns a list of paths to the temperature sensors.
567    """
568    # Some systems like daisy_spring only have the virtual hwmon.
569    # And other systems like rambi only have coretemp.0. See crbug.com/360249.
570    #    /sys/class/hwmon/hwmon*/
571    #    /sys/devices/virtual/hwmon/hwmon*/
572    #    /sys/devices/platform/coretemp.0/
573    cmd = 'find /sys/ -name "' + file_pattern + '"'
574    paths = utils.run(cmd, verbose=False).stdout.splitlines()
575    return paths
576
577
578def get_temperature_critical():
579    """
580    Returns temperature at which we will see some throttling in the system.
581    """
582    min_temperature = 1000.0
583    paths = _get_hwmon_paths('temp*_crit')
584    for path in paths:
585        temperature = _get_float_from_file(path, 0, None, None) * 0.001
586        # Today typical for Intel is 98'C to 105'C while ARM is 85'C. Clamp to
587        # the lowest known value.
588        if ((min_temperature < 60.0) or min_temperature > 150.0):
589            min_temperature = 85.0
590
591        min_temperature = min(temperature, min_temperature)
592    return min_temperature
593
594
595def get_temperature_input_max():
596    """
597    Returns the maximum currently observed temperature.
598    """
599    max_temperature = -1000.0
600    paths = _get_hwmon_paths('temp*_input')
601    for path in paths:
602        temperature = _get_float_from_file(path, 0, None, None) * 0.001
603        max_temperature = max(temperature, max_temperature)
604    # Sanity check for real world values.
605    assert ((max_temperature > 10.0) and
606            (max_temperature < 150.0)), 'Unreasonable temperature.'
607    return max_temperature
608
609
610def get_ec_temperatures():
611    """
612    Uses ectool to return a list of all sensor temperatures in Celsius.
613    """
614    temperatures = []
615    # TODO(ihf): On all ARM boards I tested 'ectool temps all' returns 200K
616    # for all sensors. Remove this check once crbug.com/358342 is fixed.
617    if 'arm' in utils.get_arch():
618        return temperatures
619    try:
620        full_cmd = 'ectool temps all'
621        lines = utils.run(full_cmd, verbose=False).stdout.splitlines()
622        for line in lines:
623            temperature = int(line.split(': ')[1]) - 273
624            temperatures.append(temperature)
625    except Exception:
626        logging.warn('Unable to read temperature sensors using ectool.')
627    for temperature in temperatures:
628        # Sanity check for real world values.
629        assert ((temperature > 10.0) and
630                (temperature < 150.0)), 'Unreasonable temperature.'
631    return temperatures
632
633
634def get_cpu_cache_size():
635    """
636    Returns the last level CPU cache size in kBytes.
637    """
638    cache_size = _get_int_from_file(_CPUINFO, 'cache size', ': ', ' KB')
639    # Sanity check.
640    assert cache_size >= 64, 'Unreasonably small cache.'
641    return cache_size
642
643
644def get_cpu_model_frequency():
645    """
646    Returns the model frequency from the CPU model name on Intel only. This
647    might be redundant with get_cpu_max_frequency. Unit is Hz.
648    """
649    frequency = _get_float_from_file(_CPUINFO, 'model name', ' @ ', 'GHz')
650    return 1.e9 * frequency
651
652
653def get_cpu_max_frequency():
654    """
655    Returns the largest of the max CPU core frequencies. The unit is Hz.
656    """
657    max_frequency = -1
658    paths = _get_cpufreq_paths('cpuinfo_max_freq')
659    for path in paths:
660        # Convert from kHz to Hz.
661        frequency = 1000 * _get_float_from_file(path, 0, None, None)
662        max_frequency = max(frequency, max_frequency)
663    # Sanity check.
664    assert max_frequency > 1e8, 'Unreasonably low CPU frequency.'
665    return max_frequency
666
667
668def get_cpu_min_frequency():
669    """
670    Returns the smallest of the minimum CPU core frequencies.
671    """
672    min_frequency = 1e20
673    paths = _get_cpufreq_paths('cpuinfo_min_freq')
674    for path in paths:
675        frequency = _get_float_from_file(path, 0, None, None)
676        min_frequency = min(frequency, min_frequency)
677    # Sanity check.
678    assert min_frequency > 1e8, 'Unreasonably low CPU frequency.'
679    return min_frequency
680
681
682def get_cpu_model():
683    """
684    Returns the CPU model.
685    Only works on Intel.
686    """
687    cpu_model = _get_int_from_file(_CPUINFO, 'model\t', ': ', None)
688    return cpu_model
689
690
691def get_cpu_family():
692    """
693    Returns the CPU family.
694    Only works on Intel.
695    """
696    cpu_family = _get_int_from_file(_CPUINFO, 'cpu family\t', ': ', None)
697    return cpu_family
698
699
700def get_board():
701    """
702    Get the ChromeOS release board name from /etc/lsb-release.
703    """
704    f = open('/etc/lsb-release')
705    try:
706        return re.search('BOARD=(.*)', f.read()).group(1)
707    finally:
708        f.close()
709
710
711def get_board_with_frequency_and_memory():
712    """
713    Returns a board name modified with CPU frequency and memory size to
714    differentiate between different board variants. For instance
715    link -> link_1.8GHz_4GB.
716    """
717    board_name = get_board()
718    # Rounded to nearest GB and GHz.
719    memory = int(round(get_mem_total()/1024.0))
720    # Convert frequency to GHz with 1 digit accuracy after the decimal point.
721    frequency = int(round(get_cpu_max_frequency() * 1e-8)) * 0.1
722    board = "%s_%1.1fGHz_%dGB" % (board_name, frequency, memory)
723    return board
724
725
726def get_mem_total():
727    """
728    Returns the total memory available in the system in MBytes.
729    """
730    mem_total = _get_float_from_file(_MEMINFO, 'MemTotal:', 'MemTotal:', ' kB')
731    # Sanity check, all Chromebooks have at least 1GB of memory.
732    assert mem_total > 1024*1024, 'Unreasonable amount of memory.'
733    return mem_total / 1024
734
735
736def get_mem_free():
737    """
738    Returns the currently free memory in the system in MBytes.
739    """
740    mem_free = _get_float_from_file(_MEMINFO, 'MemFree:', 'MemFree:', ' kB')
741    return mem_free / 1024
742
743
744def get_kernel_max():
745    """
746    Returns content of kernel_max.
747    """
748    kernel_max = _get_int_from_file(_KERNEL_MAX, 0, None, None)
749    # Sanity check.
750    assert ((kernel_max > 0) and (kernel_max < 257)), 'Unreasonable kernel_max.'
751    return kernel_max
752
753
754def set_high_performance_mode():
755    """
756    Sets the kernel governor mode to the highest setting.
757    Returns previous governor state.
758    """
759    original_governors = get_scaling_governor_states()
760    set_scaling_governors('performance')
761    return original_governors
762
763
764def set_scaling_governors(value):
765    """
766    Sets all scaling governor to string value.
767    Sample values: 'performance', 'interactive', 'ondemand', 'powersave'.
768    """
769    paths = _get_cpufreq_paths('scaling_governor')
770    for path in paths:
771        cmd = 'sudo echo %s > %s' % (value, path)
772        logging.info('Writing scaling governor mode \'%s\' -> %s', value, path)
773        utils.system(cmd)
774
775
776def _get_cpufreq_paths(filename):
777    """
778    Returns a list of paths to the governors.
779    """
780    cmd = 'ls /sys/devices/system/cpu/cpu*/cpufreq/' + filename
781    paths = utils.run(cmd, verbose=False).stdout.splitlines()
782    return paths
783
784
785def get_scaling_governor_states():
786    """
787    Returns a list of (performance governor path, current state) tuples.
788    """
789    paths = _get_cpufreq_paths('scaling_governor')
790    path_value_list = []
791    for path in paths:
792        value = _get_line_from_file(path, 0)
793        path_value_list.append((path, value))
794    return path_value_list
795
796
797def restore_scaling_governor_states(path_value_list):
798    """
799    Restores governor states. Inverse operation to get_scaling_governor_states.
800    """
801    for (path, value) in path_value_list:
802        cmd = 'sudo echo %s > %s' % (value, path)
803        utils.system(cmd)
804
805
806def get_gpu_family():
807    """Return the GPU family name"""
808    cpuarch = base_utils.get_cpu_soc_family()
809    if cpuarch == 'exynos5':
810        return 'mali'
811    if cpuarch == 'tegra':
812        return 'tegra'
813
814    pci_path = '/sys/bus/pci/devices/0000:00:02.0/device'
815
816    if not os.path.exists(pci_path):
817        raise error.TestError('PCI device 0000:00:02.0 not found')
818
819    device_id = int(utils.read_one_line(pci_path), 16)
820    intel_architecture = {
821        0xa011: 'pinetrail',
822        0x0106: 'sandybridge',
823        0x0126: 'sandybridge',
824        0x0156: 'ivybridge',
825        0x0166: 'ivybridge',
826        0x0a06: 'haswell',
827        0x0f31: 'baytrail',
828    }
829
830    return intel_architecture[device_id]
831