• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.traceview;
18 
19 import java.io.InputStream;
20 import java.util.Arrays;
21 import java.util.regex.Pattern;
22 
23 import org.eclipse.jface.viewers.IColorProvider;
24 import org.eclipse.jface.viewers.ITableLabelProvider;
25 import org.eclipse.jface.viewers.ITreeContentProvider;
26 import org.eclipse.jface.viewers.LabelProvider;
27 import org.eclipse.jface.viewers.TreeViewer;
28 import org.eclipse.jface.viewers.Viewer;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.events.SelectionAdapter;
31 import org.eclipse.swt.events.SelectionEvent;
32 import org.eclipse.swt.graphics.Color;
33 import org.eclipse.swt.graphics.Image;
34 import org.eclipse.swt.widgets.Display;
35 import org.eclipse.swt.widgets.Tree;
36 import org.eclipse.swt.widgets.TreeColumn;
37 import org.eclipse.swt.widgets.TreeItem;
38 
39 class ProfileProvider implements ITreeContentProvider {
40 
41     private MethodData[] mRoots;
42     private SelectionAdapter mListener;
43     private TreeViewer mTreeViewer;
44     private TraceReader mReader;
45     private Image mSortUp;
46     private Image mSortDown;
47     private String mColumnNames[] = { "Name", "Incl %", "Inclusive", "Excl %",
48             "Exclusive", "Calls+Recur\nCalls/Total", "Time/Call" };
49     private int mColumnWidths[] = { 370, 70, 70, 70, 70, 90, 70 };
50     private int mColumnAlignments[] = { SWT.LEFT, SWT.RIGHT, SWT.RIGHT,
51             SWT.RIGHT, SWT.RIGHT, SWT.CENTER, SWT.RIGHT };
52     private static final int COL_NAME = 0;
53     private static final int COL_INCLUSIVE_PER = 1;
54     private static final int COL_INCLUSIVE = 2;
55     private static final int COL_EXCLUSIVE_PER = 3;
56     private static final int COL_EXCLUSIVE = 4;
57     private static final int COL_CALLS = 5;
58     private static final int COL_TIME_PER_CALL = 6;
59     private long mTotalTime;
60     private Pattern mUppercase;
61     private int mPrevMatchIndex = -1;
62 
ProfileProvider(TraceReader reader)63     public ProfileProvider(TraceReader reader) {
64         mRoots = reader.getMethods();
65         mReader = reader;
66         mTotalTime = reader.getEndTime();
67         Display display = Display.getCurrent();
68         InputStream in = getClass().getClassLoader().getResourceAsStream(
69                 "icons/sort_up.png");
70         mSortUp = new Image(display, in);
71         in = getClass().getClassLoader().getResourceAsStream(
72                 "icons/sort_down.png");
73         mSortDown = new Image(display, in);
74         mUppercase = Pattern.compile("[A-Z]");
75     }
76 
doMatchName(String name, int startIndex)77     private MethodData doMatchName(String name, int startIndex) {
78         // Check if the given "name" has any uppercase letters
79         boolean hasUpper = mUppercase.matcher(name).matches();
80         for (int ii = startIndex; ii < mRoots.length; ++ii) {
81             MethodData md = mRoots[ii];
82             String fullName = md.getName();
83             // If there were no upper case letters in the given name,
84             // then ignore case when matching.
85             if (!hasUpper)
86                 fullName = fullName.toLowerCase();
87             if (fullName.indexOf(name) != -1) {
88                 mPrevMatchIndex = ii;
89                 return md;
90             }
91         }
92         mPrevMatchIndex = -1;
93         return null;
94     }
95 
findMatchingName(String name)96     public MethodData findMatchingName(String name) {
97         return doMatchName(name, 0);
98     }
99 
findNextMatchingName(String name)100     public MethodData findNextMatchingName(String name) {
101         return doMatchName(name, mPrevMatchIndex + 1);
102     }
103 
findMatchingTreeItem(TreeItem item)104     public MethodData findMatchingTreeItem(TreeItem item) {
105         if (item == null)
106             return null;
107         String text = item.getText();
108         if (Character.isDigit(text.charAt(0)) == false)
109             return null;
110         int spaceIndex = text.indexOf(' ');
111         String numstr = text.substring(0, spaceIndex);
112         int rank = Integer.valueOf(numstr);
113         for (MethodData md : mRoots) {
114             if (md.getRank() == rank)
115                 return md;
116         }
117         return null;
118     }
119 
setTreeViewer(TreeViewer treeViewer)120     public void setTreeViewer(TreeViewer treeViewer) {
121         mTreeViewer = treeViewer;
122     }
123 
getColumnNames()124     public String[] getColumnNames() {
125         return mColumnNames;
126     }
127 
getColumnWidths()128     public int[] getColumnWidths() {
129         return mColumnWidths;
130     }
131 
getColumnAlignments()132     public int[] getColumnAlignments() {
133         return mColumnAlignments;
134     }
135 
getChildren(Object element)136     public Object[] getChildren(Object element) {
137         if (element instanceof MethodData) {
138             MethodData md = (MethodData) element;
139             return md.getProfileNodes();
140         }
141         if (element instanceof ProfileNode) {
142             ProfileNode pn = (ProfileNode) element;
143             return pn.getChildren();
144         }
145         return new Object[0];
146     }
147 
getParent(Object element)148     public Object getParent(Object element) {
149         return null;
150     }
151 
hasChildren(Object element)152     public boolean hasChildren(Object element) {
153         if (element instanceof MethodData)
154             return true;
155         if (element instanceof ProfileNode)
156             return true;
157         return false;
158     }
159 
getElements(Object element)160     public Object[] getElements(Object element) {
161         return mRoots;
162     }
163 
dispose()164     public void dispose() {
165     }
166 
inputChanged(Viewer arg0, Object arg1, Object arg2)167     public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
168     }
169 
getRoot()170     public Object getRoot() {
171         return "root";
172     }
173 
getColumnListener()174     public SelectionAdapter getColumnListener() {
175         if (mListener == null)
176             mListener = new ColumnListener();
177         return mListener;
178     }
179 
getLabelProvider()180     public LabelProvider getLabelProvider() {
181         return new ProfileLabelProvider();
182     }
183 
184     class ProfileLabelProvider extends LabelProvider implements
185             ITableLabelProvider, IColorProvider {
186         Color colorRed;
187         Color colorParentsBack;
188         Color colorChildrenBack;
189         TraceUnits traceUnits;
190 
ProfileLabelProvider()191         public ProfileLabelProvider() {
192             Display display = Display.getCurrent();
193             colorRed = display.getSystemColor(SWT.COLOR_RED);
194             colorParentsBack = new Color(display, 230, 230, 255); // blue
195             colorChildrenBack = new Color(display, 255, 255, 210); // yellow
196             traceUnits = mReader.getTraceUnits();
197         }
198 
getColumnText(Object element, int col)199         public String getColumnText(Object element, int col) {
200             if (element instanceof MethodData) {
201                 MethodData md = (MethodData) element;
202                 if (col == COL_NAME)
203                     return md.getProfileName();
204                 if (col == COL_EXCLUSIVE) {
205                     double val = md.getElapsedExclusive();
206                     val = traceUnits.getScaledValue(val);
207                     return String.format("%.3f", val);
208                 }
209                 if (col == COL_EXCLUSIVE_PER) {
210                     double val = md.getElapsedExclusive();
211                     double per = val * 100.0 / mTotalTime;
212                     return String.format("%.1f%%", per);
213                 }
214                 if (col == COL_INCLUSIVE) {
215                     double val = md.getElapsedInclusive();
216                     val = traceUnits.getScaledValue(val);
217                     return String.format("%.3f", val);
218                 }
219                 if (col == COL_INCLUSIVE_PER) {
220                     double val = md.getElapsedInclusive();
221                     double per = val * 100.0 / mTotalTime;
222                     return String.format("%.1f%%", per);
223                 }
224                 if (col == COL_CALLS)
225                     return md.getCalls();
226                 if (col == COL_TIME_PER_CALL) {
227                     int numCalls = md.getTotalCalls();
228                     double val = md.getElapsedInclusive();
229                     val = val / numCalls;
230                     val = traceUnits.getScaledValue(val);
231                     return String.format("%.3f", val);
232                 }
233             } else if (element instanceof ProfileSelf) {
234                 ProfileSelf ps = (ProfileSelf) element;
235                 if (col == COL_NAME)
236                     return ps.getProfileName();
237                 if (col == COL_INCLUSIVE) {
238                     double val = ps.getElapsedInclusive();
239                     val = traceUnits.getScaledValue(val);
240                     return String.format("%.3f", val);
241                 }
242                 if (col == COL_INCLUSIVE_PER) {
243                     double total;
244                     double val = ps.getElapsedInclusive();
245                     MethodData context = ps.getContext();
246                     total = context.getElapsedInclusive();
247                     double per = val * 100.0 / total;
248                     return String.format("%.1f%%", per);
249                 }
250                 return "";
251             } else if (element instanceof ProfileData) {
252                 ProfileData pd = (ProfileData) element;
253                 if (col == COL_NAME)
254                     return pd.getProfileName();
255                 if (col == COL_INCLUSIVE) {
256                     double val = pd.getElapsedInclusive();
257                     val = traceUnits.getScaledValue(val);
258                     return String.format("%.3f", val);
259                 }
260                 if (col == COL_INCLUSIVE_PER) {
261                     double total;
262                     double val = pd.getElapsedInclusive();
263                     MethodData context = pd.getContext();
264                     total = context.getElapsedInclusive();
265                     double per = val * 100.0 / total;
266                     return String.format("%.1f%%", per);
267                 }
268                 if (col == COL_CALLS)
269                     return pd.getNumCalls();
270                 return "";
271             } else if (element instanceof ProfileNode) {
272                 ProfileNode pn = (ProfileNode) element;
273                 if (col == COL_NAME)
274                     return pn.getLabel();
275                 return "";
276             }
277             return "col" + col;
278         }
279 
getColumnImage(Object element, int col)280         public Image getColumnImage(Object element, int col) {
281             if (col != COL_NAME)
282                 return null;
283             if (element instanceof MethodData) {
284                 MethodData md = (MethodData) element;
285                 return md.getImage();
286             }
287             if (element instanceof ProfileData) {
288                 ProfileData pd = (ProfileData) element;
289                 MethodData md = pd.getMethodData();
290                 return md.getImage();
291             }
292             return null;
293         }
294 
getForeground(Object element)295         public Color getForeground(Object element) {
296             return null;
297         }
298 
getBackground(Object element)299         public Color getBackground(Object element) {
300             if (element instanceof ProfileData) {
301                 ProfileData pd = (ProfileData) element;
302                 if (pd.isParent())
303                     return colorParentsBack;
304                 return colorChildrenBack;
305             }
306             if (element instanceof ProfileNode) {
307                 ProfileNode pn = (ProfileNode) element;
308                 if (pn.isParent())
309                     return colorParentsBack;
310                 return colorChildrenBack;
311             }
312             return null;
313         }
314     }
315 
316     class ColumnListener extends SelectionAdapter {
317         MethodData.Sorter sorter = new MethodData.Sorter();
318 
319         @Override
widgetSelected(SelectionEvent event)320         public void widgetSelected(SelectionEvent event) {
321             TreeColumn column = (TreeColumn) event.widget;
322             String name = column.getText();
323             Tree tree = column.getParent();
324             tree.setRedraw(false);
325             TreeColumn[] columns = tree.getColumns();
326             for (TreeColumn col : columns) {
327                 col.setImage(null);
328             }
329             if (name == mColumnNames[COL_NAME]) {
330                 // Sort names alphabetically
331                 sorter.setColumn(MethodData.Sorter.Column.BY_NAME);
332                 Arrays.sort(mRoots, sorter);
333             } else if (name == mColumnNames[COL_EXCLUSIVE]) {
334                 sorter.setColumn(MethodData.Sorter.Column.BY_EXCLUSIVE);
335                 Arrays.sort(mRoots, sorter);
336             } else if (name == mColumnNames[COL_EXCLUSIVE_PER]) {
337                 sorter.setColumn(MethodData.Sorter.Column.BY_EXCLUSIVE);
338                 Arrays.sort(mRoots, sorter);
339             } else if (name == mColumnNames[COL_INCLUSIVE]) {
340                 sorter.setColumn(MethodData.Sorter.Column.BY_INCLUSIVE);
341                 Arrays.sort(mRoots, sorter);
342             } else if (name == mColumnNames[COL_INCLUSIVE_PER]) {
343                 sorter.setColumn(MethodData.Sorter.Column.BY_INCLUSIVE);
344                 Arrays.sort(mRoots, sorter);
345             } else if (name == mColumnNames[COL_CALLS]) {
346                 sorter.setColumn(MethodData.Sorter.Column.BY_CALLS);
347                 Arrays.sort(mRoots, sorter);
348             } else if (name == mColumnNames[COL_TIME_PER_CALL]) {
349                 sorter.setColumn(MethodData.Sorter.Column.BY_TIME_PER_CALL);
350                 Arrays.sort(mRoots, sorter);
351             }
352             MethodData.Sorter.Direction direction = sorter.getDirection();
353             if (direction == MethodData.Sorter.Direction.INCREASING)
354                 column.setImage(mSortDown);
355             else
356                 column.setImage(mSortUp);
357             tree.setRedraw(true);
358             mTreeViewer.refresh();
359         }
360     }
361 }
362