Improve parsing error handling in dmprof.


BUG=none
TEST=none


Review URL: http://codereview.chromium.org/10096009

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132541 0039d316-1c4b-4281-b951-d872f2087c98
parent a25ead36
...@@ -66,6 +66,13 @@ appeared_addresses = set() ...@@ -66,6 +66,13 @@ appeared_addresses = set()
components = [] components = []
class ParsingException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class Policy(object): class Policy(object):
def __init__(self, name, mmap, pattern): def __init__(self, name, mmap, pattern):
...@@ -112,17 +119,16 @@ class Bucket(object): ...@@ -112,17 +119,16 @@ class Bucket(object):
class Log(object): class Log(object):
"""A class representing one dumped log data.""" """A class representing one dumped log data."""
def __init__(self, log_path, buckets): def __init__(self, log_path):
self.log_path = log_path self.log_path = log_path
self.log_lines = [ self.log_lines = [
l for l in open(self.log_path, 'r') if l and not l.startswith('#')] l for l in open(self.log_path, 'r') if l and not l.startswith('#')]
self.log_version = '' self.log_version = ''
sys.stderr.write('parsing a log file:%s\n' % log_path) sys.stderr.write('Loading a dump: %s\n' % log_path)
self.mmap_stacktrace_lines = [] self.mmap_stacktrace_lines = []
self.malloc_stacktrace_lines = [] self.malloc_stacktrace_lines = []
self.counters = {} self.counters = {}
self.log_time = os.stat(self.log_path).st_mtime self.log_time = os.stat(self.log_path).st_mtime
self.parse_log(buckets)
@staticmethod @staticmethod
def dump_stacktrace_lines(stacktrace_lines, buckets): def dump_stacktrace_lines(stacktrace_lines, buckets):
...@@ -279,13 +285,17 @@ class Log(object): ...@@ -279,13 +285,17 @@ class Log(object):
@staticmethod @staticmethod
def skip_lines_while(line_number, max_line_number, skipping_condition): def skip_lines_while(line_number, max_line_number, skipping_condition):
"""Increments line_number until skipping_condition(line_number) is false. """Increments line_number until skipping_condition(line_number) is false.
Returns:
A pair of an integer indicating a line number after skipped, and a
boolean value which is True if found a line which skipping_condition
is False for.
""" """
while skipping_condition(line_number): while skipping_condition(line_number):
line_number += 1 line_number += 1
if line_number >= max_line_number: if line_number >= max_line_number:
sys.stderr.write('invalid heap profile dump.') return line_number, False
return line_number return line_number, True
return line_number
def parse_stacktraces_while_valid(self, buckets, log_lines, line_number): def parse_stacktraces_while_valid(self, buckets, log_lines, line_number):
"""Parses stacktrace lines while the lines are valid. """Parses stacktrace lines while the lines are valid.
...@@ -301,11 +311,11 @@ class Log(object): ...@@ -301,11 +311,11 @@ class Log(object):
A pair of a list of valid lines and an integer representing the last A pair of a list of valid lines and an integer representing the last
line number in log_lines. line number in log_lines.
""" """
line_number = self.skip_lines_while( (line_number, _) = self.skip_lines_while(
line_number, len(log_lines), line_number, len(log_lines),
lambda n: not log_lines[n].split()[0].isdigit()) lambda n: not log_lines[n].split()[0].isdigit())
stacktrace_lines_start = line_number stacktrace_lines_start = line_number
line_number = self.skip_lines_while( (line_number, _) = self.skip_lines_while(
line_number, len(log_lines), line_number, len(log_lines),
lambda n: self.check_stacktrace_line(log_lines[n], buckets)) lambda n: self.check_stacktrace_line(log_lines[n], buckets))
return (log_lines[stacktrace_lines_start:line_number], line_number) return (log_lines[stacktrace_lines_start:line_number], line_number)
...@@ -323,15 +333,15 @@ class Log(object): ...@@ -323,15 +333,15 @@ class Log(object):
log_lines. log_lines.
Raises: Raises:
RuntimeException for invalid dump versions. ParsingException for invalid dump versions.
""" """
sys.stderr.write(' heap profile dump version: %s\n' % self.log_version) sys.stderr.write(' Version: %s\n' % self.log_version)
if self.log_version in (DUMP_DEEP_3, DUMP_DEEP_4): if self.log_version in (DUMP_DEEP_3, DUMP_DEEP_4):
(self.mmap_stacktrace_lines, line_number) = ( (self.mmap_stacktrace_lines, line_number) = (
self.parse_stacktraces_while_valid( self.parse_stacktraces_while_valid(
buckets, self.log_lines, line_number)) buckets, self.log_lines, line_number))
line_number = self.skip_lines_while( (line_number, _) = self.skip_lines_while(
line_number, len(self.log_lines), line_number, len(self.log_lines),
lambda n: self.log_lines[n] != 'MALLOC_STACKTRACES:\n') lambda n: self.log_lines[n] != 'MALLOC_STACKTRACES:\n')
(self.malloc_stacktrace_lines, line_number) = ( (self.malloc_stacktrace_lines, line_number) = (
...@@ -342,7 +352,7 @@ class Log(object): ...@@ -342,7 +352,7 @@ class Log(object):
(self.mmap_stacktrace_lines, line_number) = ( (self.mmap_stacktrace_lines, line_number) = (
self.parse_stacktraces_while_valid( self.parse_stacktraces_while_valid(
buckets, self.log_lines, line_number)) buckets, self.log_lines, line_number))
line_number = self.skip_lines_while( (line_number, _) = self.skip_lines_while(
line_number, len(self.log_lines), line_number, len(self.log_lines),
lambda n: self.log_lines[n] != 'MALLOC_STACKTRACES:\n') lambda n: self.log_lines[n] != 'MALLOC_STACKTRACES:\n')
(self.malloc_stacktrace_lines, line_number) = ( (self.malloc_stacktrace_lines, line_number) = (
...@@ -357,12 +367,12 @@ class Log(object): ...@@ -357,12 +367,12 @@ class Log(object):
buckets, self.log_lines, line_number)) buckets, self.log_lines, line_number))
else: else:
raise RuntimeError('invalid heap profile dump version: %s' % ( raise ParsingException('invalid heap profile dump version: %s' % (
self.log_version)) self.log_version))
def parse_global_stats(self): def parse_global_stats(self):
"""Parses lines in self.log_lines as global stats.""" """Parses lines in self.log_lines as global stats."""
ln = self.skip_lines_while( (ln, _) = self.skip_lines_while(
0, len(self.log_lines), 0, len(self.log_lines),
lambda n: self.log_lines[n] != 'GLOBAL_STATS:\n') lambda n: self.log_lines[n] != 'GLOBAL_STATS:\n')
...@@ -378,7 +388,7 @@ class Log(object): ...@@ -378,7 +388,7 @@ class Log(object):
'total', 'file', 'anonymous', 'other', 'mmap', 'tcmalloc'] 'total', 'file', 'anonymous', 'other', 'mmap', 'tcmalloc']
for prefix in global_stat_names: for prefix in global_stat_names:
ln = self.skip_lines_while( (ln, _) = self.skip_lines_while(
ln, len(self.log_lines), ln, len(self.log_lines),
lambda n: self.log_lines[n].split()[0] != prefix) lambda n: self.log_lines[n].split()[0] != prefix)
words = self.log_lines[ln].split() words = self.log_lines[ln].split()
...@@ -393,26 +403,31 @@ class Log(object): ...@@ -393,26 +403,31 @@ class Log(object):
and an integer indicating a line number next to the version string). and an integer indicating a line number next to the version string).
Raises: Raises:
RuntimeException for invalid dump versions. ParsingException for invalid dump versions.
""" """
version = '' version = ''
# Skip until an identifiable line. # Skip until an identifiable line.
headers = ('STACKTRACES:\n', 'MMAP_STACKTRACES:\n', 'heap profile: ') headers = ('STACKTRACES:\n', 'MMAP_STACKTRACES:\n', 'heap profile: ')
ln = self.skip_lines_while( if not self.log_lines:
raise ParsingException('Empty heap dump file.')
(ln, found) = self.skip_lines_while(
0, len(self.log_lines), 0, len(self.log_lines),
lambda n: not self.log_lines[n].startswith(headers)) lambda n: not self.log_lines[n].startswith(headers))
if not found:
raise ParsingException('Invalid heap dump file (no version header).')
# Identify a version. # Identify a version.
if self.log_lines[ln].startswith('heap profile: '): if self.log_lines[ln].startswith('heap profile: '):
version = self.log_lines[ln][13:].strip() version = self.log_lines[ln][13:].strip()
if (version == DUMP_DEEP_2 or version == DUMP_DEEP_3 or if (version == DUMP_DEEP_2 or version == DUMP_DEEP_3 or
version == DUMP_DEEP_4): version == DUMP_DEEP_4):
ln = self.skip_lines_while( (ln, _) = self.skip_lines_while(
ln, len(self.log_lines), ln, len(self.log_lines),
lambda n: self.log_lines[n] != 'MMAP_STACKTRACES:\n') lambda n: self.log_lines[n] != 'MMAP_STACKTRACES:\n')
else: else:
raise RuntimeError('invalid heap profile dump version: %s' % version) raise ParsingException('invalid heap profile dump version: %s'
% version)
elif self.log_lines[ln] == 'STACKTRACES:\n': elif self.log_lines[ln] == 'STACKTRACES:\n':
version = DUMP_DEEP_1 version = DUMP_DEEP_1
elif self.log_lines[ln] == 'MMAP_STACKTRACES:\n': elif self.log_lines[ln] == 'MMAP_STACKTRACES:\n':
...@@ -746,8 +761,6 @@ Examples: ...@@ -746,8 +761,6 @@ Examples:
buckets[int(words[0])] = Bucket(words[1:]) buckets[int(words[0])] = Bucket(words[1:])
n += 1 n += 1
sys.stderr.write('the number buckets: %d\n' % (bucket_count))
log_path_list = [log_path] log_path_list = [log_path]
if action in ('--csv', '--json'): if action in ('--csv', '--json'):
...@@ -762,7 +775,16 @@ Examples: ...@@ -762,7 +775,16 @@ Examples:
break break
n += 1 n += 1
logs = [Log(path, buckets) for path in log_path_list] logs = []
for path in log_path_list:
new_log = Log(path)
sys.stderr.write('Parsing a dump: %s\n' % path)
try:
new_log.parse_log(buckets)
except ParsingException:
sys.stderr.write(' Ignored an invalid dump: %s\n' % path)
else:
logs.append(new_log)
sys.stderr.write('getting symbols\n') sys.stderr.write('getting symbols\n')
update_symbols(symbol_path, maps_lines, chrome_path) update_symbols(symbol_path, maps_lines, chrome_path)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment