1# 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 5""" 6Convenience functions for use by tests or whomever. 7""" 8 9# pylint: disable=missing-docstring 10 11import commands 12import fnmatch 13import glob 14import json 15import logging 16import math 17import multiprocessing 18import os 19import 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 31 32from autotest_lib.client.common_lib.utils import * 33 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]|' 816 r'/dev/mmcblk[0-9]+|' 817 r'/dev/nvme[0-9]+n[0-9]+') 818 819 820def get_disk_from_filename(filename): 821 """ 822 Return the disk device the filename is on. 823 If the file is on tmpfs or other special file systems, 824 return None. 825 826 @param filename: name of file, full path. 827 """ 828 829 if not os.path.exists(filename): 830 raise error.TestError('file %s missing' % filename) 831 832 if filename[0] != '/': 833 raise error.TestError('This code works only with full path') 834 835 m = _DISK_DEV_RE.match(filename) 836 while not m: 837 if filename[0] != '/': 838 return None 839 if filename == '/dev/root': 840 cmd = 'rootdev -d -s' 841 elif filename.startswith('/dev/mapper'): 842 cmd = 'dmsetup table "%s"' % os.path.basename(filename) 843 dmsetup_output = utils.system_output(cmd).split(' ') 844 if dmsetup_output[2] == 'verity': 845 maj_min = dmsetup_output[4] 846 elif dmsetup_output[2] == 'crypt': 847 maj_min = dmsetup_output[6] 848 cmd = 'realpath "/dev/block/%s"' % maj_min 849 elif filename.startswith('/dev/loop'): 850 cmd = 'losetup -O BACK-FILE "%s" | tail -1' % filename 851 else: 852 cmd = 'df "%s" | tail -1 | cut -f 1 -d" "' % filename 853 filename = utils.system_output(cmd) 854 m = _DISK_DEV_RE.match(filename) 855 return m.group(0) 856 857 858def get_disk_firmware_version(disk_name): 859 """ 860 Return firmware version for internal storage device. (empty string for eMMC) 861 862 @param disk_name: disk name to find model 863 """ 864 cmd1 = 'udevadm info --query=property --name=%s' % disk_name 865 cmd2 = 'grep -E "ID_REVISION="' 866 cmd3 = 'cut -f 2 -d"="' 867 cmd = ' | '.join([cmd1, cmd2, cmd3]) 868 return utils.system_output(cmd) 869 870 871def is_disk_scsi(disk_name): 872 """ 873 Return true if disk is a scsi device, return false otherwise 874 875 @param disk_name: disk name check 876 """ 877 return re.match('/dev/sd[a-z]+', disk_name) 878 879 880def is_disk_harddisk(disk_name): 881 """ 882 Return true if disk is a harddisk, return false otherwise 883 884 @param disk_name: disk name check 885 """ 886 cmd1 = 'udevadm info --query=property --name=%s' % disk_name 887 cmd2 = 'grep -E "ID_ATA_ROTATION_RATE_RPM="' 888 cmd3 = 'cut -f 2 -d"="' 889 cmd = ' | '.join([cmd1, cmd2, cmd3]) 890 891 rtt = utils.system_output(cmd) 892 893 # eMMC will not have this field; rtt == '' 894 # SSD will have zero rotation rate; rtt == '0' 895 # For harddisk rtt > 0 896 return rtt and int(rtt) > 0 897 898 899def verify_hdparm_feature(disk_name, feature): 900 """ 901 Check for feature support for SCSI disk using hdparm 902 903 @param disk_name: target disk 904 @param feature: hdparm output string of the feature 905 """ 906 cmd = 'hdparm -I %s | grep -q "%s"' % (disk_name, feature) 907 ret = utils.system(cmd, ignore_status=True) 908 if ret == 0: 909 return True 910 elif ret == 1: 911 return False 912 else: 913 raise error.TestFail('Error running command %s' % cmd) 914 915 916def get_storage_error_msg(disk_name, reason): 917 """ 918 Get Error message for storage test which include disk model. 919 and also include the firmware version for the SCSI disk 920 921 @param disk_name: target disk 922 @param reason: Reason of the error. 923 """ 924 925 msg = reason 926 927 model = get_disk_model(disk_name) 928 msg += ' Disk model: %s' % model 929 930 if is_disk_scsi(disk_name): 931 fw = get_disk_firmware_version(disk_name) 932 msg += ' firmware: %s' % fw 933 934 return msg 935 936 937def load_module(module_name, params=None): 938 # Checks if a module has already been loaded 939 if module_is_loaded(module_name): 940 return False 941 942 cmd = '/sbin/modprobe ' + module_name 943 if params: 944 cmd += ' ' + params 945 utils.system(cmd) 946 return True 947 948 949def unload_module(module_name): 950 """ 951 Removes a module. Handles dependencies. If even then it's not possible 952 to remove one of the modules, it will trhow an error.CmdError exception. 953 954 @param module_name: Name of the module we want to remove. 955 """ 956 l_raw = utils.system_output("/bin/lsmod").splitlines() 957 lsmod = [x for x in l_raw if x.split()[0] == module_name] 958 if len(lsmod) > 0: 959 line_parts = lsmod[0].split() 960 if len(line_parts) == 4: 961 submodules = line_parts[3].split(",") 962 for submodule in submodules: 963 unload_module(submodule) 964 utils.system("/sbin/modprobe -r %s" % module_name) 965 logging.info("Module %s unloaded", module_name) 966 else: 967 logging.info("Module %s is already unloaded", module_name) 968 969 970def module_is_loaded(module_name): 971 module_name = module_name.replace('-', '_') 972 modules = utils.system_output('/bin/lsmod').splitlines() 973 for module in modules: 974 if module.startswith(module_name) and module[len(module_name)] == ' ': 975 return True 976 return False 977 978 979def get_loaded_modules(): 980 lsmod_output = utils.system_output('/bin/lsmod').splitlines()[1:] 981 return [line.split(None, 1)[0] for line in lsmod_output] 982 983 984def get_huge_page_size(): 985 output = utils.system_output('grep Hugepagesize /proc/meminfo') 986 return int(output.split()[1]) # Assumes units always in kB. :( 987 988 989def get_num_huge_pages(): 990 raw_hugepages = utils.system_output('/sbin/sysctl vm.nr_hugepages') 991 return int(raw_hugepages.split()[2]) 992 993 994def set_num_huge_pages(num): 995 utils.system('/sbin/sysctl vm.nr_hugepages=%d' % num) 996 997 998def ping_default_gateway(): 999 """Ping the default gateway.""" 1000 1001 network = open('/etc/sysconfig/network') 1002 m = re.search('GATEWAY=(\S+)', network.read()) 1003 1004 if m: 1005 gw = m.group(1) 1006 cmd = 'ping %s -c 5 > /dev/null' % gw 1007 return utils.system(cmd, ignore_status=True) 1008 1009 raise error.TestError('Unable to find default gateway') 1010 1011 1012def drop_caches(): 1013 """Writes back all dirty pages to disk and clears all the caches.""" 1014 utils.system("sync") 1015 # We ignore failures here as this will fail on 2.6.11 kernels. 1016 utils.system("echo 3 > /proc/sys/vm/drop_caches", ignore_status=True) 1017 1018 1019def process_is_alive(name_pattern): 1020 """ 1021 'pgrep name' misses all python processes and also long process names. 1022 'pgrep -f name' gets all shell commands with name in args. 1023 So look only for command whose initial pathname ends with name. 1024 Name itself is an egrep pattern, so it can use | etc for variations. 1025 """ 1026 return utils.system("pgrep -f '^([^ /]*/)*(%s)([ ]|$)'" % name_pattern, 1027 ignore_status=True) == 0 1028 1029 1030def get_hwclock_seconds(utc=True): 1031 """ 1032 Return the hardware clock in seconds as a floating point value. 1033 Use Coordinated Universal Time if utc is True, local time otherwise. 1034 Raise a ValueError if unable to read the hardware clock. 1035 """ 1036 cmd = '/sbin/hwclock --debug' 1037 if utc: 1038 cmd += ' --utc' 1039 hwclock_output = utils.system_output(cmd, ignore_status=True) 1040 match = re.search(r'= ([0-9]+) seconds since .+ (-?[0-9.]+) seconds$', 1041 hwclock_output, re.DOTALL) 1042 if match: 1043 seconds = int(match.group(1)) + float(match.group(2)) 1044 logging.debug('hwclock seconds = %f', seconds) 1045 return seconds 1046 1047 raise ValueError('Unable to read the hardware clock -- ' + 1048 hwclock_output) 1049 1050 1051def set_wake_alarm(alarm_time): 1052 """ 1053 Set the hardware RTC-based wake alarm to 'alarm_time'. 1054 """ 1055 utils.write_one_line('/sys/class/rtc/rtc0/wakealarm', str(alarm_time)) 1056 1057 1058def set_power_state(state): 1059 """ 1060 Set the system power state to 'state'. 1061 """ 1062 utils.write_one_line('/sys/power/state', state) 1063 1064 1065def standby(): 1066 """ 1067 Power-on suspend (S1) 1068 """ 1069 set_power_state('standby') 1070 1071 1072def suspend_to_ram(): 1073 """ 1074 Suspend the system to RAM (S3) 1075 """ 1076 set_power_state('mem') 1077 1078 1079def suspend_to_disk(): 1080 """ 1081 Suspend the system to disk (S4) 1082 """ 1083 set_power_state('disk') 1084 1085 1086_AMD_PCI_IDS_FILE_PATH = '/usr/local/autotest/bin/amd_pci_ids.json' 1087_INTEL_PCI_IDS_FILE_PATH = '/usr/local/autotest/bin/intel_pci_ids.json' 1088_UI_USE_FLAGS_FILE_PATH = '/etc/ui_use_flags.txt' 1089 1090# Command to check if a package is installed. If the package is not installed 1091# the command shall fail. 1092_CHECK_PACKAGE_INSTALLED_COMMAND =( 1093 "dpkg-query -W -f='${Status}\n' %s | head -n1 | awk '{print $3;}' | " 1094 "grep -q '^installed$'") 1095 1096pciid_to_amd_architecture = {} 1097pciid_to_intel_architecture = {} 1098 1099class Crossystem(object): 1100 """A wrapper for the crossystem utility.""" 1101 1102 def __init__(self, client): 1103 self.cros_system_data = {} 1104 self._client = client 1105 1106 def init(self): 1107 self.cros_system_data = {} 1108 (_, fname) = tempfile.mkstemp() 1109 f = open(fname, 'w') 1110 self._client.run('crossystem', stdout_tee=f) 1111 f.close() 1112 text = utils.read_file(fname) 1113 for line in text.splitlines(): 1114 assignment_string = line.split('#')[0] 1115 if not assignment_string.count('='): 1116 continue 1117 (name, value) = assignment_string.split('=', 1) 1118 self.cros_system_data[name.strip()] = value.strip() 1119 os.remove(fname) 1120 1121 def __getattr__(self, name): 1122 """ 1123 Retrieve a crosssystem attribute. 1124 1125 The call crossystemobject.name() will return the crossystem reported 1126 string. 1127 """ 1128 return lambda: self.cros_system_data[name] 1129 1130 1131def get_oldest_pid_by_name(name): 1132 """ 1133 Return the oldest pid of a process whose name perfectly matches |name|. 1134 1135 name is an egrep expression, which will be matched against the entire name 1136 of processes on the system. For example: 1137 1138 get_oldest_pid_by_name('chrome') 1139 1140 on a system running 1141 8600 ? 00:00:04 chrome 1142 8601 ? 00:00:00 chrome 1143 8602 ? 00:00:00 chrome-sandbox 1144 1145 would return 8600, as that's the oldest process that matches. 1146 chrome-sandbox would not be matched. 1147 1148 Arguments: 1149 name: egrep expression to match. Will be anchored at the beginning and 1150 end of the match string. 1151 1152 Returns: 1153 pid as an integer, or None if one cannot be found. 1154 1155 Raises: 1156 ValueError if pgrep returns something odd. 1157 """ 1158 str_pid = utils.system_output('pgrep -o ^%s$' % name, 1159 ignore_status=True).rstrip() 1160 if str_pid: 1161 return int(str_pid) 1162 1163 1164def get_oldest_by_name(name): 1165 """Return pid and command line of oldest process whose name matches |name|. 1166 1167 @param name: egrep expression to match desired process name. 1168 @return: A tuple of (pid, command_line) of the oldest process whose name 1169 matches |name|. 1170 1171 """ 1172 pid = get_oldest_pid_by_name(name) 1173 if pid: 1174 command_line = utils.system_output('ps -p %i -o command=' % pid, 1175 ignore_status=True).rstrip() 1176 return (pid, command_line) 1177 1178 1179def get_chrome_remote_debugging_port(): 1180 """Returns remote debugging port for Chrome. 1181 1182 Parse chrome process's command line argument to get the remote debugging 1183 port. 1184 """ 1185 _, command = get_oldest_by_name('chrome') 1186 matches = re.search('--remote-debugging-port=([0-9]+)', command) 1187 if matches: 1188 return int(matches.group(1)) 1189 1190 1191def get_process_list(name, command_line=None): 1192 """ 1193 Return the list of pid for matching process |name command_line|. 1194 1195 on a system running 1196 31475 ? 0:06 /opt/google/chrome/chrome --allow-webui-compositing - 1197 31478 ? 0:00 /opt/google/chrome/chrome-sandbox /opt/google/chrome/ 1198 31485 ? 0:00 /opt/google/chrome/chrome --type=zygote --log-level=1 1199 31532 ? 1:05 /opt/google/chrome/chrome --type=renderer 1200 1201 get_process_list('chrome') 1202 would return ['31475', '31485', '31532'] 1203 1204 get_process_list('chrome', '--type=renderer') 1205 would return ['31532'] 1206 1207 Arguments: 1208 name: process name to search for. If command_line is provided, name is 1209 matched against full command line. If command_line is not provided, 1210 name is only matched against the process name. 1211 command line: when command line is passed, the full process command line 1212 is used for matching. 1213 1214 Returns: 1215 list of PIDs of the matching processes. 1216 1217 """ 1218 # TODO(rohitbm) crbug.com/268861 1219 flag = '-x' if not command_line else '-f' 1220 name = '\'%s.*%s\'' % (name, command_line) if command_line else name 1221 str_pid = utils.system_output('pgrep %s %s' % (flag, name), 1222 ignore_status=True).rstrip() 1223 return str_pid.split() 1224 1225 1226def nuke_process_by_name(name, with_prejudice=False): 1227 """Tell the oldest process specified by name to exit. 1228 1229 Arguments: 1230 name: process name specifier, as understood by pgrep. 1231 with_prejudice: if True, don't allow for graceful exit. 1232 1233 Raises: 1234 error.AutoservPidAlreadyDeadError: no existing process matches name. 1235 """ 1236 try: 1237 pid = get_oldest_pid_by_name(name) 1238 except Exception as e: 1239 logging.error(e) 1240 return 1241 if pid is None: 1242 raise error.AutoservPidAlreadyDeadError('No process matching %s.' % 1243 name) 1244 if with_prejudice: 1245 utils.nuke_pid(pid, [signal.SIGKILL]) 1246 else: 1247 utils.nuke_pid(pid) 1248 1249 1250def ensure_processes_are_dead_by_name(name, timeout_sec=10): 1251 """Terminate all processes specified by name and ensure they're gone. 1252 1253 Arguments: 1254 name: process name specifier, as understood by pgrep. 1255 timeout_sec: maximum number of seconds to wait for processes to die. 1256 1257 Raises: 1258 error.AutoservPidAlreadyDeadError: no existing process matches name. 1259 utils.TimeoutError: if processes still exist after timeout_sec. 1260 """ 1261 1262 def list_and_kill_processes(name): 1263 process_list = get_process_list(name) 1264 try: 1265 for pid in [int(str_pid) for str_pid in process_list]: 1266 utils.nuke_pid(pid) 1267 except error.AutoservPidAlreadyDeadError: 1268 pass 1269 return process_list 1270 1271 utils.poll_for_condition(lambda: list_and_kill_processes(name) == [], 1272 timeout=timeout_sec) 1273 1274 1275def is_virtual_machine(): 1276 return 'QEMU' in platform.processor() 1277 1278 1279def save_vm_state(checkpoint): 1280 """Saves the current state of the virtual machine. 1281 1282 This function is a NOOP if the test is not running under a virtual machine 1283 with the USB serial port redirected. 1284 1285 Arguments: 1286 checkpoint - Name used to identify this state 1287 1288 Returns: 1289 None 1290 """ 1291 # The QEMU monitor has been redirected to the guest serial port located at 1292 # /dev/ttyUSB0. To save the state of the VM, we just send the 'savevm' 1293 # command to the serial port. 1294 if is_virtual_machine() and os.path.exists('/dev/ttyUSB0'): 1295 logging.info('Saving VM state "%s"', checkpoint) 1296 serial = open('/dev/ttyUSB0', 'w') 1297 serial.write('savevm %s\r\n' % checkpoint) 1298 logging.info('Done saving VM state "%s"', checkpoint) 1299 1300 1301def check_raw_dmesg(dmesg, message_level, whitelist): 1302 """Checks dmesg for unexpected warnings. 1303 1304 This function parses dmesg for message with message_level <= message_level 1305 which do not appear in the whitelist. 1306 1307 Arguments: 1308 dmesg - string containing raw dmesg buffer 1309 message_level - minimum message priority to check 1310 whitelist - messages to ignore 1311 1312 Returns: 1313 List of unexpected warnings 1314 """ 1315 whitelist_re = re.compile(r'(%s)' % '|'.join(whitelist)) 1316 unexpected = [] 1317 for line in dmesg.splitlines(): 1318 if int(line[1]) <= message_level: 1319 stripped_line = line.split('] ', 1)[1] 1320 if whitelist_re.search(stripped_line): 1321 continue 1322 unexpected.append(stripped_line) 1323 return unexpected 1324 1325 1326def verify_mesg_set(mesg, regex, whitelist): 1327 """Verifies that the exact set of messages are present in a text. 1328 1329 This function finds all strings in the text matching a certain regex, and 1330 then verifies that all expected strings are present in the set, and no 1331 unexpected strings are there. 1332 1333 Arguments: 1334 mesg - the mutiline text to be scanned 1335 regex - regular expression to match 1336 whitelist - messages to find in the output, a list of strings 1337 (potentially regexes) to look for in the filtered output. All these 1338 strings must be there, and no other strings should be present in the 1339 filtered output. 1340 1341 Returns: 1342 string of inconsistent findings (i.e. an empty string on success). 1343 """ 1344 1345 rv = [] 1346 1347 missing_strings = [] 1348 present_strings = [] 1349 for line in mesg.splitlines(): 1350 if not re.search(r'%s' % regex, line): 1351 continue 1352 present_strings.append(line.split('] ', 1)[1]) 1353 1354 for string in whitelist: 1355 for present_string in list(present_strings): 1356 if re.search(r'^%s$' % string, present_string): 1357 present_strings.remove(present_string) 1358 break 1359 else: 1360 missing_strings.append(string) 1361 1362 if present_strings: 1363 rv.append('unexpected strings:') 1364 rv.extend(present_strings) 1365 if missing_strings: 1366 rv.append('missing strings:') 1367 rv.extend(missing_strings) 1368 1369 return '\n'.join(rv) 1370 1371 1372def target_is_pie(): 1373 """Returns whether the toolchain produces a PIE (position independent 1374 executable) by default. 1375 1376 Arguments: 1377 None 1378 1379 Returns: 1380 True if the target toolchain produces a PIE by default. 1381 False otherwise. 1382 """ 1383 1384 command = 'echo | ${CC} -E -dD -P - | grep -i pie' 1385 result = utils.system_output(command, 1386 retain_output=True, 1387 ignore_status=True) 1388 if re.search('#define __PIE__', result): 1389 return True 1390 else: 1391 return False 1392 1393 1394def target_is_x86(): 1395 """Returns whether the toolchain produces an x86 object 1396 1397 Arguments: 1398 None 1399 1400 Returns: 1401 True if the target toolchain produces an x86 object 1402 False otherwise. 1403 """ 1404 1405 command = 'echo | ${CC} -E -dD -P - | grep -i 86' 1406 result = utils.system_output(command, 1407 retain_output=True, 1408 ignore_status=True) 1409 if re.search('__i386__', result) or re.search('__x86_64__', result): 1410 return True 1411 else: 1412 return False 1413 1414 1415def mounts(): 1416 ret = [] 1417 for line in file('/proc/mounts'): 1418 m = re.match( 1419 r'(?P<src>\S+) (?P<dest>\S+) (?P<type>\S+) (?P<opts>\S+).*', line) 1420 if m: 1421 ret.append(m.groupdict()) 1422 return ret 1423 1424 1425def is_mountpoint(path): 1426 return path in [m['dest'] for m in mounts()] 1427 1428 1429def require_mountpoint(path): 1430 """ 1431 Raises an exception if path is not a mountpoint. 1432 """ 1433 if not is_mountpoint(path): 1434 raise error.TestFail('Path not mounted: "%s"' % path) 1435 1436 1437def random_username(): 1438 return str(uuid.uuid4()) + '@example.com' 1439 1440 1441def get_signin_credentials(filepath): 1442 """Returns user_id, password tuple from credentials file at filepath. 1443 1444 File must have one line of the format user_id:password 1445 1446 @param filepath: path of credentials file. 1447 @return user_id, password tuple. 1448 """ 1449 user_id, password = None, None 1450 if os.path.isfile(filepath): 1451 with open(filepath) as f: 1452 user_id, password = f.read().rstrip().split(':') 1453 return user_id, password 1454 1455 1456def parse_cmd_output(command, run_method=utils.run): 1457 """Runs a command on a host object to retrieve host attributes. 1458 1459 The command should output to stdout in the format of: 1460 <key> = <value> # <optional_comment> 1461 1462 1463 @param command: Command to execute on the host. 1464 @param run_method: Function to use to execute the command. Defaults to 1465 utils.run so that the command will be executed locally. 1466 Can be replace with a host.run call so that it will 1467 execute on a DUT or external machine. Method must accept 1468 a command argument, stdout_tee and stderr_tee args and 1469 return a result object with a string attribute stdout 1470 which will be parsed. 1471 1472 @returns a dictionary mapping host attributes to their values. 1473 """ 1474 result = {} 1475 # Suppresses stdout so that the files are not printed to the logs. 1476 cmd_result = run_method(command, stdout_tee=None, stderr_tee=None) 1477 for line in cmd_result.stdout.splitlines(): 1478 # Lines are of the format "<key> = <value> # <comment>" 1479 key_value = re.match(r'^\s*(?P<key>[^ ]+)\s*=\s*(?P<value>[^ ' 1480 r']+)(?:\s*#.*)?$', line) 1481 if key_value: 1482 result[key_value.group('key')] = key_value.group('value') 1483 return result 1484 1485 1486def set_from_keyval_output(out, delimiter=' '): 1487 """Parse delimiter-separated key-val output into a set of tuples. 1488 1489 Output is expected to be multiline text output from a command. 1490 Stuffs the key-vals into tuples in a set to be later compared. 1491 1492 e.g. deactivated 0 1493 disableForceClear 0 1494 ==> set(('deactivated', '0'), ('disableForceClear', '0')) 1495 1496 @param out: multiple lines of space-separated key-val pairs. 1497 @param delimiter: character that separates key from val. Usually a 1498 space but may be '=' or something else. 1499 @return set of key-val tuples. 1500 """ 1501 results = set() 1502 kv_match_re = re.compile('([^ ]+)%s(.*)' % delimiter) 1503 for linecr in out.splitlines(): 1504 match = kv_match_re.match(linecr.strip()) 1505 if match: 1506 results.add((match.group(1), match.group(2))) 1507 return results 1508 1509 1510def get_cpu_usage(): 1511 """Returns machine's CPU usage. 1512 1513 This function uses /proc/stat to identify CPU usage. 1514 Returns: 1515 A dictionary with 'user', 'nice', 'system' and 'idle' values. 1516 Sample dictionary: 1517 { 1518 'user': 254544, 1519 'nice': 9, 1520 'system': 254768, 1521 'idle': 2859878, 1522 } 1523 """ 1524 proc_stat = open('/proc/stat') 1525 cpu_usage_str = proc_stat.readline().split() 1526 proc_stat.close() 1527 return { 1528 'user': int(cpu_usage_str[1]), 1529 'nice': int(cpu_usage_str[2]), 1530 'system': int(cpu_usage_str[3]), 1531 'idle': int(cpu_usage_str[4]) 1532 } 1533 1534 1535def compute_active_cpu_time(cpu_usage_start, cpu_usage_end): 1536 """Computes the fraction of CPU time spent non-idling. 1537 1538 This function should be invoked using before/after values from calls to 1539 get_cpu_usage(). 1540 """ 1541 time_active_end = ( 1542 cpu_usage_end['user'] + cpu_usage_end['nice'] + cpu_usage_end['system']) 1543 time_active_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] + 1544 cpu_usage_start['system']) 1545 total_time_end = (cpu_usage_end['user'] + cpu_usage_end['nice'] + 1546 cpu_usage_end['system'] + cpu_usage_end['idle']) 1547 total_time_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] + 1548 cpu_usage_start['system'] + cpu_usage_start['idle']) 1549 return ((float(time_active_end) - time_active_start) / 1550 (total_time_end - total_time_start)) 1551 1552 1553def is_pgo_mode(): 1554 return 'USE_PGO' in os.environ 1555 1556 1557def wait_for_idle_cpu(timeout, utilization): 1558 """Waits for the CPU to become idle (< utilization). 1559 1560 Args: 1561 timeout: The longest time in seconds to wait before throwing an error. 1562 utilization: The CPU usage below which the system should be considered 1563 idle (between 0 and 1.0 independent of cores/hyperthreads). 1564 """ 1565 time_passed = 0.0 1566 fraction_active_time = 1.0 1567 sleep_time = 1 1568 logging.info('Starting to wait up to %.1fs for idle CPU...', timeout) 1569 while fraction_active_time >= utilization: 1570 cpu_usage_start = get_cpu_usage() 1571 # Split timeout interval into not too many chunks to limit log spew. 1572 # Start at 1 second, increase exponentially 1573 time.sleep(sleep_time) 1574 time_passed += sleep_time 1575 sleep_time = min(16.0, 2.0 * sleep_time) 1576 cpu_usage_end = get_cpu_usage() 1577 fraction_active_time = \ 1578 compute_active_cpu_time(cpu_usage_start, cpu_usage_end) 1579 logging.info('After waiting %.1fs CPU utilization is %.3f.', 1580 time_passed, fraction_active_time) 1581 if time_passed > timeout: 1582 logging.warning('CPU did not become idle.') 1583 log_process_activity() 1584 # crosbug.com/37389 1585 if is_pgo_mode(): 1586 logging.info('Still continuing because we are in PGO mode.') 1587 return True 1588 1589 return False 1590 logging.info('Wait for idle CPU took %.1fs (utilization = %.3f).', 1591 time_passed, fraction_active_time) 1592 return True 1593 1594 1595def log_process_activity(): 1596 """Logs the output of top. 1597 1598 Useful to debug performance tests and to find runaway processes. 1599 """ 1600 logging.info('Logging current process activity using top and ps.') 1601 cmd = 'top -b -n1 -c' 1602 output = utils.run(cmd) 1603 logging.info(output) 1604 output = utils.run('ps axl') 1605 logging.info(output) 1606 1607 1608def wait_for_cool_machine(): 1609 """ 1610 A simple heuristic to wait for a machine to cool. 1611 The code looks a bit 'magic', but we don't know ambient temperature 1612 nor machine characteristics and still would like to return the caller 1613 a machine that cooled down as much as reasonably possible. 1614 """ 1615 temperature = get_current_temperature_max() 1616 # We got here with a cold machine, return immediately. This should be the 1617 # most common case. 1618 if temperature < 50: 1619 return True 1620 logging.info('Got a hot machine of %dC. Sleeping 1 minute.', temperature) 1621 # A modest wait should cool the machine. 1622 time.sleep(60.0) 1623 temperature = get_current_temperature_max() 1624 # Atoms idle below 60 and everyone else should be even lower. 1625 if temperature < 62: 1626 return True 1627 # This should be rare. 1628 logging.info('Did not cool down (%dC). Sleeping 2 minutes.', temperature) 1629 time.sleep(120.0) 1630 temperature = get_current_temperature_max() 1631 # A temperature over 65'C doesn't give us much headroom to the critical 1632 # temperatures that start at 85'C (and PerfControl as of today will fail at 1633 # critical - 10'C). 1634 if temperature < 65: 1635 return True 1636 logging.warning('Did not cool down (%dC), giving up.', temperature) 1637 log_process_activity() 1638 return False 1639 1640 1641# System paths for machine performance state. 1642_CPUINFO = '/proc/cpuinfo' 1643_DIRTY_WRITEBACK_CENTISECS = '/proc/sys/vm/dirty_writeback_centisecs' 1644_KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' 1645_MEMINFO = '/proc/meminfo' 1646_TEMP_SENSOR_RE = 'Reading temperature...([0-9]*)' 1647 1648 1649def _get_line_from_file(path, line): 1650 """ 1651 line can be an integer or 1652 line can be a string that matches the beginning of the line 1653 """ 1654 with open(path) as f: 1655 if isinstance(line, int): 1656 l = f.readline() 1657 for _ in range(0, line): 1658 l = f.readline() 1659 return l 1660 else: 1661 for l in f: 1662 if l.startswith(line): 1663 return l 1664 return None 1665 1666 1667def _get_match_from_file(path, line, prefix, postfix): 1668 """ 1669 Matches line in path and returns string between first prefix and postfix. 1670 """ 1671 match = _get_line_from_file(path, line) 1672 # Strip everything from front of line including prefix. 1673 if prefix: 1674 match = re.split(prefix, match)[1] 1675 # Strip everything from back of string including first occurence of postfix. 1676 if postfix: 1677 match = re.split(postfix, match)[0] 1678 return match 1679 1680 1681def _get_float_from_file(path, line, prefix, postfix): 1682 match = _get_match_from_file(path, line, prefix, postfix) 1683 return float(match) 1684 1685 1686def _get_int_from_file(path, line, prefix, postfix): 1687 match = _get_match_from_file(path, line, prefix, postfix) 1688 return int(match) 1689 1690 1691def _get_hex_from_file(path, line, prefix, postfix): 1692 match = _get_match_from_file(path, line, prefix, postfix) 1693 return int(match, 16) 1694 1695 1696# The paths don't change. Avoid running find all the time. 1697_hwmon_paths = None 1698 1699def _get_hwmon_paths(file_pattern): 1700 """ 1701 Returns a list of paths to the temperature sensors. 1702 """ 1703 # Some systems like daisy_spring only have the virtual hwmon. 1704 # And other systems like rambi only have coretemp.0. See crbug.com/360249. 1705 # /sys/class/hwmon/hwmon*/ 1706 # /sys/devices/virtual/hwmon/hwmon*/ 1707 # /sys/devices/platform/coretemp.0/ 1708 if not _hwmon_paths: 1709 cmd = 'find /sys/ -name "' + file_pattern + '"' 1710 _hwon_paths = utils.run(cmd, verbose=False).stdout.splitlines() 1711 return _hwon_paths 1712 1713 1714def get_temperature_critical(): 1715 """ 1716 Returns temperature at which we will see some throttling in the system. 1717 """ 1718 min_temperature = 1000.0 1719 paths = _get_hwmon_paths('temp*_crit') 1720 for path in paths: 1721 temperature = _get_float_from_file(path, 0, None, None) * 0.001 1722 # Today typical for Intel is 98'C to 105'C while ARM is 85'C. Clamp to 1723 # the lowest known value. 1724 if (min_temperature < 60.0) or min_temperature > 150.0: 1725 logging.warning('Critical temperature of %.1fC was reset to 85.0C.', 1726 min_temperature) 1727 min_temperature = 85.0 1728 1729 min_temperature = min(temperature, min_temperature) 1730 return min_temperature 1731 1732 1733def get_temperature_input_max(): 1734 """ 1735 Returns the maximum currently observed temperature. 1736 """ 1737 max_temperature = -1000.0 1738 paths = _get_hwmon_paths('temp*_input') 1739 for path in paths: 1740 temperature = _get_float_from_file(path, 0, None, None) * 0.001 1741 max_temperature = max(temperature, max_temperature) 1742 return max_temperature 1743 1744 1745def get_thermal_zone_temperatures(): 1746 """ 1747 Returns the maximum currently observered temperature in thermal_zones. 1748 """ 1749 temperatures = [] 1750 for path in glob.glob('/sys/class/thermal/thermal_zone*/temp'): 1751 try: 1752 temperatures.append( 1753 _get_float_from_file(path, 0, None, None) * 0.001) 1754 except IOError: 1755 # Some devices (e.g. Veyron) may have reserved thermal zones that 1756 # are not active. Trying to read the temperature value would cause a 1757 # EINVAL IO error. 1758 continue 1759 return temperatures 1760 1761 1762def get_ec_temperatures(): 1763 """ 1764 Uses ectool to return a list of all sensor temperatures in Celsius. 1765 """ 1766 temperatures = [] 1767 try: 1768 full_cmd = 'ectool temps all' 1769 lines = utils.run(full_cmd, verbose=False).stdout.splitlines() 1770 for line in lines: 1771 temperature = int(line.split(': ')[1]) - 273 1772 temperatures.append(temperature) 1773 except Exception: 1774 logging.warning('Unable to read temperature sensors using ectool.') 1775 for temperature in temperatures: 1776 # Sanity check for real world values. 1777 assert ((temperature > 10.0) and 1778 (temperature < 150.0)), ('Unreasonable temperature %.1fC.' % 1779 temperature) 1780 1781 return temperatures 1782 1783 1784def get_current_temperature_max(): 1785 """ 1786 Returns the highest reported board temperature (all sensors) in Celsius. 1787 """ 1788 temperature = max([get_temperature_input_max()] + 1789 get_thermal_zone_temperatures() + 1790 get_ec_temperatures()) 1791 # Sanity check for real world values. 1792 assert ((temperature > 10.0) and 1793 (temperature < 150.0)), ('Unreasonable temperature %.1fC.' % 1794 temperature) 1795 return temperature 1796 1797 1798def get_cpu_cache_size(): 1799 """ 1800 Returns the last level CPU cache size in kBytes. 1801 """ 1802 cache_size = _get_int_from_file(_CPUINFO, 'cache size', ': ', ' KB') 1803 # Sanity check. 1804 assert cache_size >= 64, 'Unreasonably small cache.' 1805 return cache_size 1806 1807 1808def get_cpu_model_frequency(): 1809 """ 1810 Returns the model frequency from the CPU model name on Intel only. This 1811 might be redundant with get_cpu_max_frequency. Unit is Hz. 1812 """ 1813 frequency = _get_float_from_file(_CPUINFO, 'model name', ' @ ', 'GHz') 1814 return 1.e9 * frequency 1815 1816 1817def get_cpu_max_frequency(): 1818 """ 1819 Returns the largest of the max CPU core frequencies. The unit is Hz. 1820 """ 1821 max_frequency = -1 1822 paths = _get_cpufreq_paths('cpuinfo_max_freq') 1823 for path in paths: 1824 # Convert from kHz to Hz. 1825 frequency = 1000 * _get_float_from_file(path, 0, None, None) 1826 max_frequency = max(frequency, max_frequency) 1827 # Sanity check. 1828 assert max_frequency > 1e8, 'Unreasonably low CPU frequency.' 1829 return max_frequency 1830 1831 1832def get_cpu_min_frequency(): 1833 """ 1834 Returns the smallest of the minimum CPU core frequencies. 1835 """ 1836 min_frequency = 1e20 1837 paths = _get_cpufreq_paths('cpuinfo_min_freq') 1838 for path in paths: 1839 frequency = _get_float_from_file(path, 0, None, None) 1840 min_frequency = min(frequency, min_frequency) 1841 # Sanity check. 1842 assert min_frequency > 1e8, 'Unreasonably low CPU frequency.' 1843 return min_frequency 1844 1845 1846def get_cpu_model(): 1847 """ 1848 Returns the CPU model. 1849 Only works on Intel. 1850 """ 1851 cpu_model = _get_int_from_file(_CPUINFO, 'model\t', ': ', None) 1852 return cpu_model 1853 1854 1855def get_cpu_family(): 1856 """ 1857 Returns the CPU family. 1858 Only works on Intel. 1859 """ 1860 cpu_family = _get_int_from_file(_CPUINFO, 'cpu family\t', ': ', None) 1861 return cpu_family 1862 1863 1864def get_board_property(key): 1865 """ 1866 Get a specific property from /etc/lsb-release. 1867 1868 @param key: board property to return value for 1869 1870 @return the value or '' if not present 1871 """ 1872 with open('/etc/lsb-release') as f: 1873 pattern = '%s=(.*)' % key 1874 pat = re.search(pattern, f.read()) 1875 if pat: 1876 return pat.group(1) 1877 return '' 1878 1879 1880def get_board(): 1881 """ 1882 Get the ChromeOS release board name from /etc/lsb-release. 1883 """ 1884 return get_board_property('BOARD') 1885 1886 1887def get_board_type(): 1888 """ 1889 Get the ChromeOS board type from /etc/lsb-release. 1890 1891 @return device type. 1892 """ 1893 return get_board_property('DEVICETYPE') 1894 1895 1896def get_board_with_frequency_and_memory(): 1897 """ 1898 Returns a board name modified with CPU frequency and memory size to 1899 differentiate between different board variants. For instance 1900 link -> link_1.8GHz_4GB. 1901 """ 1902 board_name = get_board() 1903 if is_virtual_machine(): 1904 board = '%s_VM' % board_name 1905 else: 1906 # Rounded to nearest GB and GHz. 1907 memory = int(round(get_mem_total() / 1024.0)) 1908 # Convert frequency to GHz with 1 digit accuracy after the 1909 # decimal point. 1910 frequency = int(round(get_cpu_max_frequency() * 1e-8)) * 0.1 1911 board = '%s_%1.1fGHz_%dGB' % (board_name, frequency, memory) 1912 return board 1913 1914 1915def get_mem_total(): 1916 """ 1917 Returns the total memory available in the system in MBytes. 1918 """ 1919 mem_total = _get_float_from_file(_MEMINFO, 'MemTotal:', 'MemTotal:', ' kB') 1920 # Sanity check, all Chromebooks have at least 1GB of memory. 1921 assert mem_total > 256 * 1024, 'Unreasonable amount of memory.' 1922 return mem_total / 1024 1923 1924 1925def get_mem_free(): 1926 """ 1927 Returns the currently free memory in the system in MBytes. 1928 """ 1929 mem_free = _get_float_from_file(_MEMINFO, 'MemFree:', 'MemFree:', ' kB') 1930 return mem_free / 1024 1931 1932 1933def get_kernel_max(): 1934 """ 1935 Returns content of kernel_max. 1936 """ 1937 kernel_max = _get_int_from_file(_KERNEL_MAX, 0, None, None) 1938 # Sanity check. 1939 assert ((kernel_max > 0) and (kernel_max < 257)), 'Unreasonable kernel_max.' 1940 return kernel_max 1941 1942 1943def set_high_performance_mode(): 1944 """ 1945 Sets the kernel governor mode to the highest setting. 1946 Returns previous governor state. 1947 """ 1948 original_governors = get_scaling_governor_states() 1949 set_scaling_governors('performance') 1950 return original_governors 1951 1952 1953def set_scaling_governors(value): 1954 """ 1955 Sets all scaling governor to string value. 1956 Sample values: 'performance', 'interactive', 'ondemand', 'powersave'. 1957 """ 1958 paths = _get_cpufreq_paths('scaling_governor') 1959 for path in paths: 1960 cmd = 'echo %s > %s' % (value, path) 1961 logging.info('Writing scaling governor mode \'%s\' -> %s', value, path) 1962 # On Tegra CPUs can be dynamically enabled/disabled. Ignore failures. 1963 utils.system(cmd, ignore_status=True) 1964 1965 1966def _get_cpufreq_paths(filename): 1967 """ 1968 Returns a list of paths to the governors. 1969 """ 1970 cmd = 'ls /sys/devices/system/cpu/cpu*/cpufreq/' + filename 1971 paths = utils.run(cmd, verbose=False).stdout.splitlines() 1972 return paths 1973 1974 1975def get_scaling_governor_states(): 1976 """ 1977 Returns a list of (performance governor path, current state) tuples. 1978 """ 1979 paths = _get_cpufreq_paths('scaling_governor') 1980 path_value_list = [] 1981 for path in paths: 1982 value = _get_line_from_file(path, 0) 1983 path_value_list.append((path, value)) 1984 return path_value_list 1985 1986 1987def restore_scaling_governor_states(path_value_list): 1988 """ 1989 Restores governor states. Inverse operation to get_scaling_governor_states. 1990 """ 1991 for (path, value) in path_value_list: 1992 cmd = 'echo %s > %s' % (value.rstrip('\n'), path) 1993 # On Tegra CPUs can be dynamically enabled/disabled. Ignore failures. 1994 utils.system(cmd, ignore_status=True) 1995 1996 1997def get_dirty_writeback_centisecs(): 1998 """ 1999 Reads /proc/sys/vm/dirty_writeback_centisecs. 2000 """ 2001 time = _get_int_from_file(_DIRTY_WRITEBACK_CENTISECS, 0, None, None) 2002 return time 2003 2004 2005def set_dirty_writeback_centisecs(time=60000): 2006 """ 2007 In hundredths of a second, this is how often pdflush wakes up to write data 2008 to disk. The default wakes up the two (or more) active threads every five 2009 seconds. The ChromeOS default is 10 minutes. 2010 2011 We use this to set as low as 1 second to flush error messages in system 2012 logs earlier to disk. 2013 """ 2014 # Flush buffers first to make this function synchronous. 2015 utils.system('sync') 2016 if time >= 0: 2017 cmd = 'echo %d > %s' % (time, _DIRTY_WRITEBACK_CENTISECS) 2018 utils.system(cmd) 2019 2020 2021def wflinfo_cmd(): 2022 """ 2023 Returns a wflinfo command appropriate to the current graphics platform/api. 2024 """ 2025 return 'wflinfo -p %s -a %s' % (graphics_platform(), graphics_api()) 2026 2027 2028def has_mali(): 2029 """ @return: True if system has a Mali GPU enabled.""" 2030 return os.path.exists('/dev/mali0') 2031 2032def get_gpu_family(): 2033 """Returns the GPU family name.""" 2034 global pciid_to_amd_architecture 2035 global pciid_to_intel_architecture 2036 2037 socfamily = get_cpu_soc_family() 2038 if socfamily == 'exynos5' or socfamily == 'rockchip' or has_mali(): 2039 cmd = wflinfo_cmd() 2040 wflinfo = utils.system_output(cmd, 2041 retain_output=True, 2042 ignore_status=False) 2043 version = re.findall(r'OpenGL renderer string: ' 2044 r'Mali-T([0-9]+)', wflinfo) 2045 if version: 2046 return 'mali-t%s' % version[0] 2047 return 'mali-unrecognized' 2048 if socfamily == 'tegra': 2049 return 'tegra' 2050 if os.path.exists('/sys/kernel/debug/pvr'): 2051 return 'rogue' 2052 2053 pci_vga_device = utils.run("lspci | grep VGA").stdout.rstrip('\n') 2054 bus_device_function = pci_vga_device.partition(' ')[0] 2055 pci_path = '/sys/bus/pci/devices/0000:' + bus_device_function + '/device' 2056 2057 if not os.path.exists(pci_path): 2058 raise error.TestError('PCI device 0000:' + bus_device_function + ' not found') 2059 2060 device_id = utils.read_one_line(pci_path).lower() 2061 2062 if "Advanced Micro Devices" in pci_vga_device: 2063 if not pciid_to_amd_architecture: 2064 with open(_AMD_PCI_IDS_FILE_PATH, 'r') as in_f: 2065 pciid_to_amd_architecture = json.load(in_f) 2066 2067 return pciid_to_amd_architecture[device_id] 2068 2069 if "Intel Corporation" in pci_vga_device: 2070 # Only load Intel PCI ID file once and only if necessary. 2071 if not pciid_to_intel_architecture: 2072 with open(_INTEL_PCI_IDS_FILE_PATH, 'r') as in_f: 2073 pciid_to_intel_architecture = json.load(in_f) 2074 2075 return pciid_to_intel_architecture[device_id] 2076 2077# TODO(ihf): Consider using /etc/lsb-release DEVICETYPE != CHROMEBOOK/CHROMEBASE 2078# for sanity check, but usage seems a bit inconsistent. See 2079# src/third_party/chromiumos-overlay/eclass/appid.eclass 2080_BOARDS_WITHOUT_MONITOR = [ 2081 'anglar', 'mccloud', 'monroe', 'ninja', 'rikku', 'guado', 'jecht', 'tidus', 2082 'beltino', 'panther', 'stumpy', 'panther', 'tricky', 'zako', 'veyron_rialto' 2083] 2084 2085 2086def has_no_monitor(): 2087 """Returns whether a machine doesn't have a built-in monitor.""" 2088 board_name = get_board() 2089 if board_name in _BOARDS_WITHOUT_MONITOR: 2090 return True 2091 2092 return False 2093 2094 2095def get_fixed_dst_drive(): 2096 """ 2097 Return device name for internal disk. 2098 Example: return /dev/sda for falco booted from usb 2099 """ 2100 cmd = ' '.join(['. /usr/sbin/write_gpt.sh;', 2101 '. /usr/share/misc/chromeos-common.sh;', 2102 'load_base_vars;', 2103 'get_fixed_dst_drive']) 2104 return utils.system_output(cmd) 2105 2106 2107def get_root_device(): 2108 """ 2109 Return root device. 2110 Will return correct disk device even system boot from /dev/dm-0 2111 Example: return /dev/sdb for falco booted from usb 2112 """ 2113 return utils.system_output('rootdev -s -d') 2114 2115 2116def get_root_partition(): 2117 """ 2118 Return current root partition 2119 Example: return /dev/sdb3 for falco booted from usb 2120 """ 2121 return utils.system_output('rootdev -s') 2122 2123 2124def get_free_root_partition(root_part=None): 2125 """ 2126 Return currently unused root partion 2127 Example: return /dev/sdb5 for falco booted from usb 2128 2129 @param root_part: cuurent root partition 2130 """ 2131 spare_root_map = {'3': '5', '5': '3'} 2132 if not root_part: 2133 root_part = get_root_partition() 2134 return root_part[:-1] + spare_root_map[root_part[-1]] 2135 2136 2137def get_kernel_partition(root_part=None): 2138 """ 2139 Return current kernel partition 2140 Example: return /dev/sda2 for falco booted from usb 2141 2142 @param root_part: current root partition 2143 """ 2144 if not root_part: 2145 root_part = get_root_partition() 2146 current_kernel_map = {'3': '2', '5': '4'} 2147 return root_part[:-1] + current_kernel_map[root_part[-1]] 2148 2149 2150def get_free_kernel_partition(root_part=None): 2151 """ 2152 return currently unused kernel partition 2153 Example: return /dev/sda4 for falco booted from usb 2154 2155 @param root_part: current root partition 2156 """ 2157 kernel_part = get_kernel_partition(root_part) 2158 spare_kernel_map = {'2': '4', '4': '2'} 2159 return kernel_part[:-1] + spare_kernel_map[kernel_part[-1]] 2160 2161 2162def is_booted_from_internal_disk(): 2163 """Return True if boot from internal disk. False, otherwise.""" 2164 return get_root_device() == get_fixed_dst_drive() 2165 2166 2167def get_ui_use_flags(): 2168 """Parses the USE flags as listed in /etc/ui_use_flags.txt. 2169 2170 @return: A list of flag strings found in the ui use flags file. 2171 """ 2172 flags = [] 2173 for flag in utils.read_file(_UI_USE_FLAGS_FILE_PATH).splitlines(): 2174 # Removes everything after the '#'. 2175 flag_before_comment = flag.split('#')[0].strip() 2176 if len(flag_before_comment) != 0: 2177 flags.append(flag_before_comment) 2178 2179 return flags 2180 2181 2182def graphics_platform(): 2183 """ 2184 Return a string identifying the graphics platform, 2185 e.g. 'glx' or 'x11_egl' or 'gbm' 2186 """ 2187 return 'null' 2188 2189 2190def graphics_api(): 2191 """Return a string identifying the graphics api, e.g. gl or gles2.""" 2192 use_flags = get_ui_use_flags() 2193 if 'opengles' in use_flags: 2194 return 'gles2' 2195 return 'gl' 2196 2197 2198def is_vm(): 2199 """Check if the process is running in a virtual machine. 2200 2201 @return: True if the process is running in a virtual machine, otherwise 2202 return False. 2203 """ 2204 try: 2205 virt = utils.run('sudo -n virt-what').stdout.strip() 2206 logging.debug('virt-what output: %s', virt) 2207 return bool(virt) 2208 except error.CmdError: 2209 logging.warn('Package virt-what is not installed, default to assume ' 2210 'it is not a virtual machine.') 2211 return False 2212 2213 2214def is_package_installed(package): 2215 """Check if a package is installed already. 2216 2217 @return: True if the package is already installed, otherwise return False. 2218 """ 2219 try: 2220 utils.run(_CHECK_PACKAGE_INSTALLED_COMMAND % package) 2221 return True 2222 except error.CmdError: 2223 logging.warn('Package %s is not installed.', package) 2224 return False 2225 2226 2227def is_python_package_installed(package): 2228 """Check if a Python package is installed already. 2229 2230 @return: True if the package is already installed, otherwise return False. 2231 """ 2232 try: 2233 __import__(package) 2234 return True 2235 except ImportError: 2236 logging.warn('Python package %s is not installed.', package) 2237 return False 2238 2239 2240def run_sql_cmd(server, user, password, command, database=''): 2241 """Run the given sql command against the specified database. 2242 2243 @param server: Hostname or IP address of the MySQL server. 2244 @param user: User name to log in the MySQL server. 2245 @param password: Password to log in the MySQL server. 2246 @param command: SQL command to run. 2247 @param database: Name of the database to run the command. Default to empty 2248 for command that does not require specifying database. 2249 2250 @return: The stdout of the command line. 2251 """ 2252 cmd = ('mysql -u%s -p%s --host %s %s -e "%s"' % 2253 (user, password, server, database, command)) 2254 # Set verbose to False so the command line won't be logged, as it includes 2255 # database credential. 2256