Index: tools/ll_prof.py
|
diff --git a/tools/ll_prof.py b/tools/ll_prof.py
|
index 7f12c133c55b71a769d56d68e7ed62916c16da44..650f923a2d5f397990c83d677f272147137151f1 100755
|
--- a/tools/ll_prof.py
|
+++ b/tools/ll_prof.py
|
@@ -124,7 +124,7 @@ class Code(object):
|
self.callee_ticks = collections.defaultdict(lambda: 0)
|
self.callee_ticks[callee] += 1
|
|
- def PrintAnnotated(self, code_info, options):
|
+ def PrintAnnotated(self, arch, options):
|
if self.self_ticks_map is None:
|
ticks_map = []
|
else:
|
@@ -135,7 +135,7 @@ class Code(object):
|
ticks_offsets = [t[0] for t in ticks_map]
|
ticks_counts = [t[1] for t in ticks_map]
|
# Get a list of disassembled lines and their addresses.
|
- lines = self._GetDisasmLines(code_info, options)
|
+ lines = self._GetDisasmLines(arch, options)
|
if len(lines) == 0:
|
return
|
# Print annotated lines.
|
@@ -174,17 +174,17 @@ class Code(object):
|
self.end_address - self.start_address,
|
self.origin)
|
|
- def _GetDisasmLines(self, code_info, options):
|
+ def _GetDisasmLines(self, arch, options):
|
if self.origin == JS_ORIGIN or self.origin == JS_SNAPSHOT_ORIGIN:
|
inplace = False
|
- filename = options.log + ".code"
|
+ filename = options.log + ".ll"
|
else:
|
inplace = True
|
filename = self.origin
|
return disasm.GetDisasmLines(filename,
|
self.origin_offset,
|
self.end_address - self.start_address,
|
- code_info.arch,
|
+ arch,
|
inplace)
|
|
|
@@ -304,76 +304,102 @@ class CodeInfo(object):
|
self.header_size = header_size
|
|
|
-class CodeLogReader(object):
|
- """V8 code event log reader."""
|
+class SnapshotLogReader(object):
|
+ """V8 snapshot log reader."""
|
|
- _CODE_INFO_RE = re.compile(
|
- r"code-info,([^,]+),(\d+)")
|
+ _SNAPSHOT_CODE_NAME_RE = re.compile(
|
+ r"snapshot-code-name,(\d+),\"(.*)\"")
|
|
- _CODE_CREATE_RE = re.compile(
|
- r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(0x[a-f0-9]+),([~*])?)?(?:,(\d+))?")
|
+ def __init__(self, log_name):
|
+ self.log_name = log_name
|
+
|
+ def ReadNameMap(self):
|
+ log = open(self.log_name, "r")
|
+ try:
|
+ snapshot_pos_to_name = {}
|
+ for line in log:
|
+ match = SnapshotLogReader._SNAPSHOT_CODE_NAME_RE.match(line)
|
+ if match:
|
+ pos = int(match.group(1))
|
+ name = match.group(2)
|
+ snapshot_pos_to_name[pos] = name
|
+ finally:
|
+ log.close()
|
+ return snapshot_pos_to_name
|
|
- _CODE_MOVE_RE = re.compile(
|
- r"code-move,(0x[a-f0-9]+),(0x[a-f0-9]+)")
|
|
- _CODE_DELETE_RE = re.compile(
|
- r"code-delete,(0x[a-f0-9]+)")
|
+class LogReader(object):
|
+ """V8 low-level (binary) log reader."""
|
|
- _SNAPSHOT_POS_RE = re.compile(
|
- r"snapshot-pos,(0x[a-f0-9]+),(\d+)")
|
+ _ARCH_TO_POINTER_TYPE_MAP = {
|
+ "ia32": ctypes.c_uint32,
|
+ "arm": ctypes.c_uint32,
|
+ "x64": ctypes.c_uint64
|
+ }
|
|
- _CODE_MOVING_GC = "code-moving-gc"
|
+ _CODE_CREATE_TAG = "C"
|
+ _CODE_MOVE_TAG = "M"
|
+ _CODE_DELETE_TAG = "D"
|
+ _SNAPSHOT_POSITION_TAG = "P"
|
+ _CODE_MOVING_GC_TAG = "G"
|
|
- def __init__(self, log_name, code_map, is_snapshot, snapshot_pos_to_name):
|
- self.log = open(log_name, "r")
|
+ def __init__(self, log_name, code_map, snapshot_pos_to_name):
|
+ self.log_file = open(log_name, "r")
|
+ self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE)
|
+ self.log_pos = 0
|
self.code_map = code_map
|
- self.is_snapshot = is_snapshot
|
self.snapshot_pos_to_name = snapshot_pos_to_name
|
self.address_to_snapshot_name = {}
|
|
- def ReadCodeInfo(self):
|
- line = self.log.readline() or ""
|
- match = CodeLogReader._CODE_INFO_RE.match(line)
|
- assert match, "No code info in log"
|
- return CodeInfo(arch=match.group(1), header_size=int(match.group(2)))
|
-
|
- def ReadUpToGC(self, code_info):
|
- made_progress = False
|
- code_header_size = code_info.header_size
|
- while True:
|
- line = self.log.readline()
|
- if not line:
|
- return made_progress
|
- made_progress = True
|
-
|
- if line.startswith(CodeLogReader._CODE_MOVING_GC):
|
+ self.arch = self.log[:self.log.find("\0")]
|
+ self.log_pos += len(self.arch) + 1
|
+ assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \
|
+ "Unsupported architecture %s" % self.arch
|
+ pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch]
|
+
|
+ self.code_create_struct = LogReader._DefineStruct([
|
+ ("name_size", ctypes.c_int32),
|
+ ("code_address", pointer_type),
|
+ ("code_size", ctypes.c_int32)])
|
+
|
+ self.code_move_struct = LogReader._DefineStruct([
|
+ ("from_address", pointer_type),
|
+ ("to_address", pointer_type)])
|
+
|
+ self.code_delete_struct = LogReader._DefineStruct([
|
+ ("address", pointer_type)])
|
+
|
+ self.snapshot_position_struct = LogReader._DefineStruct([
|
+ ("address", pointer_type),
|
+ ("position", ctypes.c_int32)])
|
+
|
+ def ReadUpToGC(self):
|
+ while self.log_pos < self.log.size():
|
+ tag = self.log[self.log_pos]
|
+ self.log_pos += 1
|
+
|
+ if tag == LogReader._CODE_MOVING_GC_TAG:
|
self.address_to_snapshot_name.clear()
|
- return made_progress
|
+ return
|
|
- match = CodeLogReader._CODE_CREATE_RE.match(line)
|
- if match:
|
- start_address = int(match.group(2), 16) + code_header_size
|
- end_address = start_address + int(match.group(3)) - code_header_size
|
+ if tag == LogReader._CODE_CREATE_TAG:
|
+ event = self.code_create_struct.from_buffer(self.log, self.log_pos)
|
+ self.log_pos += ctypes.sizeof(event)
|
+ start_address = event.code_address
|
+ end_address = start_address + event.code_size
|
if start_address in self.address_to_snapshot_name:
|
name = self.address_to_snapshot_name[start_address]
|
origin = JS_SNAPSHOT_ORIGIN
|
else:
|
- tag = match.group(1)
|
- optimization_status = match.group(6)
|
- func_name = match.group(4)
|
- if optimization_status:
|
- name = "%s:%s%s" % (tag, optimization_status, func_name)
|
- else:
|
- name = "%s:%s" % (tag, func_name)
|
+ name = self.log[self.log_pos:self.log_pos + event.name_size]
|
origin = JS_ORIGIN
|
- if self.is_snapshot:
|
- origin_offset = 0
|
- else:
|
- origin_offset = int(match.group(7))
|
+ self.log_pos += event.name_size
|
+ origin_offset = self.log_pos
|
+ self.log_pos += event.code_size
|
code = Code(name, start_address, end_address, origin, origin_offset)
|
conficting_code = self.code_map.Find(start_address)
|
if conficting_code:
|
- CodeLogReader._HandleCodeConflict(conficting_code, code)
|
+ LogReader._HandleCodeConflict(conficting_code, code)
|
# TODO(vitalyr): this warning is too noisy because of our
|
# attempts to reconstruct code log from the snapshot.
|
# print >>sys.stderr, \
|
@@ -382,10 +408,11 @@ class CodeLogReader(object):
|
self.code_map.Add(code)
|
continue
|
|
- match = CodeLogReader._CODE_MOVE_RE.match(line)
|
- if match:
|
- old_start_address = int(match.group(1), 16) + code_header_size
|
- new_start_address = int(match.group(2), 16) + code_header_size
|
+ if tag == LogReader._CODE_MOVE_TAG:
|
+ event = self.code_move_struct.from_buffer(self.log, self.log_pos)
|
+ self.log_pos += ctypes.sizeof(event)
|
+ old_start_address = event.from_address
|
+ new_start_address = event.to_address
|
if old_start_address == new_start_address:
|
# Skip useless code move entries.
|
continue
|
@@ -402,9 +429,10 @@ class CodeLogReader(object):
|
self.code_map.Add(code)
|
continue
|
|
- match = CodeLogReader._CODE_DELETE_RE.match(line)
|
- if match:
|
- old_start_address = int(match.group(1), 16) + code_header_size
|
+ if tag == LogReader._CODE_DELETE_TAG:
|
+ event = self.code_delete_struct.from_buffer(self.log, self.log_pos)
|
+ self.log_pos += ctypes.sizeof(event)
|
+ old_start_address = event.address
|
code = self.code_map.Find(old_start_address)
|
if not code:
|
print >>sys.stderr, "Warning: Not found %x" % old_start_address
|
@@ -414,40 +442,36 @@ class CodeLogReader(object):
|
self.code_map.Remove(code)
|
continue
|
|
- match = CodeLogReader._SNAPSHOT_POS_RE.match(line)
|
- if match:
|
- start_address = int(match.group(1), 16) + code_header_size
|
- snapshot_pos = int(match.group(2))
|
- if self.is_snapshot:
|
- code = self.code_map.Find(start_address)
|
- if code:
|
- assert code.start_address == start_address, \
|
- "Inexact snapshot address %x for %s" % (start_address, code)
|
- self.snapshot_pos_to_name[snapshot_pos] = code.name
|
- else:
|
- if snapshot_pos in self.snapshot_pos_to_name:
|
- self.address_to_snapshot_name[start_address] = \
|
- self.snapshot_pos_to_name[snapshot_pos]
|
+ if tag == LogReader._SNAPSHOT_POSITION_TAG:
|
+ event = self.snapshot_position_struct.from_buffer(self.log,
|
+ self.log_pos)
|
+ self.log_pos += ctypes.sizeof(event)
|
+ start_address = event.address
|
+ snapshot_pos = event.position
|
+ if snapshot_pos in self.snapshot_pos_to_name:
|
+ self.address_to_snapshot_name[start_address] = \
|
+ self.snapshot_pos_to_name[snapshot_pos]
|
+ continue
|
+
|
+ assert False, "Unknown tag %s" % tag
|
|
def Dispose(self):
|
self.log.close()
|
+ self.log_file.close()
|
+
|
+ @staticmethod
|
+ def _DefineStruct(fields):
|
+ class Struct(ctypes.Structure):
|
+ _fields_ = fields
|
+ return Struct
|
|
@staticmethod
|
def _HandleCodeConflict(old_code, new_code):
|
assert (old_code.start_address == new_code.start_address and
|
old_code.end_address == new_code.end_address), \
|
"Conficting code log entries %s and %s" % (old_code, new_code)
|
- CodeLogReader._UpdateNames(old_code, new_code)
|
-
|
- @staticmethod
|
- def _UpdateNames(old_code, new_code):
|
if old_code.name == new_code.name:
|
return
|
- # Kludge: there are code objects with custom names that don't
|
- # match their flags.
|
- misnamed_code = set(["Builtin:CpuFeatures::Probe"])
|
- if old_code.name in misnamed_code:
|
- return
|
# Code object may be shared by a few functions. Collect the full
|
# set of names.
|
old_code.AddName(new_code.name)
|
@@ -756,14 +780,14 @@ class LibraryRepo(object):
|
return True
|
|
|
-def PrintReport(code_map, library_repo, code_info, options):
|
+def PrintReport(code_map, library_repo, arch, options):
|
print "Ticks per symbol:"
|
used_code = [code for code in code_map.UsedCode()]
|
used_code.sort(key=lambda x: x.self_ticks, reverse=True)
|
for i, code in enumerate(used_code):
|
print "%10d %s [%s]" % (code.self_ticks, code.FullName(), code.origin)
|
if options.disasm_all or i < options.disasm_top:
|
- code.PrintAnnotated(code_info, options)
|
+ code.PrintAnnotated(arch, options)
|
print
|
print "Ticks per library:"
|
mmap_infos = [m for m in library_repo.infos]
|
@@ -825,11 +849,11 @@ if __name__ == "__main__":
|
|
if not options.quiet:
|
if options.snapshot:
|
- print "V8 logs: %s, %s, %s.code" % (options.snapshot_log,
|
- options.log,
|
- options.log)
|
+ print "V8 logs: %s, %s, %s.ll" % (options.snapshot_log,
|
+ options.log,
|
+ options.log)
|
else:
|
- print "V8 log: %s, %s.code (no snapshot)" % (options.log, options.log)
|
+ print "V8 log: %s, %s.ll (no snapshot)" % (options.log, options.log)
|
print "Perf trace file: %s" % options.trace
|
|
# Stats.
|
@@ -840,30 +864,24 @@ if __name__ == "__main__":
|
mmap_time = 0
|
sample_time = 0
|
|
- # Initialize the log reader and get the code info.
|
- code_map = CodeMap()
|
+ # Process the snapshot log to fill the snapshot name map.
|
snapshot_name_map = {}
|
- log_reader = CodeLogReader(log_name=options.log,
|
- code_map=code_map,
|
- is_snapshot=False,
|
- snapshot_pos_to_name=snapshot_name_map)
|
- code_info = log_reader.ReadCodeInfo()
|
+ if options.snapshot:
|
+ snapshot_log_reader = SnapshotLogReader(log_name=options.snapshot_log)
|
+ snapshot_name_map = snapshot_log_reader.ReadNameMap()
|
+
|
+ # Initialize the log reader.
|
+ code_map = CodeMap()
|
+ log_reader = LogReader(log_name=options.log + ".ll",
|
+ code_map=code_map,
|
+ snapshot_pos_to_name=snapshot_name_map)
|
if not options.quiet:
|
- print "Generated code architecture: %s" % code_info.arch
|
+ print "Generated code architecture: %s" % log_reader.arch
|
print
|
|
- # Process the snapshot log to fill the snapshot name map.
|
- if options.snapshot:
|
- snapshot_log_reader = CodeLogReader(log_name=options.snapshot_log,
|
- code_map=CodeMap(),
|
- is_snapshot=True,
|
- snapshot_pos_to_name=snapshot_name_map)
|
- while snapshot_log_reader.ReadUpToGC(code_info):
|
- pass
|
-
|
# Process the code and trace logs.
|
library_repo = LibraryRepo()
|
- log_reader.ReadUpToGC(code_info)
|
+ log_reader.ReadUpToGC()
|
trace_reader = TraceReader(options.trace)
|
while True:
|
header, offset = trace_reader.ReadEventHeader()
|
@@ -874,7 +892,7 @@ if __name__ == "__main__":
|
start = time.time()
|
mmap_info = trace_reader.ReadMmap(header, offset)
|
if mmap_info.filename == V8_GC_FAKE_MMAP:
|
- log_reader.ReadUpToGC(code_info)
|
+ log_reader.ReadUpToGC()
|
else:
|
library_repo.Load(mmap_info, code_map, options)
|
mmap_time += time.time() - start
|
@@ -901,7 +919,7 @@ if __name__ == "__main__":
|
if options.dot:
|
PrintDot(code_map, options)
|
else:
|
- PrintReport(code_map, library_repo, code_info, options)
|
+ PrintReport(code_map, library_repo, log_reader.arch, options)
|
|
if not options.quiet:
|
print
|
|