1*9c5db199SXin Li# Lint as: python2, python3 2*9c5db199SXin Li# Copyright 2017 The Chromium OS Authors. All rights reserved. 3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 4*9c5db199SXin Li# found in the LICENSE file. 5*9c5db199SXin Li 6*9c5db199SXin Li""" 7*9c5db199SXin LiConvenience functions for use by tests or whomever. 8*9c5db199SXin Li""" 9*9c5db199SXin Li 10*9c5db199SXin Li# pylint: disable=missing-docstring 11*9c5db199SXin Li 12*9c5db199SXin Lifrom __future__ import absolute_import 13*9c5db199SXin Lifrom __future__ import division 14*9c5db199SXin Lifrom __future__ import print_function 15*9c5db199SXin Li 16*9c5db199SXin Liimport base64 17*9c5db199SXin Liimport chardet 18*9c5db199SXin Liimport collections 19*9c5db199SXin Liimport errno 20*9c5db199SXin Liimport glob 21*9c5db199SXin Liimport json 22*9c5db199SXin Liimport logging 23*9c5db199SXin Liimport math 24*9c5db199SXin Liimport multiprocessing 25*9c5db199SXin Liimport os 26*9c5db199SXin Liimport platform 27*9c5db199SXin Liimport re 28*9c5db199SXin Liimport shutil 29*9c5db199SXin Liimport signal 30*9c5db199SXin Liimport string 31*9c5db199SXin Liimport subprocess 32*9c5db199SXin Liimport sys 33*9c5db199SXin Liimport tempfile 34*9c5db199SXin Liimport time 35*9c5db199SXin Liimport uuid 36*9c5db199SXin Li 37*9c5db199SXin Lifrom autotest_lib.client.common_lib import error 38*9c5db199SXin Lifrom autotest_lib.client.common_lib import magic 39*9c5db199SXin Lifrom autotest_lib.client.common_lib import utils 40*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import cros_config 41*9c5db199SXin Li 42*9c5db199SXin Lifrom autotest_lib.client.common_lib.utils import * 43*9c5db199SXin Liimport six 44*9c5db199SXin Lifrom six.moves import map 45*9c5db199SXin Lifrom six.moves import range 46*9c5db199SXin Lifrom six.moves import zip 47*9c5db199SXin Li 48*9c5db199SXin Li 49*9c5db199SXin Lidef grep(pattern, file): 50*9c5db199SXin Li """ 51*9c5db199SXin Li This is mainly to fix the return code inversion from grep 52*9c5db199SXin Li Also handles compressed files. 53*9c5db199SXin Li 54*9c5db199SXin Li returns 1 if the pattern is present in the file, 0 if not. 55*9c5db199SXin Li """ 56*9c5db199SXin Li command = 'grep "%s" > /dev/null' % pattern 57*9c5db199SXin Li ret = cat_file_to_cmd(file, command, ignore_status=True) 58*9c5db199SXin Li return not ret 59*9c5db199SXin Li 60*9c5db199SXin Li 61*9c5db199SXin Lidef cat_file_to_cmd(file, command, ignore_status=0, return_output=False): 62*9c5db199SXin Li """ 63*9c5db199SXin Li equivalent to 'cat file | command' but knows to use 64*9c5db199SXin Li zcat or bzcat if appropriate 65*9c5db199SXin Li """ 66*9c5db199SXin Li if not os.path.isfile(file): 67*9c5db199SXin Li raise NameError('invalid file %s to cat to command %s' 68*9c5db199SXin Li % (file, command)) 69*9c5db199SXin Li 70*9c5db199SXin Li if return_output: 71*9c5db199SXin Li run_cmd = utils.system_output 72*9c5db199SXin Li else: 73*9c5db199SXin Li run_cmd = utils.system 74*9c5db199SXin Li 75*9c5db199SXin Li if magic.guess_type(file) == 'application/x-bzip2': 76*9c5db199SXin Li cat = 'bzcat' 77*9c5db199SXin Li elif magic.guess_type(file) == 'application/x-gzip': 78*9c5db199SXin Li cat = 'zcat' 79*9c5db199SXin Li else: 80*9c5db199SXin Li cat = 'cat' 81*9c5db199SXin Li return run_cmd('%s %s | %s' % (cat, file, command), 82*9c5db199SXin Li ignore_status=ignore_status) 83*9c5db199SXin Li 84*9c5db199SXin Li 85*9c5db199SXin Lidef extract_tarball_to_dir(tarball, dir): 86*9c5db199SXin Li """ 87*9c5db199SXin Li Extract a tarball to a specified directory name instead of whatever 88*9c5db199SXin Li the top level of a tarball is - useful for versioned directory names, etc 89*9c5db199SXin Li """ 90*9c5db199SXin Li if os.path.exists(dir): 91*9c5db199SXin Li if os.path.isdir(dir): 92*9c5db199SXin Li shutil.rmtree(dir) 93*9c5db199SXin Li else: 94*9c5db199SXin Li os.remove(dir) 95*9c5db199SXin Li pwd = os.getcwd() 96*9c5db199SXin Li os.chdir(os.path.dirname(os.path.abspath(dir))) 97*9c5db199SXin Li newdir = extract_tarball(tarball) 98*9c5db199SXin Li os.rename(newdir, dir) 99*9c5db199SXin Li os.chdir(pwd) 100*9c5db199SXin Li 101*9c5db199SXin Li 102*9c5db199SXin Lidef extract_tarball(tarball): 103*9c5db199SXin Li """Returns the directory extracted by the tarball.""" 104*9c5db199SXin Li extracted = cat_file_to_cmd(tarball, 'tar xvf - 2>/dev/null', 105*9c5db199SXin Li return_output=True).splitlines() 106*9c5db199SXin Li 107*9c5db199SXin Li dir = None 108*9c5db199SXin Li 109*9c5db199SXin Li for line in extracted: 110*9c5db199SXin Li if line.startswith('./'): 111*9c5db199SXin Li line = line[2:] 112*9c5db199SXin Li if not line or line == '.': 113*9c5db199SXin Li continue 114*9c5db199SXin Li topdir = line.split('/')[0] 115*9c5db199SXin Li if os.path.isdir(topdir): 116*9c5db199SXin Li if dir: 117*9c5db199SXin Li assert(dir == topdir), 'tarball must be a a single directory' 118*9c5db199SXin Li else: 119*9c5db199SXin Li dir = topdir 120*9c5db199SXin Li if dir: 121*9c5db199SXin Li return dir 122*9c5db199SXin Li else: 123*9c5db199SXin Li raise NameError('extracting tarball produced no dir') 124*9c5db199SXin Li 125*9c5db199SXin Li 126*9c5db199SXin Lidef force_copy(src, dest): 127*9c5db199SXin Li """Replace dest with a new copy of src, even if it exists""" 128*9c5db199SXin Li if os.path.isfile(dest): 129*9c5db199SXin Li os.remove(dest) 130*9c5db199SXin Li if os.path.isdir(dest): 131*9c5db199SXin Li dest = os.path.join(dest, os.path.basename(src)) 132*9c5db199SXin Li shutil.copyfile(src, dest) 133*9c5db199SXin Li return dest 134*9c5db199SXin Li 135*9c5db199SXin Li 136*9c5db199SXin Lidef file_contains_pattern(file, pattern): 137*9c5db199SXin Li """Return true if file contains the specified egrep pattern""" 138*9c5db199SXin Li if not os.path.isfile(file): 139*9c5db199SXin Li raise NameError('file %s does not exist' % file) 140*9c5db199SXin Li return not utils.system('egrep -q "' + pattern + '" ' + file, 141*9c5db199SXin Li ignore_status=True) 142*9c5db199SXin Li 143*9c5db199SXin Li 144*9c5db199SXin Lidef list_grep(list, pattern): 145*9c5db199SXin Li """True if any item in list matches the specified pattern.""" 146*9c5db199SXin Li compiled = re.compile(pattern) 147*9c5db199SXin Li for line in list: 148*9c5db199SXin Li match = compiled.search(line) 149*9c5db199SXin Li if (match): 150*9c5db199SXin Li return 1 151*9c5db199SXin Li return 0 152*9c5db199SXin Li 153*9c5db199SXin Li 154*9c5db199SXin Lidef get_os_vendor(): 155*9c5db199SXin Li """Try to guess what's the os vendor 156*9c5db199SXin Li """ 157*9c5db199SXin Li if os.path.isfile('/etc/SuSE-release'): 158*9c5db199SXin Li return 'SUSE' 159*9c5db199SXin Li 160*9c5db199SXin Li issue = '/etc/issue' 161*9c5db199SXin Li 162*9c5db199SXin Li if not os.path.isfile(issue): 163*9c5db199SXin Li return 'Unknown' 164*9c5db199SXin Li 165*9c5db199SXin Li if file_contains_pattern(issue, 'Red Hat'): 166*9c5db199SXin Li return 'Red Hat' 167*9c5db199SXin Li elif file_contains_pattern(issue, 'Fedora'): 168*9c5db199SXin Li return 'Fedora Core' 169*9c5db199SXin Li elif file_contains_pattern(issue, 'SUSE'): 170*9c5db199SXin Li return 'SUSE' 171*9c5db199SXin Li elif file_contains_pattern(issue, 'Ubuntu'): 172*9c5db199SXin Li return 'Ubuntu' 173*9c5db199SXin Li elif file_contains_pattern(issue, 'Debian'): 174*9c5db199SXin Li return 'Debian' 175*9c5db199SXin Li else: 176*9c5db199SXin Li return 'Unknown' 177*9c5db199SXin Li 178*9c5db199SXin Li 179*9c5db199SXin Lidef get_cc(): 180*9c5db199SXin Li try: 181*9c5db199SXin Li return os.environ['CC'] 182*9c5db199SXin Li except KeyError: 183*9c5db199SXin Li return 'gcc' 184*9c5db199SXin Li 185*9c5db199SXin Li 186*9c5db199SXin Lidef get_vmlinux(): 187*9c5db199SXin Li """Return the full path to vmlinux 188*9c5db199SXin Li 189*9c5db199SXin Li Ahem. This is crap. Pray harder. Bad Martin. 190*9c5db199SXin Li """ 191*9c5db199SXin Li vmlinux = '/boot/vmlinux-%s' % utils.system_output('uname -r') 192*9c5db199SXin Li if os.path.isfile(vmlinux): 193*9c5db199SXin Li return vmlinux 194*9c5db199SXin Li vmlinux = '/lib/modules/%s/build/vmlinux' % utils.system_output('uname -r') 195*9c5db199SXin Li if os.path.isfile(vmlinux): 196*9c5db199SXin Li return vmlinux 197*9c5db199SXin Li return None 198*9c5db199SXin Li 199*9c5db199SXin Li 200*9c5db199SXin Lidef get_systemmap(): 201*9c5db199SXin Li """Return the full path to System.map 202*9c5db199SXin Li 203*9c5db199SXin Li Ahem. This is crap. Pray harder. Bad Martin. 204*9c5db199SXin Li """ 205*9c5db199SXin Li map = '/boot/System.map-%s' % utils.system_output('uname -r') 206*9c5db199SXin Li if os.path.isfile(map): 207*9c5db199SXin Li return map 208*9c5db199SXin Li map = '/lib/modules/%s/build/System.map' % utils.system_output('uname -r') 209*9c5db199SXin Li if os.path.isfile(map): 210*9c5db199SXin Li return map 211*9c5db199SXin Li return None 212*9c5db199SXin Li 213*9c5db199SXin Li 214*9c5db199SXin Lidef get_modules_dir(): 215*9c5db199SXin Li """Return the modules dir for the running kernel version""" 216*9c5db199SXin Li kernel_version = utils.system_output('uname -r') 217*9c5db199SXin Li return '/lib/modules/%s/kernel' % kernel_version 218*9c5db199SXin Li 219*9c5db199SXin Li 220*9c5db199SXin Li_CPUINFO_RE = re.compile(r'^(?P<key>[^\t]*)\t*: ?(?P<value>.*)$') 221*9c5db199SXin Li 222*9c5db199SXin Li 223*9c5db199SXin Lidef get_cpuinfo(): 224*9c5db199SXin Li """Read /proc/cpuinfo and convert to a list of dicts.""" 225*9c5db199SXin Li cpuinfo = [] 226*9c5db199SXin Li with open('/proc/cpuinfo', 'r') as f: 227*9c5db199SXin Li cpu = {} 228*9c5db199SXin Li for line in f: 229*9c5db199SXin Li line = line.strip() 230*9c5db199SXin Li if not line: 231*9c5db199SXin Li cpuinfo.append(cpu) 232*9c5db199SXin Li cpu = {} 233*9c5db199SXin Li continue 234*9c5db199SXin Li match = _CPUINFO_RE.match(line) 235*9c5db199SXin Li cpu[match.group('key')] = match.group('value') 236*9c5db199SXin Li if cpu: 237*9c5db199SXin Li # cpuinfo usually ends in a blank line, so this shouldn't happen. 238*9c5db199SXin Li cpuinfo.append(cpu) 239*9c5db199SXin Li return cpuinfo 240*9c5db199SXin Li 241*9c5db199SXin Li 242*9c5db199SXin Lidef get_cpu_arch(): 243*9c5db199SXin Li """Work out which CPU architecture we're running on""" 244*9c5db199SXin Li 245*9c5db199SXin Li # Using 'uname -m' should be a very portable way to do this since the 246*9c5db199SXin Li # format is pretty standard. 247*9c5db199SXin Li machine_name = utils.system_output('uname -m').strip() 248*9c5db199SXin Li 249*9c5db199SXin Li # Apparently ARM64 and ARM have both historically returned the string 'arm' 250*9c5db199SXin Li # here so continue the tradition. Use startswith() because: 251*9c5db199SXin Li # - On most of our arm devices we'll actually see the string armv7l. 252*9c5db199SXin Li # - In theory the machine name could include a suffix for endianness. 253*9c5db199SXin Li if machine_name.startswith('aarch64') or machine_name.startswith('arm'): 254*9c5db199SXin Li return 'arm' 255*9c5db199SXin Li 256*9c5db199SXin Li # Historically we _have_ treated x86_64 and i386 separately. 257*9c5db199SXin Li if machine_name in ('x86_64', 'i386'): 258*9c5db199SXin Li return machine_name 259*9c5db199SXin Li 260*9c5db199SXin Li raise error.TestError('unsupported machine type %s' % machine_name) 261*9c5db199SXin Li 262*9c5db199SXin Li 263*9c5db199SXin Lidef get_arm_soc_family_from_devicetree(): 264*9c5db199SXin Li """ 265*9c5db199SXin Li Work out which ARM SoC we're running on based on the 'compatible' property 266*9c5db199SXin Li of the base node of devicetree, if it exists. 267*9c5db199SXin Li """ 268*9c5db199SXin Li devicetree_compatible = '/sys/firmware/devicetree/base/compatible' 269*9c5db199SXin Li if not os.path.isfile(devicetree_compatible): 270*9c5db199SXin Li return None 271*9c5db199SXin Li f = open(devicetree_compatible, 'r') 272*9c5db199SXin Li compatible = f.read().split(chr(0)) 273*9c5db199SXin Li f.close() 274*9c5db199SXin Li if list_grep(compatible, '^rockchip,'): 275*9c5db199SXin Li return 'rockchip' 276*9c5db199SXin Li elif list_grep(compatible, '^mediatek,'): 277*9c5db199SXin Li return 'mediatek' 278*9c5db199SXin Li elif list_grep(compatible, '^qcom,'): 279*9c5db199SXin Li return 'qualcomm' 280*9c5db199SXin Li return None 281*9c5db199SXin Li 282*9c5db199SXin Li 283*9c5db199SXin Lidef get_arm_soc_family(): 284*9c5db199SXin Li """Work out which ARM SoC we're running on""" 285*9c5db199SXin Li family = get_arm_soc_family_from_devicetree() 286*9c5db199SXin Li if family is not None: 287*9c5db199SXin Li return family 288*9c5db199SXin Li 289*9c5db199SXin Li f = open('/proc/cpuinfo', 'r') 290*9c5db199SXin Li cpuinfo = f.readlines() 291*9c5db199SXin Li f.close() 292*9c5db199SXin Li if list_grep(cpuinfo, 'EXYNOS5'): 293*9c5db199SXin Li return 'exynos5' 294*9c5db199SXin Li elif list_grep(cpuinfo, 'Tegra'): 295*9c5db199SXin Li return 'tegra' 296*9c5db199SXin Li elif list_grep(cpuinfo, 'Rockchip'): 297*9c5db199SXin Li return 'rockchip' 298*9c5db199SXin Li return 'arm' 299*9c5db199SXin Li 300*9c5db199SXin Li 301*9c5db199SXin Lidef get_cpu_soc_family(): 302*9c5db199SXin Li """Like get_cpu_arch, but for ARM, returns the SoC family name""" 303*9c5db199SXin Li f = open('/proc/cpuinfo', 'r') 304*9c5db199SXin Li cpuinfo = f.readlines() 305*9c5db199SXin Li f.close() 306*9c5db199SXin Li family = get_cpu_arch() 307*9c5db199SXin Li if family == 'arm': 308*9c5db199SXin Li family = get_arm_soc_family() 309*9c5db199SXin Li if list_grep(cpuinfo, '^vendor_id.*:.*AMD'): 310*9c5db199SXin Li family = 'amd' 311*9c5db199SXin Li return family 312*9c5db199SXin Li 313*9c5db199SXin Li 314*9c5db199SXin Li# When adding entries here, also add them at the right spot in the 315*9c5db199SXin Li# INTEL_*_ORDER lists below. 316*9c5db199SXin LiINTEL_UARCH_TABLE = { 317*9c5db199SXin Li '06_9A': 'Alder Lake', 318*9c5db199SXin Li '06_4C': 'Airmont', 319*9c5db199SXin Li '06_1C': 'Atom', 320*9c5db199SXin Li '06_26': 'Atom', 321*9c5db199SXin Li '06_27': 'Atom', 322*9c5db199SXin Li '06_35': 'Atom', 323*9c5db199SXin Li '06_36': 'Atom', 324*9c5db199SXin Li '06_3D': 'Broadwell', 325*9c5db199SXin Li '06_47': 'Broadwell', 326*9c5db199SXin Li '06_4F': 'Broadwell', 327*9c5db199SXin Li '06_56': 'Broadwell', 328*9c5db199SXin Li '06_A5': 'Comet Lake', 329*9c5db199SXin Li '06_A6': 'Comet Lake', 330*9c5db199SXin Li '06_0D': 'Dothan', 331*9c5db199SXin Li '06_5C': 'Goldmont', 332*9c5db199SXin Li '06_7A': 'Goldmont', 333*9c5db199SXin Li '06_3C': 'Haswell', 334*9c5db199SXin Li '06_45': 'Haswell', 335*9c5db199SXin Li '06_46': 'Haswell', 336*9c5db199SXin Li '06_3F': 'Haswell-E', 337*9c5db199SXin Li '06_7D': 'Ice Lake', 338*9c5db199SXin Li '06_7E': 'Ice Lake', 339*9c5db199SXin Li '06_3A': 'Ivy Bridge', 340*9c5db199SXin Li '06_3E': 'Ivy Bridge-E', 341*9c5db199SXin Li '06_8E': 'Kaby Lake', 342*9c5db199SXin Li '06_9E': 'Kaby Lake', 343*9c5db199SXin Li '06_0F': 'Merom', 344*9c5db199SXin Li '06_16': 'Merom', 345*9c5db199SXin Li '06_17': 'Nehalem', 346*9c5db199SXin Li '06_1A': 'Nehalem', 347*9c5db199SXin Li '06_1D': 'Nehalem', 348*9c5db199SXin Li '06_1E': 'Nehalem', 349*9c5db199SXin Li '06_1F': 'Nehalem', 350*9c5db199SXin Li '06_2E': 'Nehalem', 351*9c5db199SXin Li '0F_03': 'Prescott', 352*9c5db199SXin Li '0F_04': 'Prescott', 353*9c5db199SXin Li '0F_06': 'Presler', 354*9c5db199SXin Li '06_2A': 'Sandy Bridge', 355*9c5db199SXin Li '06_2D': 'Sandy Bridge', 356*9c5db199SXin Li '06_37': 'Silvermont', 357*9c5db199SXin Li '06_4A': 'Silvermont', 358*9c5db199SXin Li '06_4D': 'Silvermont', 359*9c5db199SXin Li '06_5A': 'Silvermont', 360*9c5db199SXin Li '06_5D': 'Silvermont', 361*9c5db199SXin Li '06_4E': 'Skylake', 362*9c5db199SXin Li '06_5E': 'Skylake', 363*9c5db199SXin Li '06_55': 'Skylake', 364*9c5db199SXin Li '06_8C': 'Tiger Lake', 365*9c5db199SXin Li '06_8D': 'Tiger Lake', 366*9c5db199SXin Li '06_86': 'Tremont', 367*9c5db199SXin Li '06_96': 'Tremont', 368*9c5db199SXin Li '06_9C': 'Tremont', 369*9c5db199SXin Li '06_25': 'Westmere', 370*9c5db199SXin Li '06_2C': 'Westmere', 371*9c5db199SXin Li '06_2F': 'Westmere', 372*9c5db199SXin Li} 373*9c5db199SXin Li 374*9c5db199SXin LiINTEL_ATOM_ORDER = ['Silvermont', 'Airmont', 'Goldmont', 'Tremont', 'Gracemont'] 375*9c5db199SXin Li 376*9c5db199SXin LiINTEL_BIGCORE_ORDER = [ 377*9c5db199SXin Li 'Prescott', 'Presler', 'Dothan', 'Merom', 'Nehalem', 'Westmere', 378*9c5db199SXin Li 'Sandy Bridge', 'Ivy Bridge', 'Ivy Bridge-E', 'Haswell', 'Haswell-E', 379*9c5db199SXin Li 'Broadwell', 'Skylake', 'Kaby Lake', 'Coffee Lake', 'Whiskey Lake', 380*9c5db199SXin Li 'Cannon Lake', 'Comet Lake', 'Ice Lake', 'Tiger Lake', 'Alder Lake' 381*9c5db199SXin Li] 382*9c5db199SXin Li 383*9c5db199SXin Li 384*9c5db199SXin Lidef get_intel_cpu_uarch(numeric=False): 385*9c5db199SXin Li """Return the Intel microarchitecture we're running on, or None. 386*9c5db199SXin Li 387*9c5db199SXin Li Returns None if this is not an Intel CPU. Returns the family and model as 388*9c5db199SXin Li underscore-separated hex (per Intel manual convention) if the uarch is not 389*9c5db199SXin Li known, or if numeric is True. 390*9c5db199SXin Li """ 391*9c5db199SXin Li if not get_current_kernel_arch().startswith('x86'): 392*9c5db199SXin Li return None 393*9c5db199SXin Li cpuinfo = get_cpuinfo()[0] 394*9c5db199SXin Li if cpuinfo['vendor_id'] != 'GenuineIntel': 395*9c5db199SXin Li return None 396*9c5db199SXin Li family_model = '%02X_%02X' % (int(cpuinfo['cpu family']), 397*9c5db199SXin Li int(cpuinfo['model'])) 398*9c5db199SXin Li if numeric: 399*9c5db199SXin Li return family_model 400*9c5db199SXin Li return INTEL_UARCH_TABLE.get(family_model, family_model) 401*9c5db199SXin Li 402*9c5db199SXin Li 403*9c5db199SXin Lidef is_intel_uarch_older_than(reference): 404*9c5db199SXin Li """Returns True if the DUT's is older than reference, False otherwise. 405*9c5db199SXin Li 406*9c5db199SXin Li Raises a test error exception if the uarch is unknown to make developers 407*9c5db199SXin Li add entries to the tables above. 408*9c5db199SXin Li """ 409*9c5db199SXin Li 410*9c5db199SXin Li uarch = get_intel_cpu_uarch() 411*9c5db199SXin Li if uarch is None: 412*9c5db199SXin Li raise error.TestError("Doing Intel test for non-Intel hardware.") 413*9c5db199SXin Li 414*9c5db199SXin Li if "_" in uarch: 415*9c5db199SXin Li raise error.TestError("Intel uarch unknown. Add to tables.") 416*9c5db199SXin Li 417*9c5db199SXin Li if reference not in INTEL_BIGCORE_ORDER and reference not in INTEL_ATOM_ORDER: 418*9c5db199SXin Li raise error.TestError("Testing for unknown reference Intel uarch.") 419*9c5db199SXin Li 420*9c5db199SXin Li result = False 421*9c5db199SXin Li 422*9c5db199SXin Li if reference in INTEL_BIGCORE_ORDER: 423*9c5db199SXin Li for v in INTEL_BIGCORE_ORDER: 424*9c5db199SXin Li if v == reference: 425*9c5db199SXin Li break 426*9c5db199SXin Li if v == uarch: 427*9c5db199SXin Li result = True 428*9c5db199SXin Li 429*9c5db199SXin Li elif reference in INTEL_ATOM_ORDER: 430*9c5db199SXin Li for v in INTEL_ATOM_ORDER: 431*9c5db199SXin Li if v == reference: 432*9c5db199SXin Li break 433*9c5db199SXin Li if v == uarch: 434*9c5db199SXin Li result = True 435*9c5db199SXin Li 436*9c5db199SXin Li return result 437*9c5db199SXin Li 438*9c5db199SXin Li 439*9c5db199SXin LiINTEL_SILVERMONT_BCLK_TABLE = [83333, 100000, 133333, 116667, 80000] 440*9c5db199SXin Li 441*9c5db199SXin Li 442*9c5db199SXin Lidef get_intel_bclk_khz(): 443*9c5db199SXin Li """Return Intel CPU base clock. 444*9c5db199SXin Li 445*9c5db199SXin Li This only worked with SandyBridge (released in 2011) or newer. Older CPU has 446*9c5db199SXin Li 133 MHz bclk. See turbostat code for implementation that also works with 447*9c5db199SXin Li older CPU. https://git.io/vpyKT 448*9c5db199SXin Li """ 449*9c5db199SXin Li if get_intel_cpu_uarch() == 'Silvermont': 450*9c5db199SXin Li MSR_FSB_FREQ = 0xcd 451*9c5db199SXin Li return INTEL_SILVERMONT_BCLK_TABLE[utils.rdmsr(MSR_FSB_FREQ) & 0xf] 452*9c5db199SXin Li return 100000 453*9c5db199SXin Li 454*9c5db199SXin Li 455*9c5db199SXin Lidef get_energy_usage(): 456*9c5db199SXin Li """On Intel chips that support it, return the energy usage.""" 457*9c5db199SXin Li if get_intel_cpu_uarch() == None: 458*9c5db199SXin Li return 0 459*9c5db199SXin Li 460*9c5db199SXin Li with open('/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj') as fd: 461*9c5db199SXin Li return fd.readline() 462*9c5db199SXin Li 463*9c5db199SXin Li 464*9c5db199SXin Lidef get_current_kernel_arch(): 465*9c5db199SXin Li """Get the machine architecture, now just a wrap of 'uname -m'.""" 466*9c5db199SXin Li return os.popen('uname -m').read().rstrip() 467*9c5db199SXin Li 468*9c5db199SXin Li 469*9c5db199SXin Lidef count_cpus(): 470*9c5db199SXin Li """number of CPUs in the local machine according to /proc/cpuinfo""" 471*9c5db199SXin Li try: 472*9c5db199SXin Li return multiprocessing.cpu_count() 473*9c5db199SXin Li except Exception: 474*9c5db199SXin Li logging.exception('can not get cpu count from' 475*9c5db199SXin Li ' multiprocessing.cpu_count()') 476*9c5db199SXin Li cpuinfo = get_cpuinfo() 477*9c5db199SXin Li # Returns at least one cpu. Check comment #1 in crosbug.com/p/9582. 478*9c5db199SXin Li return len(cpuinfo) or 1 479*9c5db199SXin Li 480*9c5db199SXin Li 481*9c5db199SXin Lidef cpu_online_map(): 482*9c5db199SXin Li """ 483*9c5db199SXin Li Check out the available cpu online map 484*9c5db199SXin Li """ 485*9c5db199SXin Li cpuinfo = get_cpuinfo() 486*9c5db199SXin Li cpus = [] 487*9c5db199SXin Li for cpu in cpuinfo: 488*9c5db199SXin Li cpus.append(cpu['processor']) # grab cpu number 489*9c5db199SXin Li return cpus 490*9c5db199SXin Li 491*9c5db199SXin Li 492*9c5db199SXin Li# Returns total memory in kb 493*9c5db199SXin Lidef read_from_meminfo(key): 494*9c5db199SXin Li meminfo = utils.system_output('grep %s /proc/meminfo' % key) 495*9c5db199SXin Li return int(re.search(r'\d+', meminfo).group(0)) 496*9c5db199SXin Li 497*9c5db199SXin Li 498*9c5db199SXin Lidef memtotal(): 499*9c5db199SXin Li return read_from_meminfo('MemTotal') 500*9c5db199SXin Li 501*9c5db199SXin Li 502*9c5db199SXin Lidef freememtotal(): 503*9c5db199SXin Li return read_from_meminfo('MemFree') 504*9c5db199SXin Li 505*9c5db199SXin Lidef usable_memtotal(): 506*9c5db199SXin Li # Reserved 5% for OS use 507*9c5db199SXin Li return int(read_from_meminfo('MemFree') * 0.95) 508*9c5db199SXin Li 509*9c5db199SXin Lidef swaptotal(): 510*9c5db199SXin Li return read_from_meminfo('SwapTotal') 511*9c5db199SXin Li 512*9c5db199SXin Lidef rounded_memtotal(): 513*9c5db199SXin Li # Get total of all physical mem, in kbytes 514*9c5db199SXin Li usable_kbytes = memtotal() 515*9c5db199SXin Li # usable_kbytes is system's usable DRAM in kbytes, 516*9c5db199SXin Li # as reported by memtotal() from device /proc/meminfo memtotal 517*9c5db199SXin Li # after Linux deducts 1.5% to 5.1% for system table overhead 518*9c5db199SXin Li # Undo the unknown actual deduction by rounding up 519*9c5db199SXin Li # to next small multiple of a big power-of-two 520*9c5db199SXin Li # eg 12GB - 5.1% gets rounded back up to 12GB 521*9c5db199SXin Li mindeduct = 0.015 # 1.5 percent 522*9c5db199SXin Li maxdeduct = 0.055 # 5.5 percent 523*9c5db199SXin Li # deduction range 1.5% .. 5.5% supports physical mem sizes 524*9c5db199SXin Li # 6GB .. 12GB in steps of .5GB 525*9c5db199SXin Li # 12GB .. 24GB in steps of 1 GB 526*9c5db199SXin Li # 24GB .. 48GB in steps of 2 GB ... 527*9c5db199SXin Li # Finer granularity in physical mem sizes would require 528*9c5db199SXin Li # tighter spread between min and max possible deductions 529*9c5db199SXin Li 530*9c5db199SXin Li # increase mem size by at least min deduction, without rounding 531*9c5db199SXin Li min_kbytes = int(usable_kbytes / (1.0 - mindeduct)) 532*9c5db199SXin Li # increase mem size further by 2**n rounding, by 0..roundKb or more 533*9c5db199SXin Li round_kbytes = int(usable_kbytes / (1.0 - maxdeduct)) - min_kbytes 534*9c5db199SXin Li # find least binary roundup 2**n that covers worst-cast roundKb 535*9c5db199SXin Li mod2n = 1 << int(math.ceil(math.log(round_kbytes, 2))) 536*9c5db199SXin Li # have round_kbytes <= mod2n < round_kbytes*2 537*9c5db199SXin Li # round min_kbytes up to next multiple of mod2n 538*9c5db199SXin Li phys_kbytes = min_kbytes + mod2n - 1 539*9c5db199SXin Li phys_kbytes = phys_kbytes - (phys_kbytes % mod2n) # clear low bits 540*9c5db199SXin Li return phys_kbytes 541*9c5db199SXin Li 542*9c5db199SXin Li 543*9c5db199SXin Li_MEMINFO_RE = re.compile('^(\w+)(\(\w+\))?:\s+(\d+)') 544*9c5db199SXin Li 545*9c5db199SXin Li 546*9c5db199SXin Lidef get_meminfo(): 547*9c5db199SXin Li """Returns a namedtuple of pairs from /proc/meminfo. 548*9c5db199SXin Li 549*9c5db199SXin Li Example /proc/meminfo snippets: 550*9c5db199SXin Li MemTotal: 2048000 kB 551*9c5db199SXin Li Active(anon): 409600 kB 552*9c5db199SXin Li Example usage: 553*9c5db199SXin Li meminfo = utils.get_meminfo() 554*9c5db199SXin Li print meminfo.Active_anon 555*9c5db199SXin Li """ 556*9c5db199SXin Li info = {} 557*9c5db199SXin Li with _open_file('/proc/meminfo') as f: 558*9c5db199SXin Li for line in f: 559*9c5db199SXin Li m = _MEMINFO_RE.match(line) 560*9c5db199SXin Li if m: 561*9c5db199SXin Li if m.group(2): 562*9c5db199SXin Li name = m.group(1) + '_' + m.group(2)[1:-1] 563*9c5db199SXin Li else: 564*9c5db199SXin Li name = m.group(1) 565*9c5db199SXin Li info[name] = int(m.group(3)) 566*9c5db199SXin Li return collections.namedtuple('MemInfo', list(info.keys()))(**info) 567*9c5db199SXin Li 568*9c5db199SXin Li 569*9c5db199SXin Lidef sysctl(key, value=None): 570*9c5db199SXin Li """Generic implementation of sysctl, to read and write. 571*9c5db199SXin Li 572*9c5db199SXin Li @param key: A location under /proc/sys 573*9c5db199SXin Li @param value: If not None, a value to write into the sysctl. 574*9c5db199SXin Li 575*9c5db199SXin Li @return The single-line sysctl value as a string. 576*9c5db199SXin Li """ 577*9c5db199SXin Li path = '/proc/sys/%s' % key 578*9c5db199SXin Li if value is not None: 579*9c5db199SXin Li utils.write_one_line(path, str(value)) 580*9c5db199SXin Li return utils.read_one_line(path) 581*9c5db199SXin Li 582*9c5db199SXin Li 583*9c5db199SXin Lidef sysctl_kernel(key, value=None): 584*9c5db199SXin Li """(Very) partial implementation of sysctl, for kernel params""" 585*9c5db199SXin Li if value is not None: 586*9c5db199SXin Li # write 587*9c5db199SXin Li utils.write_one_line('/proc/sys/kernel/%s' % key, str(value)) 588*9c5db199SXin Li else: 589*9c5db199SXin Li # read 590*9c5db199SXin Li out = utils.read_one_line('/proc/sys/kernel/%s' % key) 591*9c5db199SXin Li return int(re.search(r'\d+', out).group(0)) 592*9c5db199SXin Li 593*9c5db199SXin Li 594*9c5db199SXin Lidef get_num_allocated_file_handles(): 595*9c5db199SXin Li """ 596*9c5db199SXin Li Returns the number of currently allocated file handles. 597*9c5db199SXin Li 598*9c5db199SXin Li Gets this information by parsing /proc/sys/fs/file-nr. 599*9c5db199SXin Li See https://www.kernel.org/doc/Documentation/sysctl/fs.txt 600*9c5db199SXin Li for details on this file. 601*9c5db199SXin Li """ 602*9c5db199SXin Li with _open_file('/proc/sys/fs/file-nr') as f: 603*9c5db199SXin Li line = f.readline() 604*9c5db199SXin Li allocated_handles = int(line.split()[0]) 605*9c5db199SXin Li return allocated_handles 606*9c5db199SXin Li 607*9c5db199SXin Li 608*9c5db199SXin Lidef dump_object(object): 609*9c5db199SXin Li """Dump an object's attributes and methods 610*9c5db199SXin Li 611*9c5db199SXin Li kind of like dir() 612*9c5db199SXin Li """ 613*9c5db199SXin Li for item in six.iteritems(object.__dict__): 614*9c5db199SXin Li print(item) 615*9c5db199SXin Li try: 616*9c5db199SXin Li (key, value) = item 617*9c5db199SXin Li dump_object(value) 618*9c5db199SXin Li except: 619*9c5db199SXin Li continue 620*9c5db199SXin Li 621*9c5db199SXin Li 622*9c5db199SXin Lidef environ(env_key): 623*9c5db199SXin Li """return the requested environment variable, or '' if unset""" 624*9c5db199SXin Li if (env_key in os.environ): 625*9c5db199SXin Li return os.environ[env_key] 626*9c5db199SXin Li else: 627*9c5db199SXin Li return '' 628*9c5db199SXin Li 629*9c5db199SXin Li 630*9c5db199SXin Lidef prepend_path(newpath, oldpath): 631*9c5db199SXin Li """prepend newpath to oldpath""" 632*9c5db199SXin Li if (oldpath): 633*9c5db199SXin Li return newpath + ':' + oldpath 634*9c5db199SXin Li else: 635*9c5db199SXin Li return newpath 636*9c5db199SXin Li 637*9c5db199SXin Li 638*9c5db199SXin Lidef append_path(oldpath, newpath): 639*9c5db199SXin Li """append newpath to oldpath""" 640*9c5db199SXin Li if (oldpath): 641*9c5db199SXin Li return oldpath + ':' + newpath 642*9c5db199SXin Li else: 643*9c5db199SXin Li return newpath 644*9c5db199SXin Li 645*9c5db199SXin Li 646*9c5db199SXin Li_TIME_OUTPUT_RE = re.compile( 647*9c5db199SXin Li r'([\d\.]*)user ([\d\.]*)system ' 648*9c5db199SXin Li r'(\d*):([\d\.]*)elapsed (\d*)%CPU') 649*9c5db199SXin Li 650*9c5db199SXin Li 651*9c5db199SXin Lidef to_seconds(time_string): 652*9c5db199SXin Li """Converts a string in M+:SS.SS format to S+.SS""" 653*9c5db199SXin Li elts = time_string.split(':') 654*9c5db199SXin Li if len(elts) == 1: 655*9c5db199SXin Li return time_string 656*9c5db199SXin Li return str(int(elts[0]) * 60 + float(elts[1])) 657*9c5db199SXin Li 658*9c5db199SXin Li 659*9c5db199SXin Li_TIME_OUTPUT_RE_2 = re.compile(r'(.*?)user (.*?)system (.*?)elapsed') 660*9c5db199SXin Li 661*9c5db199SXin Li 662*9c5db199SXin Lidef running_config(): 663*9c5db199SXin Li """ 664*9c5db199SXin Li Return path of config file of the currently running kernel 665*9c5db199SXin Li """ 666*9c5db199SXin Li version = utils.system_output('uname -r') 667*9c5db199SXin Li for config in ('/proc/config.gz', \ 668*9c5db199SXin Li '/boot/config-%s' % version, 669*9c5db199SXin Li '/lib/modules/%s/build/.config' % version): 670*9c5db199SXin Li if os.path.isfile(config): 671*9c5db199SXin Li return config 672*9c5db199SXin Li return None 673*9c5db199SXin Li 674*9c5db199SXin Li 675*9c5db199SXin Lidef check_for_kernel_feature(feature): 676*9c5db199SXin Li config = running_config() 677*9c5db199SXin Li 678*9c5db199SXin Li if not config: 679*9c5db199SXin Li raise TypeError("Can't find kernel config file") 680*9c5db199SXin Li 681*9c5db199SXin Li if magic.guess_type(config) == 'application/x-gzip': 682*9c5db199SXin Li grep = 'zgrep' 683*9c5db199SXin Li else: 684*9c5db199SXin Li grep = 'grep' 685*9c5db199SXin Li grep += ' ^CONFIG_%s= %s' % (feature, config) 686*9c5db199SXin Li 687*9c5db199SXin Li if not utils.system_output(grep, ignore_status=True): 688*9c5db199SXin Li raise ValueError("Kernel doesn't have a %s feature" % (feature)) 689*9c5db199SXin Li 690*9c5db199SXin Li 691*9c5db199SXin Lidef check_glibc_ver(ver): 692*9c5db199SXin Li try: 693*9c5db199SXin Li glibc_ver = subprocess.check_output("ldd --version", shell=True) 694*9c5db199SXin Li except subprocess.CalledProcessError: 695*9c5db199SXin Li # To mimic previous behavior, if the command errors set the result to 696*9c5db199SXin Li # an empty str 697*9c5db199SXin Li glibc_ver = '' 698*9c5db199SXin Li glibc_ver = glibc_ver.splitlines()[0].decode() 699*9c5db199SXin Li glibc_ver = re.search(r'(\d+\.\d+(\.\d+)?)', glibc_ver).group() 700*9c5db199SXin Li if utils.compare_versions(glibc_ver, ver) == -1: 701*9c5db199SXin Li raise error.TestError("Glibc too old (%s). Glibc >= %s is needed." % 702*9c5db199SXin Li (glibc_ver, ver)) 703*9c5db199SXin Li 704*9c5db199SXin Lidef check_kernel_ver(ver): 705*9c5db199SXin Li kernel_ver = utils.system_output('uname -r') 706*9c5db199SXin Li kv_tmp = re.split(r'[-]', kernel_ver)[0:3] 707*9c5db199SXin Li # In compare_versions, if v1 < v2, return value == -1 708*9c5db199SXin Li if utils.compare_versions(kv_tmp[0], ver) == -1: 709*9c5db199SXin Li raise error.TestError("Kernel too old (%s). Kernel > %s is needed." % 710*9c5db199SXin Li (kernel_ver, ver)) 711*9c5db199SXin Li 712*9c5db199SXin Li 713*9c5db199SXin Lidef numa_nodes(): 714*9c5db199SXin Li node_paths = glob.glob('/sys/devices/system/node/node*') 715*9c5db199SXin Li nodes = [int(re.sub(r'.*node(\d+)', r'\1', x)) for x in node_paths] 716*9c5db199SXin Li return (sorted(nodes)) 717*9c5db199SXin Li 718*9c5db199SXin Li 719*9c5db199SXin Li# Return the kernel version and build timestamp. 720*9c5db199SXin Lidef running_os_release(): 721*9c5db199SXin Li return os.uname()[2:4] 722*9c5db199SXin Li 723*9c5db199SXin Li 724*9c5db199SXin Lidef running_os_ident(): 725*9c5db199SXin Li (version, timestamp) = running_os_release() 726*9c5db199SXin Li return version + '::' + timestamp 727*9c5db199SXin Li 728*9c5db199SXin Li 729*9c5db199SXin Lidef freespace(path): 730*9c5db199SXin Li """Return the disk free space, in bytes""" 731*9c5db199SXin Li s = os.statvfs(path) 732*9c5db199SXin Li return s.f_bavail * s.f_bsize 733*9c5db199SXin Li 734*9c5db199SXin Li 735*9c5db199SXin Li_DISK_PARTITION_3_RE = re.compile(r'^(/dev/hd[a-z]+)3', re.M) 736*9c5db199SXin Li 737*9c5db199SXin Li 738*9c5db199SXin Lidef get_disk_size(disk_name): 739*9c5db199SXin Li """ 740*9c5db199SXin Li Return size of disk in byte. Return 0 in Error Case 741*9c5db199SXin Li 742*9c5db199SXin Li @param disk_name: disk name to find size 743*9c5db199SXin Li """ 744*9c5db199SXin Li device = os.path.basename(disk_name) 745*9c5db199SXin Li with open('/proc/partitions') as f: 746*9c5db199SXin Li lines = f.readlines() 747*9c5db199SXin Li for line in lines: 748*9c5db199SXin Li try: 749*9c5db199SXin Li _, _, blocks, name = re.split(r' +', line.strip()) 750*9c5db199SXin Li except ValueError: 751*9c5db199SXin Li continue 752*9c5db199SXin Li if name == device: 753*9c5db199SXin Li return 1024 * int(blocks) 754*9c5db199SXin Li return 0 755*9c5db199SXin Li 756*9c5db199SXin Li 757*9c5db199SXin Lidef get_disk_size_gb(disk_name): 758*9c5db199SXin Li """ 759*9c5db199SXin Li Return size of disk in GB (10^9). Return 0 in Error Case 760*9c5db199SXin Li 761*9c5db199SXin Li @param disk_name: disk name to find size 762*9c5db199SXin Li """ 763*9c5db199SXin Li return int(get_disk_size(disk_name) / (10.0 ** 9) + 0.5) 764*9c5db199SXin Li 765*9c5db199SXin Li 766*9c5db199SXin Lidef get_disk_model(disk_name): 767*9c5db199SXin Li """ 768*9c5db199SXin Li Return model name for internal storage device 769*9c5db199SXin Li 770*9c5db199SXin Li @param disk_name: disk name to find model 771*9c5db199SXin Li """ 772*9c5db199SXin Li cmd1 = 'udevadm info --query=property --name=%s' % disk_name 773*9c5db199SXin Li cmd2 = 'grep -E "ID_(NAME|MODEL)="' 774*9c5db199SXin Li cmd3 = 'cut -f 2 -d"="' 775*9c5db199SXin Li cmd = ' | '.join([cmd1, cmd2, cmd3]) 776*9c5db199SXin Li return utils.system_output(cmd) 777*9c5db199SXin Li 778*9c5db199SXin Li 779*9c5db199SXin Li_DISK_DEV_RE = re.compile(r'/dev/sd[a-z]|' 780*9c5db199SXin Li r'/dev/mmcblk[0-9]+|' 781*9c5db199SXin Li r'/dev/nvme[0-9]+n[0-9]+') 782*9c5db199SXin Li 783*9c5db199SXin Li 784*9c5db199SXin Lidef get_disk_from_filename(filename): 785*9c5db199SXin Li """ 786*9c5db199SXin Li Return the disk device the filename is on. 787*9c5db199SXin Li If the file is on tmpfs or other special file systems, 788*9c5db199SXin Li return None. 789*9c5db199SXin Li 790*9c5db199SXin Li @param filename: name of file, full path. 791*9c5db199SXin Li """ 792*9c5db199SXin Li 793*9c5db199SXin Li if not os.path.exists(filename): 794*9c5db199SXin Li raise error.TestError('file %s missing' % filename) 795*9c5db199SXin Li 796*9c5db199SXin Li if filename[0] != '/': 797*9c5db199SXin Li raise error.TestError('This code works only with full path') 798*9c5db199SXin Li 799*9c5db199SXin Li m = _DISK_DEV_RE.match(filename) 800*9c5db199SXin Li while not m: 801*9c5db199SXin Li if filename[0] != '/': 802*9c5db199SXin Li return None 803*9c5db199SXin Li if filename == '/dev/root': 804*9c5db199SXin Li cmd = 'rootdev -d -s' 805*9c5db199SXin Li elif filename.startswith('/dev/mapper'): 806*9c5db199SXin Li cmd = 'dmsetup table "%s"' % os.path.basename(filename) 807*9c5db199SXin Li dmsetup_output = utils.system_output(cmd).split(' ') 808*9c5db199SXin Li if dmsetup_output[2] == 'verity': 809*9c5db199SXin Li maj_min = dmsetup_output[4] 810*9c5db199SXin Li elif dmsetup_output[2] == 'crypt': 811*9c5db199SXin Li maj_min = dmsetup_output[6] 812*9c5db199SXin Li elif dmsetup_output[2] in ['thin', 'thin-pool', 'linear']: 813*9c5db199SXin Li maj_min = dmsetup_output[3] 814*9c5db199SXin Li cmd = 'realpath "/dev/block/%s"' % maj_min 815*9c5db199SXin Li elif filename.startswith('/dev/loop'): 816*9c5db199SXin Li cmd = 'losetup -O BACK-FILE "%s" | tail -1' % filename 817*9c5db199SXin Li else: 818*9c5db199SXin Li cmd = 'df "%s" | tail -1 | cut -f 1 -d" "' % filename 819*9c5db199SXin Li filename = utils.system_output(cmd) 820*9c5db199SXin Li m = _DISK_DEV_RE.match(filename) 821*9c5db199SXin Li return m.group(0) 822*9c5db199SXin Li 823*9c5db199SXin Li 824*9c5db199SXin Lidef get_disk_firmware_version(disk_name): 825*9c5db199SXin Li """ 826*9c5db199SXin Li Return firmware version for internal storage device. (empty string for eMMC) 827*9c5db199SXin Li 828*9c5db199SXin Li @param disk_name: disk name to find model 829*9c5db199SXin Li """ 830*9c5db199SXin Li cmd1 = 'udevadm info --query=property --name=%s' % disk_name 831*9c5db199SXin Li cmd2 = 'grep -E "ID_REVISION="' 832*9c5db199SXin Li cmd3 = 'cut -f 2 -d"="' 833*9c5db199SXin Li cmd = ' | '.join([cmd1, cmd2, cmd3]) 834*9c5db199SXin Li return utils.system_output(cmd) 835*9c5db199SXin Li 836*9c5db199SXin Li 837*9c5db199SXin Lidef is_disk_nvme(disk_name): 838*9c5db199SXin Li """ 839*9c5db199SXin Li Return true if disk is a nvme device, return false otherwise 840*9c5db199SXin Li 841*9c5db199SXin Li @param disk_name: disk name to check 842*9c5db199SXin Li """ 843*9c5db199SXin Li return re.match('/dev/nvme[0-9]+n[0-9]+', disk_name) 844*9c5db199SXin Li 845*9c5db199SXin Li 846*9c5db199SXin Lidef is_disk_scsi(disk_name): 847*9c5db199SXin Li """ 848*9c5db199SXin Li Return true if disk is a scsi device, return false otherwise 849*9c5db199SXin Li 850*9c5db199SXin Li @param disk_name: disk name check 851*9c5db199SXin Li """ 852*9c5db199SXin Li return re.match('/dev/sd[a-z]+', disk_name) 853*9c5db199SXin Li 854*9c5db199SXin Li 855*9c5db199SXin Lidef is_disk_harddisk(disk_name): 856*9c5db199SXin Li """ 857*9c5db199SXin Li Return true if disk is a harddisk, return false otherwise 858*9c5db199SXin Li 859*9c5db199SXin Li @param disk_name: disk name check 860*9c5db199SXin Li """ 861*9c5db199SXin Li cmd1 = 'udevadm info --query=property --name=%s' % disk_name 862*9c5db199SXin Li cmd2 = 'grep -E "ID_ATA_ROTATION_RATE_RPM="' 863*9c5db199SXin Li cmd3 = 'cut -f 2 -d"="' 864*9c5db199SXin Li cmd = ' | '.join([cmd1, cmd2, cmd3]) 865*9c5db199SXin Li 866*9c5db199SXin Li rtt = utils.system_output(cmd) 867*9c5db199SXin Li 868*9c5db199SXin Li # eMMC will not have this field; rtt == '' 869*9c5db199SXin Li # SSD will have zero rotation rate; rtt == '0' 870*9c5db199SXin Li # For harddisk rtt > 0 871*9c5db199SXin Li return rtt and int(rtt) > 0 872*9c5db199SXin Li 873*9c5db199SXin Lidef concat_partition(disk_name, partition_number): 874*9c5db199SXin Li """ 875*9c5db199SXin Li Return the name of a partition: 876*9c5db199SXin Li sda, 3 --> sda3 877*9c5db199SXin Li mmcblk0, 3 --> mmcblk0p3 878*9c5db199SXin Li 879*9c5db199SXin Li @param disk_name: diskname string 880*9c5db199SXin Li @param partition_number: integer 881*9c5db199SXin Li """ 882*9c5db199SXin Li if disk_name.endswith(tuple(str(i) for i in range(0, 10))): 883*9c5db199SXin Li sep = 'p' 884*9c5db199SXin Li else: 885*9c5db199SXin Li sep = '' 886*9c5db199SXin Li return disk_name + sep + str(partition_number) 887*9c5db199SXin Li 888*9c5db199SXin Lidef verify_hdparm_feature(disk_name, feature): 889*9c5db199SXin Li """ 890*9c5db199SXin Li Check for feature support for SCSI disk using hdparm 891*9c5db199SXin Li 892*9c5db199SXin Li @param disk_name: target disk 893*9c5db199SXin Li @param feature: hdparm output string of the feature 894*9c5db199SXin Li """ 895*9c5db199SXin Li cmd = 'hdparm -I %s | grep -q "%s"' % (disk_name, feature) 896*9c5db199SXin Li ret = utils.system(cmd, ignore_status=True) 897*9c5db199SXin Li if ret == 0: 898*9c5db199SXin Li return True 899*9c5db199SXin Li elif ret == 1: 900*9c5db199SXin Li return False 901*9c5db199SXin Li else: 902*9c5db199SXin Li raise error.TestFail('Error running command %s' % cmd) 903*9c5db199SXin Li 904*9c5db199SXin Lidef get_nvme_id_ns_feature(disk_name, feature): 905*9c5db199SXin Li """ 906*9c5db199SXin Li Return feature value for NVMe disk using nvme id-ns 907*9c5db199SXin Li 908*9c5db199SXin Li @param disk_name: target disk 909*9c5db199SXin Li @param feature: output string of the feature 910*9c5db199SXin Li """ 911*9c5db199SXin Li cmd = "nvme id-ns -n 1 %s | grep %s" % (disk_name, feature) 912*9c5db199SXin Li feat = utils.system_output(cmd, ignore_status=True) 913*9c5db199SXin Li if not feat: 914*9c5db199SXin Li return 'None' 915*9c5db199SXin Li start = feat.find(':') 916*9c5db199SXin Li value = feat[start+2:] 917*9c5db199SXin Li return value 918*9c5db199SXin Li 919*9c5db199SXin Lidef get_storage_error_msg(disk_name, reason): 920*9c5db199SXin Li """ 921*9c5db199SXin Li Get Error message for storage test which include disk model. 922*9c5db199SXin Li and also include the firmware version for the SCSI disk 923*9c5db199SXin Li 924*9c5db199SXin Li @param disk_name: target disk 925*9c5db199SXin Li @param reason: Reason of the error. 926*9c5db199SXin Li """ 927*9c5db199SXin Li 928*9c5db199SXin Li msg = reason 929*9c5db199SXin Li 930*9c5db199SXin Li model = get_disk_model(disk_name) 931*9c5db199SXin Li msg += ' Disk model: %s' % model 932*9c5db199SXin Li 933*9c5db199SXin Li if is_disk_scsi(disk_name): 934*9c5db199SXin Li fw = get_disk_firmware_version(disk_name) 935*9c5db199SXin Li msg += ' firmware: %s' % fw 936*9c5db199SXin Li 937*9c5db199SXin Li return msg 938*9c5db199SXin Li 939*9c5db199SXin Li 940*9c5db199SXin Li_IOSTAT_FIELDS = ('transfers_per_s', 'read_kb_per_s', 'written_kb_per_s', 941*9c5db199SXin Li 'read_kb', 'written_kb') 942*9c5db199SXin Li_IOSTAT_RE = re.compile('ALL' + len(_IOSTAT_FIELDS) * r'\s+([\d\.]+)') 943*9c5db199SXin Li 944*9c5db199SXin Lidef get_storage_statistics(device=None): 945*9c5db199SXin Li """ 946*9c5db199SXin Li Fetches statistics for a storage device. 947*9c5db199SXin Li 948*9c5db199SXin Li Using iostat(1) it retrieves statistics for a device since last boot. See 949*9c5db199SXin Li the man page for iostat(1) for details on the different fields. 950*9c5db199SXin Li 951*9c5db199SXin Li @param device: Path to a block device. Defaults to the device where root 952*9c5db199SXin Li is mounted. 953*9c5db199SXin Li 954*9c5db199SXin Li @returns a dict mapping each field to its statistic. 955*9c5db199SXin Li 956*9c5db199SXin Li @raises ValueError: If the output from iostat(1) can not be parsed. 957*9c5db199SXin Li """ 958*9c5db199SXin Li if device is None: 959*9c5db199SXin Li device = get_root_device() 960*9c5db199SXin Li cmd = 'iostat -d -k -g ALL -H %s' % device 961*9c5db199SXin Li output = utils.system_output(cmd, ignore_status=True) 962*9c5db199SXin Li match = _IOSTAT_RE.search(output) 963*9c5db199SXin Li if not match: 964*9c5db199SXin Li raise ValueError('Unable to get iostat for %s' % device) 965*9c5db199SXin Li return dict(list(zip(_IOSTAT_FIELDS, list(map(float, match.groups()))))) 966*9c5db199SXin Li 967*9c5db199SXin Li 968*9c5db199SXin Lidef load_module(module_name, params=None): 969*9c5db199SXin Li # Checks if a module has already been loaded 970*9c5db199SXin Li if module_is_loaded(module_name): 971*9c5db199SXin Li return False 972*9c5db199SXin Li 973*9c5db199SXin Li cmd = '/sbin/modprobe ' + module_name 974*9c5db199SXin Li if params: 975*9c5db199SXin Li cmd += ' ' + params 976*9c5db199SXin Li utils.system(cmd) 977*9c5db199SXin Li return True 978*9c5db199SXin Li 979*9c5db199SXin Li 980*9c5db199SXin Lidef unload_module(module_name): 981*9c5db199SXin Li """ 982*9c5db199SXin Li Removes a module. Handles dependencies. If even then it's not possible 983*9c5db199SXin Li to remove one of the modules, it will trhow an error.CmdError exception. 984*9c5db199SXin Li 985*9c5db199SXin Li @param module_name: Name of the module we want to remove. 986*9c5db199SXin Li """ 987*9c5db199SXin Li module_name = module_name.replace('-', '_') 988*9c5db199SXin Li l_raw = utils.system_output("/bin/lsmod").splitlines() 989*9c5db199SXin Li lsmod = [x for x in l_raw if x.split()[0] == module_name] 990*9c5db199SXin Li if len(lsmod) > 0: 991*9c5db199SXin Li line_parts = lsmod[0].split() 992*9c5db199SXin Li if len(line_parts) == 4: 993*9c5db199SXin Li submodules = line_parts[3].split(",") 994*9c5db199SXin Li for submodule in submodules: 995*9c5db199SXin Li unload_module(submodule) 996*9c5db199SXin Li utils.system("/sbin/modprobe -r %s" % module_name) 997*9c5db199SXin Li logging.info("Module %s unloaded", module_name) 998*9c5db199SXin Li else: 999*9c5db199SXin Li logging.info("Module %s is already unloaded", module_name) 1000*9c5db199SXin Li 1001*9c5db199SXin Li 1002*9c5db199SXin Lidef module_is_loaded(module_name): 1003*9c5db199SXin Li module_name = module_name.replace('-', '_') 1004*9c5db199SXin Li modules = utils.system_output('/bin/lsmod').splitlines() 1005*9c5db199SXin Li for module in modules: 1006*9c5db199SXin Li if module.startswith(module_name) and module[len(module_name)] == ' ': 1007*9c5db199SXin Li return True 1008*9c5db199SXin Li return False 1009*9c5db199SXin Li 1010*9c5db199SXin Li 1011*9c5db199SXin Lidef ping_default_gateway(): 1012*9c5db199SXin Li """Ping the default gateway.""" 1013*9c5db199SXin Li 1014*9c5db199SXin Li network = open('/etc/sysconfig/network') 1015*9c5db199SXin Li m = re.search('GATEWAY=(\S+)', network.read()) 1016*9c5db199SXin Li 1017*9c5db199SXin Li if m: 1018*9c5db199SXin Li gw = m.group(1) 1019*9c5db199SXin Li cmd = 'ping %s -c 5 > /dev/null' % gw 1020*9c5db199SXin Li return utils.system(cmd, ignore_status=True) 1021*9c5db199SXin Li 1022*9c5db199SXin Li raise error.TestError('Unable to find default gateway') 1023*9c5db199SXin Li 1024*9c5db199SXin Li 1025*9c5db199SXin Lidef drop_caches(): 1026*9c5db199SXin Li """Writes back all dirty pages to disk and clears all the caches.""" 1027*9c5db199SXin Li utils.system("sync") 1028*9c5db199SXin Li # We ignore failures here as this will fail on 2.6.11 kernels. 1029*9c5db199SXin Li utils.system("echo 3 > /proc/sys/vm/drop_caches", ignore_status=True) 1030*9c5db199SXin Li 1031*9c5db199SXin Li 1032*9c5db199SXin Lidef set_hwclock(time='system', 1033*9c5db199SXin Li utc=True, 1034*9c5db199SXin Li rtc=None, 1035*9c5db199SXin Li noadjfile=False, 1036*9c5db199SXin Li ignore_status=False): 1037*9c5db199SXin Li """Uses the hwclock command to set time of an RTC. 1038*9c5db199SXin Li 1039*9c5db199SXin Li @param time: Either 'system', meaning use the system time, or a string 1040*9c5db199SXin Li to be passed to the --date argument of hwclock. 1041*9c5db199SXin Li @param utc: Boolean of whether to use UTC or localtime. 1042*9c5db199SXin Li @param rtc: String to be passed to the --rtc arg of hwclock. 1043*9c5db199SXin Li @param noadjfile: Boolean of whether to use --noadjfile flag with hwclock. 1044*9c5db199SXin Li @param ignore_status: Boolean of whether to ignore exit code of hwclock. 1045*9c5db199SXin Li """ 1046*9c5db199SXin Li cmd = '/sbin/hwclock' 1047*9c5db199SXin Li if time == 'system': 1048*9c5db199SXin Li cmd += ' --systohc' 1049*9c5db199SXin Li else: 1050*9c5db199SXin Li cmd += ' --set --date "{}"'.format(time) 1051*9c5db199SXin Li if utc: 1052*9c5db199SXin Li cmd += ' --utc' 1053*9c5db199SXin Li else: 1054*9c5db199SXin Li cmd += ' --localtime' 1055*9c5db199SXin Li if rtc is not None: 1056*9c5db199SXin Li cmd += ' --rtc={}'.format(rtc) 1057*9c5db199SXin Li if noadjfile: 1058*9c5db199SXin Li cmd += ' --noadjfile' 1059*9c5db199SXin Li return utils.system(cmd, ignore_status=ignore_status) 1060*9c5db199SXin Li 1061*9c5db199SXin Lidef set_wake_alarm(alarm_time): 1062*9c5db199SXin Li """ 1063*9c5db199SXin Li Set the hardware RTC-based wake alarm to 'alarm_time'. 1064*9c5db199SXin Li """ 1065*9c5db199SXin Li utils.write_one_line('/sys/class/rtc/rtc0/wakealarm', str(alarm_time)) 1066*9c5db199SXin Li 1067*9c5db199SXin Li 1068*9c5db199SXin Li_AUTOTEST_CLIENT_PATH = os.path.join(os.path.dirname(__file__), '..') 1069*9c5db199SXin Li_AMD_PCI_IDS_FILE_PATH = os.path.join(_AUTOTEST_CLIENT_PATH, 1070*9c5db199SXin Li 'bin/amd_pci_ids.json') 1071*9c5db199SXin Li_INTEL_PCI_IDS_FILE_PATH = os.path.join(_AUTOTEST_CLIENT_PATH, 1072*9c5db199SXin Li 'bin/intel_pci_ids.json') 1073*9c5db199SXin Li_UI_USE_FLAGS_FILE_PATH = '/etc/ui_use_flags.txt' 1074*9c5db199SXin Li 1075*9c5db199SXin Li# Command to check if a package is installed. If the package is not installed 1076*9c5db199SXin Li# the command shall fail. 1077*9c5db199SXin Li_CHECK_PACKAGE_INSTALLED_COMMAND =( 1078*9c5db199SXin Li "dpkg-query -W -f='${Status}\n' %s | head -n1 | awk '{print $3;}' | " 1079*9c5db199SXin Li "grep -q '^installed$'") 1080*9c5db199SXin Li 1081*9c5db199SXin Lipciid_to_amd_architecture = {} 1082*9c5db199SXin Lipciid_to_intel_architecture = {} 1083*9c5db199SXin Li 1084*9c5db199SXin Liclass Crossystem(object): 1085*9c5db199SXin Li """A wrapper for the crossystem utility.""" 1086*9c5db199SXin Li 1087*9c5db199SXin Li def __init__(self, client): 1088*9c5db199SXin Li self.cros_system_data = {} 1089*9c5db199SXin Li self._client = client 1090*9c5db199SXin Li 1091*9c5db199SXin Li def init(self): 1092*9c5db199SXin Li self.cros_system_data = {} 1093*9c5db199SXin Li (_, fname) = tempfile.mkstemp() 1094*9c5db199SXin Li f = open(fname, 'w') 1095*9c5db199SXin Li self._client.run('crossystem', stdout_tee=f) 1096*9c5db199SXin Li f.close() 1097*9c5db199SXin Li text = utils.read_file(fname) 1098*9c5db199SXin Li for line in text.splitlines(): 1099*9c5db199SXin Li assignment_string = line.split('#')[0] 1100*9c5db199SXin Li if not assignment_string.count('='): 1101*9c5db199SXin Li continue 1102*9c5db199SXin Li (name, value) = assignment_string.split('=', 1) 1103*9c5db199SXin Li self.cros_system_data[name.strip()] = value.strip() 1104*9c5db199SXin Li os.remove(fname) 1105*9c5db199SXin Li 1106*9c5db199SXin Li def __getattr__(self, name): 1107*9c5db199SXin Li """ 1108*9c5db199SXin Li Retrieve a crosssystem attribute. 1109*9c5db199SXin Li 1110*9c5db199SXin Li The call crossystemobject.name() will return the crossystem reported 1111*9c5db199SXin Li string. 1112*9c5db199SXin Li """ 1113*9c5db199SXin Li return lambda: self.cros_system_data[name] 1114*9c5db199SXin Li 1115*9c5db199SXin Li 1116*9c5db199SXin Lidef get_oldest_pid_by_name(name): 1117*9c5db199SXin Li """ 1118*9c5db199SXin Li Return the oldest pid of a process whose name perfectly matches |name|. 1119*9c5db199SXin Li 1120*9c5db199SXin Li name is an egrep expression, which will be matched against the entire name 1121*9c5db199SXin Li of processes on the system. For example: 1122*9c5db199SXin Li 1123*9c5db199SXin Li get_oldest_pid_by_name('chrome') 1124*9c5db199SXin Li 1125*9c5db199SXin Li on a system running 1126*9c5db199SXin Li 8600 ? 00:00:04 chrome 1127*9c5db199SXin Li 8601 ? 00:00:00 chrome 1128*9c5db199SXin Li 8602 ? 00:00:00 chrome-sandbox 1129*9c5db199SXin Li 1130*9c5db199SXin Li would return 8600, as that's the oldest process that matches. 1131*9c5db199SXin Li chrome-sandbox would not be matched. 1132*9c5db199SXin Li 1133*9c5db199SXin Li Arguments: 1134*9c5db199SXin Li name: egrep expression to match. Will be anchored at the beginning and 1135*9c5db199SXin Li end of the match string. 1136*9c5db199SXin Li 1137*9c5db199SXin Li Returns: 1138*9c5db199SXin Li pid as an integer, or None if one cannot be found. 1139*9c5db199SXin Li 1140*9c5db199SXin Li Raises: 1141*9c5db199SXin Li ValueError if pgrep returns something odd. 1142*9c5db199SXin Li """ 1143*9c5db199SXin Li str_pid = utils.system_output('pgrep -o ^%s$' % name, 1144*9c5db199SXin Li ignore_status=True).rstrip() 1145*9c5db199SXin Li if str_pid: 1146*9c5db199SXin Li return int(str_pid) 1147*9c5db199SXin Li 1148*9c5db199SXin Li 1149*9c5db199SXin Lidef get_oldest_by_name(name): 1150*9c5db199SXin Li """Return pid and command line of oldest process whose name matches |name|. 1151*9c5db199SXin Li 1152*9c5db199SXin Li @param name: egrep expression to match desired process name. 1153*9c5db199SXin Li @return: A tuple of (pid, command_line) of the oldest process whose name 1154*9c5db199SXin Li matches |name|. 1155*9c5db199SXin Li 1156*9c5db199SXin Li """ 1157*9c5db199SXin Li pid = get_oldest_pid_by_name(name) 1158*9c5db199SXin Li if pid: 1159*9c5db199SXin Li command_line = utils.system_output('ps -p %i -o command=' % pid, 1160*9c5db199SXin Li ignore_status=True).rstrip() 1161*9c5db199SXin Li return (pid, command_line) 1162*9c5db199SXin Li 1163*9c5db199SXin Li 1164*9c5db199SXin Lidef get_chrome_remote_debugging_port(): 1165*9c5db199SXin Li """Returns remote debugging port for Chrome. 1166*9c5db199SXin Li 1167*9c5db199SXin Li Parse chrome process's command line argument to get the remote debugging 1168*9c5db199SXin Li port. if it is 0, look at DevToolsActivePort for the ephemeral port. 1169*9c5db199SXin Li """ 1170*9c5db199SXin Li _, command = get_oldest_by_name('chrome') 1171*9c5db199SXin Li matches = re.search('--remote-debugging-port=([0-9]+)', command) 1172*9c5db199SXin Li if not matches: 1173*9c5db199SXin Li return 0 1174*9c5db199SXin Li port = int(matches.group(1)) 1175*9c5db199SXin Li if port: 1176*9c5db199SXin Li return port 1177*9c5db199SXin Li with open('/home/chronos/DevToolsActivePort') as f: 1178*9c5db199SXin Li return int(f.readline().rstrip()) 1179*9c5db199SXin Li 1180*9c5db199SXin Li 1181*9c5db199SXin Lidef get_process_list(name, command_line=None): 1182*9c5db199SXin Li """ 1183*9c5db199SXin Li Return the list of pid for matching process |name command_line|. 1184*9c5db199SXin Li 1185*9c5db199SXin Li on a system running 1186*9c5db199SXin Li 31475 ? 0:06 /opt/google/chrome/chrome --allow-webui-compositing - 1187*9c5db199SXin Li 31478 ? 0:00 /opt/google/chrome/chrome-sandbox /opt/google/chrome/ 1188*9c5db199SXin Li 31485 ? 0:00 /opt/google/chrome/chrome --type=zygote --log-level=1 1189*9c5db199SXin Li 31532 ? 1:05 /opt/google/chrome/chrome --type=renderer 1190*9c5db199SXin Li 1191*9c5db199SXin Li get_process_list('chrome') 1192*9c5db199SXin Li would return ['31475', '31485', '31532'] 1193*9c5db199SXin Li 1194*9c5db199SXin Li get_process_list('chrome', '--type=renderer') 1195*9c5db199SXin Li would return ['31532'] 1196*9c5db199SXin Li 1197*9c5db199SXin Li Arguments: 1198*9c5db199SXin Li name: process name to search for. If command_line is provided, name is 1199*9c5db199SXin Li matched against full command line. If command_line is not provided, 1200*9c5db199SXin Li name is only matched against the process name. 1201*9c5db199SXin Li command line: when command line is passed, the full process command line 1202*9c5db199SXin Li is used for matching. 1203*9c5db199SXin Li 1204*9c5db199SXin Li Returns: 1205*9c5db199SXin Li list of PIDs of the matching processes. 1206*9c5db199SXin Li 1207*9c5db199SXin Li """ 1208*9c5db199SXin Li # TODO(rohitbm) crbug.com/268861 1209*9c5db199SXin Li flag = '-x' if not command_line else '-f' 1210*9c5db199SXin Li name = '\'%s.*%s\'' % (name, command_line) if command_line else name 1211*9c5db199SXin Li str_pid = utils.system_output('pgrep %s %s' % (flag, name), 1212*9c5db199SXin Li ignore_status=True).rstrip() 1213*9c5db199SXin Li return str_pid.split() 1214*9c5db199SXin Li 1215*9c5db199SXin Li 1216*9c5db199SXin Lidef nuke_process_by_name(name, with_prejudice=False): 1217*9c5db199SXin Li """Tell the oldest process specified by name to exit. 1218*9c5db199SXin Li 1219*9c5db199SXin Li Arguments: 1220*9c5db199SXin Li name: process name specifier, as understood by pgrep. 1221*9c5db199SXin Li with_prejudice: if True, don't allow for graceful exit. 1222*9c5db199SXin Li 1223*9c5db199SXin Li Raises: 1224*9c5db199SXin Li error.AutoservPidAlreadyDeadError: no existing process matches name. 1225*9c5db199SXin Li """ 1226*9c5db199SXin Li try: 1227*9c5db199SXin Li pid = get_oldest_pid_by_name(name) 1228*9c5db199SXin Li except Exception as e: 1229*9c5db199SXin Li logging.error(e) 1230*9c5db199SXin Li return 1231*9c5db199SXin Li if pid is None: 1232*9c5db199SXin Li raise error.AutoservPidAlreadyDeadError('No process matching %s.' % 1233*9c5db199SXin Li name) 1234*9c5db199SXin Li if with_prejudice: 1235*9c5db199SXin Li utils.nuke_pid(pid, [signal.SIGKILL]) 1236*9c5db199SXin Li else: 1237*9c5db199SXin Li utils.nuke_pid(pid) 1238*9c5db199SXin Li 1239*9c5db199SXin Li 1240*9c5db199SXin Lidef is_virtual_machine(): 1241*9c5db199SXin Li if 'QEMU' in platform.processor(): 1242*9c5db199SXin Li return True 1243*9c5db199SXin Li 1244*9c5db199SXin Li try: 1245*9c5db199SXin Li with open('/sys/devices/virtual/dmi/id/sys_vendor') as f: 1246*9c5db199SXin Li if 'QEMU' in f.read(): 1247*9c5db199SXin Li return True 1248*9c5db199SXin Li except IOError: 1249*9c5db199SXin Li pass 1250*9c5db199SXin Li 1251*9c5db199SXin Li return False 1252*9c5db199SXin Li 1253*9c5db199SXin Li 1254*9c5db199SXin Lidef save_vm_state(checkpoint): 1255*9c5db199SXin Li """Saves the current state of the virtual machine. 1256*9c5db199SXin Li 1257*9c5db199SXin Li This function is a NOOP if the test is not running under a virtual machine 1258*9c5db199SXin Li with the USB serial port redirected. 1259*9c5db199SXin Li 1260*9c5db199SXin Li Arguments: 1261*9c5db199SXin Li checkpoint - Name used to identify this state 1262*9c5db199SXin Li 1263*9c5db199SXin Li Returns: 1264*9c5db199SXin Li None 1265*9c5db199SXin Li """ 1266*9c5db199SXin Li # The QEMU monitor has been redirected to the guest serial port located at 1267*9c5db199SXin Li # /dev/ttyUSB0. To save the state of the VM, we just send the 'savevm' 1268*9c5db199SXin Li # command to the serial port. 1269*9c5db199SXin Li if is_virtual_machine() and os.path.exists('/dev/ttyUSB0'): 1270*9c5db199SXin Li logging.info('Saving VM state "%s"', checkpoint) 1271*9c5db199SXin Li serial = open('/dev/ttyUSB0', 'w') 1272*9c5db199SXin Li serial.write('savevm %s\r\n' % checkpoint) 1273*9c5db199SXin Li logging.info('Done saving VM state "%s"', checkpoint) 1274*9c5db199SXin Li 1275*9c5db199SXin Li 1276*9c5db199SXin Lidef mounts(): 1277*9c5db199SXin Li ret = [] 1278*9c5db199SXin Li with open('/proc/mounts') as f: 1279*9c5db199SXin Li lines = f.readlines() 1280*9c5db199SXin Li for line in lines: 1281*9c5db199SXin Li m = re.match( 1282*9c5db199SXin Li r'(?P<src>\S+) (?P<dest>\S+) (?P<type>\S+) (?P<opts>\S+).*', line) 1283*9c5db199SXin Li if m: 1284*9c5db199SXin Li ret.append(m.groupdict()) 1285*9c5db199SXin Li return ret 1286*9c5db199SXin Li 1287*9c5db199SXin Li 1288*9c5db199SXin Lidef is_mountpoint(path): 1289*9c5db199SXin Li return path in [m['dest'] for m in mounts()] 1290*9c5db199SXin Li 1291*9c5db199SXin Li 1292*9c5db199SXin Lidef require_mountpoint(path): 1293*9c5db199SXin Li """ 1294*9c5db199SXin Li Raises an exception if path is not a mountpoint. 1295*9c5db199SXin Li """ 1296*9c5db199SXin Li if not is_mountpoint(path): 1297*9c5db199SXin Li raise error.TestFail('Path not mounted: "%s"' % path) 1298*9c5db199SXin Li 1299*9c5db199SXin Li 1300*9c5db199SXin Lidef random_username(): 1301*9c5db199SXin Li return str(uuid.uuid4()) + '@example.com' 1302*9c5db199SXin Li 1303*9c5db199SXin Li 1304*9c5db199SXin Lidef get_signin_credentials(filepath): 1305*9c5db199SXin Li """Returns user_id, password tuple from credentials file at filepath. 1306*9c5db199SXin Li 1307*9c5db199SXin Li File must have one line of the format user_id:password 1308*9c5db199SXin Li 1309*9c5db199SXin Li @param filepath: path of credentials file. 1310*9c5db199SXin Li @return user_id, password tuple. 1311*9c5db199SXin Li """ 1312*9c5db199SXin Li user_id, password = None, None 1313*9c5db199SXin Li if os.path.isfile(filepath): 1314*9c5db199SXin Li with open(filepath) as f: 1315*9c5db199SXin Li user_id, password = f.read().rstrip().split(':') 1316*9c5db199SXin Li return user_id, password 1317*9c5db199SXin Li 1318*9c5db199SXin Li 1319*9c5db199SXin Lidef parse_cmd_output(command, run_method=utils.run): 1320*9c5db199SXin Li """Runs a command on a host object to retrieve host attributes. 1321*9c5db199SXin Li 1322*9c5db199SXin Li The command should output to stdout in the format of: 1323*9c5db199SXin Li <key> = <value> # <optional_comment> 1324*9c5db199SXin Li 1325*9c5db199SXin Li 1326*9c5db199SXin Li @param command: Command to execute on the host. 1327*9c5db199SXin Li @param run_method: Function to use to execute the command. Defaults to 1328*9c5db199SXin Li utils.run so that the command will be executed locally. 1329*9c5db199SXin Li Can be replace with a host.run call so that it will 1330*9c5db199SXin Li execute on a DUT or external machine. Method must accept 1331*9c5db199SXin Li a command argument, stdout_tee and stderr_tee args and 1332*9c5db199SXin Li return a result object with a string attribute stdout 1333*9c5db199SXin Li which will be parsed. 1334*9c5db199SXin Li 1335*9c5db199SXin Li @returns a dictionary mapping host attributes to their values. 1336*9c5db199SXin Li """ 1337*9c5db199SXin Li result = {} 1338*9c5db199SXin Li # Suppresses stdout so that the files are not printed to the logs. 1339*9c5db199SXin Li cmd_result = run_method(command, stdout_tee=None, stderr_tee=None) 1340*9c5db199SXin Li for line in cmd_result.stdout.splitlines(): 1341*9c5db199SXin Li # Lines are of the format "<key> = <value> # <comment>" 1342*9c5db199SXin Li key_value = re.match(r'^\s*(?P<key>[^ ]+)\s*=\s*(?P<value>[^ ' 1343*9c5db199SXin Li r']+)(?:\s*#.*)?$', line) 1344*9c5db199SXin Li if key_value: 1345*9c5db199SXin Li result[key_value.group('key')] = key_value.group('value') 1346*9c5db199SXin Li return result 1347*9c5db199SXin Li 1348*9c5db199SXin Li 1349*9c5db199SXin Lidef set_from_keyval_output(out, delimiter=' '): 1350*9c5db199SXin Li """Parse delimiter-separated key-val output into a set of tuples. 1351*9c5db199SXin Li 1352*9c5db199SXin Li Output is expected to be multiline text output from a command. 1353*9c5db199SXin Li Stuffs the key-vals into tuples in a set to be later compared. 1354*9c5db199SXin Li 1355*9c5db199SXin Li e.g. deactivated 0 1356*9c5db199SXin Li disableForceClear 0 1357*9c5db199SXin Li ==> set(('deactivated', '0'), ('disableForceClear', '0')) 1358*9c5db199SXin Li 1359*9c5db199SXin Li @param out: multiple lines of space-separated key-val pairs. 1360*9c5db199SXin Li @param delimiter: character that separates key from val. Usually a 1361*9c5db199SXin Li space but may be '=' or something else. 1362*9c5db199SXin Li @return set of key-val tuples. 1363*9c5db199SXin Li """ 1364*9c5db199SXin Li results = set() 1365*9c5db199SXin Li kv_match_re = re.compile('([^ ]+)%s(.*)' % delimiter) 1366*9c5db199SXin Li for linecr in out.splitlines(): 1367*9c5db199SXin Li match = kv_match_re.match(linecr.strip()) 1368*9c5db199SXin Li if match: 1369*9c5db199SXin Li results.add((match.group(1), match.group(2))) 1370*9c5db199SXin Li return results 1371*9c5db199SXin Li 1372*9c5db199SXin Li 1373*9c5db199SXin Lidef get_cpu_usage(): 1374*9c5db199SXin Li """Returns machine's CPU usage. 1375*9c5db199SXin Li 1376*9c5db199SXin Li This function uses /proc/stat to identify CPU usage. 1377*9c5db199SXin Li Returns: 1378*9c5db199SXin Li A dictionary with values for all columns in /proc/stat 1379*9c5db199SXin Li Sample dictionary: 1380*9c5db199SXin Li { 1381*9c5db199SXin Li 'user': 254544, 1382*9c5db199SXin Li 'nice': 9, 1383*9c5db199SXin Li 'system': 254768, 1384*9c5db199SXin Li 'idle': 2859878, 1385*9c5db199SXin Li 'iowait': 1, 1386*9c5db199SXin Li 'irq': 2, 1387*9c5db199SXin Li 'softirq': 3, 1388*9c5db199SXin Li 'steal': 4, 1389*9c5db199SXin Li 'guest': 5, 1390*9c5db199SXin Li 'guest_nice': 6 1391*9c5db199SXin Li } 1392*9c5db199SXin Li If a column is missing or malformed in /proc/stat (typically on older 1393*9c5db199SXin Li systems), the value for that column is set to 0. 1394*9c5db199SXin Li """ 1395*9c5db199SXin Li with _open_file('/proc/stat') as proc_stat: 1396*9c5db199SXin Li cpu_usage_str = proc_stat.readline().split() 1397*9c5db199SXin Li columns = ('user', 'nice', 'system', 'idle', 'iowait', 'irq', 'softirq', 1398*9c5db199SXin Li 'steal', 'guest', 'guest_nice') 1399*9c5db199SXin Li d = {} 1400*9c5db199SXin Li for index, col in enumerate(columns, 1): 1401*9c5db199SXin Li try: 1402*9c5db199SXin Li d[col] = int(cpu_usage_str[index]) 1403*9c5db199SXin Li except: 1404*9c5db199SXin Li d[col] = 0 1405*9c5db199SXin Li return d 1406*9c5db199SXin Li 1407*9c5db199SXin Lidef compute_active_cpu_time(cpu_usage_start, cpu_usage_end): 1408*9c5db199SXin Li """Computes the fraction of CPU time spent non-idling. 1409*9c5db199SXin Li 1410*9c5db199SXin Li This function should be invoked using before/after values from calls to 1411*9c5db199SXin Li get_cpu_usage(). 1412*9c5db199SXin Li 1413*9c5db199SXin Li See https://stackoverflow.com/a/23376195 and 1414*9c5db199SXin Li https://unix.stackexchange.com/a/303224 for some more context how 1415*9c5db199SXin Li to calculate usage given two /proc/stat snapshots. 1416*9c5db199SXin Li """ 1417*9c5db199SXin Li idle_cols = ('idle', 'iowait') # All other cols are calculated as active. 1418*9c5db199SXin Li time_active_start = sum([x[1] for x in six.iteritems(cpu_usage_start) 1419*9c5db199SXin Li if x[0] not in idle_cols]) 1420*9c5db199SXin Li time_active_end = sum([x[1] for x in six.iteritems(cpu_usage_end) 1421*9c5db199SXin Li if x[0] not in idle_cols]) 1422*9c5db199SXin Li total_time_start = sum(cpu_usage_start.values()) 1423*9c5db199SXin Li total_time_end = sum(cpu_usage_end.values()) 1424*9c5db199SXin Li # Avoid bogus division which has been observed on Tegra. 1425*9c5db199SXin Li if total_time_end <= total_time_start: 1426*9c5db199SXin Li logging.warning('compute_active_cpu_time observed bogus data') 1427*9c5db199SXin Li # We pretend to be busy, this will force a longer wait for idle CPU. 1428*9c5db199SXin Li return 1.0 1429*9c5db199SXin Li return ((float(time_active_end) - time_active_start) / 1430*9c5db199SXin Li (total_time_end - total_time_start)) 1431*9c5db199SXin Li 1432*9c5db199SXin Li 1433*9c5db199SXin Lidef is_pgo_mode(): 1434*9c5db199SXin Li return 'USE_PGO' in os.environ 1435*9c5db199SXin Li 1436*9c5db199SXin Li 1437*9c5db199SXin Lidef wait_for_idle_cpu(timeout, utilization): 1438*9c5db199SXin Li """Waits for the CPU to become idle (< utilization). 1439*9c5db199SXin Li 1440*9c5db199SXin Li Args: 1441*9c5db199SXin Li timeout: The longest time in seconds to wait before throwing an error. 1442*9c5db199SXin Li utilization: The CPU usage below which the system should be considered 1443*9c5db199SXin Li idle (between 0 and 1.0 independent of cores/hyperthreads). 1444*9c5db199SXin Li """ 1445*9c5db199SXin Li time_passed = 0.0 1446*9c5db199SXin Li fraction_active_time = 1.0 1447*9c5db199SXin Li sleep_time = 1 1448*9c5db199SXin Li logging.info('Starting to wait up to %.1fs for idle CPU...', timeout) 1449*9c5db199SXin Li while fraction_active_time >= utilization: 1450*9c5db199SXin Li cpu_usage_start = get_cpu_usage() 1451*9c5db199SXin Li # Split timeout interval into not too many chunks to limit log spew. 1452*9c5db199SXin Li # Start at 1 second, increase exponentially 1453*9c5db199SXin Li time.sleep(sleep_time) 1454*9c5db199SXin Li time_passed += sleep_time 1455*9c5db199SXin Li sleep_time = min(16.0, 2.0 * sleep_time) 1456*9c5db199SXin Li cpu_usage_end = get_cpu_usage() 1457*9c5db199SXin Li fraction_active_time = compute_active_cpu_time(cpu_usage_start, 1458*9c5db199SXin Li cpu_usage_end) 1459*9c5db199SXin Li logging.info('After waiting %.1fs CPU utilization is %.3f.', 1460*9c5db199SXin Li time_passed, fraction_active_time) 1461*9c5db199SXin Li if time_passed > timeout: 1462*9c5db199SXin Li if fraction_active_time < utilization: 1463*9c5db199SXin Li break 1464*9c5db199SXin Li logging.warning('CPU did not become idle.') 1465*9c5db199SXin Li log_process_activity() 1466*9c5db199SXin Li # crosbug.com/37389 1467*9c5db199SXin Li if is_pgo_mode(): 1468*9c5db199SXin Li logging.info('Still continuing because we are in PGO mode.') 1469*9c5db199SXin Li return True 1470*9c5db199SXin Li 1471*9c5db199SXin Li return False 1472*9c5db199SXin Li logging.info('Wait for idle CPU took %.1fs (utilization = %.3f).', 1473*9c5db199SXin Li time_passed, fraction_active_time) 1474*9c5db199SXin Li return True 1475*9c5db199SXin Li 1476*9c5db199SXin Li 1477*9c5db199SXin Lidef log_process_activity(): 1478*9c5db199SXin Li """Logs the output of top. 1479*9c5db199SXin Li 1480*9c5db199SXin Li Useful to debug performance tests and to find runaway processes. 1481*9c5db199SXin Li """ 1482*9c5db199SXin Li logging.info('Logging current process activity using top and ps.') 1483*9c5db199SXin Li cmd = 'top -b -n1 -c' 1484*9c5db199SXin Li output = utils.run(cmd) 1485*9c5db199SXin Li logging.info(output) 1486*9c5db199SXin Li output = utils.run('ps axl') 1487*9c5db199SXin Li logging.info(output) 1488*9c5db199SXin Li 1489*9c5db199SXin Li 1490*9c5db199SXin Lidef wait_for_cool_machine(): 1491*9c5db199SXin Li """ 1492*9c5db199SXin Li A simple heuristic to wait for a machine to cool. 1493*9c5db199SXin Li The code looks a bit 'magic', but we don't know ambient temperature 1494*9c5db199SXin Li nor machine characteristics and still would like to return the caller 1495*9c5db199SXin Li a machine that cooled down as much as reasonably possible. 1496*9c5db199SXin Li """ 1497*9c5db199SXin Li temperature = get_current_temperature_max() 1498*9c5db199SXin Li # We got here with a cold machine, return immediately. This should be the 1499*9c5db199SXin Li # most common case. 1500*9c5db199SXin Li if temperature < 45: 1501*9c5db199SXin Li return True 1502*9c5db199SXin Li logging.info('Got a hot machine of %dC. Sleeping 1 minute.', temperature) 1503*9c5db199SXin Li # A modest wait should cool the machine. 1504*9c5db199SXin Li time.sleep(60.0) 1505*9c5db199SXin Li temperature = get_current_temperature_max() 1506*9c5db199SXin Li # Atoms idle below 60 and everyone else should be even lower. 1507*9c5db199SXin Li if temperature < 62: 1508*9c5db199SXin Li return True 1509*9c5db199SXin Li # This should be rare. 1510*9c5db199SXin Li logging.info('Did not cool down (%dC). Sleeping 2 minutes.', temperature) 1511*9c5db199SXin Li time.sleep(120.0) 1512*9c5db199SXin Li temperature = get_current_temperature_max() 1513*9c5db199SXin Li # A temperature over 65'C doesn't give us much headroom to the critical 1514*9c5db199SXin Li # temperatures that start at 85'C (and PerfControl as of today will fail at 1515*9c5db199SXin Li # critical - 10'C). 1516*9c5db199SXin Li if temperature < 65: 1517*9c5db199SXin Li return True 1518*9c5db199SXin Li logging.warning('Did not cool down (%dC), giving up.', temperature) 1519*9c5db199SXin Li log_process_activity() 1520*9c5db199SXin Li return False 1521*9c5db199SXin Li 1522*9c5db199SXin Li 1523*9c5db199SXin Lidef report_temperature(test, keyname): 1524*9c5db199SXin Li """Report current max observed temperature with given keyname. 1525*9c5db199SXin Li 1526*9c5db199SXin Li @param test: autotest_lib.client.bin.test.test instance 1527*9c5db199SXin Li @param keyname: key to be used when reporting perf value. 1528*9c5db199SXin Li """ 1529*9c5db199SXin Li temperature = get_current_temperature_max() 1530*9c5db199SXin Li logging.info('%s = %f degree Celsius', keyname, temperature) 1531*9c5db199SXin Li test.output_perf_value( 1532*9c5db199SXin Li description=keyname, 1533*9c5db199SXin Li value=temperature, 1534*9c5db199SXin Li units='Celsius', 1535*9c5db199SXin Li higher_is_better=False) 1536*9c5db199SXin Li 1537*9c5db199SXin Li 1538*9c5db199SXin Li# System paths for machine performance state. 1539*9c5db199SXin Li_CPUINFO = '/proc/cpuinfo' 1540*9c5db199SXin Li_DIRTY_WRITEBACK_CENTISECS = '/proc/sys/vm/dirty_writeback_centisecs' 1541*9c5db199SXin Li_KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' 1542*9c5db199SXin Li_MEMINFO = '/proc/meminfo' 1543*9c5db199SXin Li_TEMP_SENSOR_RE = 'Reading temperature...([0-9]*)' 1544*9c5db199SXin Li 1545*9c5db199SXin Lidef _open_file(path): 1546*9c5db199SXin Li """ 1547*9c5db199SXin Li Opens a file and returns the file object. 1548*9c5db199SXin Li 1549*9c5db199SXin Li This method is intended to be mocked by tests. 1550*9c5db199SXin Li @return The open file object. 1551*9c5db199SXin Li """ 1552*9c5db199SXin Li return open(path) 1553*9c5db199SXin Li 1554*9c5db199SXin Lidef _get_line_from_file(path, line): 1555*9c5db199SXin Li """ 1556*9c5db199SXin Li line can be an integer or 1557*9c5db199SXin Li line can be a string that matches the beginning of the line 1558*9c5db199SXin Li """ 1559*9c5db199SXin Li with _open_file(path) as f: 1560*9c5db199SXin Li if isinstance(line, int): 1561*9c5db199SXin Li l = f.readline() 1562*9c5db199SXin Li for _ in range(0, line): 1563*9c5db199SXin Li l = f.readline() 1564*9c5db199SXin Li return l 1565*9c5db199SXin Li else: 1566*9c5db199SXin Li for l in f: 1567*9c5db199SXin Li if l.startswith(line): 1568*9c5db199SXin Li return l 1569*9c5db199SXin Li return None 1570*9c5db199SXin Li 1571*9c5db199SXin Li 1572*9c5db199SXin Lidef _get_match_from_file(path, line, prefix, postfix): 1573*9c5db199SXin Li """ 1574*9c5db199SXin Li Matches line in path and returns string between first prefix and postfix. 1575*9c5db199SXin Li """ 1576*9c5db199SXin Li match = _get_line_from_file(path, line) 1577*9c5db199SXin Li # Strip everything from front of line including prefix. 1578*9c5db199SXin Li if prefix: 1579*9c5db199SXin Li match = re.split(prefix, match)[1] 1580*9c5db199SXin Li # Strip everything from back of string including first occurence of postfix. 1581*9c5db199SXin Li if postfix: 1582*9c5db199SXin Li match = re.split(postfix, match)[0] 1583*9c5db199SXin Li return match 1584*9c5db199SXin Li 1585*9c5db199SXin Li 1586*9c5db199SXin Lidef _get_float_from_file(path, line, prefix, postfix): 1587*9c5db199SXin Li match = _get_match_from_file(path, line, prefix, postfix) 1588*9c5db199SXin Li return float(match) 1589*9c5db199SXin Li 1590*9c5db199SXin Li 1591*9c5db199SXin Lidef _get_int_from_file(path, line, prefix, postfix): 1592*9c5db199SXin Li match = _get_match_from_file(path, line, prefix, postfix) 1593*9c5db199SXin Li return int(match) 1594*9c5db199SXin Li 1595*9c5db199SXin Li 1596*9c5db199SXin Lidef _get_hex_from_file(path, line, prefix, postfix): 1597*9c5db199SXin Li match = _get_match_from_file(path, line, prefix, postfix) 1598*9c5db199SXin Li return int(match, 16) 1599*9c5db199SXin Li 1600*9c5db199SXin Li 1601*9c5db199SXin Lidef is_system_thermally_throttled(): 1602*9c5db199SXin Li """ 1603*9c5db199SXin Li Returns whether the system appears to be thermally throttled. 1604*9c5db199SXin Li """ 1605*9c5db199SXin Li for path in glob.glob('/sys/class/thermal/cooling_device*/type'): 1606*9c5db199SXin Li with _open_file(path) as f: 1607*9c5db199SXin Li cdev_type = f.read().strip() 1608*9c5db199SXin Li 1609*9c5db199SXin Li if not (cdev_type == 'Processor' or 1610*9c5db199SXin Li cdev_type.startswith('thermal-devfreq') or 1611*9c5db199SXin Li cdev_type.startswith('thermal-cpufreq')): 1612*9c5db199SXin Li continue 1613*9c5db199SXin Li 1614*9c5db199SXin Li cur_state_path = os.path.join(os.path.dirname(path), 'cur_state') 1615*9c5db199SXin Li if _get_int_from_file(cur_state_path, 0, None, None) > 0: 1616*9c5db199SXin Li return True 1617*9c5db199SXin Li 1618*9c5db199SXin Li return False 1619*9c5db199SXin Li 1620*9c5db199SXin Li 1621*9c5db199SXin Li# The paths don't change. Avoid running find all the time. 1622*9c5db199SXin Li_hwmon_paths = {} 1623*9c5db199SXin Li 1624*9c5db199SXin Lidef _get_hwmon_datas(file_pattern): 1625*9c5db199SXin Li """Returns a list of reading from hwmon.""" 1626*9c5db199SXin Li # Some systems like daisy_spring only have the virtual hwmon. 1627*9c5db199SXin Li # And other systems like rambi only have coretemp.0. See crbug.com/360249. 1628*9c5db199SXin Li # /sys/class/hwmon/hwmon*/ 1629*9c5db199SXin Li # /sys/devices/virtual/hwmon/hwmon*/ 1630*9c5db199SXin Li # /sys/devices/platform/coretemp.0/ 1631*9c5db199SXin Li if file_pattern not in _hwmon_paths: 1632*9c5db199SXin Li cmd = 'find /sys/class /sys/devices -name "' + file_pattern + '"' 1633*9c5db199SXin Li _hwmon_paths[file_pattern] = \ 1634*9c5db199SXin Li utils.run(cmd, verbose=False).stdout.splitlines() 1635*9c5db199SXin Li for _hwmon_path in _hwmon_paths[file_pattern]: 1636*9c5db199SXin Li try: 1637*9c5db199SXin Li yield _get_float_from_file(_hwmon_path, 0, None, None) * 0.001 1638*9c5db199SXin Li except IOError as err: 1639*9c5db199SXin Li # Files under /sys may get truncated and result in ENODATA. 1640*9c5db199SXin Li # Ignore those. 1641*9c5db199SXin Li if err.errno is not errno.ENODATA: 1642*9c5db199SXin Li raise 1643*9c5db199SXin Li 1644*9c5db199SXin Li 1645*9c5db199SXin Lidef _get_hwmon_temperatures(): 1646*9c5db199SXin Li """ 1647*9c5db199SXin Li Returns the currently observed temperatures from hwmon 1648*9c5db199SXin Li """ 1649*9c5db199SXin Li return list(_get_hwmon_datas('temp*_input')) 1650*9c5db199SXin Li 1651*9c5db199SXin Li 1652*9c5db199SXin Lidef _get_thermal_zone_temperatures(): 1653*9c5db199SXin Li """ 1654*9c5db199SXin Li Returns the maximum currently observered temperature in thermal_zones. 1655*9c5db199SXin Li """ 1656*9c5db199SXin Li temperatures = [] 1657*9c5db199SXin Li for path in glob.glob('/sys/class/thermal/thermal_zone*/temp'): 1658*9c5db199SXin Li try: 1659*9c5db199SXin Li temperatures.append( 1660*9c5db199SXin Li _get_float_from_file(path, 0, None, None) * 0.001) 1661*9c5db199SXin Li except IOError: 1662*9c5db199SXin Li # Some devices (e.g. Veyron) may have reserved thermal zones that 1663*9c5db199SXin Li # are not active. Trying to read the temperature value would cause a 1664*9c5db199SXin Li # EINVAL IO error. 1665*9c5db199SXin Li continue 1666*9c5db199SXin Li return temperatures 1667*9c5db199SXin Li 1668*9c5db199SXin Li 1669*9c5db199SXin Lidef get_ec_temperatures(): 1670*9c5db199SXin Li """ 1671*9c5db199SXin Li Uses ectool to return a list of all sensor temperatures in Celsius. 1672*9c5db199SXin Li 1673*9c5db199SXin Li Output from ectool is either '0: 300' or '0: 300 K' (newer ectool 1674*9c5db199SXin Li includes the unit). 1675*9c5db199SXin Li """ 1676*9c5db199SXin Li temperatures = [] 1677*9c5db199SXin Li try: 1678*9c5db199SXin Li full_cmd = 'ectool temps all' 1679*9c5db199SXin Li lines = utils.run(full_cmd, verbose=False).stdout.splitlines() 1680*9c5db199SXin Li pattern = re.compile('.*: (\d+)') 1681*9c5db199SXin Li for line in lines: 1682*9c5db199SXin Li matched = pattern.match(line) 1683*9c5db199SXin Li temperature = int(matched.group(1)) - 273 1684*9c5db199SXin Li temperatures.append(temperature) 1685*9c5db199SXin Li except Exception as e: 1686*9c5db199SXin Li logging.warning('Unable to read temperature sensors using ectool %s.', 1687*9c5db199SXin Li e) 1688*9c5db199SXin Li # Check for real world values. 1689*9c5db199SXin Li if not all(10.0 <= temperature <= 150.0 for temperature in temperatures): 1690*9c5db199SXin Li logging.warning('Unreasonable EC temperatures: %s.', temperatures) 1691*9c5db199SXin Li return temperatures 1692*9c5db199SXin Li 1693*9c5db199SXin Li 1694*9c5db199SXin Lidef get_current_temperature_max(): 1695*9c5db199SXin Li """ 1696*9c5db199SXin Li Returns the highest reported board temperature (all sensors) in Celsius. 1697*9c5db199SXin Li """ 1698*9c5db199SXin Li all_temps = (_get_hwmon_temperatures() + 1699*9c5db199SXin Li _get_thermal_zone_temperatures() + 1700*9c5db199SXin Li get_ec_temperatures()) 1701*9c5db199SXin Li if all_temps: 1702*9c5db199SXin Li temperature = max(all_temps) 1703*9c5db199SXin Li else: 1704*9c5db199SXin Li temperature = -1 1705*9c5db199SXin Li # Check for real world values. 1706*9c5db199SXin Li assert ((temperature > 10.0) and 1707*9c5db199SXin Li (temperature < 150.0)), ('Unreasonable temperature %.1fC.' % 1708*9c5db199SXin Li temperature) 1709*9c5db199SXin Li return temperature 1710*9c5db199SXin Li 1711*9c5db199SXin Li 1712*9c5db199SXin Lidef get_cpu_max_frequency(): 1713*9c5db199SXin Li """ 1714*9c5db199SXin Li Returns the largest of the max CPU core frequencies. The unit is Hz. 1715*9c5db199SXin Li """ 1716*9c5db199SXin Li max_frequency = -1 1717*9c5db199SXin Li paths = utils._get_cpufreq_paths('cpuinfo_max_freq') 1718*9c5db199SXin Li if not paths: 1719*9c5db199SXin Li raise ValueError('Could not find max freq; is cpufreq supported?') 1720*9c5db199SXin Li for path in paths: 1721*9c5db199SXin Li try: 1722*9c5db199SXin Li # Convert from kHz to Hz. 1723*9c5db199SXin Li frequency = 1000 * _get_float_from_file(path, 0, None, None) 1724*9c5db199SXin Li # CPUs may come and go. A missing entry or two aren't critical. 1725*9c5db199SXin Li except IOError: 1726*9c5db199SXin Li continue 1727*9c5db199SXin Li max_frequency = max(frequency, max_frequency) 1728*9c5db199SXin Li # Confidence check. 1729*9c5db199SXin Li assert max_frequency > 1e8, ('Unreasonably low CPU frequency: %.1f' % 1730*9c5db199SXin Li max_frequency) 1731*9c5db199SXin Li return max_frequency 1732*9c5db199SXin Li 1733*9c5db199SXin Li 1734*9c5db199SXin Lidef get_board_property(key): 1735*9c5db199SXin Li """ 1736*9c5db199SXin Li Get a specific property from /etc/lsb-release. 1737*9c5db199SXin Li 1738*9c5db199SXin Li @param key: board property to return value for 1739*9c5db199SXin Li 1740*9c5db199SXin Li @return the value or '' if not present 1741*9c5db199SXin Li """ 1742*9c5db199SXin Li with open('/etc/lsb-release') as f: 1743*9c5db199SXin Li pattern = '%s=(.*)' % key 1744*9c5db199SXin Li pat = re.search(pattern, f.read()) 1745*9c5db199SXin Li if pat: 1746*9c5db199SXin Li return pat.group(1) 1747*9c5db199SXin Li return '' 1748*9c5db199SXin Li 1749*9c5db199SXin Li 1750*9c5db199SXin Lidef get_board(): 1751*9c5db199SXin Li """ 1752*9c5db199SXin Li Get the ChromeOS release board name from /etc/lsb-release. 1753*9c5db199SXin Li """ 1754*9c5db199SXin Li return get_board_property('BOARD') 1755*9c5db199SXin Li 1756*9c5db199SXin Li 1757*9c5db199SXin Lidef get_board_type(): 1758*9c5db199SXin Li """ 1759*9c5db199SXin Li Get the ChromeOS board type from /etc/lsb-release. 1760*9c5db199SXin Li 1761*9c5db199SXin Li @return device type. 1762*9c5db199SXin Li """ 1763*9c5db199SXin Li return get_board_property('DEVICETYPE') 1764*9c5db199SXin Li 1765*9c5db199SXin Li 1766*9c5db199SXin Lidef get_chromeos_version(): 1767*9c5db199SXin Li """ 1768*9c5db199SXin Li Get the ChromeOS build version from /etc/lsb-release. 1769*9c5db199SXin Li 1770*9c5db199SXin Li @return chromeos release version. 1771*9c5db199SXin Li """ 1772*9c5db199SXin Li return get_board_property('CHROMEOS_RELEASE_VERSION') 1773*9c5db199SXin Li 1774*9c5db199SXin Li 1775*9c5db199SXin Lidef get_android_version(): 1776*9c5db199SXin Li """ 1777*9c5db199SXin Li Get the Android SDK version from /etc/lsb-release. 1778*9c5db199SXin Li 1779*9c5db199SXin Li @return android sdk version. 1780*9c5db199SXin Li """ 1781*9c5db199SXin Li return get_board_property('CHROMEOS_ARC_ANDROID_SDK_VERSION') 1782*9c5db199SXin Li 1783*9c5db199SXin Li 1784*9c5db199SXin Lidef is_arcvm(): 1785*9c5db199SXin Li try: 1786*9c5db199SXin Li return int(get_android_version()) >= 30 1787*9c5db199SXin Li except: 1788*9c5db199SXin Li return False 1789*9c5db199SXin Li 1790*9c5db199SXin Li 1791*9c5db199SXin Lidef get_platform(): 1792*9c5db199SXin Li """ 1793*9c5db199SXin Li Get the ChromeOS platform name. 1794*9c5db199SXin Li 1795*9c5db199SXin Li For unibuild this should be equal to model name. For non-unibuild 1796*9c5db199SXin Li it will either be board name or empty string. In the case of 1797*9c5db199SXin Li empty string return board name to match equivalent logic in 1798*9c5db199SXin Li server/hosts/cros_host.py 1799*9c5db199SXin Li 1800*9c5db199SXin Li @returns platform name 1801*9c5db199SXin Li """ 1802*9c5db199SXin Li platform = cros_config.call_cros_config_get_output('/ name', utils.run) 1803*9c5db199SXin Li if platform == '': 1804*9c5db199SXin Li platform = get_board() 1805*9c5db199SXin Li return platform 1806*9c5db199SXin Li 1807*9c5db199SXin Li 1808*9c5db199SXin Lidef get_sku(): 1809*9c5db199SXin Li """ 1810*9c5db199SXin Li Get the SKU number. 1811*9c5db199SXin Li 1812*9c5db199SXin Li @returns SKU number 1813*9c5db199SXin Li """ 1814*9c5db199SXin Li return cros_config.call_cros_config_get_output('/identity sku-id', 1815*9c5db199SXin Li utils.run) 1816*9c5db199SXin Li 1817*9c5db199SXin Li 1818*9c5db199SXin Lidef get_ec_version(): 1819*9c5db199SXin Li """Get the ec version as strings. 1820*9c5db199SXin Li 1821*9c5db199SXin Li @returns a string representing this host's ec version. 1822*9c5db199SXin Li """ 1823*9c5db199SXin Li command = 'mosys ec info -s fw_version' 1824*9c5db199SXin Li result = utils.run(command, ignore_status=True) 1825*9c5db199SXin Li if result.exit_status != 0: 1826*9c5db199SXin Li return '' 1827*9c5db199SXin Li return result.stdout.strip() 1828*9c5db199SXin Li 1829*9c5db199SXin Li 1830*9c5db199SXin Lidef get_firmware_version(): 1831*9c5db199SXin Li """Get the firmware version as strings. 1832*9c5db199SXin Li 1833*9c5db199SXin Li @returns a string representing this host's firmware version. 1834*9c5db199SXin Li """ 1835*9c5db199SXin Li return utils.run('crossystem fwid').stdout.strip() 1836*9c5db199SXin Li 1837*9c5db199SXin Li 1838*9c5db199SXin Lidef get_hardware_id(): 1839*9c5db199SXin Li """Get hardware id as strings. 1840*9c5db199SXin Li 1841*9c5db199SXin Li @returns a string representing this host's hardware id. 1842*9c5db199SXin Li """ 1843*9c5db199SXin Li return utils.run('crossystem hwid').stdout.strip() 1844*9c5db199SXin Li 1845*9c5db199SXin Li 1846*9c5db199SXin Lidef get_hardware_revision(): 1847*9c5db199SXin Li """Get the hardware revision as strings. 1848*9c5db199SXin Li 1849*9c5db199SXin Li @returns a string representing this host's hardware revision. 1850*9c5db199SXin Li """ 1851*9c5db199SXin Li command = 'mosys platform version' 1852*9c5db199SXin Li result = utils.run(command, ignore_status=True) 1853*9c5db199SXin Li if result.exit_status != 0: 1854*9c5db199SXin Li return '' 1855*9c5db199SXin Li return result.stdout.strip() 1856*9c5db199SXin Li 1857*9c5db199SXin Li 1858*9c5db199SXin Lidef get_kernel_version(): 1859*9c5db199SXin Li """Get the kernel version as strings. 1860*9c5db199SXin Li 1861*9c5db199SXin Li @returns a string representing this host's kernel version. 1862*9c5db199SXin Li """ 1863*9c5db199SXin Li return utils.run('uname -r').stdout.strip() 1864*9c5db199SXin Li 1865*9c5db199SXin Li 1866*9c5db199SXin Lidef get_cpu_name(): 1867*9c5db199SXin Li """Get the cpu name as strings. 1868*9c5db199SXin Li 1869*9c5db199SXin Li @returns a string representing this host's cpu name. 1870*9c5db199SXin Li """ 1871*9c5db199SXin Li 1872*9c5db199SXin Li # Try get cpu name from device tree first 1873*9c5db199SXin Li if os.path.exists("/proc/device-tree/compatible"): 1874*9c5db199SXin Li command = "sed -e 's/\\x0/\\n/g' /proc/device-tree/compatible | tail -1" 1875*9c5db199SXin Li return utils.run(command).stdout.strip().replace(',', ' ') 1876*9c5db199SXin Li 1877*9c5db199SXin Li 1878*9c5db199SXin Li # Get cpu name from uname -p 1879*9c5db199SXin Li command = "uname -p" 1880*9c5db199SXin Li ret = utils.run(command).stdout.strip() 1881*9c5db199SXin Li 1882*9c5db199SXin Li # 'uname -p' return variant of unknown or amd64 or x86_64 or i686 1883*9c5db199SXin Li # Try get cpu name from /proc/cpuinfo instead 1884*9c5db199SXin Li if re.match("unknown|amd64|[ix][0-9]?86(_64)?", ret, re.IGNORECASE): 1885*9c5db199SXin Li command = "grep model.name /proc/cpuinfo | cut -f 2 -d: | head -1" 1886*9c5db199SXin Li ret = utils.run(command).stdout.strip() 1887*9c5db199SXin Li 1888*9c5db199SXin Li # Remove bloat from CPU name, for example 1889*9c5db199SXin Li # 'Intel(R) Core(TM) i5-7Y57 CPU @ 1.20GHz' -> 'Intel Core i5-7Y57' 1890*9c5db199SXin Li # 'Intel(R) Xeon(R) CPU E5-2690 v4 @ 2.60GHz' -> 'Intel Xeon E5-2690 v4' 1891*9c5db199SXin Li # 'AMD A10-7850K APU with Radeon(TM) R7 Graphics' -> 'AMD A10-7850K' 1892*9c5db199SXin Li # 'AMD GX-212JC SOC with Radeon(TM) R2E Graphics' -> 'AMD GX-212JC' 1893*9c5db199SXin Li trim_re = " (@|processor|apu|soc|radeon).*|\(.*?\)| cpu" 1894*9c5db199SXin Li return re.sub(trim_re, '', ret, flags=re.IGNORECASE) 1895*9c5db199SXin Li 1896*9c5db199SXin Li 1897*9c5db199SXin Lidef get_screen_resolution(): 1898*9c5db199SXin Li """Get the screen(s) resolution as strings. 1899*9c5db199SXin Li In case of more than 1 monitor, return resolution for each monitor separate 1900*9c5db199SXin Li with plus sign. 1901*9c5db199SXin Li 1902*9c5db199SXin Li @returns a string representing this host's screen(s) resolution. 1903*9c5db199SXin Li """ 1904*9c5db199SXin Li command = 'for f in /sys/class/drm/*/*/modes; do head -1 $f; done' 1905*9c5db199SXin Li ret = utils.run(command, ignore_status=True) 1906*9c5db199SXin Li # We might have Chromebox without a screen 1907*9c5db199SXin Li if ret.exit_status != 0: 1908*9c5db199SXin Li return '' 1909*9c5db199SXin Li return ret.stdout.strip().replace('\n', '+') 1910*9c5db199SXin Li 1911*9c5db199SXin Li 1912*9c5db199SXin Lidef get_board_with_frequency_and_memory(): 1913*9c5db199SXin Li """ 1914*9c5db199SXin Li Returns a board name modified with CPU frequency and memory size to 1915*9c5db199SXin Li differentiate between different board variants. For instance 1916*9c5db199SXin Li link -> link_1.8GHz_4GB. 1917*9c5db199SXin Li """ 1918*9c5db199SXin Li board_name = get_board() 1919*9c5db199SXin Li if is_virtual_machine(): 1920*9c5db199SXin Li board = '%s_VM' % board_name 1921*9c5db199SXin Li else: 1922*9c5db199SXin Li memory = get_mem_total_gb() 1923*9c5db199SXin Li # Convert frequency to GHz with 1 digit accuracy after the 1924*9c5db199SXin Li # decimal point. 1925*9c5db199SXin Li frequency = int(round(get_cpu_max_frequency() * 1e-8)) * 0.1 1926*9c5db199SXin Li board = '%s_%1.1fGHz_%dGB' % (board_name, frequency, memory) 1927*9c5db199SXin Li return board 1928*9c5db199SXin Li 1929*9c5db199SXin Li 1930*9c5db199SXin Lidef get_mem_total(): 1931*9c5db199SXin Li """ 1932*9c5db199SXin Li Returns the total memory available in the system in MBytes. 1933*9c5db199SXin Li """ 1934*9c5db199SXin Li mem_total = _get_float_from_file(_MEMINFO, 'MemTotal:', 'MemTotal:', ' kB') 1935*9c5db199SXin Li # Confidence check, all Chromebooks have at least 1GB of memory. 1936*9c5db199SXin Li assert mem_total > 256 * 1024, 'Unreasonable amount of memory.' 1937*9c5db199SXin Li return int(mem_total / 1024) 1938*9c5db199SXin Li 1939*9c5db199SXin Li 1940*9c5db199SXin Lidef get_mem_total_gb(): 1941*9c5db199SXin Li """ 1942*9c5db199SXin Li Returns the total memory available in the system in GBytes. 1943*9c5db199SXin Li """ 1944*9c5db199SXin Li return int(round(get_mem_total() / 1024.0)) 1945*9c5db199SXin Li 1946*9c5db199SXin Li 1947*9c5db199SXin Lidef get_mem_free(): 1948*9c5db199SXin Li """ 1949*9c5db199SXin Li Returns the currently free memory in the system in MBytes. 1950*9c5db199SXin Li """ 1951*9c5db199SXin Li mem_free = _get_float_from_file(_MEMINFO, 'MemFree:', 'MemFree:', ' kB') 1952*9c5db199SXin Li return int(mem_free / 1024) 1953*9c5db199SXin Li 1954*9c5db199SXin Lidef get_mem_free_plus_buffers_and_cached(): 1955*9c5db199SXin Li """ 1956*9c5db199SXin Li Returns the free memory in MBytes, counting buffers and cached as free. 1957*9c5db199SXin Li 1958*9c5db199SXin Li This is most often the most interesting number since buffers and cached 1959*9c5db199SXin Li memory can be reclaimed on demand. Note however, that there are cases 1960*9c5db199SXin Li where this as misleading as well, for example used tmpfs space 1961*9c5db199SXin Li count as Cached but can not be reclaimed on demand. 1962*9c5db199SXin Li See https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt. 1963*9c5db199SXin Li """ 1964*9c5db199SXin Li free_mb = get_mem_free() 1965*9c5db199SXin Li cached_mb = (_get_float_from_file( 1966*9c5db199SXin Li _MEMINFO, 'Cached:', 'Cached:', ' kB') / 1024) 1967*9c5db199SXin Li buffers_mb = (_get_float_from_file( 1968*9c5db199SXin Li _MEMINFO, 'Buffers:', 'Buffers:', ' kB') / 1024) 1969*9c5db199SXin Li return free_mb + buffers_mb + cached_mb 1970*9c5db199SXin Li 1971*9c5db199SXin Li 1972*9c5db199SXin Lidef get_dirty_writeback_centisecs(): 1973*9c5db199SXin Li """ 1974*9c5db199SXin Li Reads /proc/sys/vm/dirty_writeback_centisecs. 1975*9c5db199SXin Li """ 1976*9c5db199SXin Li time = _get_int_from_file(_DIRTY_WRITEBACK_CENTISECS, 0, None, None) 1977*9c5db199SXin Li return time 1978*9c5db199SXin Li 1979*9c5db199SXin Li 1980*9c5db199SXin Lidef set_dirty_writeback_centisecs(time=60000): 1981*9c5db199SXin Li """ 1982*9c5db199SXin Li In hundredths of a second, this is how often pdflush wakes up to write data 1983*9c5db199SXin Li to disk. The default wakes up the two (or more) active threads every five 1984*9c5db199SXin Li seconds. The ChromeOS default is 10 minutes. 1985*9c5db199SXin Li 1986*9c5db199SXin Li We use this to set as low as 1 second to flush error messages in system 1987*9c5db199SXin Li logs earlier to disk. 1988*9c5db199SXin Li """ 1989*9c5db199SXin Li # Flush buffers first to make this function synchronous. 1990*9c5db199SXin Li utils.system('sync') 1991*9c5db199SXin Li if time >= 0: 1992*9c5db199SXin Li cmd = 'echo %d > %s' % (time, _DIRTY_WRITEBACK_CENTISECS) 1993*9c5db199SXin Li utils.system(cmd) 1994*9c5db199SXin Li 1995*9c5db199SXin Li 1996*9c5db199SXin Lidef wflinfo_cmd(): 1997*9c5db199SXin Li """ 1998*9c5db199SXin Li Returns a wflinfo command appropriate to the current graphics platform/api. 1999*9c5db199SXin Li """ 2000*9c5db199SXin Li return 'wflinfo -p %s -a %s' % (graphics_platform(), graphics_api()) 2001*9c5db199SXin Li 2002*9c5db199SXin Li 2003*9c5db199SXin Lidef has_mali(): 2004*9c5db199SXin Li """ @return: True if system has a Mali GPU enabled.""" 2005*9c5db199SXin Li return os.path.exists('/dev/mali0') 2006*9c5db199SXin Li 2007*9c5db199SXin Lidef get_gpu_family(): 2008*9c5db199SXin Li """Returns the GPU family name.""" 2009*9c5db199SXin Li global pciid_to_amd_architecture 2010*9c5db199SXin Li global pciid_to_intel_architecture 2011*9c5db199SXin Li 2012*9c5db199SXin Li socfamily = get_cpu_soc_family() 2013*9c5db199SXin Li if socfamily == 'exynos5' or socfamily == 'rockchip' or has_mali(): 2014*9c5db199SXin Li cmd = wflinfo_cmd() 2015*9c5db199SXin Li wflinfo = utils.system_output(cmd, 2016*9c5db199SXin Li retain_output=True, 2017*9c5db199SXin Li ignore_status=False) 2018*9c5db199SXin Li m = re.findall(r'OpenGL renderer string: (Mali-\w+)', wflinfo) 2019*9c5db199SXin Li if m: 2020*9c5db199SXin Li return m[0].lower() 2021*9c5db199SXin Li return 'mali-unrecognized' 2022*9c5db199SXin Li if socfamily == 'tegra': 2023*9c5db199SXin Li return 'tegra' 2024*9c5db199SXin Li if socfamily == 'qualcomm': 2025*9c5db199SXin Li return 'qualcomm' 2026*9c5db199SXin Li if os.path.exists('/sys/kernel/debug/pvr'): 2027*9c5db199SXin Li return 'rogue' 2028*9c5db199SXin Li 2029*9c5db199SXin Li pci_vga_device = utils.run("lspci | grep VGA").stdout.rstrip('\n') 2030*9c5db199SXin Li bus_device_function = pci_vga_device.partition(' ')[0] 2031*9c5db199SXin Li pci_path = '/sys/bus/pci/devices/0000:' + bus_device_function + '/device' 2032*9c5db199SXin Li 2033*9c5db199SXin Li if not os.path.exists(pci_path): 2034*9c5db199SXin Li raise error.TestError('PCI device 0000:' + bus_device_function + ' not found') 2035*9c5db199SXin Li 2036*9c5db199SXin Li device_id = utils.read_one_line(pci_path).lower() 2037*9c5db199SXin Li 2038*9c5db199SXin Li if "Advanced Micro Devices" in pci_vga_device: 2039*9c5db199SXin Li if not pciid_to_amd_architecture: 2040*9c5db199SXin Li with open(_AMD_PCI_IDS_FILE_PATH, 'r') as in_f: 2041*9c5db199SXin Li pciid_to_amd_architecture = json.load(in_f) 2042*9c5db199SXin Li 2043*9c5db199SXin Li return pciid_to_amd_architecture[device_id] 2044*9c5db199SXin Li 2045*9c5db199SXin Li if "Intel Corporation" in pci_vga_device: 2046*9c5db199SXin Li # Only load Intel PCI ID file once and only if necessary. 2047*9c5db199SXin Li if not pciid_to_intel_architecture: 2048*9c5db199SXin Li with open(_INTEL_PCI_IDS_FILE_PATH, 'r') as in_f: 2049*9c5db199SXin Li pciid_to_intel_architecture = json.load(in_f) 2050*9c5db199SXin Li 2051*9c5db199SXin Li return pciid_to_intel_architecture[device_id] 2052*9c5db199SXin Li 2053*9c5db199SXin Li# TODO(ihf): Consider using /etc/lsb-release DEVICETYPE != CHROMEBOOK/CHROMEBASE 2054*9c5db199SXin Li# for confidence check, but usage seems a bit inconsistent. See 2055*9c5db199SXin Li# src/third_party/chromiumos-overlay/eclass/appid.eclass 2056*9c5db199SXin Li_BOARDS_WITHOUT_MONITOR = [ 2057*9c5db199SXin Li 'anglar', 'mccloud', 'monroe', 'ninja', 'rikku', 'guado', 'jecht', 'tidus', 2058*9c5db199SXin Li 'beltino', 'panther', 'stumpy', 'panther', 'tricky', 'zako', 'veyron_rialto' 2059*9c5db199SXin Li] 2060*9c5db199SXin Li 2061*9c5db199SXin Li 2062*9c5db199SXin Lidef has_no_monitor(): 2063*9c5db199SXin Li """Returns whether a machine doesn't have a built-in monitor.""" 2064*9c5db199SXin Li board_name = get_board() 2065*9c5db199SXin Li if board_name in _BOARDS_WITHOUT_MONITOR: 2066*9c5db199SXin Li return True 2067*9c5db199SXin Li 2068*9c5db199SXin Li return False 2069*9c5db199SXin Li 2070*9c5db199SXin Li 2071*9c5db199SXin Lidef get_fixed_dst_drive(): 2072*9c5db199SXin Li """ 2073*9c5db199SXin Li Return device name for internal disk. 2074*9c5db199SXin Li Example: return /dev/sda for falco booted from usb 2075*9c5db199SXin Li """ 2076*9c5db199SXin Li cmd = ' '.join(['. /usr/sbin/write_gpt.sh;', 2077*9c5db199SXin Li '. /usr/share/misc/chromeos-common.sh;', 2078*9c5db199SXin Li 'load_base_vars;', 2079*9c5db199SXin Li 'get_fixed_dst_drive']) 2080*9c5db199SXin Li return utils.system_output(cmd) 2081*9c5db199SXin Li 2082*9c5db199SXin Li 2083*9c5db199SXin Lidef get_root_device(): 2084*9c5db199SXin Li """ 2085*9c5db199SXin Li Return root device. 2086*9c5db199SXin Li Will return correct disk device even system boot from /dev/dm-0 2087*9c5db199SXin Li Example: return /dev/sdb for falco booted from usb 2088*9c5db199SXin Li """ 2089*9c5db199SXin Li return utils.system_output('rootdev -s -d') 2090*9c5db199SXin Li 2091*9c5db199SXin Li 2092*9c5db199SXin Lidef get_other_device(): 2093*9c5db199SXin Li """ 2094*9c5db199SXin Li Return the non root devices. 2095*9c5db199SXin Li Will return a list of other block devices, that are not the root device. 2096*9c5db199SXin Li """ 2097*9c5db199SXin Li 2098*9c5db199SXin Li cmd = 'lsblk -dpn -o NAME | grep -v -E "(loop|zram|boot|rpmb)"' 2099*9c5db199SXin Li devs = utils.system_output(cmd).splitlines() 2100*9c5db199SXin Li 2101*9c5db199SXin Li for dev in devs[:]: 2102*9c5db199SXin Li if not re.match(r'/dev/(sd[a-z]|mmcblk[0-9]+|nvme[0-9]+)p?[0-9]*', dev): 2103*9c5db199SXin Li devs.remove(dev) 2104*9c5db199SXin Li if dev == get_root_device(): 2105*9c5db199SXin Li devs.remove(dev) 2106*9c5db199SXin Li return devs 2107*9c5db199SXin Li 2108*9c5db199SXin Li 2109*9c5db199SXin Lidef get_root_partition(): 2110*9c5db199SXin Li """ 2111*9c5db199SXin Li Return current root partition 2112*9c5db199SXin Li Example: return /dev/sdb3 for falco booted from usb 2113*9c5db199SXin Li """ 2114*9c5db199SXin Li return utils.system_output('rootdev -s') 2115*9c5db199SXin Li 2116*9c5db199SXin Li 2117*9c5db199SXin Lidef get_free_root_partition(root_part=None): 2118*9c5db199SXin Li """ 2119*9c5db199SXin Li Return currently unused root partion 2120*9c5db199SXin Li Example: return /dev/sdb5 for falco booted from usb 2121*9c5db199SXin Li 2122*9c5db199SXin Li @param root_part: cuurent root partition 2123*9c5db199SXin Li """ 2124*9c5db199SXin Li spare_root_map = {'3': '5', '5': '3'} 2125*9c5db199SXin Li if not root_part: 2126*9c5db199SXin Li root_part = get_root_partition() 2127*9c5db199SXin Li return root_part[:-1] + spare_root_map[root_part[-1]] 2128*9c5db199SXin Li 2129*9c5db199SXin Li 2130*9c5db199SXin Lidef get_kernel_partition(root_part=None): 2131*9c5db199SXin Li """ 2132*9c5db199SXin Li Return current kernel partition 2133*9c5db199SXin Li Example: return /dev/sda2 for falco booted from usb 2134*9c5db199SXin Li 2135*9c5db199SXin Li @param root_part: current root partition 2136*9c5db199SXin Li """ 2137*9c5db199SXin Li if not root_part: 2138*9c5db199SXin Li root_part = get_root_partition() 2139*9c5db199SXin Li current_kernel_map = {'3': '2', '5': '4'} 2140*9c5db199SXin Li return root_part[:-1] + current_kernel_map[root_part[-1]] 2141*9c5db199SXin Li 2142*9c5db199SXin Li 2143*9c5db199SXin Lidef get_free_kernel_partition(root_part=None): 2144*9c5db199SXin Li """ 2145*9c5db199SXin Li return currently unused kernel partition 2146*9c5db199SXin Li Example: return /dev/sda4 for falco booted from usb 2147*9c5db199SXin Li 2148*9c5db199SXin Li @param root_part: current root partition 2149*9c5db199SXin Li """ 2150*9c5db199SXin Li kernel_part = get_kernel_partition(root_part) 2151*9c5db199SXin Li spare_kernel_map = {'2': '4', '4': '2'} 2152*9c5db199SXin Li return kernel_part[:-1] + spare_kernel_map[kernel_part[-1]] 2153*9c5db199SXin Li 2154*9c5db199SXin Li 2155*9c5db199SXin Lidef is_booted_from_internal_disk(): 2156*9c5db199SXin Li """Return True if boot from internal disk. False, otherwise.""" 2157*9c5db199SXin Li return get_root_device() == get_fixed_dst_drive() 2158*9c5db199SXin Li 2159*9c5db199SXin Li 2160*9c5db199SXin Lidef get_ui_use_flags(): 2161*9c5db199SXin Li """Parses the USE flags as listed in /etc/ui_use_flags.txt. 2162*9c5db199SXin Li 2163*9c5db199SXin Li @return: A list of flag strings found in the ui use flags file. 2164*9c5db199SXin Li """ 2165*9c5db199SXin Li flags = [] 2166*9c5db199SXin Li for flag in utils.read_file(_UI_USE_FLAGS_FILE_PATH).splitlines(): 2167*9c5db199SXin Li # Removes everything after the '#'. 2168*9c5db199SXin Li flag_before_comment = flag.split('#')[0].strip() 2169*9c5db199SXin Li if len(flag_before_comment) != 0: 2170*9c5db199SXin Li flags.append(flag_before_comment) 2171*9c5db199SXin Li 2172*9c5db199SXin Li return flags 2173*9c5db199SXin Li 2174*9c5db199SXin Li 2175*9c5db199SXin Lidef graphics_platform(): 2176*9c5db199SXin Li """ 2177*9c5db199SXin Li Return a string identifying the graphics platform, 2178*9c5db199SXin Li e.g. 'glx' or 'x11_egl' or 'gbm' 2179*9c5db199SXin Li """ 2180*9c5db199SXin Li return 'null' 2181*9c5db199SXin Li 2182*9c5db199SXin Li 2183*9c5db199SXin Lidef graphics_api(): 2184*9c5db199SXin Li """Return a string identifying the graphics api, e.g. gl or gles2.""" 2185*9c5db199SXin Li use_flags = get_ui_use_flags() 2186*9c5db199SXin Li if 'opengles' in use_flags: 2187*9c5db199SXin Li return 'gles2' 2188*9c5db199SXin Li return 'gl' 2189*9c5db199SXin Li 2190*9c5db199SXin Li 2191*9c5db199SXin Lidef is_package_installed(package): 2192*9c5db199SXin Li """Check if a package is installed already. 2193*9c5db199SXin Li 2194*9c5db199SXin Li @return: True if the package is already installed, otherwise return False. 2195*9c5db199SXin Li """ 2196*9c5db199SXin Li try: 2197*9c5db199SXin Li utils.run(_CHECK_PACKAGE_INSTALLED_COMMAND % package) 2198*9c5db199SXin Li return True 2199*9c5db199SXin Li except error.CmdError: 2200*9c5db199SXin Li logging.warning('Package %s is not installed.', package) 2201*9c5db199SXin Li return False 2202*9c5db199SXin Li 2203*9c5db199SXin Li 2204*9c5db199SXin Lidef is_python_package_installed(package): 2205*9c5db199SXin Li """Check if a Python package is installed already. 2206*9c5db199SXin Li 2207*9c5db199SXin Li @return: True if the package is already installed, otherwise return False. 2208*9c5db199SXin Li """ 2209*9c5db199SXin Li try: 2210*9c5db199SXin Li __import__(package) 2211*9c5db199SXin Li return True 2212*9c5db199SXin Li except ImportError: 2213*9c5db199SXin Li logging.warning('Python package %s is not installed.', package) 2214*9c5db199SXin Li return False 2215*9c5db199SXin Li 2216*9c5db199SXin Li 2217*9c5db199SXin Lidef run_sql_cmd(server, user, password, command, database=''): 2218*9c5db199SXin Li """Run the given sql command against the specified database. 2219*9c5db199SXin Li 2220*9c5db199SXin Li @param server: Hostname or IP address of the MySQL server. 2221*9c5db199SXin Li @param user: User name to log in the MySQL server. 2222*9c5db199SXin Li @param password: Password to log in the MySQL server. 2223*9c5db199SXin Li @param command: SQL command to run. 2224*9c5db199SXin Li @param database: Name of the database to run the command. Default to empty 2225*9c5db199SXin Li for command that does not require specifying database. 2226*9c5db199SXin Li 2227*9c5db199SXin Li @return: The stdout of the command line. 2228*9c5db199SXin Li """ 2229*9c5db199SXin Li cmd = ('mysql -u%s -p%s --host %s %s -e "%s"' % 2230*9c5db199SXin Li (user, password, server, database, command)) 2231*9c5db199SXin Li # Set verbose to False so the command line won't be logged, as it includes 2232*9c5db199SXin Li # database credential. 2233*9c5db199SXin Li return utils.run(cmd, verbose=False).stdout 2234*9c5db199SXin Li 2235*9c5db199SXin Li 2236*9c5db199SXin Lidef strip_non_printable(s): 2237*9c5db199SXin Li """Strip non printable characters from string. 2238*9c5db199SXin Li 2239*9c5db199SXin Li @param s: Input string 2240*9c5db199SXin Li 2241*9c5db199SXin Li @return: The input string with only printable characters. 2242*9c5db199SXin Li """ 2243*9c5db199SXin Li return ''.join(x for x in s if x in string.printable) 2244*9c5db199SXin Li 2245*9c5db199SXin Li 2246*9c5db199SXin Lidef recursive_func(obj, func, types, sequence_types=(list, tuple, set), 2247*9c5db199SXin Li dict_types=(dict,), fix_num_key=False): 2248*9c5db199SXin Li """Apply func to obj recursively. 2249*9c5db199SXin Li 2250*9c5db199SXin Li This function traverses recursively through any sequence-like and 2251*9c5db199SXin Li dict-like elements in obj. 2252*9c5db199SXin Li 2253*9c5db199SXin Li @param obj: the object to apply the function func recursively. 2254*9c5db199SXin Li @param func: the function to invoke. 2255*9c5db199SXin Li @param types: the target types in the object to apply func. 2256*9c5db199SXin Li @param sequence_types: the sequence types in python. 2257*9c5db199SXin Li @param dict_types: the dict types in python. 2258*9c5db199SXin Li @param fix_num_key: to indicate if the key of a dict should be 2259*9c5db199SXin Li converted from str type to a number, int or float, type. 2260*9c5db199SXin Li It is a culprit of json that it always treats the key of 2261*9c5db199SXin Li a dict as string. 2262*9c5db199SXin Li Refer to https://docs.python.org/2/library/json.html 2263*9c5db199SXin Li for more information. 2264*9c5db199SXin Li 2265*9c5db199SXin Li @return: the result object after applying the func recursively. 2266*9c5db199SXin Li """ 2267*9c5db199SXin Li def ancestors(obj, types): 2268*9c5db199SXin Li """Any ancestor of the object class is a subclass of the types? 2269*9c5db199SXin Li 2270*9c5db199SXin Li @param obj: the object to apply the function func. 2271*9c5db199SXin Li @param types: the target types of the object. 2272*9c5db199SXin Li 2273*9c5db199SXin Li @return: True if any ancestor class of the obj is found in types; 2274*9c5db199SXin Li False otherwise. 2275*9c5db199SXin Li """ 2276*9c5db199SXin Li return any([issubclass(anc, types) for anc in type(obj).__mro__]) 2277*9c5db199SXin Li 2278*9c5db199SXin Li if isinstance(obj, sequence_types) or ancestors(obj, sequence_types): 2279*9c5db199SXin Li result_lst = [recursive_func(elm, func, types, fix_num_key=fix_num_key) 2280*9c5db199SXin Li for elm in obj] 2281*9c5db199SXin Li # Convert the result list to the object's original sequence type. 2282*9c5db199SXin Li return type(obj)(result_lst) 2283*9c5db199SXin Li elif isinstance(obj, dict_types) or ancestors(obj, dict_types): 2284*9c5db199SXin Li result_lst = [ 2285*9c5db199SXin Li (recursive_func(key, func, types, fix_num_key=fix_num_key), 2286*9c5db199SXin Li recursive_func(value, func, types, fix_num_key=fix_num_key)) 2287*9c5db199SXin Li for (key, value) in obj.items()] 2288*9c5db199SXin Li # Convert the result list to the object's original dict type. 2289*9c5db199SXin Li return type(obj)(result_lst) 2290*9c5db199SXin Li # Here are the basic types. 2291*9c5db199SXin Li elif isinstance(obj, types) or ancestors(obj, types): 2292*9c5db199SXin Li if fix_num_key: 2293*9c5db199SXin Li # Check if this is a int or float 2294*9c5db199SXin Li try: 2295*9c5db199SXin Li result_obj = int(obj) 2296*9c5db199SXin Li return result_obj 2297*9c5db199SXin Li except ValueError: 2298*9c5db199SXin Li try: 2299*9c5db199SXin Li result_obj = float(obj) 2300*9c5db199SXin Li return result_obj 2301*9c5db199SXin Li except ValueError: 2302*9c5db199SXin Li pass 2303*9c5db199SXin Li try: 2304*9c5db199SXin Li result_obj = func(obj) 2305*9c5db199SXin Li return result_obj 2306*9c5db199SXin Li except UnicodeEncodeError: 2307*9c5db199SXin Li pass 2308*9c5db199SXin Li else: 2309*9c5db199SXin Li return obj 2310*9c5db199SXin Li 2311*9c5db199SXin Li 2312*9c5db199SXin Lidef is_python2(): 2313*9c5db199SXin Li """True if it is interpreted by Python 2.""" 2314*9c5db199SXin Li return sys.version_info.major == 2 2315*9c5db199SXin Li 2316*9c5db199SXin Li 2317*9c5db199SXin Lidef base64_recursive_encode(obj): 2318*9c5db199SXin Li """Apply base64 encode recursively into the obj structure. 2319*9c5db199SXin Li 2320*9c5db199SXin Li Python 2 case: 2321*9c5db199SXin Li Most of the string-like types could be traced to basestring and bytearray 2322*9c5db199SXin Li as follows: 2323*9c5db199SXin Li str: basestring 2324*9c5db199SXin Li bytes: basestring 2325*9c5db199SXin Li dbus.String: basestring 2326*9c5db199SXin Li dbus.Signature: basestring 2327*9c5db199SXin Li dbus.ByteArray: basestring 2328*9c5db199SXin Li 2329*9c5db199SXin Li Note that all the above types except dbus.String could be traced back to 2330*9c5db199SXin Li str. In order to cover dbus.String, basestring is used as the ancestor 2331*9c5db199SXin Li class for string-like types. 2332*9c5db199SXin Li 2333*9c5db199SXin Li Python 3 case: 2334*9c5db199SXin Li Perform base64 encode on bytes element only. 2335*9c5db199SXin Li 2336*9c5db199SXin Li The other type that needs encoding with base64 in a structure includes 2337*9c5db199SXin Li bytearray: bytearray 2338*9c5db199SXin Li 2339*9c5db199SXin Li The sequence types include (list, tuple, set). The dbus.Array is also 2340*9c5db199SXin Li covered as 2341*9c5db199SXin Li dbus.Array: list 2342*9c5db199SXin Li 2343*9c5db199SXin Li The base dictionary type is dict. The dbus.Dictionary is also covered as 2344*9c5db199SXin Li dbus.Dictionary: dict 2345*9c5db199SXin Li 2346*9c5db199SXin Li An example code and output look like 2347*9c5db199SXin Li in Python 2: 2348*9c5db199SXin Li obj = {'a': 10, 'b': 'hello', 2349*9c5db199SXin Li 'c': [100, 200, bytearray(b'\xf0\xf1\xf2\xf3\xf4')], 2350*9c5db199SXin Li 'd': {784: bytearray(b'@\x14\x01P'), 2351*9c5db199SXin Li 78.0: bytearray(b'\x10\x05\x0b\x10\xb2\x1b\x00')}} 2352*9c5db199SXin Li encode_obj = base64_recursive_encode(obj) 2353*9c5db199SXin Li decode_obj = base64_recursive_decode(encode_obj) 2354*9c5db199SXin Li 2355*9c5db199SXin Li encode_obj: {'YQ==': 10, 2356*9c5db199SXin Li 'Yw==': [100, 200, '8PHy8/Q='], 2357*9c5db199SXin Li 'Yg==': 'aGVsbG8=' 2358*9c5db199SXin Li 'ZA==': {784: 'QBQBUA==', 78.0: 'EAULELIbAA=='}} 2359*9c5db199SXin Li decode_obj: {'a': 10, 2360*9c5db199SXin Li 'c': [100, 200, '\xf0\xf1\xf2\xf3\xf4'], 2361*9c5db199SXin Li 'b': 'hello', 2362*9c5db199SXin Li 'd': {784: '@\x14\x01P', 2363*9c5db199SXin Li 78.0: '\x10\x05\x0b\x10\xb2\x1b\x00'}} 2364*9c5db199SXin Li 2365*9c5db199SXin Li in Python 3: 2366*9c5db199SXin Li obj = {'a': 10, 'b': 'hello', 2367*9c5db199SXin Li 'c': [100, 200, bytearray(b'\xf0\xf1\xf2\xf3\xf4')], 2368*9c5db199SXin Li 'd': {784: bytearray(b'@\x14\x01P'), 2369*9c5db199SXin Li 78.0: bytearray(b'\x10\x05\x0b\x10\xb2\x1b\x00')}} 2370*9c5db199SXin Li encode_obj = base64_recursive_encode(obj) 2371*9c5db199SXin Li decode_obj = base64_recursive_decode(encode_obj) 2372*9c5db199SXin Li 2373*9c5db199SXin Li encode_obj: {'a': 10, 2374*9c5db199SXin Li 'c': [100, 200, '8PHy8/Q='], 2375*9c5db199SXin Li 'b': 'hello', 2376*9c5db199SXin Li 'ZA==': {784: 'QBQBUA==', 78.0: 'EAULELIbAA=='}} 2377*9c5db199SXin Li decode_obj: {'a': 10, 2378*9c5db199SXin Li 'c': [100, 200, '\xf0\xf1\xf2\xf3\xf4'], 2379*9c5db199SXin Li 'b': 'hello', 2380*9c5db199SXin Li 'd': {784: '@\x14\x01P', 2381*9c5db199SXin Li 78.0: '\x10\x05\x0b\x10\xb2\x1b\x00'}} 2382*9c5db199SXin Li 2383*9c5db199SXin Li @param obj: the object to apply base64 encoding recursively. 2384*9c5db199SXin Li 2385*9c5db199SXin Li @return: the base64 encoded object. 2386*9c5db199SXin Li """ 2387*9c5db199SXin Li if is_python2(): 2388*9c5db199SXin Li encode_types = (six.string_types, bytearray) 2389*9c5db199SXin Li else: 2390*9c5db199SXin Li encode_types = (bytes, bytearray) 2391*9c5db199SXin Li 2392*9c5db199SXin Li return recursive_func(obj, base64.standard_b64encode, encode_types) 2393*9c5db199SXin Li 2394*9c5db199SXin Li 2395*9c5db199SXin Lidef base64_recursive_decode(obj): 2396*9c5db199SXin Li """Apply base64 decode recursively into the obj structure. 2397*9c5db199SXin Li 2398*9c5db199SXin Li @param obj: the object to apply base64 decoding recursively. 2399*9c5db199SXin Li 2400*9c5db199SXin Li @return: the base64 decoded object. 2401*9c5db199SXin Li """ 2402*9c5db199SXin Li if is_python2(): 2403*9c5db199SXin Li decode_types = (six.string_types, ) 2404*9c5db199SXin Li else: 2405*9c5db199SXin Li decode_types = (bytes, bytearray) 2406*9c5db199SXin Li return recursive_func(obj, base64.standard_b64decode, decode_types, 2407*9c5db199SXin Li fix_num_key=True) 2408*9c5db199SXin Li 2409*9c5db199SXin Li 2410*9c5db199SXin Lidef bytes_to_str_recursive(obj): 2411*9c5db199SXin Li """Converts obj's bytes elements to str. 2412*9c5db199SXin Li 2413*9c5db199SXin Li It focuses on elements in the input obj whose type is bytes or byearray. 2414*9c5db199SXin Li For the elements, it first guesses the encoding of the input bytes (or 2415*9c5db199SXin Li bytearray) and decode the bytes to str. For unknown encoding, try UTF-8. 2416*9c5db199SXin Li If it still fails, converts the element as "ERROR_DECODE_BYTES_TO_STR". 2417*9c5db199SXin Li 2418*9c5db199SXin Li @param obj: an object. 2419*9c5db199SXin Li 2420*9c5db199SXin Li @return: an object that converts the input object's bytes elements to 2421*9c5db199SXin Li strings. 2422*9c5db199SXin Li """ 2423*9c5db199SXin Li # Python 2's bytes is equivalent to string. Do nothing. 2424*9c5db199SXin Li if is_python2(): 2425*9c5db199SXin Li return obj 2426*9c5db199SXin Li 2427*9c5db199SXin Li def bytes_to_str(bytes_obj): 2428*9c5db199SXin Li guessed_encoding = chardet.detect(bytes_obj).get('encoding') 2429*9c5db199SXin Li if not guessed_encoding: 2430*9c5db199SXin Li guessed_encoding = 'utf-8' 2431*9c5db199SXin Li try: 2432*9c5db199SXin Li return bytes_obj.decode(guessed_encoding, 'backslashreplace') 2433*9c5db199SXin Li except: 2434*9c5db199SXin Li logging.info("Failed to decode bytes %r to str with encoding %r", 2435*9c5db199SXin Li bytes_obj, guessed_encoding) 2436*9c5db199SXin Li return 'ERROR_DECODE_BYTES_TO_STR' 2437*9c5db199SXin Li 2438*9c5db199SXin Li return recursive_func(obj, bytes_to_str, (bytes, bytearray)) 2439