blob: b19684e574cb5a899d2477284c0f4fc9f758717d [file] [log] [blame]
Allen Li2c32d6b2017-02-03 15:28:10 -08001# Copyright 2017 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
mblighaece77e2009-01-21 19:06:52 +00005"""
6Convenience functions for use by tests or whomever.
mblighaece77e2009-01-21 19:06:52 +00007"""
Allen Li2c32d6b2017-02-03 15:28:10 -08008
9# pylint: disable=missing-docstring
10
11import commands
12import fnmatch
13import glob
14import json
15import logging
16import math
17import multiprocessing
mblighcc038642009-02-05 20:15:52 +000018import os
Allen Li2c32d6b2017-02-03 15:28:10 -080019import pickle
20import platform
21import re
22import shutil
23import signal
24import tempfile
25import time
26import uuid
27
28from autotest_lib.client.common_lib import error
29from autotest_lib.client.common_lib import magic
30from autotest_lib.client.common_lib import utils
mblighaece77e2009-01-21 19:06:52 +000031
32from autotest_lib.client.common_lib.utils import *
Allen Li2c32d6b2017-02-03 15:28:10 -080033
34
35def grep(pattern, file):
36 """
37 This is mainly to fix the return code inversion from grep
38 Also handles compressed files.
39
40 returns 1 if the pattern is present in the file, 0 if not.
41 """
42 command = 'grep "%s" > /dev/null' % pattern
43 ret = cat_file_to_cmd(file, command, ignore_status=True)
44 return not ret
45
46
47def difflist(list1, list2):
48 """returns items in list2 that are not in list1"""
49 diff = [];
50 for x in list2:
51 if x not in list1:
52 diff.append(x)
53 return diff
54
55
56def cat_file_to_cmd(file, command, ignore_status=0, return_output=False):
57 """
58 equivalent to 'cat file | command' but knows to use
59 zcat or bzcat if appropriate
60 """
61 if not os.path.isfile(file):
62 raise NameError('invalid file %s to cat to command %s'
63 % (file, command))
64
65 if return_output:
66 run_cmd = utils.system_output
67 else:
68 run_cmd = utils.system
69
70 if magic.guess_type(file) == 'application/x-bzip2':
71 cat = 'bzcat'
72 elif magic.guess_type(file) == 'application/x-gzip':
73 cat = 'zcat'
74 else:
75 cat = 'cat'
76 return run_cmd('%s %s | %s' % (cat, file, command),
77 ignore_status=ignore_status)
78
79
80def extract_tarball_to_dir(tarball, dir):
81 """
82 Extract a tarball to a specified directory name instead of whatever
83 the top level of a tarball is - useful for versioned directory names, etc
84 """
85 if os.path.exists(dir):
86 if os.path.isdir(dir):
87 shutil.rmtree(dir)
88 else:
89 os.remove(dir)
90 pwd = os.getcwd()
91 os.chdir(os.path.dirname(os.path.abspath(dir)))
92 newdir = extract_tarball(tarball)
93 os.rename(newdir, dir)
94 os.chdir(pwd)
95
96
97def extract_tarball(tarball):
98 """Returns the directory extracted by the tarball."""
99 extracted = cat_file_to_cmd(tarball, 'tar xvf - 2>/dev/null',
100 return_output=True).splitlines()
101
102 dir = None
103
104 for line in extracted:
105 if line.startswith('./'):
106 line = line[2:]
107 if not line or line == '.':
108 continue
109 topdir = line.split('/')[0]
110 if os.path.isdir(topdir):
111 if dir:
112 assert(dir == topdir)
113 else:
114 dir = topdir
115 if dir:
116 return dir
117 else:
118 raise NameError('extracting tarball produced no dir')
119
120
121def unmap_url_cache(cachedir, url, expected_hash, method="md5"):
122 """
123 Downloads a file from a URL to a cache directory. If the file is already
124 at the expected position and has the expected hash, let's not download it
125 again.
126
127 @param cachedir: Directory that might hold a copy of the file we want to
128 download.
129 @param url: URL for the file we want to download.
130 @param expected_hash: Hash string that we expect the file downloaded to
131 have.
132 @param method: Method used to calculate the hash string (md5, sha1).
133 """
134 # Let's convert cachedir to a canonical path, if it's not already
135 cachedir = os.path.realpath(cachedir)
136 if not os.path.isdir(cachedir):
137 try:
138 os.makedirs(cachedir)
139 except:
140 raise ValueError('Could not create cache directory %s' % cachedir)
141 file_from_url = os.path.basename(url)
142 file_local_path = os.path.join(cachedir, file_from_url)
143
144 file_hash = None
145 failure_counter = 0
146 while not file_hash == expected_hash:
147 if os.path.isfile(file_local_path):
148 file_hash = hash_file(file_local_path, method)
149 if file_hash == expected_hash:
150 # File is already at the expected position and ready to go
151 src = file_from_url
152 else:
153 # Let's download the package again, it's corrupted...
154 logging.error("Seems that file %s is corrupted, trying to "
155 "download it again", file_from_url)
156 src = url
157 failure_counter += 1
158 else:
159 # File is not there, let's download it
160 src = url
161 if failure_counter > 1:
162 raise EnvironmentError("Consistently failed to download the "
163 "package %s. Aborting further download "
164 "attempts. This might mean either the "
165 "network connection has problems or the "
166 "expected hash string that was determined "
167 "for this file is wrong", file_from_url)
168 file_path = utils.unmap_url(cachedir, src, cachedir)
169
170 return file_path
171
172
173def force_copy(src, dest):
174 """Replace dest with a new copy of src, even if it exists"""
175 if os.path.isfile(dest):
176 os.remove(dest)
177 if os.path.isdir(dest):
178 dest = os.path.join(dest, os.path.basename(src))
179 shutil.copyfile(src, dest)
180 return dest
181
182
183def force_link(src, dest):
184 """Link src to dest, overwriting it if it exists"""
185 return utils.system("ln -sf %s %s" % (src, dest))
186
187
188def file_contains_pattern(file, pattern):
189 """Return true if file contains the specified egrep pattern"""
190 if not os.path.isfile(file):
191 raise NameError('file %s does not exist' % file)
192 return not utils.system('egrep -q "' + pattern + '" ' + file,
193 ignore_status=True)
194
195
196def list_grep(list, pattern):
197 """True if any item in list matches the specified pattern."""
198 compiled = re.compile(pattern)
199 for line in list:
200 match = compiled.search(line)
201 if (match):
202 return 1
203 return 0
204
205
206def get_os_vendor():
207 """Try to guess what's the os vendor
208 """
209 if os.path.isfile('/etc/SuSE-release'):
210 return 'SUSE'
211
212 issue = '/etc/issue'
213
214 if not os.path.isfile(issue):
215 return 'Unknown'
216
217 if file_contains_pattern(issue, 'Red Hat'):
218 return 'Red Hat'
219 elif file_contains_pattern(issue, 'Fedora'):
220 return 'Fedora Core'
221 elif file_contains_pattern(issue, 'SUSE'):
222 return 'SUSE'
223 elif file_contains_pattern(issue, 'Ubuntu'):
224 return 'Ubuntu'
225 elif file_contains_pattern(issue, 'Debian'):
226 return 'Debian'
227 else:
228 return 'Unknown'
229
230
231def get_cc():
232 try:
233 return os.environ['CC']
234 except KeyError:
235 return 'gcc'
236
237
238def get_vmlinux():
239 """Return the full path to vmlinux
240
241 Ahem. This is crap. Pray harder. Bad Martin.
242 """
243 vmlinux = '/boot/vmlinux-%s' % utils.system_output('uname -r')
244 if os.path.isfile(vmlinux):
245 return vmlinux
246 vmlinux = '/lib/modules/%s/build/vmlinux' % utils.system_output('uname -r')
247 if os.path.isfile(vmlinux):
248 return vmlinux
249 return None
250
251
252def get_systemmap():
253 """Return the full path to System.map
254
255 Ahem. This is crap. Pray harder. Bad Martin.
256 """
257 map = '/boot/System.map-%s' % utils.system_output('uname -r')
258 if os.path.isfile(map):
259 return map
260 map = '/lib/modules/%s/build/System.map' % utils.system_output('uname -r')
261 if os.path.isfile(map):
262 return map
263 return None
264
265
266def get_modules_dir():
267 """Return the modules dir for the running kernel version"""
268 kernel_version = utils.system_output('uname -r')
269 return '/lib/modules/%s/kernel' % kernel_version
270
271
272_CPUINFO_RE = re.compile(r'^(?P<key>[^\t]*)\t*: ?(?P<value>.*)$')
273
274
275def get_cpuinfo():
276 """Read /proc/cpuinfo and convert to a list of dicts."""
277 cpuinfo = []
278 with open('/proc/cpuinfo', 'r') as f:
279 cpu = {}
280 for line in f:
281 line = line.strip()
282 if not line:
283 cpuinfo.append(cpu)
284 cpu = {}
285 continue
286 match = _CPUINFO_RE.match(line)
287 cpu[match.group('key')] = match.group('value')
288 if cpu:
289 # cpuinfo usually ends in a blank line, so this shouldn't happen.
290 cpuinfo.append(cpu)
291 return cpuinfo
292
293
294def get_cpu_arch():
295 """Work out which CPU architecture we're running on"""
296 f = open('/proc/cpuinfo', 'r')
297 cpuinfo = f.readlines()
298 f.close()
299 if list_grep(cpuinfo, '^cpu.*(RS64|POWER3|Broadband Engine)'):
300 return 'power'
301 elif list_grep(cpuinfo, '^cpu.*POWER4'):
302 return 'power4'
303 elif list_grep(cpuinfo, '^cpu.*POWER5'):
304 return 'power5'
305 elif list_grep(cpuinfo, '^cpu.*POWER6'):
306 return 'power6'
307 elif list_grep(cpuinfo, '^cpu.*POWER7'):
308 return 'power7'
309 elif list_grep(cpuinfo, '^cpu.*PPC970'):
310 return 'power970'
311 elif list_grep(cpuinfo, 'ARM'):
312 return 'arm'
313 elif list_grep(cpuinfo, '^flags.*:.* lm .*'):
314 return 'x86_64'
315 elif list_grep(cpuinfo, 'CPU.*implementer.*0x41'):
316 return 'arm'
317 else:
318 return 'i386'
319
320
321def get_arm_soc_family_from_devicetree():
322 """
323 Work out which ARM SoC we're running on based on the 'compatible' property
324 of the base node of devicetree, if it exists.
325 """
326 devicetree_compatible = '/sys/firmware/devicetree/base/compatible'
327 if not os.path.isfile(devicetree_compatible):
328 return None
329 f = open(devicetree_compatible, 'r')
330 compatible = f.readlines()
331 f.close()
332 if list_grep(compatible, 'rk3399'):
333 return 'rockchip'
334 elif list_grep(compatible, 'mt8173'):
335 return 'mediatek'
336 return None
337
338
339def get_arm_soc_family():
340 """Work out which ARM SoC we're running on"""
341 family = get_arm_soc_family_from_devicetree()
342 if family is not None:
343 return family
344
345 f = open('/proc/cpuinfo', 'r')
346 cpuinfo = f.readlines()
347 f.close()
348 if list_grep(cpuinfo, 'EXYNOS5'):
349 return 'exynos5'
350 elif list_grep(cpuinfo, 'Tegra'):
351 return 'tegra'
352 elif list_grep(cpuinfo, 'Rockchip'):
353 return 'rockchip'
354 return 'arm'
355
356
357def get_cpu_soc_family():
358 """Like get_cpu_arch, but for ARM, returns the SoC family name"""
359 f = open('/proc/cpuinfo', 'r')
360 cpuinfo = f.readlines()
361 f.close()
362 family = get_cpu_arch()
363 if family == 'arm':
364 family = get_arm_soc_family()
365 if list_grep(cpuinfo, '^vendor_id.*:.*AMD'):
366 family = 'amd'
367 return family
368
369
370INTEL_UARCH_TABLE = {
371 '06_1C': 'Atom',
372 '06_26': 'Atom',
373 '06_36': 'Atom',
374 '06_4C': 'Braswell',
375 '06_3D': 'Broadwell',
376 '06_0D': 'Dothan',
377 '06_3A': 'IvyBridge',
378 '06_3E': 'IvyBridge',
379 '06_3C': 'Haswell',
380 '06_3F': 'Haswell',
381 '06_45': 'Haswell',
382 '06_46': 'Haswell',
383 '06_0F': 'Merom',
384 '06_16': 'Merom',
385 '06_17': 'Nehalem',
386 '06_1A': 'Nehalem',
387 '06_1D': 'Nehalem',
388 '06_1E': 'Nehalem',
389 '06_1F': 'Nehalem',
390 '06_2E': 'Nehalem',
391 '06_2A': 'SandyBridge',
392 '06_2D': 'SandyBridge',
393 '06_4E': 'Skylake',
394 '0F_03': 'Prescott',
395 '0F_04': 'Prescott',
396 '0F_06': 'Presler',
397 '06_25': 'Westmere',
398 '06_2C': 'Westmere',
399 '06_2F': 'Westmere',
400}
401
402
403def get_intel_cpu_uarch(numeric=False):
404 """Return the Intel microarchitecture we're running on, or None.
405
406 Returns None if this is not an Intel CPU. Returns the family and model as
407 underscore-separated hex (per Intel manual convention) if the uarch is not
408 known, or if numeric is True.
409 """
410 if not get_current_kernel_arch().startswith('x86'):
411 return None
412 cpuinfo = get_cpuinfo()[0]
413 if cpuinfo['vendor_id'] != 'GenuineIntel':
414 return None
415 family_model = '%02X_%02X' % (int(cpuinfo['cpu family']),
416 int(cpuinfo['model']))
417 if numeric:
418 return family_model
419 return INTEL_UARCH_TABLE.get(family_model, family_model)
420
421
422def get_current_kernel_arch():
423 """Get the machine architecture, now just a wrap of 'uname -m'."""
424 return os.popen('uname -m').read().rstrip()
425
426
427def get_file_arch(filename):
428 # -L means follow symlinks
429 file_data = utils.system_output('file -L ' + filename)
430 if file_data.count('80386'):
431 return 'i386'
432 return None
433
434
435def count_cpus():
436 """number of CPUs in the local machine according to /proc/cpuinfo"""
437 try:
438 return multiprocessing.cpu_count()
439 except Exception:
440 logging.exception('can not get cpu count from'
441 ' multiprocessing.cpu_count()')
442 cpuinfo = get_cpuinfo()
443 # Returns at least one cpu. Check comment #1 in crosbug.com/p/9582.
444 return len(cpuinfo) or 1
445
446
447def cpu_online_map():
448 """
449 Check out the available cpu online map
450 """
451 cpuinfo = get_cpuinfo()
452 cpus = []
453 for cpu in cpuinfo:
454 cpus.append(cpu['processor']) # grab cpu number
455 return cpus
456
457
458def get_cpu_family():
459 cpuinfo = get_cpuinfo()[0]
460 return int(cpuinfo['cpu_family'])
461
462
463def get_cpu_vendor():
464 cpuinfo = get_cpuinfo()
465 vendors = [cpu['vendor_id'] for cpu in cpuinfo]
466 for v in vendors[1:]:
467 if v != vendors[0]:
468 raise error.TestError('multiple cpu vendors found: ' + str(vendors))
469 return vendors[0]
470
471
472def probe_cpus():
473 """
474 This routine returns a list of cpu devices found under
475 /sys/devices/system/cpu.
476 """
477 cmd = 'find /sys/devices/system/cpu/ -maxdepth 1 -type d -name cpu*'
478 return utils.system_output(cmd).splitlines()
479
480
481# Returns total memory in kb
482def read_from_meminfo(key):
483 meminfo = utils.system_output('grep %s /proc/meminfo' % key)
484 return int(re.search(r'\d+', meminfo).group(0))
485
486
487def memtotal():
488 return read_from_meminfo('MemTotal')
489
490
491def freememtotal():
492 return read_from_meminfo('MemFree')
493
494def usable_memtotal():
495 # Reserved 5% for OS use
496 return int(read_from_meminfo('MemFree') * 0.95)
497
498
499def rounded_memtotal():
500 # Get total of all physical mem, in kbytes
501 usable_kbytes = memtotal()
502 # usable_kbytes is system's usable DRAM in kbytes,
503 # as reported by memtotal() from device /proc/meminfo memtotal
504 # after Linux deducts 1.5% to 5.1% for system table overhead
505 # Undo the unknown actual deduction by rounding up
506 # to next small multiple of a big power-of-two
507 # eg 12GB - 5.1% gets rounded back up to 12GB
508 mindeduct = 0.015 # 1.5 percent
509 maxdeduct = 0.055 # 5.5 percent
510 # deduction range 1.5% .. 5.5% supports physical mem sizes
511 # 6GB .. 12GB in steps of .5GB
512 # 12GB .. 24GB in steps of 1 GB
513 # 24GB .. 48GB in steps of 2 GB ...
514 # Finer granularity in physical mem sizes would require
515 # tighter spread between min and max possible deductions
516
517 # increase mem size by at least min deduction, without rounding
518 min_kbytes = int(usable_kbytes / (1.0 - mindeduct))
519 # increase mem size further by 2**n rounding, by 0..roundKb or more
520 round_kbytes = int(usable_kbytes / (1.0 - maxdeduct)) - min_kbytes
521 # find least binary roundup 2**n that covers worst-cast roundKb
522 mod2n = 1 << int(math.ceil(math.log(round_kbytes, 2)))
523 # have round_kbytes <= mod2n < round_kbytes*2
524 # round min_kbytes up to next multiple of mod2n
525 phys_kbytes = min_kbytes + mod2n - 1
526 phys_kbytes = phys_kbytes - (phys_kbytes % mod2n) # clear low bits
527 return phys_kbytes
528
529
530def sysctl(key, value=None):
531 """Generic implementation of sysctl, to read and write.
532
533 @param key: A location under /proc/sys
534 @param value: If not None, a value to write into the sysctl.
535
536 @return The single-line sysctl value as a string.
537 """
538 path = '/proc/sys/%s' % key
539 if value is not None:
540 utils.write_one_line(path, str(value))
541 return utils.read_one_line(path)
542
543
544def sysctl_kernel(key, value=None):
545 """(Very) partial implementation of sysctl, for kernel params"""
546 if value is not None:
547 # write
548 utils.write_one_line('/proc/sys/kernel/%s' % key, str(value))
549 else:
550 # read
551 out = utils.read_one_line('/proc/sys/kernel/%s' % key)
552 return int(re.search(r'\d+', out).group(0))
553
554
555def _convert_exit_status(sts):
556 if os.WIFSIGNALED(sts):
557 return -os.WTERMSIG(sts)
558 elif os.WIFEXITED(sts):
559 return os.WEXITSTATUS(sts)
560 else:
561 # impossible?
562 raise RuntimeError("Unknown exit status %d!" % sts)
563
564
565def where_art_thy_filehandles():
566 """Dump the current list of filehandles"""
567 os.system("ls -l /proc/%d/fd >> /dev/tty" % os.getpid())
568
569
570def print_to_tty(string):
571 """Output string straight to the tty"""
572 open('/dev/tty', 'w').write(string + '\n')
573
574
575def dump_object(object):
576 """Dump an object's attributes and methods
577
578 kind of like dir()
579 """
580 for item in object.__dict__.iteritems():
581 print item
582 try:
583 (key, value) = item
584 dump_object(value)
585 except:
586 continue
587
588
589def environ(env_key):
590 """return the requested environment variable, or '' if unset"""
591 if (os.environ.has_key(env_key)):
592 return os.environ[env_key]
593 else:
594 return ''
595
596
597def prepend_path(newpath, oldpath):
598 """prepend newpath to oldpath"""
599 if (oldpath):
600 return newpath + ':' + oldpath
601 else:
602 return newpath
603
604
605def append_path(oldpath, newpath):
606 """append newpath to oldpath"""
607 if (oldpath):
608 return oldpath + ':' + newpath
609 else:
610 return newpath
611
612
613_TIME_OUTPUT_RE = re.compile(
614 r'([\d\.]*)user ([\d\.]*)system '
615 r'(\d*):([\d\.]*)elapsed (\d*)%CPU')
616
617
618def avgtime_print(dir):
619 """ Calculate some benchmarking statistics.
620 Input is a directory containing a file called 'time'.
621 File contains one-per-line results of /usr/bin/time.
622 Output is average Elapsed, User, and System time in seconds,
623 and average CPU percentage.
624 """
625 user = system = elapsed = cpu = count = 0
626 with open(dir + "/time") as f:
627 for line in f:
628 try:
629 m = _TIME_OUTPUT_RE.match(line);
630 user += float(m.group(1))
631 system += float(m.group(2))
632 elapsed += (float(m.group(3)) * 60) + float(m.group(4))
633 cpu += float(m.group(5))
634 count += 1
635 except:
636 raise ValueError("badly formatted times")
637
638 return "Elapsed: %0.2fs User: %0.2fs System: %0.2fs CPU: %0.0f%%" % \
639 (elapsed / count, user / count, system / count, cpu / count)
640
641
642def to_seconds(time_string):
643 """Converts a string in M+:SS.SS format to S+.SS"""
644 elts = time_string.split(':')
645 if len(elts) == 1:
646 return time_string
647 return str(int(elts[0]) * 60 + float(elts[1]))
648
649
650_TIME_OUTPUT_RE_2 = re.compile(r'(.*?)user (.*?)system (.*?)elapsed')
651
652
653def extract_all_time_results(results_string):
654 """Extract user, system, and elapsed times into a list of tuples"""
655 results = []
656 for result in _TIME_OUTPUT_RE_2.findall(results_string):
657 results.append(tuple([to_seconds(elt) for elt in result]))
658 return results
659
660
661def running_config():
662 """
663 Return path of config file of the currently running kernel
664 """
665 version = utils.system_output('uname -r')
666 for config in ('/proc/config.gz', \
667 '/boot/config-%s' % version,
668 '/lib/modules/%s/build/.config' % version):
669 if os.path.isfile(config):
670 return config
671 return None
672
673
674def check_for_kernel_feature(feature):
675 config = running_config()
676
677 if not config:
678 raise TypeError("Can't find kernel config file")
679
680 if magic.guess_type(config) == 'application/x-gzip':
681 grep = 'zgrep'
682 else:
683 grep = 'grep'
684 grep += ' ^CONFIG_%s= %s' % (feature, config)
685
686 if not utils.system_output(grep, ignore_status=True):
687 raise ValueError("Kernel doesn't have a %s feature" % (feature))
688
689
690def check_glibc_ver(ver):
691 glibc_ver = commands.getoutput('ldd --version').splitlines()[0]
692 glibc_ver = re.search(r'(\d+\.\d+(\.\d+)?)', glibc_ver).group()
693 if utils.compare_versions(glibc_ver, ver) == -1:
694 raise error.TestError("Glibc too old (%s). Glibc >= %s is needed." %
695 (glibc_ver, ver))
696
697def check_kernel_ver(ver):
698 kernel_ver = utils.system_output('uname -r')
699 kv_tmp = re.split(r'[-]', kernel_ver)[0:3]
700 # In compare_versions, if v1 < v2, return value == -1
701 if utils.compare_versions(kv_tmp[0], ver) == -1:
702 raise error.TestError("Kernel too old (%s). Kernel > %s is needed." %
703 (kernel_ver, ver))
704
705
706def human_format(number):
707 # Convert number to kilo / mega / giga format.
708 if number < 1024:
709 return "%d" % number
710 kilo = float(number) / 1024.0
711 if kilo < 1024:
712 return "%.2fk" % kilo
713 meg = kilo / 1024.0
714 if meg < 1024:
715 return "%.2fM" % meg
716 gig = meg / 1024.0
717 return "%.2fG" % gig
718
719
720def numa_nodes():
721 node_paths = glob.glob('/sys/devices/system/node/node*')
722 nodes = [int(re.sub(r'.*node(\d+)', r'\1', x)) for x in node_paths]
723 return (sorted(nodes))
724
725
726def node_size():
727 nodes = max(len(numa_nodes()), 1)
728 return ((memtotal() * 1024) / nodes)
729
730
731def pickle_load(filename):
732 return pickle.load(open(filename, 'r'))
733
734
735# Return the kernel version and build timestamp.
736def running_os_release():
737 return os.uname()[2:4]
738
739
740def running_os_ident():
741 (version, timestamp) = running_os_release()
742 return version + '::' + timestamp
743
744
745def running_os_full_version():
746 (version, timestamp) = running_os_release()
747 return version
748
749
750# much like find . -name 'pattern'
751def locate(pattern, root=os.getcwd()):
752 for path, dirs, files in os.walk(root):
753 for f in files:
754 if fnmatch.fnmatch(f, pattern):
755 yield os.path.abspath(os.path.join(path, f))
756
757
758def freespace(path):
759 """Return the disk free space, in bytes"""
760 s = os.statvfs(path)
761 return s.f_bavail * s.f_bsize
762
763
764def disk_block_size(path):
765 """Return the disk block size, in bytes"""
766 return os.statvfs(path).f_bsize
767
768
769_DISK_PARTITION_3_RE = re.compile(r'^(/dev/hd[a-z]+)3', re.M)
770
771def get_disks():
772 df_output = utils.system_output('df')
773 return _DISK_PARTITION_3_RE.findall(df_output)
774
775
776def get_disk_size(disk_name):
777 """
778 Return size of disk in byte. Return 0 in Error Case
779
780 @param disk_name: disk name to find size
781 """
782 device = os.path.basename(disk_name)
783 for line in file('/proc/partitions'):
784 try:
785 _, _, blocks, name = re.split(r' +', line.strip())
786 except ValueError:
787 continue
788 if name == device:
789 return 1024 * int(blocks)
790 return 0
791
792
793def get_disk_size_gb(disk_name):
794 """
795 Return size of disk in GB (10^9). Return 0 in Error Case
796
797 @param disk_name: disk name to find size
798 """
799 return int(get_disk_size(disk_name) / (10.0 ** 9) + 0.5)
800
801
802def get_disk_model(disk_name):
803 """
804 Return model name for internal storage device
805
806 @param disk_name: disk name to find model
807 """
808 cmd1 = 'udevadm info --query=property --name=%s' % disk_name
809 cmd2 = 'grep -E "ID_(NAME|MODEL)="'
810 cmd3 = 'cut -f 2 -d"="'
811 cmd = ' | '.join([cmd1, cmd2, cmd3])
812 return utils.system_output(cmd)
813
814
815_DISK_DEV_RE = re.compile(r'/dev/sd[a-z]|/dev/mmcblk[0-9]*|/dev/nvme[0-9]*')
816
817
818def get_disk_from_filename(filename):
819 """
820 Return the disk device the filename is on.
821 If the file is on tmpfs or other special file systems,
822 return None.
823
824 @param filename: name of file, full path.
825 """
826
827 if not os.path.exists(filename):
828 raise error.TestError('file %s missing' % filename)
829
830 if filename[0] != '/':
831 raise error.TestError('This code works only with full path')
832
833 m = _DISK_DEV_RE.match(filename)
834 while not m:
835 if filename[0] != '/':
836 return None
837 if filename == '/dev/root':
838 cmd = 'rootdev -d -s'
839 elif filename.startswith('/dev/mapper'):
840 cmd = 'dmsetup table "%s"' % os.path.basename(filename)
841 dmsetup_output = utils.system_output(cmd).split(' ')
842 if dmsetup_output[2] == 'verity':
843 maj_min = dmsetup_output[4]
844 elif dmsetup_output[2] == 'crypt':
845 maj_min = dmsetup_output[6]
846 cmd = 'realpath "/dev/block/%s"' % maj_min
847 elif filename.startswith('/dev/loop'):
848 cmd = 'losetup -O BACK-FILE "%s" | tail -1' % filename
849 else:
850 cmd = 'df "%s" | tail -1 | cut -f 1 -d" "' % filename
851 filename = utils.system_output(cmd)
852 m = _DISK_DEV_RE.match(filename)
853 return m.group(0)
854
855
856def get_disk_firmware_version(disk_name):
857 """
858 Return firmware version for internal storage device. (empty string for eMMC)
859
860 @param disk_name: disk name to find model
861 """
862 cmd1 = 'udevadm info --query=property --name=%s' % disk_name
863 cmd2 = 'grep -E "ID_REVISION="'
864 cmd3 = 'cut -f 2 -d"="'
865 cmd = ' | '.join([cmd1, cmd2, cmd3])
866 return utils.system_output(cmd)
867
868
869def is_disk_scsi(disk_name):
870 """
871 Return true if disk is a scsi device, return false otherwise
872
873 @param disk_name: disk name check
874 """
875 return re.match('/dev/sd[a-z]+', disk_name)
876
877
878def is_disk_harddisk(disk_name):
879 """
880 Return true if disk is a harddisk, return false otherwise
881
882 @param disk_name: disk name check
883 """
884 cmd1 = 'udevadm info --query=property --name=%s' % disk_name
885 cmd2 = 'grep -E "ID_ATA_ROTATION_RATE_RPM="'
886 cmd3 = 'cut -f 2 -d"="'
887 cmd = ' | '.join([cmd1, cmd2, cmd3])
888
889 rtt = utils.system_output(cmd)
890
891 # eMMC will not have this field; rtt == ''
892 # SSD will have zero rotation rate; rtt == '0'
893 # For harddisk rtt > 0
894 return rtt and int(rtt) > 0
895
896
897def verify_hdparm_feature(disk_name, feature):
898 """
899 Check for feature support for SCSI disk using hdparm
900
901 @param disk_name: target disk
902 @param feature: hdparm output string of the feature
903 """
904 cmd = 'hdparm -I %s | grep -q "%s"' % (disk_name, feature)
905 ret = utils.system(cmd, ignore_status=True)
906 if ret == 0:
907 return True
908 elif ret == 1:
909 return False
910 else:
911 raise error.TestFail('Error running command %s' % cmd)
912
913
914def get_storage_error_msg(disk_name, reason):
915 """
916 Get Error message for storage test which include disk model.
917 and also include the firmware version for the SCSI disk
918
919 @param disk_name: target disk
920 @param reason: Reason of the error.
921 """
922
923 msg = reason
924
925 model = get_disk_model(disk_name)
926 msg += ' Disk model: %s' % model
927
928 if is_disk_scsi(disk_name):
929 fw = get_disk_firmware_version(disk_name)
930 msg += ' firmware: %s' % fw
931
932 return msg
933
934
935def load_module(module_name, params=None):
936 # Checks if a module has already been loaded
937 if module_is_loaded(module_name):
938 return False
939
940 cmd = '/sbin/modprobe ' + module_name
941 if params:
942 cmd += ' ' + params
943 utils.system(cmd)
944 return True
945
946
947def unload_module(module_name):
948 """
949 Removes a module. Handles dependencies. If even then it's not possible
950 to remove one of the modules, it will trhow an error.CmdError exception.
951
952 @param module_name: Name of the module we want to remove.
953 """
954 l_raw = utils.system_output("/bin/lsmod").splitlines()
955 lsmod = [x for x in l_raw if x.split()[0] == module_name]
956 if len(lsmod) > 0:
957 line_parts = lsmod[0].split()
958 if len(line_parts) == 4:
959 submodules = line_parts[3].split(",")
960 for submodule in submodules:
961 unload_module(submodule)
962 utils.system("/sbin/modprobe -r %s" % module_name)
963 logging.info("Module %s unloaded", module_name)
964 else:
965 logging.info("Module %s is already unloaded", module_name)
966
967
968def module_is_loaded(module_name):
969 module_name = module_name.replace('-', '_')
970 modules = utils.system_output('/bin/lsmod').splitlines()
971 for module in modules:
972 if module.startswith(module_name) and module[len(module_name)] == ' ':
973 return True
974 return False
975
976
977def get_loaded_modules():
978 lsmod_output = utils.system_output('/bin/lsmod').splitlines()[1:]
979 return [line.split(None, 1)[0] for line in lsmod_output]
980
981
982def get_huge_page_size():
983 output = utils.system_output('grep Hugepagesize /proc/meminfo')
984 return int(output.split()[1]) # Assumes units always in kB. :(
985
986
987def get_num_huge_pages():
988 raw_hugepages = utils.system_output('/sbin/sysctl vm.nr_hugepages')
989 return int(raw_hugepages.split()[2])
990
991
992def set_num_huge_pages(num):
993 utils.system('/sbin/sysctl vm.nr_hugepages=%d' % num)
994
995
996def ping_default_gateway():
997 """Ping the default gateway."""
998
999 network = open('/etc/sysconfig/network')
1000 m = re.search('GATEWAY=(\S+)', network.read())
1001
1002 if m:
1003 gw = m.group(1)
1004 cmd = 'ping %s -c 5 > /dev/null' % gw
1005 return utils.system(cmd, ignore_status=True)
1006
1007 raise error.TestError('Unable to find default gateway')
1008
1009
1010def drop_caches():
1011 """Writes back all dirty pages to disk and clears all the caches."""
1012 utils.system("sync")
1013 # We ignore failures here as this will fail on 2.6.11 kernels.
1014 utils.system("echo 3 > /proc/sys/vm/drop_caches", ignore_status=True)
1015
1016
1017def process_is_alive(name_pattern):
1018 """
1019 'pgrep name' misses all python processes and also long process names.
1020 'pgrep -f name' gets all shell commands with name in args.
1021 So look only for command whose initial pathname ends with name.
1022 Name itself is an egrep pattern, so it can use | etc for variations.
1023 """
1024 return utils.system("pgrep -f '^([^ /]*/)*(%s)([ ]|$)'" % name_pattern,
1025 ignore_status=True) == 0
1026
1027
1028def get_hwclock_seconds(utc=True):
1029 """
1030 Return the hardware clock in seconds as a floating point value.
1031 Use Coordinated Universal Time if utc is True, local time otherwise.
1032 Raise a ValueError if unable to read the hardware clock.
1033 """
1034 cmd = '/sbin/hwclock --debug'
1035 if utc:
1036 cmd += ' --utc'
1037 hwclock_output = utils.system_output(cmd, ignore_status=True)
1038 match = re.search(r'= ([0-9]+) seconds since .+ (-?[0-9.]+) seconds$',
1039 hwclock_output, re.DOTALL)
1040 if match:
1041 seconds = int(match.group(1)) + float(match.group(2))
1042 logging.debug('hwclock seconds = %f', seconds)
1043 return seconds
1044
1045 raise ValueError('Unable to read the hardware clock -- ' +
1046 hwclock_output)
1047
1048
1049def set_wake_alarm(alarm_time):
1050 """
1051 Set the hardware RTC-based wake alarm to 'alarm_time'.
1052 """
1053 utils.write_one_line('/sys/class/rtc/rtc0/wakealarm', str(alarm_time))
1054
1055
1056def set_power_state(state):
1057 """
1058 Set the system power state to 'state'.
1059 """
1060 utils.write_one_line('/sys/power/state', state)
1061
1062
1063def standby():
1064 """
1065 Power-on suspend (S1)
1066 """
1067 set_power_state('standby')
1068
1069
1070def suspend_to_ram():
1071 """
1072 Suspend the system to RAM (S3)
1073 """
1074 set_power_state('mem')
1075
1076
1077def suspend_to_disk():
1078 """
1079 Suspend the system to disk (S4)
1080 """
1081 set_power_state('disk')
1082
1083
1084_AMD_PCI_IDS_FILE_PATH = '/usr/local/autotest/bin/amd_pci_ids.json'
1085_INTEL_PCI_IDS_FILE_PATH = '/usr/local/autotest/bin/intel_pci_ids.json'
1086_UI_USE_FLAGS_FILE_PATH = '/etc/ui_use_flags.txt'
1087
1088# Command to check if a package is installed. If the package is not installed
1089# the command shall fail.
1090_CHECK_PACKAGE_INSTALLED_COMMAND =(
1091 "dpkg-query -W -f='${Status}\n' %s | head -n1 | awk '{print $3;}' | "
1092 "grep -q '^installed$'")
1093
1094pciid_to_amd_architecture = {}
1095pciid_to_intel_architecture = {}
1096
1097class Crossystem(object):
1098 """A wrapper for the crossystem utility."""
1099
1100 def __init__(self, client):
1101 self.cros_system_data = {}
1102 self._client = client
1103
1104 def init(self):
1105 self.cros_system_data = {}
1106 (_, fname) = tempfile.mkstemp()
1107 f = open(fname, 'w')
1108 self._client.run('crossystem', stdout_tee=f)
1109 f.close()
1110 text = utils.read_file(fname)
1111 for line in text.splitlines():
1112 assignment_string = line.split('#')[0]
1113 if not assignment_string.count('='):
1114 continue
1115 (name, value) = assignment_string.split('=', 1)
1116 self.cros_system_data[name.strip()] = value.strip()
1117 os.remove(fname)
1118
1119 def __getattr__(self, name):
1120 """
1121 Retrieve a crosssystem attribute.
1122
1123 The call crossystemobject.name() will return the crossystem reported
1124 string.
1125 """
1126 return lambda: self.cros_system_data[name]
1127
1128
1129def get_oldest_pid_by_name(name):
1130 """
1131 Return the oldest pid of a process whose name perfectly matches |name|.
1132
1133 name is an egrep expression, which will be matched against the entire name
1134 of processes on the system. For example:
1135
1136 get_oldest_pid_by_name('chrome')
1137
1138 on a system running
1139 8600 ? 00:00:04 chrome
1140 8601 ? 00:00:00 chrome
1141 8602 ? 00:00:00 chrome-sandbox
1142
1143 would return 8600, as that's the oldest process that matches.
1144 chrome-sandbox would not be matched.
1145
1146 Arguments:
1147 name: egrep expression to match. Will be anchored at the beginning and
1148 end of the match string.
1149
1150 Returns:
1151 pid as an integer, or None if one cannot be found.
1152
1153 Raises:
1154 ValueError if pgrep returns something odd.
1155 """
1156 str_pid = utils.system_output('pgrep -o ^%s$' % name,
1157 ignore_status=True).rstrip()
1158 if str_pid:
1159 return int(str_pid)
1160
1161
1162def get_oldest_by_name(name):
1163 """Return pid and command line of oldest process whose name matches |name|.
1164
1165 @param name: egrep expression to match desired process name.
1166 @return: A tuple of (pid, command_line) of the oldest process whose name
1167 matches |name|.
1168
1169 """
1170 pid = get_oldest_pid_by_name(name)
1171 if pid:
1172 command_line = utils.system_output('ps -p %i -o command=' % pid,
1173 ignore_status=True).rstrip()
1174 return (pid, command_line)
1175
1176
1177def get_chrome_remote_debugging_port():
1178 """Returns remote debugging port for Chrome.
1179
1180 Parse chrome process's command line argument to get the remote debugging
1181 port.
1182 """
1183 _, command = get_oldest_by_name('chrome')
1184 matches = re.search('--remote-debugging-port=([0-9]+)', command)
1185 if matches:
1186 return int(matches.group(1))
1187
1188
1189def get_process_list(name, command_line=None):
1190 """
1191 Return the list of pid for matching process |name command_line|.
1192
1193 on a system running
1194 31475 ? 0:06 /opt/google/chrome/chrome --allow-webui-compositing -
1195 31478 ? 0:00 /opt/google/chrome/chrome-sandbox /opt/google/chrome/
1196 31485 ? 0:00 /opt/google/chrome/chrome --type=zygote --log-level=1
1197 31532 ? 1:05 /opt/google/chrome/chrome --type=renderer
1198
1199 get_process_list('chrome')
1200 would return ['31475', '31485', '31532']
1201
1202 get_process_list('chrome', '--type=renderer')
1203 would return ['31532']
1204
1205 Arguments:
1206 name: process name to search for. If command_line is provided, name is
1207 matched against full command line. If command_line is not provided,
1208 name is only matched against the process name.
1209 command line: when command line is passed, the full process command line
1210 is used for matching.
1211
1212 Returns:
1213 list of PIDs of the matching processes.
1214
1215 """
1216 # TODO(rohitbm) crbug.com/268861
1217 flag = '-x' if not command_line else '-f'
1218 name = '\'%s.*%s\'' % (name, command_line) if command_line else name
1219 str_pid = utils.system_output('pgrep %s %s' % (flag, name),
1220 ignore_status=True).rstrip()
1221 return str_pid.split()
1222
1223
1224def nuke_process_by_name(name, with_prejudice=False):
1225 """Tell the oldest process specified by name to exit.
1226
1227 Arguments:
1228 name: process name specifier, as understood by pgrep.
1229 with_prejudice: if True, don't allow for graceful exit.
1230
1231 Raises:
1232 error.AutoservPidAlreadyDeadError: no existing process matches name.
1233 """
1234 try:
1235 pid = get_oldest_pid_by_name(name)
1236 except Exception as e:
1237 logging.error(e)
1238 return
1239 if pid is None:
1240 raise error.AutoservPidAlreadyDeadError('No process matching %s.' %
1241 name)
1242 if with_prejudice:
1243 utils.nuke_pid(pid, [signal.SIGKILL])
1244 else:
1245 utils.nuke_pid(pid)
1246
1247
1248def ensure_processes_are_dead_by_name(name, timeout_sec=10):
1249 """Terminate all processes specified by name and ensure they're gone.
1250
1251 Arguments:
1252 name: process name specifier, as understood by pgrep.
1253 timeout_sec: maximum number of seconds to wait for processes to die.
1254
1255 Raises:
1256 error.AutoservPidAlreadyDeadError: no existing process matches name.
1257 site_utils.TimeoutError: if processes still exist after timeout_sec.
1258 """
1259
1260 def list_and_kill_processes(name):
1261 process_list = get_process_list(name)
1262 try:
1263 for pid in [int(str_pid) for str_pid in process_list]:
1264 utils.nuke_pid(pid)
1265 except error.AutoservPidAlreadyDeadError:
1266 pass
1267 return process_list
1268
1269 utils.poll_for_condition(lambda: list_and_kill_processes(name) == [],
1270 timeout=timeout_sec)
1271
1272
1273def is_virtual_machine():
1274 return 'QEMU' in platform.processor()
1275
1276
1277def save_vm_state(checkpoint):
1278 """Saves the current state of the virtual machine.
1279
1280 This function is a NOOP if the test is not running under a virtual machine
1281 with the USB serial port redirected.
1282
1283 Arguments:
1284 checkpoint - Name used to identify this state
1285
1286 Returns:
1287 None
1288 """
1289 # The QEMU monitor has been redirected to the guest serial port located at
1290 # /dev/ttyUSB0. To save the state of the VM, we just send the 'savevm'
1291 # command to the serial port.
1292 if is_virtual_machine() and os.path.exists('/dev/ttyUSB0'):
1293 logging.info('Saving VM state "%s"', checkpoint)
1294 serial = open('/dev/ttyUSB0', 'w')
1295 serial.write('savevm %s\r\n' % checkpoint)
1296 logging.info('Done saving VM state "%s"', checkpoint)
1297
1298
1299def check_raw_dmesg(dmesg, message_level, whitelist):
1300 """Checks dmesg for unexpected warnings.
1301
1302 This function parses dmesg for message with message_level <= message_level
1303 which do not appear in the whitelist.
1304
1305 Arguments:
1306 dmesg - string containing raw dmesg buffer
1307 message_level - minimum message priority to check
1308 whitelist - messages to ignore
1309
1310 Returns:
1311 List of unexpected warnings
1312 """
1313 whitelist_re = re.compile(r'(%s)' % '|'.join(whitelist))
1314 unexpected = []
1315 for line in dmesg.splitlines():
1316 if int(line[1]) <= message_level:
1317 stripped_line = line.split('] ', 1)[1]
1318 if whitelist_re.search(stripped_line):
1319 continue
1320 unexpected.append(stripped_line)
1321 return unexpected
1322
1323
1324def verify_mesg_set(mesg, regex, whitelist):
1325 """Verifies that the exact set of messages are present in a text.
1326
1327 This function finds all strings in the text matching a certain regex, and
1328 then verifies that all expected strings are present in the set, and no
1329 unexpected strings are there.
1330
1331 Arguments:
1332 mesg - the mutiline text to be scanned
1333 regex - regular expression to match
1334 whitelist - messages to find in the output, a list of strings
1335 (potentially regexes) to look for in the filtered output. All these
1336 strings must be there, and no other strings should be present in the
1337 filtered output.
1338
1339 Returns:
1340 string of inconsistent findings (i.e. an empty string on success).
1341 """
1342
1343 rv = []
1344
1345 missing_strings = []
1346 present_strings = []
1347 for line in mesg.splitlines():
1348 if not re.search(r'%s' % regex, line):
1349 continue
1350 present_strings.append(line.split('] ', 1)[1])
1351
1352 for string in whitelist:
1353 for present_string in list(present_strings):
1354 if re.search(r'^%s$' % string, present_string):
1355 present_strings.remove(present_string)
1356 break
1357 else:
1358 missing_strings.append(string)
1359
1360 if present_strings:
1361 rv.append('unexpected strings:')
1362 rv.extend(present_strings)
1363 if missing_strings:
1364 rv.append('missing strings:')
1365 rv.extend(missing_strings)
1366
1367 return '\n'.join(rv)
1368
1369
1370def target_is_pie():
1371 """Returns whether the toolchain produces a PIE (position independent
1372 executable) by default.
1373
1374 Arguments:
1375 None
1376
1377 Returns:
1378 True if the target toolchain produces a PIE by default.
1379 False otherwise.
1380 """
1381
1382 command = 'echo | ${CC} -E -dD -P - | grep -i pie'
1383 result = utils.system_output(command,
1384 retain_output=True,
1385 ignore_status=True)
1386 if re.search('#define __PIE__', result):
1387 return True
1388 else:
1389 return False
1390
1391
1392def target_is_x86():
1393 """Returns whether the toolchain produces an x86 object
1394
1395 Arguments:
1396 None
1397
1398 Returns:
1399 True if the target toolchain produces an x86 object
1400 False otherwise.
1401 """
1402
1403 command = 'echo | ${CC} -E -dD -P - | grep -i 86'
1404 result = utils.system_output(command,
1405 retain_output=True,
1406 ignore_status=True)
1407 if re.search('__i386__', result) or re.search('__x86_64__', result):
1408 return True
1409 else:
1410 return False
1411
1412
1413def mounts():
1414 ret = []
1415 for line in file('/proc/mounts'):
1416 m = re.match(
1417 r'(?P<src>\S+) (?P<dest>\S+) (?P<type>\S+) (?P<opts>\S+).*', line)
1418 if m:
1419 ret.append(m.groupdict())
1420 return ret
1421
1422
1423def is_mountpoint(path):
1424 return path in [m['dest'] for m in mounts()]
1425
1426
1427def require_mountpoint(path):
1428 """
1429 Raises an exception if path is not a mountpoint.
1430 """
1431 if not is_mountpoint(path):
1432 raise error.TestFail('Path not mounted: "%s"' % path)
1433
1434
1435def random_username():
1436 return str(uuid.uuid4()) + '@example.com'
1437
1438
1439def get_signin_credentials(filepath):
1440 """Returns user_id, password tuple from credentials file at filepath.
1441
1442 File must have one line of the format user_id:password
1443
1444 @param filepath: path of credentials file.
1445 @return user_id, password tuple.
1446 """
1447 user_id, password = None, None
1448 if os.path.isfile(filepath):
1449 with open(filepath) as f:
1450 user_id, password = f.read().rstrip().split(':')
1451 return user_id, password
1452
1453
1454def parse_cmd_output(command, run_method=utils.run):
1455 """Runs a command on a host object to retrieve host attributes.
1456
1457 The command should output to stdout in the format of:
1458 <key> = <value> # <optional_comment>
1459
1460
1461 @param command: Command to execute on the host.
1462 @param run_method: Function to use to execute the command. Defaults to
1463 utils.run so that the command will be executed locally.
1464 Can be replace with a host.run call so that it will
1465 execute on a DUT or external machine. Method must accept
1466 a command argument, stdout_tee and stderr_tee args and
1467 return a result object with a string attribute stdout
1468 which will be parsed.
1469
1470 @returns a dictionary mapping host attributes to their values.
1471 """
1472 result = {}
1473 # Suppresses stdout so that the files are not printed to the logs.
1474 cmd_result = run_method(command, stdout_tee=None, stderr_tee=None)
1475 for line in cmd_result.stdout.splitlines():
1476 # Lines are of the format "<key> = <value> # <comment>"
1477 key_value = re.match(r'^\s*(?P<key>[^ ]+)\s*=\s*(?P<value>[^ '
1478 r']+)(?:\s*#.*)?$', line)
1479 if key_value:
1480 result[key_value.group('key')] = key_value.group('value')
1481 return result
1482
1483
1484def set_from_keyval_output(out, delimiter=' '):
1485 """Parse delimiter-separated key-val output into a set of tuples.
1486
1487 Output is expected to be multiline text output from a command.
1488 Stuffs the key-vals into tuples in a set to be later compared.
1489
1490 e.g. deactivated 0
1491 disableForceClear 0
1492 ==> set(('deactivated', '0'), ('disableForceClear', '0'))
1493
1494 @param out: multiple lines of space-separated key-val pairs.
1495 @param delimiter: character that separates key from val. Usually a
1496 space but may be '=' or something else.
1497 @return set of key-val tuples.
1498 """
1499 results = set()
1500 kv_match_re = re.compile('([^ ]+)%s(.*)' % delimiter)
1501 for linecr in out.splitlines():
1502 match = kv_match_re.match(linecr.strip())
1503 if match:
1504 results.add((match.group(1), match.group(2)))
1505 return results
1506
1507
1508def get_cpu_usage():
1509 """Returns machine's CPU usage.
1510
1511 This function uses /proc/stat to identify CPU usage.
1512 Returns:
1513 A dictionary with 'user', 'nice', 'system' and 'idle' values.
1514 Sample dictionary:
1515 {
1516 'user': 254544,
1517 'nice': 9,
1518 'system': 254768,
1519 'idle': 2859878,
1520 }
1521 """
1522 proc_stat = open('/proc/stat')
1523 cpu_usage_str = proc_stat.readline().split()
1524 proc_stat.close()
1525 return {
1526 'user': int(cpu_usage_str[1]),
1527 'nice': int(cpu_usage_str[2]),
1528 'system': int(cpu_usage_str[3]),
1529 'idle': int(cpu_usage_str[4])
1530 }
1531
1532
1533def compute_active_cpu_time(cpu_usage_start, cpu_usage_end):
1534 """Computes the fraction of CPU time spent non-idling.
1535
1536 This function should be invoked using before/after values from calls to
1537 get_cpu_usage().
1538 """
1539 time_active_end = (
1540 cpu_usage_end['user'] + cpu_usage_end['nice'] + cpu_usage_end['system'])
1541 time_active_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
1542 cpu_usage_start['system'])
1543 total_time_end = (cpu_usage_end['user'] + cpu_usage_end['nice'] +
1544 cpu_usage_end['system'] + cpu_usage_end['idle'])
1545 total_time_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
1546 cpu_usage_start['system'] + cpu_usage_start['idle'])
1547 return ((float(time_active_end) - time_active_start) /
1548 (total_time_end - total_time_start))
1549
1550
1551def is_pgo_mode():
1552 return 'USE_PGO' in os.environ
1553
1554
1555def wait_for_idle_cpu(timeout, utilization):
1556 """Waits for the CPU to become idle (< utilization).
1557
1558 Args:
1559 timeout: The longest time in seconds to wait before throwing an error.
1560 utilization: The CPU usage below which the system should be considered
1561 idle (between 0 and 1.0 independent of cores/hyperthreads).
1562 """
1563 time_passed = 0.0
1564 fraction_active_time = 1.0
1565 sleep_time = 1
1566 logging.info('Starting to wait up to %.1fs for idle CPU...', timeout)
1567 while fraction_active_time >= utilization:
1568 cpu_usage_start = get_cpu_usage()
1569 # Split timeout interval into not too many chunks to limit log spew.
1570 # Start at 1 second, increase exponentially
1571 time.sleep(sleep_time)
1572 time_passed += sleep_time
1573 sleep_time = min(16.0, 2.0 * sleep_time)
1574 cpu_usage_end = get_cpu_usage()
1575 fraction_active_time = \
1576 compute_active_cpu_time(cpu_usage_start, cpu_usage_end)
1577 logging.info('After waiting %.1fs CPU utilization is %.3f.',
1578 time_passed, fraction_active_time)
1579 if time_passed > timeout:
1580 logging.warning('CPU did not become idle.')
1581 log_process_activity()
1582 # crosbug.com/37389
1583 if is_pgo_mode():
1584 logging.info('Still continuing because we are in PGO mode.')
1585 return True
1586
1587 return False
1588 logging.info('Wait for idle CPU took %.1fs (utilization = %.3f).',
1589 time_passed, fraction_active_time)
1590 return True
1591
1592
1593def log_process_activity():
1594 """Logs the output of top.
1595
1596 Useful to debug performance tests and to find runaway processes.
1597 """
1598 logging.info('Logging current process activity using top and ps.')
1599 cmd = 'top -b -n1 -c'
1600 output = utils.run(cmd)
1601 logging.info(output)
1602 output = utils.run('ps axl')
1603 logging.info(output)
1604
1605
1606def wait_for_cool_machine():
1607 """
1608 A simple heuristic to wait for a machine to cool.
1609 The code looks a bit 'magic', but we don't know ambient temperature
1610 nor machine characteristics and still would like to return the caller
1611 a machine that cooled down as much as reasonably possible.
1612 """
1613 temperature = get_current_temperature_max()
1614 # We got here with a cold machine, return immediately. This should be the
1615 # most common case.
1616 if temperature < 50:
1617 return True
1618 logging.info('Got a hot machine of %dC. Sleeping 1 minute.', temperature)
1619 # A modest wait should cool the machine.
1620 time.sleep(60.0)
1621 temperature = get_current_temperature_max()
1622 # Atoms idle below 60 and everyone else should be even lower.
1623 if temperature < 62:
1624 return True
1625 # This should be rare.
1626 logging.info('Did not cool down (%dC). Sleeping 2 minutes.', temperature)
1627 time.sleep(120.0)
1628 temperature = get_current_temperature_max()
1629 # A temperature over 65'C doesn't give us much headroom to the critical
1630 # temperatures that start at 85'C (and PerfControl as of today will fail at
1631 # critical - 10'C).
1632 if temperature < 65:
1633 return True
1634 logging.warning('Did not cool down (%dC), giving up.', temperature)
1635 log_process_activity()
1636 return False
1637
1638
1639# System paths for machine performance state.
1640_CPUINFO = '/proc/cpuinfo'
1641_DIRTY_WRITEBACK_CENTISECS = '/proc/sys/vm/dirty_writeback_centisecs'
1642_KERNEL_MAX = '/sys/devices/system/cpu/kernel_max'
1643_MEMINFO = '/proc/meminfo'
1644_TEMP_SENSOR_RE = 'Reading temperature...([0-9]*)'
1645
1646
1647def _get_line_from_file(path, line):
1648 """
1649 line can be an integer or
1650 line can be a string that matches the beginning of the line
1651 """
1652 with open(path) as f:
1653 if isinstance(line, int):
1654 l = f.readline()
1655 for _ in range(0, line):
1656 l = f.readline()
1657 return l
1658 else:
1659 for l in f:
1660 if l.startswith(line):
1661 return l
1662 return None
1663
1664
1665def _get_match_from_file(path, line, prefix, postfix):
1666 """
1667 Matches line in path and returns string between first prefix and postfix.
1668 """
1669 match = _get_line_from_file(path, line)
1670 # Strip everything from front of line including prefix.
1671 if prefix:
1672 match = re.split(prefix, match)[1]
1673 # Strip everything from back of string including first occurence of postfix.
1674 if postfix:
1675 match = re.split(postfix, match)[0]
1676 return match
1677
1678
1679def _get_float_from_file(path, line, prefix, postfix):
1680 match = _get_match_from_file(path, line, prefix, postfix)
1681 return float(match)
1682
1683
1684def _get_int_from_file(path, line, prefix, postfix):
1685 match = _get_match_from_file(path, line, prefix, postfix)
1686 return int(match)
1687
1688
1689def _get_hex_from_file(path, line, prefix, postfix):
1690 match = _get_match_from_file(path, line, prefix, postfix)
1691 return int(match, 16)
1692
1693
1694# The paths don't change. Avoid running find all the time.
1695_hwmon_paths = None
1696
1697def _get_hwmon_paths(file_pattern):
1698 """
1699 Returns a list of paths to the temperature sensors.
1700 """
1701 # Some systems like daisy_spring only have the virtual hwmon.
1702 # And other systems like rambi only have coretemp.0. See crbug.com/360249.
1703 # /sys/class/hwmon/hwmon*/
1704 # /sys/devices/virtual/hwmon/hwmon*/
1705 # /sys/devices/platform/coretemp.0/
1706 if not _hwmon_paths:
1707 cmd = 'find /sys/ -name "' + file_pattern + '"'
1708 _hwon_paths = utils.run(cmd, verbose=False).stdout.splitlines()
1709 return _hwon_paths
1710
1711
1712def get_temperature_critical():
1713 """
1714 Returns temperature at which we will see some throttling in the system.
1715 """
1716 min_temperature = 1000.0
1717 paths = _get_hwmon_paths('temp*_crit')
1718 for path in paths:
1719 temperature = _get_float_from_file(path, 0, None, None) * 0.001
1720 # Today typical for Intel is 98'C to 105'C while ARM is 85'C. Clamp to
1721 # the lowest known value.
1722 if (min_temperature < 60.0) or min_temperature > 150.0:
1723 logging.warning('Critical temperature of %.1fC was reset to 85.0C.',
1724 min_temperature)
1725 min_temperature = 85.0
1726
1727 min_temperature = min(temperature, min_temperature)
1728 return min_temperature
1729
1730
1731def get_temperature_input_max():
1732 """
1733 Returns the maximum currently observed temperature.
1734 """
1735 max_temperature = -1000.0
1736 paths = _get_hwmon_paths('temp*_input')
1737 for path in paths:
1738 temperature = _get_float_from_file(path, 0, None, None) * 0.001
1739 max_temperature = max(temperature, max_temperature)
1740 return max_temperature
1741
1742
1743def get_thermal_zone_temperatures():
1744 """
1745 Returns the maximum currently observered temperature in thermal_zones.
1746 """
1747 temperatures = []
1748 for path in glob.glob('/sys/class/thermal/thermal_zone*/temp'):
1749 try:
1750 temperatures.append(
1751 _get_float_from_file(path, 0, None, None) * 0.001)
1752 except IOError:
1753 # Some devices (e.g. Veyron) may have reserved thermal zones that
1754 # are not active. Trying to read the temperature value would cause a
1755 # EINVAL IO error.
1756 continue
1757 return temperatures
1758
1759
1760def get_ec_temperatures():
1761 """
1762 Uses ectool to return a list of all sensor temperatures in Celsius.
1763 """
1764 temperatures = []
1765 try:
1766 full_cmd = 'ectool temps all'
1767 lines = utils.run(full_cmd, verbose=False).stdout.splitlines()
1768 for line in lines:
1769 temperature = int(line.split(': ')[1]) - 273
1770 temperatures.append(temperature)
1771 except Exception:
1772 logging.warning('Unable to read temperature sensors using ectool.')
1773 for temperature in temperatures:
1774 # Sanity check for real world values.
1775 assert ((temperature > 10.0) and
1776 (temperature < 150.0)), ('Unreasonable temperature %.1fC.' %
1777 temperature)
1778
1779 return temperatures
1780
1781
1782def get_current_temperature_max():
1783 """
1784 Returns the highest reported board temperature (all sensors) in Celsius.
1785 """
1786 temperature = max([get_temperature_input_max()] +
1787 get_thermal_zone_temperatures() +
1788 get_ec_temperatures())
1789 # Sanity check for real world values.
1790 assert ((temperature > 10.0) and
1791 (temperature < 150.0)), ('Unreasonable temperature %.1fC.' %
1792 temperature)
1793 return temperature
1794
1795
1796def get_cpu_cache_size():
1797 """
1798 Returns the last level CPU cache size in kBytes.
1799 """
1800 cache_size = _get_int_from_file(_CPUINFO, 'cache size', ': ', ' KB')
1801 # Sanity check.
1802 assert cache_size >= 64, 'Unreasonably small cache.'
1803 return cache_size
1804
1805
1806def get_cpu_model_frequency():
1807 """
1808 Returns the model frequency from the CPU model name on Intel only. This
1809 might be redundant with get_cpu_max_frequency. Unit is Hz.
1810 """
1811 frequency = _get_float_from_file(_CPUINFO, 'model name', ' @ ', 'GHz')
1812 return 1.e9 * frequency
1813
1814
1815def get_cpu_max_frequency():
1816 """
1817 Returns the largest of the max CPU core frequencies. The unit is Hz.
1818 """
1819 max_frequency = -1
1820 paths = _get_cpufreq_paths('cpuinfo_max_freq')
1821 for path in paths:
1822 # Convert from kHz to Hz.
1823 frequency = 1000 * _get_float_from_file(path, 0, None, None)
1824 max_frequency = max(frequency, max_frequency)
1825 # Sanity check.
1826 assert max_frequency > 1e8, 'Unreasonably low CPU frequency.'
1827 return max_frequency
1828
1829
1830def get_cpu_min_frequency():
1831 """
1832 Returns the smallest of the minimum CPU core frequencies.
1833 """
1834 min_frequency = 1e20
1835 paths = _get_cpufreq_paths('cpuinfo_min_freq')
1836 for path in paths:
1837 frequency = _get_float_from_file(path, 0, None, None)
1838 min_frequency = min(frequency, min_frequency)
1839 # Sanity check.
1840 assert min_frequency > 1e8, 'Unreasonably low CPU frequency.'
1841 return min_frequency
1842
1843
1844def get_cpu_model():
1845 """
1846 Returns the CPU model.
1847 Only works on Intel.
1848 """
1849 cpu_model = _get_int_from_file(_CPUINFO, 'model\t', ': ', None)
1850 return cpu_model
1851
1852
1853def get_cpu_family():
1854 """
1855 Returns the CPU family.
1856 Only works on Intel.
1857 """
1858 cpu_family = _get_int_from_file(_CPUINFO, 'cpu family\t', ': ', None)
1859 return cpu_family
1860
1861
1862def get_board_property(key):
1863 """
1864 Get a specific property from /etc/lsb-release.
1865
1866 @param key: board property to return value for
1867
1868 @return the value or '' if not present
1869 """
1870 with open('/etc/lsb-release') as f:
1871 pattern = '%s=(.*)' % key
1872 pat = re.search(pattern, f.read())
1873 if pat:
1874 return pat.group(1)
1875 return ''
1876
1877
1878def get_board():
1879 """
1880 Get the ChromeOS release board name from /etc/lsb-release.
1881 """
1882 return get_board_property('BOARD')
1883
1884
1885def get_board_type():
1886 """
1887 Get the ChromeOS board type from /etc/lsb-release.
1888
1889 @return device type.
1890 """
1891 return get_board_property('DEVICETYPE')
1892
1893
1894def get_board_with_frequency_and_memory():
1895 """
1896 Returns a board name modified with CPU frequency and memory size to
1897 differentiate between different board variants. For instance
1898 link -> link_1.8GHz_4GB.
1899 """
1900 board_name = get_board()
1901 if is_virtual_machine():
1902 board = '%s_VM' % board_name
1903 else:
1904 # Rounded to nearest GB and GHz.
1905 memory = int(round(get_mem_total() / 1024.0))
1906 # Convert frequency to GHz with 1 digit accuracy after the
1907 # decimal point.
1908 frequency = int(round(get_cpu_max_frequency() * 1e-8)) * 0.1
1909 board = '%s_%1.1fGHz_%dGB' % (board_name, frequency, memory)
1910 return board
1911
1912
1913def get_mem_total():
1914 """
1915 Returns the total memory available in the system in MBytes.
1916 """
1917 mem_total = _get_float_from_file(_MEMINFO, 'MemTotal:', 'MemTotal:', ' kB')
1918 # Sanity check, all Chromebooks have at least 1GB of memory.
1919 assert mem_total > 256 * 1024, 'Unreasonable amount of memory.'
1920 return mem_total / 1024
1921
1922
1923def get_mem_free():
1924 """
1925 Returns the currently free memory in the system in MBytes.
1926 """
1927 mem_free = _get_float_from_file(_MEMINFO, 'MemFree:', 'MemFree:', ' kB')
1928 return mem_free / 1024
1929
1930
1931def get_kernel_max():
1932 """
1933 Returns content of kernel_max.
1934 """
1935 kernel_max = _get_int_from_file(_KERNEL_MAX, 0, None, None)
1936 # Sanity check.
1937 assert ((kernel_max > 0) and (kernel_max < 257)), 'Unreasonable kernel_max.'
1938 return kernel_max
1939
1940
1941def set_high_performance_mode():
1942 """
1943 Sets the kernel governor mode to the highest setting.
1944 Returns previous governor state.
1945 """
1946 original_governors = get_scaling_governor_states()
1947 set_scaling_governors('performance')
1948 return original_governors
1949
1950
1951def set_scaling_governors(value):
1952 """
1953 Sets all scaling governor to string value.
1954 Sample values: 'performance', 'interactive', 'ondemand', 'powersave'.
1955 """
1956 paths = _get_cpufreq_paths('scaling_governor')
1957 for path in paths:
1958 cmd = 'echo %s > %s' % (value, path)
1959 logging.info('Writing scaling governor mode \'%s\' -> %s', value, path)
1960 # On Tegra CPUs can be dynamically enabled/disabled. Ignore failures.
1961 utils.system(cmd, ignore_status=True)
1962
1963
1964def _get_cpufreq_paths(filename):
1965 """
1966 Returns a list of paths to the governors.
1967 """
1968 cmd = 'ls /sys/devices/system/cpu/cpu*/cpufreq/' + filename
1969 paths = utils.run(cmd, verbose=False).stdout.splitlines()
1970 return paths
1971
1972
1973def get_scaling_governor_states():
1974 """
1975 Returns a list of (performance governor path, current state) tuples.
1976 """
1977 paths = _get_cpufreq_paths('scaling_governor')
1978 path_value_list = []
1979 for path in paths:
1980 value = _get_line_from_file(path, 0)
1981 path_value_list.append((path, value))
1982 return path_value_list
1983
1984
1985def restore_scaling_governor_states(path_value_list):
1986 """
1987 Restores governor states. Inverse operation to get_scaling_governor_states.
1988 """
1989 for (path, value) in path_value_list:
1990 cmd = 'echo %s > %s' % (value.rstrip('\n'), path)
1991 # On Tegra CPUs can be dynamically enabled/disabled. Ignore failures.
1992 utils.system(cmd, ignore_status=True)
1993
1994
1995def get_dirty_writeback_centisecs():
1996 """
1997 Reads /proc/sys/vm/dirty_writeback_centisecs.
1998 """
1999 time = _get_int_from_file(_DIRTY_WRITEBACK_CENTISECS, 0, None, None)
2000 return time
2001
2002
2003def set_dirty_writeback_centisecs(time=60000):
2004 """
2005 In hundredths of a second, this is how often pdflush wakes up to write data
2006 to disk. The default wakes up the two (or more) active threads every five
2007 seconds. The ChromeOS default is 10 minutes.
2008
2009 We use this to set as low as 1 second to flush error messages in system
2010 logs earlier to disk.
2011 """
2012 # Flush buffers first to make this function synchronous.
2013 utils.system('sync')
2014 if time >= 0:
2015 cmd = 'echo %d > %s' % (time, _DIRTY_WRITEBACK_CENTISECS)
2016 utils.system(cmd)
2017
2018
2019def wflinfo_cmd():
2020 """
2021 Returns a wflinfo command appropriate to the current graphics platform/api.
2022 """
2023 return 'wflinfo -p %s -a %s' % (graphics_platform(), graphics_api())
2024
2025
2026def has_mali():
2027 """ @return: True if system has a Mali GPU enabled."""
2028 return os.path.exists('/dev/mali0')
2029
2030def get_gpu_family():
2031 """Returns the GPU family name."""
2032 global pciid_to_amd_architecture
2033 global pciid_to_intel_architecture
2034
2035 socfamily = get_cpu_soc_family()
2036 if socfamily == 'exynos5' or socfamily == 'rockchip' or has_mali():
2037 cmd = wflinfo_cmd()
2038 wflinfo = utils.system_output(cmd,
2039 retain_output=True,
2040 ignore_status=False)
2041 version = re.findall(r'OpenGL renderer string: '
2042 r'Mali-T([0-9]+)', wflinfo)
2043 if version:
2044 return 'mali-t%s' % version[0]
2045 return 'mali-unrecognized'
2046 if socfamily == 'tegra':
2047 return 'tegra'
2048 if os.path.exists('/sys/kernel/debug/pvr'):
2049 return 'rogue'
2050
2051 pci_vga_device = utils.run("lspci | grep VGA").stdout.rstrip('\n')
2052 bus_device_function = pci_vga_device.partition(' ')[0]
2053 pci_path = '/sys/bus/pci/devices/0000:' + bus_device_function + '/device'
2054
2055 if not os.path.exists(pci_path):
2056 raise error.TestError('PCI device 0000:' + bus_device_function + ' not found')
2057
2058 device_id = utils.read_one_line(pci_path).lower()
2059
2060 if "Advanced Micro Devices" in pci_vga_device:
2061 if not pciid_to_amd_architecture:
2062 with open(_AMD_PCI_IDS_FILE_PATH, 'r') as in_f:
2063 pciid_to_amd_architecture = json.load(in_f)
2064
2065 return pciid_to_amd_architecture[device_id]
2066
2067 if "Intel Corporation" in pci_vga_device:
2068 # Only load Intel PCI ID file once and only if necessary.
2069 if not pciid_to_intel_architecture:
2070 with open(_INTEL_PCI_IDS_FILE_PATH, 'r') as in_f:
2071 pciid_to_intel_architecture = json.load(in_f)
2072
2073 return pciid_to_intel_architecture[device_id]
2074
2075# TODO(ihf): Consider using /etc/lsb-release DEVICETYPE != CHROMEBOOK/CHROMEBASE
2076# for sanity check, but usage seems a bit inconsistent. See
2077# src/third_party/chromiumos-overlay/eclass/appid.eclass
2078_BOARDS_WITHOUT_MONITOR = [
2079 'anglar', 'mccloud', 'monroe', 'ninja', 'rikku', 'guado', 'jecht', 'tidus',
2080 'veyron_brian', 'beltino', 'panther', 'stumpy', 'panther', 'tricky', 'zako',
2081 'veyron_rialto'
2082]
2083
2084
2085def has_no_monitor():
2086 """Returns whether a machine doesn't have a built-in monitor."""
2087 board_name = get_board()
2088 if board_name in _BOARDS_WITHOUT_MONITOR:
2089 return True
2090
2091 return False
2092
2093
2094def get_fixed_dst_drive():
2095 """
2096 Return device name for internal disk.
2097 Example: return /dev/sda for falco booted from usb
2098 """
2099 cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
2100 '. /usr/share/misc/chromeos-common.sh;',
2101 'load_base_vars;',
2102 'get_fixed_dst_drive'])
2103 return utils.system_output(cmd)
2104
2105
2106def get_root_device():
2107 """
2108 Return root device.
2109 Will return correct disk device even system boot from /dev/dm-0
2110 Example: return /dev/sdb for falco booted from usb
2111 """
2112 return utils.system_output('rootdev -s -d')
2113
2114
2115def get_root_partition():
2116 """
2117 Return current root partition
2118 Example: return /dev/sdb3 for falco booted from usb
2119 """
2120 return utils.system_output('rootdev -s')
2121
2122
2123def get_free_root_partition(root_part=None):
2124 """
2125 Return currently unused root partion
2126 Example: return /dev/sdb5 for falco booted from usb
2127
2128 @param root_part: cuurent root partition
2129 """
2130 spare_root_map = {'3': '5', '5': '3'}
2131 if not root_part:
2132 root_part = get_root_partition()
2133 return root_part[:-1] + spare_root_map[root_part[-1]]
2134
2135
2136def get_kernel_partition(root_part=None):
2137 """
2138 Return current kernel partition
2139 Example: return /dev/sda2 for falco booted from usb
2140
2141 @param root_part: current root partition
2142 """
2143 if not root_part:
2144 root_part = get_root_partition()
2145 current_kernel_map = {'3': '2', '5': '4'}
2146 return root_part[:-1] + current_kernel_map[root_part[-1]]
2147
2148
2149def get_free_kernel_partition(root_part=None):
2150 """
2151 return currently unused kernel partition
2152 Example: return /dev/sda4 for falco booted from usb
2153
2154 @param root_part: current root partition
2155 """
2156 kernel_part = get_kernel_partition(root_part)
2157 spare_kernel_map = {'2': '4', '4': '2'}
2158 return kernel_part[:-1] + spare_kernel_map[kernel_part[-1]]
2159
2160
2161def is_booted_from_internal_disk():
2162 """Return True if boot from internal disk. False, otherwise."""
2163 return get_root_device() == get_fixed_dst_drive()
2164
2165
2166def get_ui_use_flags():
2167 """Parses the USE flags as listed in /etc/ui_use_flags.txt.
2168
2169 @return: A list of flag strings found in the ui use flags file.
2170 """
2171 flags = []
2172 for flag in utils.read_file(_UI_USE_FLAGS_FILE_PATH).splitlines():
2173 # Removes everything after the '#'.
2174 flag_before_comment = flag.split('#')[0].strip()
2175 if len(flag_before_comment) != 0:
2176 flags.append(flag_before_comment)
2177
2178 return flags
2179
2180
2181def is_freon():
2182 """Returns False if the system uses X, True otherwise."""
2183 return 'X' not in get_ui_use_flags()
2184
2185
2186def graphics_platform():
2187 """
2188 Return a string identifying the graphics platform,
2189 e.g. 'glx' or 'x11_egl' or 'gbm'
2190 """
2191 use_flags = get_ui_use_flags()
2192 if 'X' not in use_flags:
2193 return 'null'
2194 elif 'opengles' in use_flags:
2195 return 'x11_egl'
2196 return 'glx'
2197
2198
2199def graphics_api():
2200 """Return a string identifying the graphics api, e.g. gl or gles2."""
2201 use_flags = get_ui_use_flags()
2202 if 'opengles' in use_flags:
2203 return 'gles2'
2204 return 'gl'
2205
2206
2207def assert_has_X_server():
2208 """Using X is soon to be deprecated. Print warning or raise error."""
2209 if is_freon():
2210 # TODO(ihf): Think about if we could support X for testing for a while.
2211 raise error.TestFail('freon: can\'t use X server.')
2212 logging.warning('freon: Using the X server will be deprecated soon.')
2213
2214
2215def is_vm():
2216 """Check if the process is running in a virtual machine.
2217
2218 @return: True if the process is running in a virtual machine, otherwise
2219 return False.
2220 """
2221 try:
2222 virt = utils.run('sudo -n virt-what').stdout.strip()
2223 logging.debug('virt-what output: %s', virt)
2224 return bool(virt)
2225 except error.CmdError:
2226 logging.warn('Package virt-what is not installed, default to assume '
2227 'it is not a virtual machine.')
2228 return False
2229
2230
2231def is_package_installed(package):
2232 """Check if a package is installed already.
2233
2234 @return: True if the package is already installed, otherwise return False.
2235 """
2236 try:
2237 utils.run(_CHECK_PACKAGE_INSTALLED_COMMAND % package)
2238 return True
2239 except error.CmdError:
2240 logging.warn('Package %s is not installed.', package)
2241 return False
2242
2243
2244def is_python_package_installed(package):
2245 """Check if a Python package is installed already.
2246
2247 @return: True if the package is already installed, otherwise return False.
2248 """
2249 try:
2250 __import__(package)
2251 return True
2252 except ImportError:
2253 logging.warn('Python package %s is not installed.', package)
2254 return False
2255
2256
2257def run_sql_cmd(server, user, password, command, database=''):
2258 """Run the given sql command against the specified database.
2259
2260 @param server: Hostname or IP address of the MySQL server.
2261 @param user: User name to log in the MySQL server.
2262 @param password: Password to log in the MySQL server.
2263 @param command: SQL command to run.
2264 @param database: Name of the database to run the command. Default to empty
2265 for command that does not require specifying database.
2266
2267 @return: The stdout of the command line.
2268 """
2269 cmd = ('mysql -u%s -p%s --host %s %s -e "%s"' %
2270 (user, password, server, database, command))
2271 # Set verbose to False so the command line won't be logged, as it includes
2272 # database credential.