• 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 org.eclipse.swt.graphics.Color;
20 import org.eclipse.swt.graphics.Image;
21 
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Comparator;
26 import java.util.HashMap;
27 
28 public class MethodData {
29 
30     private int mId;
31     private int mRank = -1;
32     private String mClassName;
33     private String mMethodName;
34     private String mSignature;
35     private String mName;
36     private String mProfileName;
37     private String mPathname;
38     private int mLineNumber;
39     private long mElapsedExclusiveCpuTime;
40     private long mElapsedInclusiveCpuTime;
41     private long mTopExclusiveCpuTime;
42     private long mElapsedExclusiveRealTime;
43     private long mElapsedInclusiveRealTime;
44     private long mTopExclusiveRealTime;
45     private int[] mNumCalls = new int[2]; // index 0=normal, 1=recursive
46     private Color mColor;
47     private Color mFadedColor;
48     private Image mImage;
49     private Image mFadedImage;
50     private HashMap<Integer, ProfileData> mParents;
51     private HashMap<Integer, ProfileData> mChildren;
52 
53     // The parents of this method when this method was in a recursive call
54     private HashMap<Integer, ProfileData> mRecursiveParents;
55 
56     // The children of this method when this method was in a recursive call
57     private HashMap<Integer, ProfileData> mRecursiveChildren;
58 
59     private ProfileNode[] mProfileNodes;
60     private int mX;
61     private int mY;
62     private double mWeight;
63 
MethodData(int id, String className)64     public MethodData(int id, String className) {
65         mId = id;
66         mClassName = className;
67         mMethodName = null;
68         mSignature = null;
69         mPathname = null;
70         mLineNumber = -1;
71         computeName();
72         computeProfileName();
73     }
74 
MethodData(int id, String className, String methodName, String signature, String pathname, int lineNumber)75     public MethodData(int id, String className, String methodName,
76             String signature, String pathname, int lineNumber) {
77         mId = id;
78         mClassName = className;
79         mMethodName = methodName;
80         mSignature = signature;
81         mPathname = pathname;
82         mLineNumber = lineNumber;
83         computeName();
84         computeProfileName();
85     }
86 
addWeight(int x, int y, double weight)87     public double addWeight(int x, int y, double weight) {
88         if (mX == x && mY == y)
89             mWeight += weight;
90         else {
91             mX = x;
92             mY = y;
93             mWeight = weight;
94         }
95         return mWeight;
96     }
97 
clearWeight()98     public void clearWeight() {
99         mWeight = 0;
100     }
101 
getRank()102     public int getRank() {
103         return mRank;
104     }
105 
setRank(int rank)106     public void setRank(int rank) {
107         mRank = rank;
108         computeProfileName();
109     }
110 
addElapsedExclusive(long cpuTime, long realTime)111     public void addElapsedExclusive(long cpuTime, long realTime) {
112         mElapsedExclusiveCpuTime += cpuTime;
113         mElapsedExclusiveRealTime += realTime;
114     }
115 
addElapsedInclusive(long cpuTime, long realTime, boolean isRecursive, Call parent)116     public void addElapsedInclusive(long cpuTime, long realTime,
117             boolean isRecursive, Call parent) {
118         if (isRecursive == false) {
119             mElapsedInclusiveCpuTime += cpuTime;
120             mElapsedInclusiveRealTime += realTime;
121             mNumCalls[0] += 1;
122         } else {
123             mNumCalls[1] += 1;
124         }
125 
126         if (parent == null)
127             return;
128 
129         // Find the child method in the parent
130         MethodData parentMethod = parent.getMethodData();
131         if (parent.isRecursive()) {
132             parentMethod.mRecursiveChildren = updateInclusive(cpuTime, realTime,
133                     parentMethod, this, false,
134                     parentMethod.mRecursiveChildren);
135         } else {
136             parentMethod.mChildren = updateInclusive(cpuTime, realTime,
137                     parentMethod, this, false, parentMethod.mChildren);
138         }
139 
140         // Find the parent method in the child
141         if (isRecursive) {
142             mRecursiveParents = updateInclusive(cpuTime, realTime, this, parentMethod, true,
143                     mRecursiveParents);
144         } else {
145             mParents = updateInclusive(cpuTime, realTime, this, parentMethod, true,
146                     mParents);
147         }
148     }
149 
updateInclusive(long cpuTime, long realTime, MethodData contextMethod, MethodData elementMethod, boolean elementIsParent, HashMap<Integer, ProfileData> map)150     private HashMap<Integer, ProfileData> updateInclusive(long cpuTime, long realTime,
151             MethodData contextMethod, MethodData elementMethod,
152             boolean elementIsParent, HashMap<Integer, ProfileData> map) {
153         if (map == null) {
154             map = new HashMap<Integer, ProfileData>(4);
155         } else {
156             ProfileData profileData = map.get(elementMethod.mId);
157             if (profileData != null) {
158                 profileData.addElapsedInclusive(cpuTime, realTime);
159                 return map;
160             }
161         }
162 
163         ProfileData elementData = new ProfileData(contextMethod,
164                 elementMethod, elementIsParent);
165         elementData.setElapsedInclusive(cpuTime, realTime);
166         elementData.setNumCalls(1);
167         map.put(elementMethod.mId, elementData);
168         return map;
169     }
170 
analyzeData(TimeBase timeBase)171     public void analyzeData(TimeBase timeBase) {
172         // Sort the parents and children into decreasing inclusive time
173         ProfileData[] sortedParents;
174         ProfileData[] sortedChildren;
175         ProfileData[] sortedRecursiveParents;
176         ProfileData[] sortedRecursiveChildren;
177 
178         sortedParents = sortProfileData(mParents, timeBase);
179         sortedChildren = sortProfileData(mChildren, timeBase);
180         sortedRecursiveParents = sortProfileData(mRecursiveParents, timeBase);
181         sortedRecursiveChildren = sortProfileData(mRecursiveChildren, timeBase);
182 
183         // Add "self" time to the top of the sorted children
184         sortedChildren = addSelf(sortedChildren);
185 
186         // Create the ProfileNode objects that we need
187         ArrayList<ProfileNode> nodes = new ArrayList<ProfileNode>();
188         ProfileNode profileNode;
189         if (mParents != null) {
190             profileNode = new ProfileNode("Parents", this, sortedParents,
191                     true, false);
192             nodes.add(profileNode);
193         }
194         if (mChildren != null) {
195             profileNode = new ProfileNode("Children", this, sortedChildren,
196                     false, false);
197             nodes.add(profileNode);
198         }
199         if (mRecursiveParents!= null) {
200             profileNode = new ProfileNode("Parents while recursive", this,
201                     sortedRecursiveParents, true, true);
202             nodes.add(profileNode);
203         }
204         if (mRecursiveChildren != null) {
205             profileNode = new ProfileNode("Children while recursive", this,
206                     sortedRecursiveChildren, false, true);
207             nodes.add(profileNode);
208         }
209         mProfileNodes = nodes.toArray(new ProfileNode[nodes.size()]);
210     }
211 
212     // Create and return a ProfileData[] array that is a sorted copy
213     // of the given HashMap values.
sortProfileData(HashMap<Integer, ProfileData> map, final TimeBase timeBase)214     private ProfileData[] sortProfileData(HashMap<Integer, ProfileData> map,
215             final TimeBase timeBase) {
216         if (map == null)
217             return null;
218 
219         // Convert the hash values to an array of ProfileData
220         Collection<ProfileData> values = map.values();
221         ProfileData[] sorted = values.toArray(new ProfileData[values.size()]);
222 
223         // Sort the array by elapsed inclusive time
224         Arrays.sort(sorted, new Comparator<ProfileData>() {
225             public int compare(ProfileData pd1, ProfileData pd2) {
226                 if (timeBase.getElapsedInclusiveTime(pd2) > timeBase.getElapsedInclusiveTime(pd1))
227                     return 1;
228                 if (timeBase.getElapsedInclusiveTime(pd2) < timeBase.getElapsedInclusiveTime(pd1))
229                     return -1;
230                 return 0;
231             }
232         });
233         return sorted;
234     }
235 
addSelf(ProfileData[] children)236     private ProfileData[] addSelf(ProfileData[] children) {
237         ProfileData[] pdata;
238         if (children == null) {
239             pdata = new ProfileData[1];
240         } else {
241             pdata = new ProfileData[children.length + 1];
242             System.arraycopy(children, 0, pdata, 1, children.length);
243         }
244         pdata[0] = new ProfileSelf(this);
245         return pdata;
246     }
247 
addTopExclusive(long cpuTime, long realTime)248     public void addTopExclusive(long cpuTime, long realTime) {
249         mTopExclusiveCpuTime += cpuTime;
250         mTopExclusiveRealTime += realTime;
251     }
252 
getTopExclusiveCpuTime()253     public long getTopExclusiveCpuTime() {
254         return mTopExclusiveCpuTime;
255     }
256 
getTopExclusiveRealTime()257     public long getTopExclusiveRealTime() {
258         return mTopExclusiveRealTime;
259     }
260 
getId()261     public int getId() {
262         return mId;
263     }
264 
computeName()265     private void computeName() {
266         if (mMethodName == null) {
267             mName = mClassName;
268             return;
269         }
270 
271         StringBuilder sb = new StringBuilder();
272         sb.append(mClassName);
273         sb.append(".");  //$NON-NLS-1$
274         sb.append(mMethodName);
275         sb.append(" ");  //$NON-NLS-1$
276         sb.append(mSignature);
277         mName = sb.toString();
278     }
279 
getName()280     public String getName() {
281         return mName;
282     }
283 
getClassName()284     public String getClassName() {
285         return mClassName;
286     }
287 
getMethodName()288     public String getMethodName() {
289         return mMethodName;
290     }
291 
getProfileName()292     public String getProfileName() {
293         return mProfileName;
294     }
295 
getSignature()296     public String getSignature() {
297         return mSignature;
298     }
299 
computeProfileName()300     public void computeProfileName() {
301         if (mRank == -1) {
302             mProfileName = mName;
303             return;
304         }
305 
306         StringBuilder sb = new StringBuilder();
307         sb.append(mRank);
308         sb.append(" ");  //$NON-NLS-1$
309         sb.append(getName());
310         mProfileName = sb.toString();
311     }
312 
getCalls()313     public String getCalls() {
314         return String.format("%d+%d", mNumCalls[0], mNumCalls[1]);
315     }
316 
getTotalCalls()317     public int getTotalCalls() {
318         return mNumCalls[0] + mNumCalls[1];
319     }
320 
getColor()321     public Color getColor() {
322         return mColor;
323     }
324 
setColor(Color color)325     public void setColor(Color color) {
326         mColor = color;
327     }
328 
setImage(Image image)329     public void setImage(Image image) {
330         mImage = image;
331     }
332 
getImage()333     public Image getImage() {
334         return mImage;
335     }
336 
337     @Override
toString()338     public String toString() {
339         return getName();
340     }
341 
getElapsedExclusiveCpuTime()342     public long getElapsedExclusiveCpuTime() {
343         return mElapsedExclusiveCpuTime;
344     }
345 
getElapsedExclusiveRealTime()346     public long getElapsedExclusiveRealTime() {
347         return mElapsedExclusiveRealTime;
348     }
349 
getElapsedInclusiveCpuTime()350     public long getElapsedInclusiveCpuTime() {
351         return mElapsedInclusiveCpuTime;
352     }
353 
getElapsedInclusiveRealTime()354     public long getElapsedInclusiveRealTime() {
355         return mElapsedInclusiveRealTime;
356     }
357 
setFadedColor(Color fadedColor)358     public void setFadedColor(Color fadedColor) {
359         mFadedColor = fadedColor;
360     }
361 
getFadedColor()362     public Color getFadedColor() {
363         return mFadedColor;
364     }
365 
setFadedImage(Image fadedImage)366     public void setFadedImage(Image fadedImage) {
367         mFadedImage = fadedImage;
368     }
369 
getFadedImage()370     public Image getFadedImage() {
371         return mFadedImage;
372     }
373 
setPathname(String pathname)374     public void setPathname(String pathname) {
375         mPathname = pathname;
376     }
377 
getPathname()378     public String getPathname() {
379         return mPathname;
380     }
381 
setLineNumber(int lineNumber)382     public void setLineNumber(int lineNumber) {
383         mLineNumber = lineNumber;
384     }
385 
getLineNumber()386     public int getLineNumber() {
387         return mLineNumber;
388     }
389 
getProfileNodes()390     public ProfileNode[] getProfileNodes() {
391         return mProfileNodes;
392     }
393 
394     public static class Sorter implements Comparator<MethodData> {
compare(MethodData md1, MethodData md2)395         public int compare(MethodData md1, MethodData md2) {
396             if (mColumn == Column.BY_NAME) {
397                 int result = md1.getName().compareTo(md2.getName());
398                 return (mDirection == Direction.INCREASING) ? result : -result;
399             }
400             if (mColumn == Column.BY_INCLUSIVE_CPU_TIME) {
401                 if (md2.getElapsedInclusiveCpuTime() > md1.getElapsedInclusiveCpuTime())
402                     return (mDirection == Direction.INCREASING) ? -1 : 1;
403                 if (md2.getElapsedInclusiveCpuTime() < md1.getElapsedInclusiveCpuTime())
404                     return (mDirection == Direction.INCREASING) ? 1 : -1;
405                 return md1.getName().compareTo(md2.getName());
406             }
407             if (mColumn == Column.BY_EXCLUSIVE_CPU_TIME) {
408                 if (md2.getElapsedExclusiveCpuTime() > md1.getElapsedExclusiveCpuTime())
409                     return (mDirection == Direction.INCREASING) ? -1 : 1;
410                 if (md2.getElapsedExclusiveCpuTime() < md1.getElapsedExclusiveCpuTime())
411                     return (mDirection == Direction.INCREASING) ? 1 : -1;
412                 return md1.getName().compareTo(md2.getName());
413             }
414             if (mColumn == Column.BY_INCLUSIVE_REAL_TIME) {
415                 if (md2.getElapsedInclusiveRealTime() > md1.getElapsedInclusiveRealTime())
416                     return (mDirection == Direction.INCREASING) ? -1 : 1;
417                 if (md2.getElapsedInclusiveRealTime() < md1.getElapsedInclusiveRealTime())
418                     return (mDirection == Direction.INCREASING) ? 1 : -1;
419                 return md1.getName().compareTo(md2.getName());
420             }
421             if (mColumn == Column.BY_EXCLUSIVE_REAL_TIME) {
422                 if (md2.getElapsedExclusiveRealTime() > md1.getElapsedExclusiveRealTime())
423                     return (mDirection == Direction.INCREASING) ? -1 : 1;
424                 if (md2.getElapsedExclusiveRealTime() < md1.getElapsedExclusiveRealTime())
425                     return (mDirection == Direction.INCREASING) ? 1 : -1;
426                 return md1.getName().compareTo(md2.getName());
427             }
428             if (mColumn == Column.BY_CALLS) {
429                 int result = md1.getTotalCalls() - md2.getTotalCalls();
430                 if (result == 0)
431                     return md1.getName().compareTo(md2.getName());
432                 return (mDirection == Direction.INCREASING) ? result : -result;
433             }
434             if (mColumn == Column.BY_CPU_TIME_PER_CALL) {
435                 double time1 = md1.getElapsedInclusiveCpuTime();
436                 time1 = time1 / md1.getTotalCalls();
437                 double time2 = md2.getElapsedInclusiveCpuTime();
438                 time2 = time2 / md2.getTotalCalls();
439                 double diff = time1 - time2;
440                 int result = 0;
441                 if (diff < 0)
442                     result = -1;
443                 else if (diff > 0)
444                     result = 1;
445                 if (result == 0)
446                     return md1.getName().compareTo(md2.getName());
447                 return (mDirection == Direction.INCREASING) ? result : -result;
448             }
449             if (mColumn == Column.BY_REAL_TIME_PER_CALL) {
450                 double time1 = md1.getElapsedInclusiveRealTime();
451                 time1 = time1 / md1.getTotalCalls();
452                 double time2 = md2.getElapsedInclusiveRealTime();
453                 time2 = time2 / md2.getTotalCalls();
454                 double diff = time1 - time2;
455                 int result = 0;
456                 if (diff < 0)
457                     result = -1;
458                 else if (diff > 0)
459                     result = 1;
460                 if (result == 0)
461                     return md1.getName().compareTo(md2.getName());
462                 return (mDirection == Direction.INCREASING) ? result : -result;
463             }
464             return 0;
465         }
466 
setColumn(Column column)467         public void setColumn(Column column) {
468             // If the sort column specified is the same as last time,
469             // then reverse the sort order.
470             if (mColumn == column) {
471                 // Reverse the sort order
472                 if (mDirection == Direction.INCREASING)
473                     mDirection = Direction.DECREASING;
474                 else
475                     mDirection = Direction.INCREASING;
476             } else {
477                 // Sort names into increasing order, data into decreasing order.
478                 if (column == Column.BY_NAME)
479                     mDirection = Direction.INCREASING;
480                 else
481                     mDirection = Direction.DECREASING;
482             }
483             mColumn = column;
484         }
485 
getColumn()486         public Column getColumn() {
487             return mColumn;
488         }
489 
setDirection(Direction direction)490         public void setDirection(Direction direction) {
491             mDirection = direction;
492         }
493 
getDirection()494         public Direction getDirection() {
495             return mDirection;
496         }
497 
498         public static enum Column {
499             BY_NAME, BY_EXCLUSIVE_CPU_TIME, BY_EXCLUSIVE_REAL_TIME,
500             BY_INCLUSIVE_CPU_TIME, BY_INCLUSIVE_REAL_TIME, BY_CALLS,
501             BY_REAL_TIME_PER_CALL, BY_CPU_TIME_PER_CALL,
502         };
503 
504         public static enum Direction {
505             INCREASING, DECREASING
506         };
507 
508         private Column mColumn;
509         private Direction mDirection;
510     }
511 }
512