| #!/usr/bin/env python |
| |
| # Copyright (C) 2015 Mark Hahnenberg. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| # THE POSSIBILITY OF SUCH DAMAGE. |
| |
| import fileinput |
| import re |
| |
| TIMING_REGEX = re.compile( |
| r'^\[(?P<pid>[0-9]+)\] ' |
| '(?P<name>[^ ]+) ' |
| '\(Parent: (?P<parent>[^\)]+)\) ' |
| '\((?P<collect_type>[^\)]+)\): ' |
| '(?P<total_time>[0-9]+\.[0-9]+)ms ' |
| '\(avg. (?P<avg_time>[^,]+), ' |
| 'min. (?P<min_time>[^,]+), ' |
| 'max. (?P<max_time>[^,]+), ' |
| 'count (?P<count>[^\)]+)\)') |
| |
| class Timing(object): |
| def __init__(self, pid, name, parent, collect_type, total_time, avg_time, min_time, max_time, count): |
| self.pid = int(pid) |
| self.name = str(name) |
| self.parent = str(parent) |
| self.collect_type = str(collect_type) |
| self.total_time = float(total_time) |
| self.avg_time = float(avg_time) |
| self.min_time = float(min_time) |
| self.max_time = float(max_time) |
| self.count = int(count) |
| self.children = [] |
| |
| def __unicode__(self): |
| return u"%s - %s total: %.2f, avg: %.2f" % (self.name, self.collect_type, self.total_time, self.avg_time) |
| |
| def __str__(self): |
| return "%s - %s total: %.2f, avg: %.2f" % (self.name, self.collect_type, self.total_time, self.avg_time) |
| |
| def __repr__(self): |
| return "%s - %s total: %.2f, avg: %.2f" % (self.name, self.collect_type, self.total_time, self.avg_time) |
| |
| |
| def parse_input(): |
| timings = [] |
| for line in fileinput.input(): |
| result = TIMING_REGEX.match(line) |
| if result is None: |
| continue |
| timings.append(Timing( |
| result.group('pid'), |
| result.group('name'), |
| result.group('parent'), |
| result.group('collect_type'), |
| result.group('total_time'), |
| result.group('avg_time'), |
| result.group('min_time'), |
| result.group('max_time'), |
| result.group('count'), |
| )) |
| return timings |
| |
| |
| def print_timing_node(root, timings, tabs): |
| for _ in range(tabs): |
| print " ", |
| percent_time = 1.0 |
| if root.parent is not None: |
| percent_time = float(root.total_time) / float(root.parent.total_time) |
| print "%s - %.2f%%" % (str(root), percent_time * 100.0) |
| for child in reversed(sorted(root.children, key=lambda t: t.total_time)): |
| if child.parent != root: |
| continue |
| if child.collect_type != root.collect_type: |
| continue |
| print_timing_node(child, timings, tabs + 1) |
| |
| |
| def print_timing_tree(timings): |
| timings.sort(key=lambda t: t.total_time) |
| timings.reverse() |
| collection_types = ["All", "Eden", "Full"] |
| for collect_type in collection_types: |
| for timing in timings: |
| if timing.collect_type != collect_type: |
| continue |
| if timing.parent is not None: |
| continue |
| print_timing_node(timing, timings, 0) |
| print "" |
| |
| |
| def link_parents(timings): |
| for timing in timings: |
| if timing.parent == "nullptr": |
| timing.parent = None |
| continue |
| for parent in timings: |
| if timing.parent != parent.name: |
| continue |
| if timing.collect_type != parent.collect_type: |
| continue |
| timing.parent = parent |
| parent.children.append(timing) |
| |
| def main(): |
| timings = parse_input() |
| link_parents(timings) |
| print_timing_tree(timings) |
| |
| if __name__ == "__main__": |
| main() |