1dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui#!/usr/bin/env python
2dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui#
3dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui# Copyright (C) 2015 The Android Open Source Project
4dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui#
5dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui# Licensed under the Apache License, Version 2.0 (the "License");
6dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui# you may not use this file except in compliance with the License.
7dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui# You may obtain a copy of the License at
8dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui#
9dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui#      http://www.apache.org/licenses/LICENSE-2.0
10dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui#
11dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui# Unless required by applicable law or agreed to in writing, software
12dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui# distributed under the License is distributed on an "AS IS" BASIS,
13dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui# See the License for the specific language governing permissions and
15dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui# limitations under the License.
16dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui#
17dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
18dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui"""Simpleperf gui reporter: provide gui interface for simpleperf report command.
19dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
20dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin CuiThere are two ways to use gui reporter. One way is to pass it a report file
21dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuigenerated by simpleperf report command, and reporter will display it. The
22dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuiother ways is to pass it any arguments you want to use when calling
23dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuisimpleperf report command. The reporter will call `simpleperf report` to
24dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuigenerate report file, and display it.
25dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui"""
26dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
27dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuiimport os.path
28dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuiimport re
29dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuiimport subprocess
30dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuiimport sys
31dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuifrom tkFont import *
32dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuifrom Tkinter import *
33dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuifrom ttk import *
34dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
35dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin CuiPAD_X = 3
36dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin CuiPAD_Y = 3
37dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
38dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
39dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuiclass CallTreeNode(object):
40dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
41dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  """Representing a node in call-graph."""
42dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
43dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def __init__(self, percentage, function_name):
44dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    self.percentage = percentage
45dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    self.call_stack = [function_name]
46dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    self.children = []
47dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
48dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def add_call(self, function_name):
49dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    self.call_stack.append(function_name)
50dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
51dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def add_child(self, node):
52dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    self.children.append(node)
53dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
54dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def __str__(self):
55dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    strs = self.dump()
56dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    return '\n'.join(strs)
57dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
58dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def dump(self):
59dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    strs = []
60dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    strs.append('CallTreeNode percentage = %.2f' % self.percentage)
61dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    for function_name in self.call_stack:
62dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      strs.append(' %s' % function_name)
63dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    for child in self.children:
64dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      child_strs = child.dump()
65dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      strs.extend(['  ' + x for x in child_strs])
66dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    return strs
67dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
68dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
69dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuiclass ReportItem(object):
70dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
71dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  """Representing one item in report, may contain a CallTree."""
72dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
73dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def __init__(self, raw_line):
74dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    self.raw_line = raw_line
75dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    self.call_tree = None
76dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
77dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def __str__(self):
78dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    strs = []
79dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    strs.append('ReportItem (raw_line %s)' % self.raw_line)
80dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    if self.call_tree is not None:
81dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      strs.append('%s' % self.call_tree)
82dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    return '\n'.join(strs)
83dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
84dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
85dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuidef parse_report_items(lines):
86dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  report_items = []
87dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  cur_report_item = None
88dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  call_tree_stack = {}
89dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  vertical_columns = []
90dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  last_node = None
91dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
92dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  for line in lines:
93dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    if not line:
94dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      continue
95dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    if not line[0].isspace():
96dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      cur_report_item = ReportItem(line)
97dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      report_items.append(cur_report_item)
98dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      # Each report item can have different column depths.
99dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      vertical_columns = []
100dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    else:
101dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      for i in range(len(line)):
102dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        if line[i] == '|':
103dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          if not vertical_columns or vertical_columns[-1] < i:
104dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui            vertical_columns.append(i)
105dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
106dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      if not line.strip('| \t'):
107dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        continue
108dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      if line.find('-') == -1:
109dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        line = line.strip('| \t')
110dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        function_name = line
111dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        last_node.add_call(function_name)
112dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      else:
113dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        pos = line.find('-')
114dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        depth = -1
115dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        for i in range(len(vertical_columns)):
116dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          if pos >= vertical_columns[i]:
117dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui            depth = i
118dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        assert depth != -1
119dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
120dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        line = line.strip('|- \t')
121dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        m = re.search(r'^([\d\.]+)%[-\s]+(.+)$', line)
122dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        if m:
123dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          percentage = float(m.group(1))
124dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          function_name = m.group(2)
125dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        else:
126dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          percentage = 100.0
127dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          function_name = line
128dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
129dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        node = CallTreeNode(percentage, function_name)
130dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        if depth == 0:
131dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          cur_report_item.call_tree = node
132dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        else:
133dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          call_tree_stack[depth - 1].add_child(node)
134dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        call_tree_stack[depth] = node
135dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        last_node = node
136dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
137dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  return report_items
138dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
139dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
140dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuiclass ReportWindow(object):
141dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
142dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  """A window used to display report file."""
143dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
144dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def __init__(self, master, report_context, title_line, report_items):
145dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    frame = Frame(master)
146dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    frame.pack(fill=BOTH, expand=1)
147dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
148dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    font = Font(family='courier', size=10)
149dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
150dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    # Report Context
151dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    for line in report_context:
152dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      label = Label(frame, text=line, font=font)
153dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      label.pack(anchor=W, padx=PAD_X, pady=PAD_Y)
154dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
155dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    # Space
156dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    label = Label(frame, text='', font=font)
157dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    label.pack(anchor=W, padx=PAD_X, pady=PAD_Y)
158dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
159dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    # Title
160dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    label = Label(frame, text='  ' + title_line, font=font)
161dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    label.pack(anchor=W, padx=PAD_X, pady=PAD_Y)
162dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
163dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    # Report Items
164dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    report_frame = Frame(frame)
165dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    report_frame.pack(fill=BOTH, expand=1)
166dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
167dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    yscrollbar = Scrollbar(report_frame)
168dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    yscrollbar.pack(side=RIGHT, fill=Y)
169dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    xscrollbar = Scrollbar(report_frame, orient=HORIZONTAL)
170dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    xscrollbar.pack(side=BOTTOM, fill=X)
171dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
172dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    tree = Treeview(report_frame, columns=[title_line], show='')
173dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    tree.pack(side=LEFT, fill=BOTH, expand=1)
174dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    tree.tag_configure('set_font', font=font)
175dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
176dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    tree.config(yscrollcommand=yscrollbar.set)
177dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    yscrollbar.config(command=tree.yview)
178dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    tree.config(xscrollcommand=xscrollbar.set)
179dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    xscrollbar.config(command=tree.xview)
180dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
181dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    self.display_report_items(tree, report_items)
182dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
183dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def display_report_items(self, tree, report_items):
184dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    for report_item in report_items:
185dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      prefix_str = '+ ' if report_item.call_tree is not None else '  '
186dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      id = tree.insert(
187dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          '',
188dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          'end',
189dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          None,
190dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          values=[
191dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui              prefix_str +
192dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui              report_item.raw_line],
193dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui          tag='set_font')
194dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      if report_item.call_tree is not None:
195dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui        self.display_call_tree(tree, id, report_item.call_tree, 1)
196dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
197dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  def display_call_tree(self, tree, parent_id, node, indent):
198dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    id = parent_id
199dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    indent_str = '  ' * indent
200dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
201dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    if node.percentage != 100.0:
202dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      percentage_str = '%.2f%%' % node.percentage
203dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    else:
204dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      percentage_str = ''
205dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    first_open = True if node.percentage == 100.0 else False
206dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
207dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    for i in range(len(node.call_stack)):
208dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      s = indent_str
209dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      s += '+ ' if node.children else '  '
210dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      s += percentage_str if i == 0 else ' ' * len(percentage_str)
211dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      s += node.call_stack[i]
212dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      child_open = first_open if i == 0 else True
213dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      id = tree.insert(id, 'end', None, values=[s], open=child_open,
214dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui                       tag='set_font')
215dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
216dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    for child in node.children:
217dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      self.display_call_tree(tree, id, child, indent + 1)
218dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
219dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
220dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuidef display_report_file(report_file):
221dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  fh = open(report_file, 'r')
222dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  lines = fh.readlines()
223dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  fh.close()
224dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
225dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  lines = [x.rstrip() for x in lines]
226dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
227dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  blank_line_index = -1
228dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  for i in range(len(lines)):
229dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    if not lines[i]:
230dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      blank_line_index = i
231dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui      break
232dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  assert blank_line_index != -1
233dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  assert blank_line_index + 1 < len(lines)
234dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
235dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  report_context = lines[:blank_line_index]
236dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  title_line = lines[blank_line_index + 1]
237dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  report_items = parse_report_items(lines[blank_line_index + 2:])
238dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
239dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  root = Tk()
240dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  ReportWindow(root, report_context, title_line, report_items)
241dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  root.mainloop()
242dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
243dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
244dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuidef call_simpleperf_report(args, report_file):
245dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  output_fh = open(report_file, 'w')
246dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  args = ['simpleperf', 'report'] + args
247dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  subprocess.check_call(args, stdout=output_fh)
248dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  output_fh.close()
249dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
250dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
251dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuidef main():
252dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  if len(sys.argv) == 2 and os.path.isfile(sys.argv[1]):
253dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    display_report_file(sys.argv[1])
254dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  else:
255dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    call_simpleperf_report(sys.argv[1:], 'perf.report')
256dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui    display_report_file('perf.report')
257dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
258dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui
259dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cuiif __name__ == '__main__':
260dae17fd9fcc78800d2447c8470f7a1ecd813c2cdYabin Cui  main()
261