diff options
author | tonyg@chromium.org <tonyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-12 22:06:48 +0000 |
---|---|---|
committer | tonyg@chromium.org <tonyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-12 22:06:48 +0000 |
commit | 5bda847a21a067c2ae877dec63d061f4513fa70e (patch) | |
tree | f5b1a0cf6ea36a628092383fd1873eaacb85e95a /tools | |
parent | e18e10788549528b0a334989e711c947f1212ff2 (diff) | |
download | chromium_src-5bda847a21a067c2ae877dec63d061f4513fa70e.zip chromium_src-5bda847a21a067c2ae877dec63d061f4513fa70e.tar.gz chromium_src-5bda847a21a067c2ae877dec63d061f4513fa70e.tar.bz2 |
[Telemetry] Make unhandled exception output more useful.
This should help tremendously in diagnosing flake on the bots.
Default format:
---------------------------
Traceback (most recent call last):
File "tools/perf/run_benchmark", line 23, in <module>
sys.exit(test_runner.Main())
File "tools/perf/../telemetry/telemetry/test_runner.py", line 290, in Main
return command.Run(options, args)
File "tools/perf/../telemetry/telemetry/test_runner.py", line 198, in Run
return min(255, self._test().Run(copy.copy(options)))
File "tools/perf/../telemetry/telemetry/test.py", line 53, in Run
results = page_runner.Run(test, ps, expectations, options)
File "tools/perf/../telemetry/telemetry/page/page_runner.py", line 330, in Run
possible_browser, results, state)
File "tools/perf/../telemetry/telemetry/page/page_runner.py", line 213, in _PrepareAndRunPage
credentials_path, page.archive_path)
File "tools/perf/../telemetry/telemetry/page/page_runner.py", line 54, in StartBrowser
test.DidStartBrowser(self.browser)
File "/work/chromium/src/tools/perf/measurements/page_cycler.py", line 71, in DidStartBrowser
self._memory_metric = memory.MemoryMetric(browser)
File "/work/chromium/src/tools/perf/metrics/memory.py", line 32, in __init__
self._start_commit_charge = self._browser.memory_stats['SystemCommitCharge']
File "tools/perf/../telemetry/telemetry/core/browser.py", line 166, in memory_stats
result = self._GetStatsCommon(self._platform_backend.GetMemoryStats)
File "tools/perf/../telemetry/telemetry/core/browser.py", line 99, in _GetStatsCommon
for child_pid in self._platform_backend.GetChildPids(browser_pid):
File "tools/perf/../telemetry/telemetry/core/platform/posix_platform_backend.py", line 44, in GetChildPids
return proc_util.GetChildPids(processes, pid)
File "tools/perf/../telemetry/telemetry/core/platform/proc_util.py", line 86, in GetChildPids
for foo, curr_pid, curr_ppid, state in processes:
ValueError: need more than 3 values to unpack
---------------------------
New format:
---------------------------
Traceback (most recent call last):
<module> at tools/perf/run_benchmark:23
sys.exit(test_runner.Main())
Main at tools/telemetry/telemetry/test_runner.py:303
return command.Run(options, args)
Run at tools/telemetry/telemetry/test_runner.py:211
return min(255, self._test().Run(copy.copy(options)))
Run at tools/telemetry/telemetry/test.py:53
results = page_runner.Run(test, ps, expectations, options)
Run at tools/telemetry/telemetry/page/page_runner.py:330
possible_browser, results, state)
_PrepareAndRunPage at tools/telemetry/telemetry/page/page_runner.py:213
credentials_path, page.archive_path)
StartBrowser at tools/telemetry/telemetry/page/page_runner.py:54
test.DidStartBrowser(self.browser)
DidStartBrowser at tools/perf/measurements/page_cycler.py:71
self._memory_metric = memory.MemoryMetric(browser)
__init__ at tools/perf/metrics/memory.py:32
self._start_commit_charge = self._browser.memory_stats['SystemCommitCharge']
memory_stats at tools/telemetry/telemetry/core/browser.py:166
result = self._GetStatsCommon(self._platform_backend.GetMemoryStats)
_GetStatsCommon at tools/telemetry/telemetry/core/browser.py:99
for child_pid in self._platform_backend.GetChildPids(browser_pid):
GetChildPids at tools/telemetry/telemetry/core/platform/posix_platform_backend.py:44
return proc_util.GetChildPids(processes, pid)
GetChildPids at tools/telemetry/telemetry/core/platform/proc_util.py:86
for foo, curr_pid, curr_ppid, state in processes:
Locals:
child_dict : defaultdict(<type 'list'>, {})
pid : 5510
processes : [['1', '0', 'Ss'], ['15', '1', 'Ss'], ['16', '1', 'Ss'], ['17 ... 99', 'R+'], ['78347', '78344', 'Ss'], ['78349', '78347', 'S']] (truncated)
ValueError: need more than 3 values to unpack
---------------------------
BUG=
Review URL: https://codereview.chromium.org/64553004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@234648 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rw-r--r-- | tools/telemetry/telemetry/test_runner.py | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/tools/telemetry/telemetry/test_runner.py b/tools/telemetry/telemetry/test_runner.py index adb95a8..ec62132 100644 --- a/tools/telemetry/telemetry/test_runner.py +++ b/tools/telemetry/telemetry/test_runner.py @@ -10,9 +10,11 @@ actually running the test is in Test and PageRunner.""" import copy import inspect import json +import math import optparse import os import sys +import traceback from telemetry import test from telemetry.core import browser_options @@ -20,6 +22,71 @@ from telemetry.core import discover from telemetry.core import util +def PrintFormattedException(exception_class, exception, tb): + """Prints an Exception in a more useful format than the default. + + TODO(tonyg): Consider further enhancements. For instance: + - Report stacks to maintainers like depot_tools does. + - Add a debug flag to automatically start pdb upon exception. + """ + def _GetFinalFrame(frame): + final_frame = None + while frame is not None: + final_frame = frame + frame = frame.tb_next + return final_frame + + def _AbbreviateMiddle(target, middle, length): + assert length >= 0, 'Must provide positive length' + assert len(middle) <= length, 'middle must not be greater than length' + if len(target) <= length: + return target + half_length = (length - len(middle)) / 2. + return '%s%s%s' % (target[:int(math.floor(half_length))], + middle, + target[-int(math.ceil(half_length)):]) + + base_dir = os.path.abspath(util.GetChromiumSrcDir()) + formatted_exception = traceback.format_exception( + exception_class, exception, tb) + extracted_tb = traceback.extract_tb(tb) + traceback_header = formatted_exception[0].strip() + exception = formatted_exception[-1].strip() + local_variables = _GetFinalFrame(tb).tb_frame.f_locals + + # Format the traceback. + print >> sys.stderr + print >> sys.stderr, traceback_header + for filename, line, function, text in extracted_tb: + filename = os.path.abspath(filename).lstrip(base_dir) + print >> sys.stderr, ' %s at %s:%d' % (function, filename, line) + print >> sys.stderr, ' %s' % text + + # Format the locals. + if local_variables: + print >> sys.stderr + print >> sys.stderr, 'Locals:' + longest_variable = max([len(v) for v in local_variables.keys()]) + for variable, value in sorted(local_variables.iteritems()): + if variable == 'self': + continue + value = repr(value) + possibly_truncated_value = _AbbreviateMiddle(value, ' ... ', 128) + truncation_indication = '' + if len(possibly_truncated_value) != len(value): + truncation_indication = ' (truncated)' + print >> sys.stderr, ' %s: %s%s' % (variable.ljust(longest_variable + 1), + possibly_truncated_value, + truncation_indication) + + # Format the exception. + print >> sys.stderr + print >> sys.stderr, exception + + +sys.excepthook = PrintFormattedException + + class Command(object): usage = '' |