Home | History | Annotate | Download | only in traceview
      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 
     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 
     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 
     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 
     98     public void clearWeight() {
     99         mWeight = 0;
    100     }
    101 
    102     public int getRank() {
    103         return mRank;
    104     }
    105 
    106     public void setRank(int rank) {
    107         mRank = rank;
    108         computeProfileName();
    109     }
    110 
    111     public void addElapsedExclusive(long cpuTime, long realTime) {
    112         mElapsedExclusiveCpuTime += cpuTime;
    113         mElapsedExclusiveRealTime += realTime;
    114     }
    115 
    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 
    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 
    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.
    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 
    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 
    249     public void addTopExclusive(long cpuTime, long realTime) {
    250         mTopExclusiveCpuTime += cpuTime;
    251         mTopExclusiveRealTime += realTime;
    252     }
    253 
    254     public long getTopExclusiveCpuTime() {
    255         return mTopExclusiveCpuTime;
    256     }
    257 
    258     public long getTopExclusiveRealTime() {
    259         return mTopExclusiveRealTime;
    260     }
    261 
    262     public int getId() {
    263         return mId;
    264     }
    265 
    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 
    281     public String getName() {
    282         return mName;
    283     }
    284 
    285     public String getClassName() {
    286         return mClassName;
    287     }
    288 
    289     public String getMethodName() {
    290         return mMethodName;
    291     }
    292 
    293     public String getProfileName() {
    294         return mProfileName;
    295     }
    296 
    297     public String getSignature() {
    298         return mSignature;
    299     }
    300 
    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 
    314     public String getCalls() {
    315         return String.format("%d+%d", mNumCalls[0], mNumCalls[1]);
    316     }
    317 
    318     public int getTotalCalls() {
    319         return mNumCalls[0] + mNumCalls[1];
    320     }
    321 
    322     public Color getColor() {
    323         return mColor;
    324     }
    325 
    326     public void setColor(Color color) {
    327         mColor = color;
    328     }
    329 
    330     public void setImage(Image image) {
    331         mImage = image;
    332     }
    333 
    334     public Image getImage() {
    335         return mImage;
    336     }
    337 
    338     @Override
    339     public String toString() {
    340         return getName();
    341     }
    342 
    343     public long getElapsedExclusiveCpuTime() {
    344         return mElapsedExclusiveCpuTime;
    345     }
    346 
    347     public long getElapsedExclusiveRealTime() {
    348         return mElapsedExclusiveRealTime;
    349     }
    350 
    351     public long getElapsedInclusiveCpuTime() {
    352         return mElapsedInclusiveCpuTime;
    353     }
    354 
    355     public long getElapsedInclusiveRealTime() {
    356         return mElapsedInclusiveRealTime;
    357     }
    358 
    359     public void setFadedColor(Color fadedColor) {
    360         mFadedColor = fadedColor;
    361     }
    362 
    363     public Color getFadedColor() {
    364         return mFadedColor;
    365     }
    366 
    367     public void setFadedImage(Image fadedImage) {
    368         mFadedImage = fadedImage;
    369     }
    370 
    371     public Image getFadedImage() {
    372         return mFadedImage;
    373     }
    374 
    375     public void setPathname(String pathname) {
    376         mPathname = pathname;
    377     }
    378 
    379     public String getPathname() {
    380         return mPathname;
    381     }
    382 
    383     public void setLineNumber(int lineNumber) {
    384         mLineNumber = lineNumber;
    385     }
    386 
    387     public int getLineNumber() {
    388         return mLineNumber;
    389     }
    390 
    391     public ProfileNode[] getProfileNodes() {
    392         return mProfileNodes;
    393     }
    394 
    395     public static class Sorter implements Comparator<MethodData> {
    396         @Override
    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 
    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 
    488         public Column getColumn() {
    489             return mColumn;
    490         }
    491 
    492         public void setDirection(Direction direction) {
    493             mDirection = direction;
    494         }
    495 
    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