Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(256)

Unified Diff: tools/ll_prof.py

Issue 6904127: ll_prof: Reduce profiling hooks overhead from >400% to 25%. (Closed)
Patch Set: Review fixes Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/utils.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « src/utils.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698