blob: 33beabd62ec4869a6081c59b15ebf07d30b4307d [file] [log] [blame]
Dan Shic1d263b2013-10-04 17:31:38 -07001#pylint: disable-msg=C0111
2
Gaurav Shaha7fb8962011-08-16 15:06:32 -07003# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Daniel Erat3e3f7f42010-03-29 17:19:14 -07004# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
Elly Jones2f0ebba2011-10-27 13:43:20 -04007import logging, os, platform, re, signal, tempfile, time, uuid
Daniel Erat3e3f7f42010-03-29 17:19:14 -07008from autotest_lib.client.common_lib import error
Vadim Bendeburye7970922011-04-07 17:07:37 -07009from autotest_lib.client.common_lib import utils
Stéphane Marchesinbf676172014-04-25 16:11:33 -070010from autotest_lib.client.bin import base_utils
Daniel Erat3e3f7f42010-03-29 17:19:14 -070011
rgindaf25f73f2010-04-07 14:55:25 -070012class TimeoutError(error.TestError):
13 """Error raised when we time out when waiting on a condition."""
David Jamesd51ac9c2011-09-10 00:45:24 -070014 pass
rgindaf25f73f2010-04-07 14:55:25 -070015
16
Vadim Bendeburye7970922011-04-07 17:07:37 -070017class Crossystem(object):
18 """A wrapper for the crossystem utility."""
19
20 def __init__(self, client):
21 self.cros_system_data = {}
22 self._client = client
23
24 def init(self):
25 self.cros_system_data = {}
26 (_, fname) = tempfile.mkstemp()
27 f = open(fname, 'w')
28 self._client.run('crossystem', stdout_tee=f)
29 f.close()
30 text = utils.read_file(fname)
31 for line in text.splitlines():
32 assignment_string = line.split('#')[0]
33 if not assignment_string.count('='):
34 continue
35 (name, value) = assignment_string.split('=', 1)
36 self.cros_system_data[name.strip()] = value.strip()
37 os.remove(fname)
38
39 def __getattr__(self, name):
40 """
41 Retrieve a crosssystem attribute.
42
43 The call crossystemobject.name() will return the crossystem reported
44 string.
45 """
46 return lambda : self.cros_system_data[name]
47
48
Chris Masoneaf859092012-11-19 16:44:44 -080049def get_oldest_pid_by_name(name):
50 """
51 Return the oldest pid of a process whose name perfectly matches |name|.
52
53 name is an egrep expression, which will be matched against the entire name
54 of processes on the system. For example:
55
56 get_oldest_pid_by_name('chrome')
57
58 on a system running
59 8600 ? 00:00:04 chrome
60 8601 ? 00:00:00 chrome
61 8602 ? 00:00:00 chrome-sandbox
62
63 would return 8600, as that's the oldest process that matches.
64 chrome-sandbox would not be matched.
65
66 Arguments:
67 name: egrep expression to match. Will be anchored at the beginning and
68 end of the match string.
69
70 Returns:
71 pid as an integer, or None if one cannot be found.
72
73 Raises:
74 ValueError if pgrep returns something odd.
75 """
76 str_pid = utils.system_output(
77 'pgrep -o ^%s$' % name, ignore_status=True).rstrip()
78 if str_pid:
79 return int(str_pid)
80
81
Dan Shi03c3e442013-10-22 14:41:23 -070082def get_oldest_by_name(name):
83 """Return pid and command line of oldest process whose name matches |name|.
84
85 @param name: egrep expression to match desired process name.
86 @return: A tuple of (pid, command_line) of the oldest process whose name
87 matches |name|.
88
89 """
90 pid = get_oldest_pid_by_name(name)
91 if pid:
92 command_line = utils.system_output('ps -p %i -o command=' % pid,
93 ignore_status=True).rstrip()
94 return (pid, command_line)
95
96
Dan Shic1d263b2013-10-04 17:31:38 -070097def get_chrome_remote_debugging_port():
98 """Returns remote debugging port for Chrome.
99
100 Parse chrome process's command line argument to get the remote debugging
101 port.
102 """
103 pid, command = get_oldest_by_name('chrome')
104 matches = re.search('--remote-debugging-port=([0-9]+)', command)
105 if matches:
106 return int(matches.group(1))
107
108
Rohit Makasanac018b972013-07-29 21:25:39 +0530109def get_process_list(name, command_line=None):
110 """
111 Return the list of pid for matching process |name command_line|.
112
113 on a system running
114 31475 ? 0:06 /opt/google/chrome/chrome --allow-webui-compositing -
115 31478 ? 0:00 /opt/google/chrome/chrome-sandbox /opt/google/chrome/
116 31485 ? 0:00 /opt/google/chrome/chrome --type=zygote --log-level=1
117 31532 ? 1:05 /opt/google/chrome/chrome --type=renderer
118
119 get_process_list('chrome')
120 would return ['31475', '31485', '31532']
121
122 get_process_list('chrome', '--type=renderer')
123 would return ['31532']
124
125 Arguments:
126 name: process name to search for. If command_line is provided, name is
127 matched against full command line. If command_line is not provided,
128 name is only matched against the process name.
129 command line: when command line is passed, the full process command line
130 is used for matching.
131
132 Returns:
133 list of PIDs of the matching processes.
134
135 """
136 # TODO(rohitbm) crbug.com/268861
137 flag = '-x' if not command_line else '-f'
138 name = '\'%s.*%s\'' % (name, command_line) if command_line else name
139 str_pid = utils.system_output(
140 'pgrep %s %s' % (flag, name), ignore_status=True).rstrip()
141 return str_pid
142
143
David Jamesd51ac9c2011-09-10 00:45:24 -0700144def nuke_process_by_name(name, with_prejudice=False):
145 try:
Chris Masoneaf859092012-11-19 16:44:44 -0800146 pid = get_oldest_pid_by_name(name)
David Jamesd51ac9c2011-09-10 00:45:24 -0700147 except Exception as e:
148 logging.error(e)
149 return
Chris Masone7d6af682013-08-06 13:47:44 -0700150 if pid is None:
151 raise error.AutoservPidAlreadyDeadError(
152 'No process matching %s.' % name)
David Jamesd51ac9c2011-09-10 00:45:24 -0700153 if with_prejudice:
154 utils.nuke_pid(pid, [signal.SIGKILL])
155 else:
156 utils.nuke_pid(pid)
157
158
Daniel Erat3e3f7f42010-03-29 17:19:14 -0700159def poll_for_condition(
rgindaf25f73f2010-04-07 14:55:25 -0700160 condition, exception=None, timeout=10, sleep_interval=0.1, desc=None):
Daniel Erat3e3f7f42010-03-29 17:19:14 -0700161 """Poll until a condition becomes true.
162
Jon Salz4f646a32011-11-30 14:42:51 +0800163 Arguments:
164 condition: function taking no args and returning bool
165 exception: exception to throw if condition doesn't become true
166 timeout: maximum number of seconds to wait
167 sleep_interval: time to sleep between polls
168 desc: description of default TimeoutError used if 'exception' is None
169
170 Returns:
171 The true value that caused the poll loop to terminate.
Daniel Erat3e3f7f42010-03-29 17:19:14 -0700172
173 Raises:
rgindaf25f73f2010-04-07 14:55:25 -0700174 'exception' arg if supplied; site_utils.TimeoutError otherwise
Daniel Erat3e3f7f42010-03-29 17:19:14 -0700175 """
176 start_time = time.time()
177 while True:
Jon Salz4f646a32011-11-30 14:42:51 +0800178 value = condition()
179 if value:
180 return value
Daniel Erat3e3f7f42010-03-29 17:19:14 -0700181 if time.time() + sleep_interval - start_time > timeout:
rgindaf25f73f2010-04-07 14:55:25 -0700182 if exception:
Gaurav Shaha7fb8962011-08-16 15:06:32 -0700183 logging.error(exception)
rgindaf25f73f2010-04-07 14:55:25 -0700184 raise exception
185
186 if desc:
187 desc = 'Timed out waiting for condition: %s' % desc
188 else:
189 desc = 'Timed out waiting for unnamed condition'
Gaurav Shaha7fb8962011-08-16 15:06:32 -0700190 logging.error(desc)
Mitsuru Oshima5d3e4542010-08-18 13:46:06 -0700191 raise TimeoutError, desc
rgindaf25f73f2010-04-07 14:55:25 -0700192
Daniel Erat3e3f7f42010-03-29 17:19:14 -0700193 time.sleep(sleep_interval)
Thieu Le1904d002010-11-30 17:10:24 -0800194
195
196def save_vm_state(checkpoint):
197 """Saves the current state of the virtual machine.
198
199 This function is a NOOP if the test is not running under a virtual machine
200 with the USB serial port redirected.
201
202 Arguments:
203 checkpoint - Name used to identify this state
204
205 Returns:
206 None
207 """
208 # The QEMU monitor has been redirected to the guest serial port located at
209 # /dev/ttyUSB0. To save the state of the VM, we just send the 'savevm'
210 # command to the serial port.
211 proc = platform.processor()
212 if 'QEMU' in proc and os.path.exists('/dev/ttyUSB0'):
Dan Shic1d263b2013-10-04 17:31:38 -0700213 logging.info('Saving VM state "%s"', checkpoint)
Thieu Le1904d002010-11-30 17:10:24 -0800214 serial = open('/dev/ttyUSB0', 'w')
215 serial.write("savevm %s\r\n" % checkpoint)
Dan Shic1d263b2013-10-04 17:31:38 -0700216 logging.info('Done saving VM state "%s"', checkpoint)
Mandeep Singh Baines142ac8d2011-02-18 13:31:08 -0800217
218
219def check_raw_dmesg(dmesg, message_level, whitelist):
220 """Checks dmesg for unexpected warnings.
221
222 This function parses dmesg for message with message_level <= message_level
223 which do not appear in the whitelist.
224
225 Arguments:
226 dmesg - string containing raw dmesg buffer
227 message_level - minimum message priority to check
228 whitelist - messages to ignore
229
230 Returns:
231 List of unexpected warnings
232 """
Vadim Bendeburye7970922011-04-07 17:07:37 -0700233 whitelist_re = re.compile(r'(%s)' % '|'.join(whitelist))
Mandeep Singh Baines142ac8d2011-02-18 13:31:08 -0800234 unexpected = []
235 for line in dmesg.splitlines():
236 if int(line[1]) <= message_level:
Vadim Bendeburye7970922011-04-07 17:07:37 -0700237 stripped_line = line.split('] ', 1)[1]
238 if whitelist_re.search(stripped_line):
239 continue
240 unexpected.append(stripped_line)
Mandeep Singh Baines142ac8d2011-02-18 13:31:08 -0800241 return unexpected
Vadim Bendebury29916f22011-04-13 10:54:47 -0700242
243def verify_mesg_set(mesg, regex, whitelist):
244 """Verifies that the exact set of messages are present in a text.
245
246 This function finds all strings in the text matching a certain regex, and
247 then verifies that all expected strings are present in the set, and no
248 unexpected strings are there.
249
250 Arguments:
251 mesg - the mutiline text to be scanned
252 regex - regular expression to match
253 whitelist - messages to find in the output, a list of strings
254 (potentially regexes) to look for in the filtered output. All these
255 strings must be there, and no other strings should be present in the
256 filtered output.
257
258 Returns:
259 string of inconsistent findings (i.e. an empty string on success).
260 """
261
262 rv = []
263
264 missing_strings = []
265 present_strings = []
266 for line in mesg.splitlines():
267 if not re.search(r'%s' % regex, line):
268 continue
269 present_strings.append(line.split('] ', 1)[1])
270
271 for string in whitelist:
272 for present_string in list(present_strings):
273 if re.search(r'^%s$' % string, present_string):
274 present_strings.remove(present_string)
275 break
276 else:
277 missing_strings.append(string)
278
279 if present_strings:
280 rv.append('unexpected strings:')
281 rv.extend(present_strings)
282 if missing_strings:
283 rv.append('missing strings:')
284 rv.extend(missing_strings)
285
286 return '\n'.join(rv)
Ahmad Shariff8e92622011-05-24 12:37:39 -0700287
288
Mike Frysingere72f7e42012-03-16 14:49:11 -0400289def target_is_pie():
290 """Returns whether the toolchain produces a PIE (position independent
Ahmad Shariff8e92622011-05-24 12:37:39 -0700291 executable) by default.
292
293 Arguments:
294 None
295
296 Returns:
Mike Frysingere72f7e42012-03-16 14:49:11 -0400297 True if the target toolchain produces a PIE by default.
Ahmad Shariff8e92622011-05-24 12:37:39 -0700298 False otherwise.
299 """
300
301
Mike Frysingere72f7e42012-03-16 14:49:11 -0400302 command = 'echo | ${CC} -E -dD -P - | grep -i pie'
Ahmad Shariff8e92622011-05-24 12:37:39 -0700303 result = utils.system_output(command, retain_output=True,
304 ignore_status=True)
Mike Frysingere72f7e42012-03-16 14:49:11 -0400305 if re.search('#define __PIE__', result):
Ahmad Shariff8e92622011-05-24 12:37:39 -0700306 return True
307 else:
308 return False
Elly Jones686c2f42011-10-24 16:45:07 -0400309
Sonny Rao172edad2012-02-07 23:23:58 +0000310def target_is_x86():
311 """Returns whether the toolchain produces an x86 object
312
313 Arguments:
314 None
315
316 Returns:
317 True if the target toolchain produces an x86 object
318 False otherwise.
319 """
320
321
Mike Frysingere72f7e42012-03-16 14:49:11 -0400322 command = 'echo | ${CC} -E -dD -P - | grep -i 86'
Sonny Rao172edad2012-02-07 23:23:58 +0000323 result = utils.system_output(command, retain_output=True,
324 ignore_status=True)
Mike Frysingere72f7e42012-03-16 14:49:11 -0400325 if re.search('__i386__', result) or re.search('__x86_64__', result):
Sonny Rao172edad2012-02-07 23:23:58 +0000326 return True
327 else:
328 return False
329
Elly Jones686c2f42011-10-24 16:45:07 -0400330def mounts():
331 ret = []
332 for line in file('/proc/mounts'):
333 m = re.match(r'(?P<src>\S+) (?P<dest>\S+) (?P<type>\S+) (?P<opts>\S+).*', line)
334 if m:
335 ret.append(m.groupdict())
336 return ret
337
338def is_mountpoint(path):
339 return path in [ m['dest'] for m in mounts() ]
340
341def require_mountpoint(path):
342 """
343 Raises an exception if path is not a mountpoint.
344 """
345 if not is_mountpoint(path):
346 raise error.TestFail('Path not mounted: "%s"' % path)
Elly Jones2f0ebba2011-10-27 13:43:20 -0400347
348def random_username():
349 return str(uuid.uuid4()) + '@example.com'
Simran Basic6f1f7a2012-10-16 10:47:46 -0700350
351
352def parse_cmd_output(command, run_method=utils.run):
353 """Runs a command on a host object to retrieve host attributes.
354
355 The command should output to stdout in the format of:
356 <key> = <value> # <optional_comment>
357
358
359 @param command: Command to execute on the host.
360 @param run_method: Function to use to execute the command. Defaults to
361 utils.run so that the command will be executed locally.
362 Can be replace with a host.run call so that it will
363 execute on a DUT or external machine. Method must accept
364 a command argument, stdout_tee and stderr_tee args and
365 return a result object with a string attribute stdout
366 which will be parsed.
367
368 @returns a dictionary mapping host attributes to their values.
369 """
370 result = {}
371 # Suppresses stdout so that the files are not printed to the logs.
372 cmd_result = run_method(command, stdout_tee=None, stderr_tee=None)
373 for line in cmd_result.stdout.splitlines():
374 # Lines are of the format "<key> = <value> # <comment>"
375 key_value = re.match('^\s*(?P<key>[^ ]+)\s*=\s*(?P<value>[^ ]+)'
376 '(?:\s*#.*)?$', line)
377 if key_value:
378 result[key_value.group('key')] = key_value.group('value')
Chris Masoneaf859092012-11-19 16:44:44 -0800379 return result
Mike Truty77f06bc2013-03-30 09:43:05 -0500380
381
382def set_from_keyval_output(out, delimiter=' '):
383 """Parse delimiter-separated key-val output into a set of tuples.
384
385 Output is expected to be multiline text output from a command.
386 Stuffs the key-vals into tuples in a set to be later compared.
387
388 e.g. deactivated 0
389 disableForceClear 0
390 ==> set(('deactivated', '0'), ('disableForceClear', '0'))
391
392 @param out: multiple lines of space-separated key-val pairs.
393 @param delimiter: character that separates key from val. Usually a
394 space but may be '=' or something else.
395 @return set of key-val tuples.
396 """
397 results = set()
398 kv_match_re = re.compile('([^ ]+)%s(.*)' % delimiter)
399 for linecr in out.splitlines():
400 match = kv_match_re.match(linecr.strip())
401 if match:
402 results.add((match.group(1), match.group(2)))
403 return results
Ilja H. Friedel42052a22014-03-05 22:54:01 -0800404
405
406def get_cpu_usage():
407 """Returns machine's CPU usage.
408
409 This function uses /proc/stat to identify CPU usage.
410 Returns:
411 A dictionary with 'user', 'nice', 'system' and 'idle' values.
412 Sample dictionary:
413 {
414 'user': 254544,
415 'nice': 9,
416 'system': 254768,
417 'idle': 2859878,
418 }
419 """
420 proc_stat = open('/proc/stat')
421 cpu_usage_str = proc_stat.readline().split()
422 proc_stat.close()
423 return {
424 'user': int(cpu_usage_str[1]),
425 'nice': int(cpu_usage_str[2]),
426 'system': int(cpu_usage_str[3]),
427 'idle': int(cpu_usage_str[4])
428 }
429
430
431def compute_active_cpu_time(cpu_usage_start, cpu_usage_end):
432 """Computes the fraction of CPU time spent non-idling.
433
434 This function should be invoked using before/after values from calls to
435 get_cpu_usage().
436 """
437 time_active_end = (cpu_usage_end['user'] + cpu_usage_end['nice'] +
438 cpu_usage_end['system'])
439 time_active_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
440 cpu_usage_start['system'])
441 total_time_end = (cpu_usage_end['user'] + cpu_usage_end['nice'] +
442 cpu_usage_end['system'] + cpu_usage_end['idle'])
443 total_time_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
444 cpu_usage_start['system'] + cpu_usage_start['idle'])
445 return ((float(time_active_end) - time_active_start) /
446 (total_time_end - total_time_start))
447
448
449def is_pgo_mode():
450 return 'USE_PGO' in os.environ
451
452
453def wait_for_idle_cpu(timeout, utilization):
454 """Waits for the CPU to become idle (< utilization).
455
456 Args:
457 timeout: The longest time in seconds to wait before throwing an error.
458 utilization: The CPU usage below which the system should be considered
459 idle (between 0 and 1.0 independent of cores/hyperthreads).
460 """
461 time_passed = 0.0
462 fraction_active_time = 1.0
463 sleep_time = 1
464 logging.info('Starting to wait up to %.1fs for idle CPU...', timeout)
465 while fraction_active_time >= utilization:
466 cpu_usage_start = get_cpu_usage()
467 # Split timeout interval into not too many chunks to limit log spew.
468 # Start at 1 second, increase exponentially
469 time.sleep(sleep_time)
470 time_passed += sleep_time
471 sleep_time = min(16.0, 2.0 * sleep_time)
472 cpu_usage_end = get_cpu_usage()
473 fraction_active_time = \
474 compute_active_cpu_time(cpu_usage_start, cpu_usage_end)
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700475 logging.info('After waiting %.1fs CPU utilization is %.3f.',
Ilja H. Friedel42052a22014-03-05 22:54:01 -0800476 time_passed, fraction_active_time)
477 if time_passed > timeout:
478 logging.warning('CPU did not become idle.')
479 log_process_activity()
480 # crosbug.com/37389
481 if is_pgo_mode():
482 logging.info('Still continuing because we are in PGO mode.')
483 return True
484
485 return False
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700486 logging.info('Wait for idle CPU took %.1fs (utilization = %.3f).',
Ilja H. Friedel42052a22014-03-05 22:54:01 -0800487 time_passed, fraction_active_time)
488 return True
489
490
491def log_process_activity():
492 """Logs the output of top.
493
494 Useful to debug performance tests and to find runaway processes.
495 """
496 logging.info('Logging current process activity using top.')
497 cmd = 'top -b -n1 -c'
498 output = utils.run(cmd)
499 logging.info(output)
500
501
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700502def wait_for_cool_machine():
Ilja Friedel977aadd2014-04-29 20:45:03 -0700503 """
504 A simple heuristic to wait for a machine to cool.
505 The code looks a bit 'magic', but we don't know ambient temperature
506 nor machine characteristics and still would like to return the caller
507 a machine that cooled down as much as reasonably possible.
508 """
509 temperature = get_current_temperature_max()
510 # We got here with a cold machine, return immediately. This should be the
511 # most common case.
512 if temperature < 50:
513 return True
514 logging.info('Got a hot machine of %dC. Sleeping 1 minute.', temperature)
515 # A modest wait should cool the machine.
516 time.sleep(60.0)
517 temperature = get_current_temperature_max()
518 # Atoms idle below 60 and everyone else should be even lower.
519 if temperature < 62:
520 return True
521 # This should be rare.
522 logging.info('Did not cool down (%dC). Sleeping 2 minutes.', temperature)
523 time.sleep(120.0)
524 temperature = get_current_temperature_max()
525 # A temperature over 65'C doesn't give us much headroom to the critical
526 # temperatures that start at 85'C (and PerfControl as of today will fail at
527 # critical - 10'C).
528 if temperature < 65:
529 return True
530 logging.warning('Did not cool down (%dC), giving up.', temperature)
531 return False
Ilja H. Friedel42052a22014-03-05 22:54:01 -0800532
533
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700534# System paths for machine performance state.
535_CPUINFO = '/proc/cpuinfo'
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700536_KERNEL_MAX = '/sys/devices/system/cpu/kernel_max'
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700537_MEMINFO = '/proc/meminfo'
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700538_TEMP_SENSOR_RE = 'Reading temperature...([0-9]*)'
Ilja H. Friedel42052a22014-03-05 22:54:01 -0800539
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700540
541def _get_line_from_file(path, line):
542 """
543 line can be an integer or
544 line can be a string that matches the beginning of the line
545 """
546 f = open(path)
547 if (isinstance(line, int)):
548 l = f.readline()
549 for _ in range(0, line):
550 l = f.readline()
551 return l
552 else:
553 for l in f:
554 if l.startswith(line):
555 return l
556 return None
557
558
559def _get_match_from_file(path, line, prefix, postfix):
560 """
561 Matches line in path and returns string between first prefix and postfix.
562 """
563 match = _get_line_from_file(path, line)
564 # Strip everything from front of line including prefix.
565 if prefix:
566 match = re.split(prefix, match)[1]
567 # Strip everything from back of string including first occurence of postfix.
568 if postfix:
569 match = re.split(postfix, match)[0]
570 return match
571
572
573def _get_float_from_file(path, line, prefix, postfix):
574 match = _get_match_from_file(path, line, prefix, postfix)
575 return float(match)
576
577
578def _get_int_from_file(path, line, prefix, postfix):
579 match = _get_match_from_file(path, line, prefix, postfix)
580 return int(match)
581
582
583def _get_hex_from_file(path, line, prefix, postfix):
584 match = _get_match_from_file(path, line, prefix, postfix)
585 return int(match, 16)
586
587
Ilja Friedel977aadd2014-04-29 20:45:03 -0700588# The paths don't change. Avoid running find all the time.
589_hwmon_paths = None
590
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700591def _get_hwmon_paths(file_pattern):
592 """
593 Returns a list of paths to the temperature sensors.
594 """
595 # Some systems like daisy_spring only have the virtual hwmon.
Ilja Friedel5a9da4a2014-04-16 16:13:24 -0700596 # And other systems like rambi only have coretemp.0. See crbug.com/360249.
597 # /sys/class/hwmon/hwmon*/
598 # /sys/devices/virtual/hwmon/hwmon*/
599 # /sys/devices/platform/coretemp.0/
Ilja Friedel977aadd2014-04-29 20:45:03 -0700600 if not _hwmon_paths:
601 cmd = 'find /sys/ -name "' + file_pattern + '"'
602 _hwon_paths = utils.run(cmd, verbose=False).stdout.splitlines()
603 return _hwon_paths
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700604
605
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700606def get_temperature_critical():
607 """
608 Returns temperature at which we will see some throttling in the system.
609 """
610 min_temperature = 1000.0
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700611 paths = _get_hwmon_paths('temp*_crit')
612 for path in paths:
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700613 temperature = _get_float_from_file(path, 0, None, None) * 0.001
Ilja Friedel5a9da4a2014-04-16 16:13:24 -0700614 # Today typical for Intel is 98'C to 105'C while ARM is 85'C. Clamp to
615 # the lowest known value.
616 if ((min_temperature < 60.0) or min_temperature > 150.0):
Ilja H. Friedel3f5d7682014-05-07 20:42:29 -0700617 logging.warning('Critical temperature of %.1fC was reset to 85.0C.')
Ilja Friedel5a9da4a2014-04-16 16:13:24 -0700618 min_temperature = 85.0
619
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700620 min_temperature = min(temperature, min_temperature)
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700621 return min_temperature
622
623
624def get_temperature_input_max():
625 """
626 Returns the maximum currently observed temperature.
627 """
628 max_temperature = -1000.0
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700629 paths = _get_hwmon_paths('temp*_input')
630 for path in paths:
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700631 temperature = _get_float_from_file(path, 0, None, None) * 0.001
632 max_temperature = max(temperature, max_temperature)
633 # Sanity check for real world values.
634 assert ((max_temperature > 10.0) and
Ilja H. Friedel3f5d7682014-05-07 20:42:29 -0700635 (max_temperature < 150.0)), ('Unreasonable temperature %.1fC.' %
636 max_temperature)
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700637 return max_temperature
638
639
640def get_ec_temperatures():
641 """
642 Uses ectool to return a list of all sensor temperatures in Celsius.
643 """
644 temperatures = []
Ilja Friedel14d14802014-03-31 14:37:14 -0700645 # TODO(ihf): On all ARM boards I tested 'ectool temps all' returns 200K
646 # for all sensors. Remove this check once crbug.com/358342 is fixed.
647 if 'arm' in utils.get_arch():
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700648 return temperatures
649 try:
650 full_cmd = 'ectool temps all'
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700651 lines = utils.run(full_cmd, verbose=False).stdout.splitlines()
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700652 for line in lines:
653 temperature = int(line.split(': ')[1]) - 273
654 temperatures.append(temperature)
655 except Exception:
Ilja H. Friedel04be2bd2014-05-07 21:29:59 -0700656 logging.warning('Unable to read temperature sensors using ectool.')
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700657 for temperature in temperatures:
658 # Sanity check for real world values.
659 assert ((temperature > 10.0) and
Ilja H. Friedel3f5d7682014-05-07 20:42:29 -0700660 (temperature < 150.0)), ('Unreasonable temperature %.1fC.' %
661 temperature)
662
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700663 return temperatures
664
665
Ilja Friedel977aadd2014-04-29 20:45:03 -0700666def get_current_temperature_max():
667 """
668 Returns the highest reported board temperature (all sensors) in Celsius.
669 """
670 temperature = get_temperature_input_max()
671 ec_temperatures = get_ec_temperatures()
672 if ec_temperatures:
673 temperature = max(max(ec_temperatures), temperature)
674 return temperature
675
676
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700677def get_cpu_cache_size():
678 """
679 Returns the last level CPU cache size in kBytes.
680 """
681 cache_size = _get_int_from_file(_CPUINFO, 'cache size', ': ', ' KB')
682 # Sanity check.
683 assert cache_size >= 64, 'Unreasonably small cache.'
684 return cache_size
685
686
687def get_cpu_model_frequency():
688 """
689 Returns the model frequency from the CPU model name on Intel only. This
690 might be redundant with get_cpu_max_frequency. Unit is Hz.
691 """
692 frequency = _get_float_from_file(_CPUINFO, 'model name', ' @ ', 'GHz')
693 return 1.e9 * frequency
694
695
696def get_cpu_max_frequency():
697 """
698 Returns the largest of the max CPU core frequencies. The unit is Hz.
699 """
700 max_frequency = -1
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700701 paths = _get_cpufreq_paths('cpuinfo_max_freq')
702 for path in paths:
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700703 # Convert from kHz to Hz.
704 frequency = 1000 * _get_float_from_file(path, 0, None, None)
705 max_frequency = max(frequency, max_frequency)
706 # Sanity check.
707 assert max_frequency > 1e8, 'Unreasonably low CPU frequency.'
708 return max_frequency
709
710
711def get_cpu_min_frequency():
712 """
713 Returns the smallest of the minimum CPU core frequencies.
714 """
715 min_frequency = 1e20
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700716 paths = _get_cpufreq_paths('cpuinfo_min_freq')
717 for path in paths:
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700718 frequency = _get_float_from_file(path, 0, None, None)
719 min_frequency = min(frequency, min_frequency)
720 # Sanity check.
721 assert min_frequency > 1e8, 'Unreasonably low CPU frequency.'
722 return min_frequency
723
724
725def get_cpu_model():
726 """
727 Returns the CPU model.
728 Only works on Intel.
729 """
730 cpu_model = _get_int_from_file(_CPUINFO, 'model\t', ': ', None)
731 return cpu_model
732
733
734def get_cpu_family():
735 """
736 Returns the CPU family.
737 Only works on Intel.
738 """
739 cpu_family = _get_int_from_file(_CPUINFO, 'cpu family\t', ': ', None)
740 return cpu_family
741
742
743def get_board():
744 """
745 Get the ChromeOS release board name from /etc/lsb-release.
746 """
747 f = open('/etc/lsb-release')
748 try:
749 return re.search('BOARD=(.*)', f.read()).group(1)
750 finally:
751 f.close()
752
753
754def get_board_with_frequency_and_memory():
755 """
756 Returns a board name modified with CPU frequency and memory size to
757 differentiate between different board variants. For instance
758 link -> link_1.8GHz_4GB.
759 """
760 board_name = get_board()
761 # Rounded to nearest GB and GHz.
Puthikorn Voravootivat540af152014-05-20 10:34:37 -0700762 memory = int(round(get_mem_total() / 1024.0))
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700763 # Convert frequency to GHz with 1 digit accuracy after the decimal point.
764 frequency = int(round(get_cpu_max_frequency() * 1e-8)) * 0.1
765 board = "%s_%1.1fGHz_%dGB" % (board_name, frequency, memory)
766 return board
767
768
769def get_mem_total():
770 """
771 Returns the total memory available in the system in MBytes.
772 """
773 mem_total = _get_float_from_file(_MEMINFO, 'MemTotal:', 'MemTotal:', ' kB')
774 # Sanity check, all Chromebooks have at least 1GB of memory.
Puthikorn Voravootivat540af152014-05-20 10:34:37 -0700775 assert mem_total > 1024 * 1024, 'Unreasonable amount of memory.'
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700776 return mem_total / 1024
777
778
779def get_mem_free():
780 """
781 Returns the currently free memory in the system in MBytes.
782 """
783 mem_free = _get_float_from_file(_MEMINFO, 'MemFree:', 'MemFree:', ' kB')
784 return mem_free / 1024
785
786
787def get_kernel_max():
788 """
789 Returns content of kernel_max.
790 """
791 kernel_max = _get_int_from_file(_KERNEL_MAX, 0, None, None)
792 # Sanity check.
793 assert ((kernel_max > 0) and (kernel_max < 257)), 'Unreasonable kernel_max.'
794 return kernel_max
795
796
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700797def set_high_performance_mode():
798 """
799 Sets the kernel governor mode to the highest setting.
800 Returns previous governor state.
801 """
802 original_governors = get_scaling_governor_states()
803 set_scaling_governors('performance')
804 return original_governors
805
806
807def set_scaling_governors(value):
808 """
809 Sets all scaling governor to string value.
810 Sample values: 'performance', 'interactive', 'ondemand', 'powersave'.
811 """
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700812 paths = _get_cpufreq_paths('scaling_governor')
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700813 for path in paths:
814 cmd = 'sudo echo %s > %s' % (value, path)
815 logging.info('Writing scaling governor mode \'%s\' -> %s', value, path)
816 utils.system(cmd)
817
818
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700819def _get_cpufreq_paths(filename):
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700820 """
821 Returns a list of paths to the governors.
822 """
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700823 cmd = 'ls /sys/devices/system/cpu/cpu*/cpufreq/' + filename
824 paths = utils.run(cmd, verbose=False).stdout.splitlines()
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700825 return paths
826
827
828def get_scaling_governor_states():
829 """
830 Returns a list of (performance governor path, current state) tuples.
831 """
Ilja H. Friedelbc575512014-03-31 17:51:10 -0700832 paths = _get_cpufreq_paths('scaling_governor')
Ilja Friedel3b4712c2014-03-14 15:44:01 -0700833 path_value_list = []
834 for path in paths:
835 value = _get_line_from_file(path, 0)
836 path_value_list.append((path, value))
837 return path_value_list
838
839
840def restore_scaling_governor_states(path_value_list):
841 """
842 Restores governor states. Inverse operation to get_scaling_governor_states.
843 """
844 for (path, value) in path_value_list:
845 cmd = 'sudo echo %s > %s' % (value, path)
846 utils.system(cmd)
Stéphane Marchesinbf676172014-04-25 16:11:33 -0700847
848
849def get_gpu_family():
850 """Return the GPU family name"""
851 cpuarch = base_utils.get_cpu_soc_family()
852 if cpuarch == 'exynos5':
853 return 'mali'
854 if cpuarch == 'tegra':
855 return 'tegra'
856
857 pci_path = '/sys/bus/pci/devices/0000:00:02.0/device'
858
859 if not os.path.exists(pci_path):
860 raise error.TestError('PCI device 0000:00:02.0 not found')
861
862 device_id = int(utils.read_one_line(pci_path), 16)
863 intel_architecture = {
864 0xa011: 'pinetrail',
865 0x0106: 'sandybridge',
Stéphane Marchesin26778372014-05-02 18:40:45 -0700866 0x0116: 'sandybridge',
Stéphane Marchesinbf676172014-04-25 16:11:33 -0700867 0x0126: 'sandybridge',
868 0x0156: 'ivybridge',
869 0x0166: 'ivybridge',
870 0x0a06: 'haswell',
Stéphane Marchesin26778372014-05-02 18:40:45 -0700871 0x0a16: 'haswell',
Stéphane Marchesinbf676172014-04-25 16:11:33 -0700872 0x0f31: 'baytrail',
873 }
874
875 return intel_architecture[device_id]
Stéphane Marchesin85185622014-05-02 18:56:00 -0700876
877
878def has_no_monitor():
879 """Return whether a machine doesn't have a built-in monitor"""
880 board_name = get_board()
881 if (board_name == 'stumpy' or board_name == 'panther' or
882 board_name == 'zako'):
883 return True
884
885 return False
Puthikorn Voravootivat540af152014-05-20 10:34:37 -0700886
887
888def get_fixed_dst_drive():
889 """
890 Return device name for internal disk.
891 Example: return /dev/sda for falco booted from usb
892 """
893 cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
894 '. /usr/share/misc/chromeos-common.sh;',
895 'load_base_vars;',
896 'get_fixed_dst_drive'])
897 return utils.system_output(cmd)
898
899
900def get_root_device():
901 """
902 Return root device.
903 Will return correct disk device even system boot from /dev/dm-0
904 Example: return /dev/sdb for falco booted from usb
905 """
906 return utils.system_output('rootdev -s -d')
907
908
909def get_root_partition():
910 """
911 Return current root partition
912 Example: return /dev/sdb3 for falco booted from usb
913 """
914 return utils.system_output('rootdev -s')
915
916
917def get_free_root_partition(root_part=None):
918 """
919 Return currently unused root partion
920 Example: return /dev/sdb5 for falco booted from usb
921
922 @param root_part: cuurent root partition
923 """
924 spare_root_map = {'3': '5', '5': '3'}
925 if not root_part:
926 root_part = get_root_partition()
927 return root_part[:-1] + spare_root_map[root_part[-1]]
928
929
930def is_booted_from_internal_disk():
931 """Return True if boot from internal disk. False, otherwise."""
932 return get_root_device() == get_fixed_dst_drive()
933
934
935def get_disk_size(disk_name):
936 """
937 Return size of disk in byte. Return 0 in Error Case
938
939 @param disk_name: disk name to find size
940 """
941 device = os.path.basename(disk_name)
942 for line in file('/proc/partitions'):
943 try:
944 major, minor, blocks, name = re.split(r' +', line.strip())
945 except ValueError:
946 continue
947 if name == device:
948 return 1024 * int(blocks)
949 return 0