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