fune/memory/replace/logalloc/replay/logalloc_munge.py
Sylvestre Ledru 3e84d308c3 Bug 1464869 - Fix flake8/pep8 issue by hand in memory/ r=njn
MozReview-Commit-ID: 8bkhAB4g6rv

--HG--
extra : rebase_source : 623f4ed95d601b47878c910859f3b91e87897011
2018-05-25 23:27:02 -07:00

150 lines
4 KiB
Python

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
This script takes a log from the replace-malloc logalloc library on stdin
and munges it so that it can be used with the logalloc-replay tool.
Given the following output:
13663 malloc(42)=0x7f0c33502040
13663 malloc(24)=0x7f0c33503040
13663 free(0x7f0c33502040)
The resulting output is:
1 malloc(42)=#1
1 malloc(24)=#2
1 free(#1)
See README for more details.
"""
from __future__ import print_function
import sys
from collections import (
defaultdict,
deque,
)
class IdMapping(object):
"""Class to map values to ids.
Each value is associated to an increasing id, starting from 1.
When a value is removed, its id is recycled and will be reused for
subsequent values.
"""
def __init__(self):
self.id = 1
self._values = {}
self._recycle = deque()
def __getitem__(self, value):
if value not in self._values:
if self._recycle:
self._values[value] = self._recycle.popleft()
else:
self._values[value] = self.id
self.id += 1
return self._values[value]
def __delitem__(self, value):
if value == 0:
return
self._recycle.append(self._values[value])
del self._values[value]
def __contains__(self, value):
return value == 0 or value in self._values
class Ignored(Exception):
pass
def split_log_line(line):
try:
# The format for each line is:
# <pid> [<tid>] <function>([<args>])[=<result>]
#
# The original format didn't include the tid, so we try to parse
# lines whether they have one or not.
pid, func_call = line.split(' ', 1)
call, result = func_call.split(')')
func, args = call.split('(')
args = args.split(',') if args else []
if result:
if result[0] != '=':
raise Ignored('Malformed input')
result = result[1:]
if ' ' in func:
tid, func = func.split(' ', 1)
else:
tid = pid
return pid, tid, func, args, result
except Exception:
raise Ignored('Malformed input')
NUM_ARGUMENTS = {
'jemalloc_stats': 0,
'free': 1,
'malloc': 1,
'posix_memalign': 2,
'aligned_alloc': 2,
'calloc': 2,
'realloc': 2,
'memalign': 2,
'valloc': 1,
}
def main():
pids = IdMapping()
processes = defaultdict(lambda: {'pointers': IdMapping(),
'tids': IdMapping()})
for line in sys.stdin:
line = line.strip()
try:
pid, tid, func, args, result = split_log_line(line)
# Replace pid with an id.
pid = pids[int(pid)]
process = processes[pid]
tid = process['tids'][int(tid)]
pointers = process['pointers']
if func not in NUM_ARGUMENTS:
raise Ignored('Unknown function')
if len(args) != NUM_ARGUMENTS[func]:
raise Ignored('Malformed input')
if func in ('jemalloc_stats', 'free') and result:
raise Ignored('Malformed input')
if func in ('free', 'realloc'):
ptr = int(args[0], 16)
if ptr and ptr not in pointers:
raise Ignored('Did not see an alloc for pointer')
args[0] = "#%d" % pointers[ptr]
del pointers[ptr]
if result:
result = int(result, 16)
if not result:
raise Ignored('Result is NULL')
result = "#%d" % pointers[result]
print('%d %d %s(%s)%s' % (pid, tid, func, ','.join(args),
'=%s' % result if result else ''))
except Exception as e:
print('Ignored "%s": %s' % (line, e.message), file=sys.stderr)
if __name__ == '__main__':
main()