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