OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Provides an interface to communicate with the device via the adb command. | 5 """Provides an interface to communicate with the device via the adb command. |
6 | 6 |
7 Assumes adb binary is currently on system path. | 7 Assumes adb binary is currently on system path. |
8 """ | 8 """ |
| 9 # pylint: disable-all |
9 | 10 |
10 import collections | 11 import collections |
11 import datetime | 12 import datetime |
12 import inspect | 13 import inspect |
13 import json | 14 import json |
14 import logging | 15 import logging |
15 import os | 16 import os |
16 import re | 17 import re |
17 import shlex | 18 import shlex |
18 import signal | 19 import signal |
19 import subprocess | 20 import subprocess |
20 import sys | 21 import sys |
21 import tempfile | 22 import tempfile |
22 import time | 23 import time |
23 | 24 |
24 import cmd_helper | 25 import cmd_helper |
25 import constants | 26 import constants |
26 import screenshot | 27 import screenshot |
27 import system_properties | 28 import system_properties |
28 | 29 |
29 try: | 30 try: |
30 from pylib import pexpect | 31 from pylib import pexpect |
31 except: | 32 except ImportError: |
32 pexpect = None | 33 pexpect = None |
33 | 34 |
34 sys.path.append(os.path.join( | 35 sys.path.append(os.path.join( |
35 constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner')) | 36 constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner')) |
36 import adb_interface | 37 import adb_interface |
37 import am_instrument_parser | 38 import am_instrument_parser |
38 import errors | 39 import errors |
39 | 40 |
40 | 41 |
41 # Pattern to search for the next whole line of pexpect output and capture it | 42 # Pattern to search for the next whole line of pexpect output and capture it |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 retries = 3 | 367 retries = 3 |
367 while retries: | 368 while retries: |
368 try: | 369 try: |
369 self._adb.WaitForDevicePm() | 370 self._adb.WaitForDevicePm() |
370 return # Success | 371 return # Success |
371 except errors.WaitForResponseTimedOutError as e: | 372 except errors.WaitForResponseTimedOutError as e: |
372 last_err = e | 373 last_err = e |
373 logging.warning('Restarting and retrying after timeout: %s', e) | 374 logging.warning('Restarting and retrying after timeout: %s', e) |
374 retries -= 1 | 375 retries -= 1 |
375 self.RestartShell() | 376 self.RestartShell() |
376 raise last_err # Only reached after max retries, re-raise the last error. | 377 raise last_err # Only reached after max retries, re-raise the last error. |
377 | 378 |
378 def RestartShell(self): | 379 def RestartShell(self): |
379 """Restarts the shell on the device. Does not block for it to return.""" | 380 """Restarts the shell on the device. Does not block for it to return.""" |
380 self.RunShellCommand('stop') | 381 self.RunShellCommand('stop') |
381 self.RunShellCommand('start') | 382 self.RunShellCommand('start') |
382 | 383 |
383 def Reboot(self, full_reboot=True): | 384 def Reboot(self, full_reboot=True): |
384 """Reboots the device and waits for the package manager to return. | 385 """Reboots the device and waits for the package manager to return. |
385 | 386 |
386 Args: | 387 Args: |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
505 out = self._adb.SendCommand('remount') | 506 out = self._adb.SendCommand('remount') |
506 if out.strip() != 'remount succeeded': | 507 if out.strip() != 'remount succeeded': |
507 raise errors.MsgException('Remount failed: %s' % out) | 508 raise errors.MsgException('Remount failed: %s' % out) |
508 | 509 |
509 def RestartAdbdOnDevice(self): | 510 def RestartAdbdOnDevice(self): |
510 logging.info('Killing adbd on the device...') | 511 logging.info('Killing adbd on the device...') |
511 adb_pids = self.ExtractPid('adbd') | 512 adb_pids = self.ExtractPid('adbd') |
512 if not adb_pids: | 513 if not adb_pids: |
513 raise errors.MsgException('Unable to obtain adbd pid') | 514 raise errors.MsgException('Unable to obtain adbd pid') |
514 try: | 515 try: |
515 self.KillAll('adbd', signal=signal.SIGTERM, with_su=True) | 516 self.KillAll('adbd', signum=signal.SIGTERM, with_su=True) |
516 logging.info('Waiting for device to settle...') | 517 logging.info('Waiting for device to settle...') |
517 self._adb.SendCommand('wait-for-device') | 518 self._adb.SendCommand('wait-for-device') |
518 new_adb_pids = self.ExtractPid('adbd') | 519 new_adb_pids = self.ExtractPid('adbd') |
519 if new_adb_pids == adb_pids: | 520 if new_adb_pids == adb_pids: |
520 logging.warning('adbd on the device may not have been restarted.') | 521 logging.warning('adbd on the device may not have been restarted.') |
521 except Exception as e: | 522 except Exception as e: |
522 logging.error('Exception when trying to kill adbd on the device [%s]', e) | 523 logging.error('Exception when trying to kill adbd on the device [%s]', e) |
523 | 524 |
524 def RestartAdbServer(self): | 525 def RestartAdbServer(self): |
525 """Restart the adb server.""" | 526 """Restart the adb server.""" |
526 ret = self.KillAdbServer() | 527 ret = self.KillAdbServer() |
527 if ret != 0: | 528 if ret != 0: |
528 raise errors.MsgException('KillAdbServer: %d' % ret) | 529 raise errors.MsgException('KillAdbServer: %d' % ret) |
529 | 530 |
530 ret = self.StartAdbServer() | 531 ret = self.StartAdbServer() |
531 if ret != 0: | 532 if ret != 0: |
532 raise errors.MsgException('StartAdbServer: %d' % ret) | 533 raise errors.MsgException('StartAdbServer: %d' % ret) |
533 | 534 |
534 def KillAdbServer(self): | 535 @staticmethod |
| 536 def KillAdbServer(): |
535 """Kill adb server.""" | 537 """Kill adb server.""" |
536 adb_cmd = [constants.GetAdbPath(), 'kill-server'] | 538 adb_cmd = [constants.GetAdbPath(), 'kill-server'] |
537 ret = cmd_helper.RunCmd(adb_cmd) | 539 ret = cmd_helper.RunCmd(adb_cmd) |
538 retry = 0 | 540 retry = 0 |
539 while retry < 3: | 541 while retry < 3: |
540 ret, _ = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb']) | 542 ret, _ = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb']) |
541 if ret != 0: | 543 if ret != 0: |
542 # pgrep didn't find adb, kill-server succeeded. | 544 # pgrep didn't find adb, kill-server succeeded. |
543 return 0 | 545 return 0 |
544 retry += 1 | 546 retry += 1 |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 timeout_time: Number of seconds to wait for command to respond before | 653 timeout_time: Number of seconds to wait for command to respond before |
652 retrying, used by AdbInterface.SendShellCommand. | 654 retrying, used by AdbInterface.SendShellCommand. |
653 log_result: Boolean to indicate whether we should log the result of the | 655 log_result: Boolean to indicate whether we should log the result of the |
654 shell command. | 656 shell command. |
655 | 657 |
656 Returns: | 658 Returns: |
657 list containing the lines of output received from running the command | 659 list containing the lines of output received from running the command |
658 """ | 660 """ |
659 self._CheckCommandIsValid(command) | 661 self._CheckCommandIsValid(command) |
660 self._LogShell(command) | 662 self._LogShell(command) |
661 if "'" in command: logging.warning(command + " contains ' quotes") | 663 if "'" in command: |
| 664 logging.warning(command + " contains ' quotes") |
662 result = self._adb.SendShellCommand( | 665 result = self._adb.SendShellCommand( |
663 "'%s'" % command, timeout_time).splitlines() | 666 "'%s'" % command, timeout_time).splitlines() |
664 # TODO(b.kelemen): we should really be able to drop the stderr of the | 667 # TODO(b.kelemen): we should really be able to drop the stderr of the |
665 # command or raise an exception based on what the caller wants. | 668 # command or raise an exception based on what the caller wants. |
666 result = [ l for l in result if not l.startswith('WARNING') ] | 669 result = [ l for l in result if not l.startswith('WARNING') ] |
667 if ['error: device not found'] == result: | 670 if ['error: device not found'] == result: |
668 raise errors.DeviceUnresponsiveError('device not found') | 671 raise errors.DeviceUnresponsiveError('device not found') |
669 if log_result: | 672 if log_result: |
670 self._LogShell('\n'.join(result)) | 673 self._LogShell('\n'.join(result)) |
671 return result | 674 return result |
(...skipping 10 matching lines...) Expand all Loading... |
682 last_line = lines[-1] | 685 last_line = lines[-1] |
683 status_pos = last_line.rfind('%') | 686 status_pos = last_line.rfind('%') |
684 assert status_pos >= 0 | 687 assert status_pos >= 0 |
685 status = int(last_line[status_pos + 1:]) | 688 status = int(last_line[status_pos + 1:]) |
686 if status_pos == 0: | 689 if status_pos == 0: |
687 lines = lines[:-1] | 690 lines = lines[:-1] |
688 else: | 691 else: |
689 lines = lines[:-1] + [last_line[:status_pos]] | 692 lines = lines[:-1] + [last_line[:status_pos]] |
690 return (status, lines) | 693 return (status, lines) |
691 | 694 |
692 def KillAll(self, process, signal=9, with_su=False): | 695 def KillAll(self, process, signum=9, with_su=False): |
693 """Android version of killall, connected via adb. | 696 """Android version of killall, connected via adb. |
694 | 697 |
695 Args: | 698 Args: |
696 process: name of the process to kill off. | 699 process: name of the process to kill off. |
697 signal: signal to use, 9 (SIGKILL) by default. | 700 signum: signal to use, 9 (SIGKILL) by default. |
698 with_su: wether or not to use su to kill the processes. | 701 with_su: wether or not to use su to kill the processes. |
699 | 702 |
700 Returns: | 703 Returns: |
701 the number of processes killed | 704 the number of processes killed |
702 """ | 705 """ |
703 pids = self.ExtractPid(process) | 706 pids = self.ExtractPid(process) |
704 if pids: | 707 if pids: |
705 cmd = 'kill -%d %s' % (signal, ' '.join(pids)) | 708 cmd = 'kill -%d %s' % (signum, ' '.join(pids)) |
706 if with_su: | 709 if with_su: |
707 self.RunShellCommandWithSU(cmd) | 710 self.RunShellCommandWithSU(cmd) |
708 else: | 711 else: |
709 self.RunShellCommand(cmd) | 712 self.RunShellCommand(cmd) |
710 return len(pids) | 713 return len(pids) |
711 | 714 |
712 def KillAllBlocking(self, process, timeout_sec): | 715 def KillAllBlocking(self, process, timeout_sec): |
713 """Blocking version of killall, connected via adb. | 716 """Blocking version of killall, connected via adb. |
714 | 717 |
715 This waits until no process matching the corresponding name appears in ps' | 718 This waits until no process matching the corresponding name appears in ps' |
(...skipping 11 matching lines...) Expand all Loading... |
727 elapsed = 0 | 730 elapsed = 0 |
728 wait_period = 0.1 | 731 wait_period = 0.1 |
729 # Note that this doesn't take into account the time spent in ExtractPid(). | 732 # Note that this doesn't take into account the time spent in ExtractPid(). |
730 while self.ExtractPid(process) and elapsed < timeout_sec: | 733 while self.ExtractPid(process) and elapsed < timeout_sec: |
731 time.sleep(wait_period) | 734 time.sleep(wait_period) |
732 elapsed += wait_period | 735 elapsed += wait_period |
733 if elapsed >= timeout_sec: | 736 if elapsed >= timeout_sec: |
734 return 0 | 737 return 0 |
735 return processes_killed | 738 return processes_killed |
736 | 739 |
737 def _GetActivityCommand(self, package, activity, wait_for_completion, action, | 740 @staticmethod |
| 741 def _GetActivityCommand(package, activity, wait_for_completion, action, |
738 category, data, extras, trace_file_name, force_stop, | 742 category, data, extras, trace_file_name, force_stop, |
739 flags): | 743 flags): |
740 """Creates command to start |package|'s activity on the device. | 744 """Creates command to start |package|'s activity on the device. |
741 | 745 |
742 Args - as for StartActivity | 746 Args - as for StartActivity |
743 | 747 |
744 Returns: | 748 Returns: |
745 the command to run on the target to start the activity | 749 the command to run on the target to start the activity |
746 """ | 750 """ |
747 cmd = 'am start -a %s' % action | 751 cmd = 'am start -a %s' % action |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 | 1090 |
1087 def CanAccessProtectedFileContents(self): | 1091 def CanAccessProtectedFileContents(self): |
1088 """Returns True if Get/SetProtectedFileContents would work via "su". | 1092 """Returns True if Get/SetProtectedFileContents would work via "su". |
1089 | 1093 |
1090 Devices running user builds don't have adb root, but may provide "su" which | 1094 Devices running user builds don't have adb root, but may provide "su" which |
1091 can be used for accessing protected files. | 1095 can be used for accessing protected files. |
1092 """ | 1096 """ |
1093 r = self.RunShellCommandWithSU('cat /dev/null') | 1097 r = self.RunShellCommandWithSU('cat /dev/null') |
1094 return r == [] or r[0].strip() == '' | 1098 return r == [] or r[0].strip() == '' |
1095 | 1099 |
1096 def GetProtectedFileContents(self, filename, log_result=False): | 1100 def GetProtectedFileContents(self, filename): |
1097 """Gets contents from the protected file specified by |filename|. | 1101 """Gets contents from the protected file specified by |filename|. |
1098 | 1102 |
1099 This is less efficient than GetFileContents, but will work for protected | 1103 This is less efficient than GetFileContents, but will work for protected |
1100 files and device files. | 1104 files and device files. |
1101 """ | 1105 """ |
1102 # Run the script as root | 1106 # Run the script as root |
1103 return self.RunShellCommandWithSU('cat "%s" 2> /dev/null' % filename) | 1107 return self.RunShellCommandWithSU('cat "%s" 2> /dev/null' % filename) |
1104 | 1108 |
1105 def SetProtectedFileContents(self, filename, contents): | 1109 def SetProtectedFileContents(self, filename, contents): |
1106 """Writes |contents| to the protected file specified by |filename|. | 1110 """Writes |contents| to the protected file specified by |filename|. |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1334 logging.info('<<< Waiting for logcat:' + str(success_re.pattern)) | 1338 logging.info('<<< Waiting for logcat:' + str(success_re.pattern)) |
1335 t0 = time.time() | 1339 t0 = time.time() |
1336 while True: | 1340 while True: |
1337 if not self._logcat: | 1341 if not self._logcat: |
1338 self.StartMonitoringLogcat(clear) | 1342 self.StartMonitoringLogcat(clear) |
1339 try: | 1343 try: |
1340 while True: | 1344 while True: |
1341 # Note this will block for upto the timeout _per log line_, so we need | 1345 # Note this will block for upto the timeout _per log line_, so we need |
1342 # to calculate the overall timeout remaining since t0. | 1346 # to calculate the overall timeout remaining since t0. |
1343 time_remaining = t0 + timeout - time.time() | 1347 time_remaining = t0 + timeout - time.time() |
1344 if time_remaining < 0: raise pexpect.TIMEOUT(self._logcat) | 1348 if time_remaining < 0: |
| 1349 raise pexpect.TIMEOUT(self._logcat) |
1345 self._logcat.expect(PEXPECT_LINE_RE, timeout=time_remaining) | 1350 self._logcat.expect(PEXPECT_LINE_RE, timeout=time_remaining) |
1346 line = self._logcat.match.group(1) | 1351 line = self._logcat.match.group(1) |
1347 if error_re: | 1352 if error_re: |
1348 error_match = error_re.search(line) | 1353 error_match = error_re.search(line) |
1349 if error_match: | 1354 if error_match: |
1350 return None | 1355 return None |
1351 success_match = success_re.search(line) | 1356 success_match = success_re.search(line) |
1352 if success_match: | 1357 if success_match: |
1353 return success_match | 1358 return success_match |
1354 logging.info('<<< Skipped Logcat Line:' + str(line)) | 1359 logging.info('<<< Skipped Logcat Line:' + str(line)) |
1355 except pexpect.TIMEOUT: | 1360 except pexpect.TIMEOUT: |
1356 raise pexpect.TIMEOUT( | 1361 raise pexpect.TIMEOUT( |
1357 'Timeout (%ds) exceeded waiting for pattern "%s" (tip: use -vv ' | 1362 'Timeout (%ds) exceeded waiting for pattern "%s" (tip: use -vv ' |
1358 'to debug)' % | 1363 'to debug)' % |
1359 (timeout, success_re.pattern)) | 1364 (timeout, success_re.pattern)) |
1360 except pexpect.EOF: | 1365 except pexpect.EOF: |
1361 # It seems that sometimes logcat can end unexpectedly. This seems | 1366 # It seems that sometimes logcat can end unexpectedly. This seems |
1362 # to happen during Chrome startup after a reboot followed by a cache | 1367 # to happen during Chrome startup after a reboot followed by a cache |
1363 # clean. I don't understand why this happens, but this code deals with | 1368 # clean. I don't understand why this happens, but this code deals with |
1364 # getting EOF in logcat. | 1369 # getting EOF in logcat. |
1365 logging.critical('Found EOF in adb logcat. Restarting...') | 1370 logging.critical('Found EOF in adb logcat. Restarting...') |
1366 # Rerun spawn with original arguments. Note that self._logcat.args[0] is | 1371 # Rerun spawn with original arguments. Note that self._logcat.args[0] is |
1367 # the path of adb, so we don't want it in the arguments. | 1372 # the path of adb, so we don't want it in the arguments. |
1368 self._logcat = pexpect.spawn(constants.GetAdbPath(), | 1373 self._logcat = pexpect.spawn(constants.GetAdbPath(), |
1369 self._logcat.args[1:], | 1374 self._logcat.args[1:], |
1370 timeout=self._logcat.timeout, | 1375 timeout=self._logcat.timeout, |
1371 logfile=self._logcat.logfile) | 1376 logfile=self._logcat.logfile) |
1372 | 1377 |
1373 def StartRecordingLogcat(self, clear=True, filters=['*:v']): | 1378 def StartRecordingLogcat(self, clear=True, filters=None): |
1374 """Starts recording logcat output to eventually be saved as a string. | 1379 """Starts recording logcat output to eventually be saved as a string. |
1375 | 1380 |
1376 This call should come before some series of tests are run, with either | 1381 This call should come before some series of tests are run, with either |
1377 StopRecordingLogcat or SearchLogcatRecord following the tests. | 1382 StopRecordingLogcat or SearchLogcatRecord following the tests. |
1378 | 1383 |
1379 Args: | 1384 Args: |
1380 clear: True if existing log output should be cleared. | 1385 clear: True if existing log output should be cleared. |
1381 filters: A list of logcat filters to be used. | 1386 filters: A list of logcat filters to be used. |
1382 """ | 1387 """ |
| 1388 if not filters: |
| 1389 filters = ['*:v'] |
1383 if clear: | 1390 if clear: |
1384 self._adb.SendCommand('logcat -c') | 1391 self._adb.SendCommand('logcat -c') |
1385 logcat_command = 'adb %s logcat -v threadtime %s' % (self._adb._target_arg, | 1392 logcat_command = 'adb %s logcat -v threadtime %s' % (self._adb._target_arg, |
1386 ' '.join(filters)) | 1393 ' '.join(filters)) |
1387 self._logcat_tmpoutfile = tempfile.NamedTemporaryFile(bufsize=0) | 1394 self._logcat_tmpoutfile = tempfile.NamedTemporaryFile(bufsize=0) |
1388 self.logcat_process = subprocess.Popen(logcat_command, shell=True, | 1395 self.logcat_process = subprocess.Popen(logcat_command, shell=True, |
1389 stdout=self._logcat_tmpoutfile) | 1396 stdout=self._logcat_tmpoutfile) |
1390 | 1397 |
1391 def GetCurrentRecordedLogcat(self): | 1398 def GetCurrentRecordedLogcat(self): |
1392 """Return the current content of the logcat being recorded. | 1399 """Return the current content of the logcat being recorded. |
(...skipping 24 matching lines...) Expand all Loading... |
1417 if self.logcat_process.poll() is None: | 1424 if self.logcat_process.poll() is None: |
1418 self.logcat_process.kill() | 1425 self.logcat_process.kill() |
1419 self.logcat_process.wait() | 1426 self.logcat_process.wait() |
1420 self.logcat_process = None | 1427 self.logcat_process = None |
1421 self._logcat_tmpoutfile.seek(0) | 1428 self._logcat_tmpoutfile.seek(0) |
1422 output = self._logcat_tmpoutfile.read() | 1429 output = self._logcat_tmpoutfile.read() |
1423 self._logcat_tmpoutfile.close() | 1430 self._logcat_tmpoutfile.close() |
1424 self._logcat_tmpoutfile = None | 1431 self._logcat_tmpoutfile = None |
1425 return output | 1432 return output |
1426 | 1433 |
1427 def SearchLogcatRecord(self, record, message, thread_id=None, proc_id=None, | 1434 @staticmethod |
| 1435 def SearchLogcatRecord(record, message, thread_id=None, proc_id=None, |
1428 log_level=None, component=None): | 1436 log_level=None, component=None): |
1429 """Searches the specified logcat output and returns results. | 1437 """Searches the specified logcat output and returns results. |
1430 | 1438 |
1431 This method searches through the logcat output specified by record for a | 1439 This method searches through the logcat output specified by record for a |
1432 certain message, narrowing results by matching them against any other | 1440 certain message, narrowing results by matching them against any other |
1433 specified criteria. It returns all matching lines as described below. | 1441 specified criteria. It returns all matching lines as described below. |
1434 | 1442 |
1435 Args: | 1443 Args: |
1436 record: A string generated by Start/StopRecordingLogcat to search. | 1444 record: A string generated by Start/StopRecordingLogcat to search. |
1437 message: An output string to search for. | 1445 message: An output string to search for. |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1533 A tuple containg: | 1541 A tuple containg: |
1534 [0]: Dict of {metric:usage_kb}, for the process which has specified pid. | 1542 [0]: Dict of {metric:usage_kb}, for the process which has specified pid. |
1535 The metric keys which may be included are: Size, Rss, Pss, Shared_Clean, | 1543 The metric keys which may be included are: Size, Rss, Pss, Shared_Clean, |
1536 Shared_Dirty, Private_Clean, Private_Dirty, Referenced, Swap, | 1544 Shared_Dirty, Private_Clean, Private_Dirty, Referenced, Swap, |
1537 KernelPageSize, MMUPageSize, Nvidia (tablet only), VmHWM. | 1545 KernelPageSize, MMUPageSize, Nvidia (tablet only), VmHWM. |
1538 [1]: Detailed /proc/[PID]/smaps information. | 1546 [1]: Detailed /proc/[PID]/smaps information. |
1539 """ | 1547 """ |
1540 usage_dict = collections.defaultdict(int) | 1548 usage_dict = collections.defaultdict(int) |
1541 smaps = collections.defaultdict(dict) | 1549 smaps = collections.defaultdict(dict) |
1542 current_smap = '' | 1550 current_smap = '' |
1543 for line in self.GetProtectedFileContents('/proc/%s/smaps' % pid, | 1551 for line in self.GetProtectedFileContents('/proc/%s/smaps' % pid): |
1544 log_result=False): | |
1545 items = line.split() | 1552 items = line.split() |
1546 # See man 5 proc for more details. The format is: | 1553 # See man 5 proc for more details. The format is: |
1547 # address perms offset dev inode pathname | 1554 # address perms offset dev inode pathname |
1548 if len(items) > 5: | 1555 if len(items) > 5: |
1549 current_smap = ' '.join(items[5:]) | 1556 current_smap = ' '.join(items[5:]) |
1550 elif len(items) > 3: | 1557 elif len(items) > 3: |
1551 current_smap = ' '.join(items[3:]) | 1558 current_smap = ' '.join(items[3:]) |
1552 match = re.match(MEMORY_INFO_RE, line) | 1559 match = re.match(MEMORY_INFO_RE, line) |
1553 if match: | 1560 if match: |
1554 key = match.group('key') | 1561 key = match.group('key') |
1555 usage_kb = int(match.group('usage_kb')) | 1562 usage_kb = int(match.group('usage_kb')) |
1556 usage_dict[key] += usage_kb | 1563 usage_dict[key] += usage_kb |
1557 if key not in smaps[current_smap]: | 1564 if key not in smaps[current_smap]: |
1558 smaps[current_smap][key] = 0 | 1565 smaps[current_smap][key] = 0 |
1559 smaps[current_smap][key] += usage_kb | 1566 smaps[current_smap][key] += usage_kb |
1560 if not usage_dict or not any(usage_dict.values()): | 1567 if not usage_dict or not any(usage_dict.values()): |
1561 # Presumably the process died between ps and calling this method. | 1568 # Presumably the process died between ps and calling this method. |
1562 logging.warning('Could not find memory usage for pid ' + str(pid)) | 1569 logging.warning('Could not find memory usage for pid ' + str(pid)) |
1563 | 1570 |
1564 for line in self.GetProtectedFileContents('/d/nvmap/generic-0/clients', | 1571 for line in self.GetProtectedFileContents('/d/nvmap/generic-0/clients'): |
1565 log_result=False): | |
1566 match = re.match(NVIDIA_MEMORY_INFO_RE, line) | 1572 match = re.match(NVIDIA_MEMORY_INFO_RE, line) |
1567 if match and match.group('pid') == pid: | 1573 if match and match.group('pid') == pid: |
1568 usage_bytes = int(match.group('usage_bytes')) | 1574 usage_bytes = int(match.group('usage_bytes')) |
1569 usage_dict['Nvidia'] = int(round(usage_bytes / 1000.0)) # kB | 1575 usage_dict['Nvidia'] = int(round(usage_bytes / 1000.0)) # kB |
1570 break | 1576 break |
1571 | 1577 |
1572 peak_value_kb = 0 | 1578 peak_value_kb = 0 |
1573 for line in self.GetProtectedFileContents('/proc/%s/status' % pid, | 1579 for line in self.GetProtectedFileContents('/proc/%s/status' % pid): |
1574 log_result=False): | |
1575 if not line.startswith('VmHWM:'): # Format: 'VmHWM: +[0-9]+ kB' | 1580 if not line.startswith('VmHWM:'): # Format: 'VmHWM: +[0-9]+ kB' |
1576 continue | 1581 continue |
1577 peak_value_kb = int(line.split(':')[1].strip().split(' ')[0]) | 1582 peak_value_kb = int(line.split(':')[1].strip().split(' ')[0]) |
1578 usage_dict['VmHWM'] = peak_value_kb | 1583 usage_dict['VmHWM'] = peak_value_kb |
1579 if not peak_value_kb: | 1584 if not peak_value_kb: |
1580 logging.warning('Could not find memory peak value for pid ' + str(pid)) | 1585 logging.warning('Could not find memory peak value for pid ' + str(pid)) |
1581 | 1586 |
1582 return (usage_dict, smaps) | 1587 return (usage_dict, smaps) |
1583 | 1588 |
1584 def GetMemoryUsageForPackage(self, package): | 1589 def GetMemoryUsageForPackage(self, package): |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1807 """ | 1812 """ |
1808 def __init__(self, output): | 1813 def __init__(self, output): |
1809 self._output = output | 1814 self._output = output |
1810 | 1815 |
1811 def write(self, data): | 1816 def write(self, data): |
1812 data = data.replace('\r\r\n', '\n') | 1817 data = data.replace('\r\r\n', '\n') |
1813 self._output.write(data) | 1818 self._output.write(data) |
1814 | 1819 |
1815 def flush(self): | 1820 def flush(self): |
1816 self._output.flush() | 1821 self._output.flush() |
OLD | NEW |