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