• 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             @Override
226             public int compare(ProfileData pd1, ProfileData pd2) {
227                 if (timeBase.getElapsedInclusiveTime(pd2) > timeBase.getElapsedInclusiveTime(pd1))
228                     return 1;
229                 if (timeBase.getElapsedInclusiveTime(pd2) < timeBase.getElapsedInclusiveTime(pd1))
230                     return -1;
231                 return 0;
232             }
233         });
234         return sorted;
235     }
236 
addSelf(ProfileData[] children)237     private ProfileData[] addSelf(ProfileData[] children) {
238         ProfileData[] pdata;
239         if (children == null) {
240             pdata = new ProfileData[1];
241         } else {
242             pdata = new ProfileData[children.length + 1];
243             System.arraycopy(children, 0, pdata, 1, children.length);
244         }
245         pdata[0] = new ProfileSelf(this);
246         return pdata;
247     }
248 
addTopExclusive(long cpuTime, long realTime)249     public void addTopExclusive(long cpuTime, long realTime) {
250         mTopExclusiveCpuTime += cpuTime;
251         mTopExclusiveRealTime += realTime;
252     }
253 
getTopExclusiveCpuTime()254     public long getTopExclusiveCpuTime() {
255         return mTopExclusiveCpuTime;
256     }
257 
getTopExclusiveRealTime()258     public long getTopExclusiveRealTime() {
259         return mTopExclusiveRealTime;
260     }
261 
getId()262     public int getId() {
263         return mId;
264     }
265 
computeName()266     private void computeName() {
267         if (mMethodName == null) {
268             mName = mClassName;
269             return;
270         }
271 
272         StringBuilder sb = new StringBuilder();
273         sb.append(mClassName);
274         sb.append(".");  //$NON-NLS-1$
275         sb.append(mMethodName);
276         sb.append(" ");  //$NON-NLS-1$
277         sb.append(mSignature);
278         mName = sb.toString();
279     }
280 
getName()281     public String getName() {
282         return mName;
283     }
284 
getClassName()285     public String getClassName() {
286         return mClassName;
287     }
288 
getMethodName()289     public String getMethodName() {
290         return mMethodName;
291     }
292 
getProfileName()293     public String getProfileName() {
294         return mProfileName;
295     }
296 
getSignature()297     public String getSignature() {
298         return mSignature;
299     }
300 
computeProfileName()301     public void computeProfileName() {
302         if (mRank == -1) {
303             mProfileName = mName;
304             return;
305         }
306 
307         StringBuilder sb = new StringBuilder();
308         sb.append(mRank);
309         sb.append(" ");  //$NON-NLS-1$
310         sb.append(getName());
311         mProfileName = sb.toString();
312     }
313 
getCalls()314     public String getCalls() {
315         return String.format("%d+%d", mNumCalls[0], mNumCalls[1]);
316     }
317 
getTotalCalls()318     public int getTotalCalls() {
319         return mNumCalls[0] + mNumCalls[1];
320     }
321 
getColor()322     public Color getColor() {
323         return mColor;
324     }
325 
setColor(Color color)326     public void setColor(Color color) {
327         mColor = color;
328     }
329 
setImage(Image image)330     public void setImage(Image image) {
331         mImage = image;
332     }
333 
getImage()334     public Image getImage() {
335         return mImage;
336     }
337 
338     @Override
toString()339     public String toString() {
340         return getName();
341     }
342 
getElapsedExclusiveCpuTime()343     public long getElapsedExclusiveCpuTime() {
344         return mElapsedExclusiveCpuTime;
345     }
346 
getElapsedExclusiveRealTime()347     public long getElapsedExclusiveRealTime() {
348         return mElapsedExclusiveRealTime;
349     }
350 
getElapsedInclusiveCpuTime()351     public long getElapsedInclusiveCpuTime() {
352         return mElapsedInclusiveCpuTime;
353     }
354 
getElapsedInclusiveRealTime()355     public long getElapsedInclusiveRealTime() {
356         return mElapsedInclusiveRealTime;
357     }
358 
setFadedColor(Color fadedColor)359     public void setFadedColor(Color fadedColor) {
360         mFadedColor = fadedColor;
361     }
362 
getFadedColor()363     public Color getFadedColor() {
364         return mFadedColor;
365     }
366 
setFadedImage(Image fadedImage)367     public void setFadedImage(Image fadedImage) {
368         mFadedImage = fadedImage;
369     }
370 
getFadedImage()371     public Image getFadedImage() {
372         return mFadedImage;
373     }
374 
setPathname(String pathname)375     public void setPathname(String pathname) {
376         mPathname = pathname;
377     }
378 
getPathname()379     public String getPathname() {
380         return mPathname;
381     }
382 
setLineNumber(int lineNumber)383     public void setLineNumber(int lineNumber) {
384         mLineNumber = lineNumber;
385     }
386 
getLineNumber()387     public int getLineNumber() {
388         return mLineNumber;
389     }
390 
getProfileNodes()391     public ProfileNode[] getProfileNodes() {
392         return mProfileNodes;
393     }
394 
395     public static class Sorter implements Comparator<MethodData> {
396         @Override
compare(MethodData md1, MethodData md2)397         public int compare(MethodData md1, MethodData md2) {
398             if (mColumn == Column.BY_NAME) {
399                 int result = md1.getName().compareTo(md2.getName());
400                 return (mDirection == Direction.INCREASING) ? result : -result;
401             }
402             if (mColumn == Column.BY_INCLUSIVE_CPU_TIME) {
403                 if (md2.getElapsedInclusiveCpuTime() > md1.getElapsedInclusiveCpuTime())
404                     return (mDirection == Direction.INCREASING) ? -1 : 1;
405                 if (md2.getElapsedInclusiveCpuTime() < md1.getElapsedInclusiveCpuTime())
406                     return (mDirection == Direction.INCREASING) ? 1 : -1;
407                 return md1.getName().compareTo(md2.getName());
408             }
409             if (mColumn == Column.BY_EXCLUSIVE_CPU_TIME) {
410                 if (md2.getElapsedExclusiveCpuTime() > md1.getElapsedExclusiveCpuTime())
411                     return (mDirection == Direction.INCREASING) ? -1 : 1;
412                 if (md2.getElapsedExclusiveCpuTime() < md1.getElapsedExclusiveCpuTime())
413                     return (mDirection == Direction.INCREASING) ? 1 : -1;
414                 return md1.getName().compareTo(md2.getName());
415             }
416             if (mColumn == Column.BY_INCLUSIVE_REAL_TIME) {
417                 if (md2.getElapsedInclusiveRealTime() > md1.getElapsedInclusiveRealTime())
418                     return (mDirection == Direction.INCREASING) ? -1 : 1;
419                 if (md2.getElapsedInclusiveRealTime() < md1.getElapsedInclusiveRealTime())
420                     return (mDirection == Direction.INCREASING) ? 1 : -1;
421                 return md1.getName().compareTo(md2.getName());
422             }
423             if (mColumn == Column.BY_EXCLUSIVE_REAL_TIME) {
424                 if (md2.getElapsedExclusiveRealTime() > md1.getElapsedExclusiveRealTime())
425                     return (mDirection == Direction.INCREASING) ? -1 : 1;
426                 if (md2.getElapsedExclusiveRealTime() < md1.getElapsedExclusiveRealTime())
427                     return (mDirection == Direction.INCREASING) ? 1 : -1;
428                 return md1.getName().compareTo(md2.getName());
429             }
430             if (mColumn == Column.BY_CALLS) {
431                 int result = md1.getTotalCalls() - md2.getTotalCalls();
432                 if (result == 0)
433                     return md1.getName().compareTo(md2.getName());
434                 return (mDirection == Direction.INCREASING) ? result : -result;
435             }
436             if (mColumn == Column.BY_CPU_TIME_PER_CALL) {
437                 double time1 = md1.getElapsedInclusiveCpuTime();
438                 time1 = time1 / md1.getTotalCalls();
439                 double time2 = md2.getElapsedInclusiveCpuTime();
440                 time2 = time2 / md2.getTotalCalls();
441                 double diff = time1 - time2;
442                 int result = 0;
443                 if (diff < 0)
444                     result = -1;
445                 else if (diff > 0)
446                     result = 1;
447                 if (result == 0)
448                     return md1.getName().compareTo(md2.getName());
449                 return (mDirection == Direction.INCREASING) ? result : -result;
450             }
451             if (mColumn == Column.BY_REAL_TIME_PER_CALL) {
452                 double time1 = md1.getElapsedInclusiveRealTime();
453                 time1 = time1 / md1.getTotalCalls();
454                 double time2 = md2.getElapsedInclusiveRealTime();
455                 time2 = time2 / md2.getTotalCalls();
456                 double diff = time1 - time2;
457                 int result = 0;
458                 if (diff < 0)
459                     result = -1;
460                 else if (diff > 0)
461                     result = 1;
462                 if (result == 0)
463                     return md1.getName().compareTo(md2.getName());
464                 return (mDirection == Direction.INCREASING) ? result : -result;
465             }
466             return 0;
467         }
468 
setColumn(Column column)469         public void setColumn(Column column) {
470             // If the sort column specified is the same as last time,
471             // then reverse the sort order.
472             if (mColumn == column) {
473                 // Reverse the sort order
474                 if (mDirection == Direction.INCREASING)
475                     mDirection = Direction.DECREASING;
476                 else
477                     mDirection = Direction.INCREASING;
478             } else {
479                 // Sort names into increasing order, data into decreasing order.
480                 if (column == Column.BY_NAME)
481                     mDirection = Direction.INCREASING;
482                 else
483                     mDirection = Direction.DECREASING;
484             }
485             mColumn = column;
486         }
487 
getColumn()488         public Column getColumn() {
489             return mColumn;
490         }
491 
setDirection(Direction direction)492         public void setDirection(Direction direction) {
493             mDirection = direction;
494         }
495 
getDirection()496         public Direction getDirection() {
497             return mDirection;
498         }
499 
500         public static enum Column {
501             BY_NAME, BY_EXCLUSIVE_CPU_TIME, BY_EXCLUSIVE_REAL_TIME,
502             BY_INCLUSIVE_CPU_TIME, BY_INCLUSIVE_REAL_TIME, BY_CALLS,
503             BY_REAL_TIME_PER_CALL, BY_CPU_TIME_PER_CALL,
504         };
505 
506         public static enum Direction {
507             INCREASING, DECREASING
508         };
509 
510         private Column mColumn;
511         private Direction mDirection;
512     }
513 }
514