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 java.util.ArrayList; 20 import java.util.HashMap; 21 22 class ThreadData implements TimeLineView.Row { 23 24 private int mId; 25 private String mName; 26 private long mGlobalStartTime = -1; 27 private long mGlobalEndTime = -1; 28 private long mLastEventTime; 29 private long mCpuTime; 30 private Call mRoot; 31 private Call mCurrent; 32 private Call mLastContextSwitch; 33 private ArrayList<Call> mStack = new ArrayList<Call>(); 34 35 // This is a hash of all the methods that are currently on the stack. 36 private HashMap<MethodData, Integer> mStackMethods = new HashMap<MethodData, Integer>(); 37 38 // True if no calls have ever been added to this thread 39 private boolean mIsEmpty; 40 ThreadData(int id, String name, MethodData topLevel)41 ThreadData(int id, String name, MethodData topLevel) { 42 mId = id; 43 mName = String.format("[%d] %s", id, name); 44 mRoot = new Call(mName, topLevel); 45 mCurrent = mRoot; 46 mIsEmpty = true; 47 } 48 isEmpty()49 public boolean isEmpty() { 50 return mIsEmpty; 51 } 52 getName()53 public String getName() { 54 return mName; 55 } 56 getCalltreeRoot()57 public Call getCalltreeRoot() { 58 return mRoot; 59 } 60 handleCall(Call call, long globalTime)61 void handleCall(Call call, long globalTime) { 62 mIsEmpty = false; 63 long currentTime = call.mThreadStartTime; 64 if (currentTime < mLastEventTime) { 65 System.err 66 .printf( 67 "ThreadData: '%1$s' call time (%2$d) is less than previous time (%3$d) for thread '%4$s'\n", 68 call.getName(), currentTime, mLastEventTime, mName); 69 System.exit(1); 70 } 71 long elapsed = currentTime - mLastEventTime; 72 mCpuTime += elapsed; 73 if (call.getMethodAction() == 0) { 74 // This is a method entry. 75 enter(call, elapsed); 76 } else { 77 // This is a method exit. 78 exit(call, elapsed, globalTime); 79 } 80 mLastEventTime = currentTime; 81 mGlobalEndTime = globalTime; 82 } 83 enter(Call c, long elapsed)84 private void enter(Call c, long elapsed) { 85 Call caller = mCurrent; 86 push(c); 87 88 // Check the stack for a matching method to determine if this call 89 // is recursive. 90 MethodData md = c.mMethodData; 91 Integer num = mStackMethods.get(md); 92 if (num == null) { 93 num = 0; 94 } else if (num > 0) { 95 c.setRecursive(true); 96 } 97 num += 1; 98 mStackMethods.put(md, num); 99 mCurrent = c; 100 101 // Add the elapsed time to the caller's exclusive time 102 caller.addExclusiveTime(elapsed); 103 } 104 exit(Call c, long elapsed, long globalTime)105 private void exit(Call c, long elapsed, long globalTime) { 106 mCurrent.mGlobalEndTime = globalTime; 107 Call top = pop(); 108 if (top == null) { 109 return; 110 } 111 112 if (mCurrent.mMethodData != c.mMethodData) { 113 String error = "Method exit (" + c.getName() 114 + ") does not match current method (" + mCurrent.getName() 115 + ")"; 116 throw new RuntimeException(error); 117 } else { 118 long duration = c.mThreadStartTime - mCurrent.mThreadStartTime; 119 Call caller = top(); 120 mCurrent.addExclusiveTime(elapsed); 121 mCurrent.addInclusiveTime(duration, caller); 122 if (caller == null) { 123 caller = mRoot; 124 } 125 mCurrent = caller; 126 } 127 } 128 push(Call c)129 public void push(Call c) { 130 mStack.add(c); 131 } 132 pop()133 public Call pop() { 134 ArrayList<Call> stack = mStack; 135 if (stack.size() == 0) 136 return null; 137 Call top = stack.get(stack.size() - 1); 138 stack.remove(stack.size() - 1); 139 140 // Decrement the count on the method in the hash table and remove 141 // the entry when it goes to zero. 142 MethodData md = top.mMethodData; 143 Integer num = mStackMethods.get(md); 144 if (num != null) { 145 num -= 1; 146 if (num <= 0) { 147 mStackMethods.remove(md); 148 } else { 149 mStackMethods.put(md, num); 150 } 151 } 152 return top; 153 } 154 top()155 public Call top() { 156 ArrayList<Call> stack = mStack; 157 if (stack.size() == 0) 158 return null; 159 return stack.get(stack.size() - 1); 160 } 161 endTrace()162 public long endTrace() { 163 // If we have calls on the stack when the trace ends, then clean up 164 // the stack and compute the inclusive time of the methods by pretending 165 // that we are exiting from their methods now. 166 while (mCurrent != mRoot) { 167 long duration = mLastEventTime - mCurrent.mThreadStartTime; 168 pop(); 169 Call caller = top(); 170 mCurrent.addInclusiveTime(duration, caller); 171 mCurrent.mGlobalEndTime = mGlobalEndTime; 172 if (caller == null) { 173 caller = mRoot; 174 } 175 mCurrent = caller; 176 } 177 return mLastEventTime; 178 } 179 180 @Override toString()181 public String toString() { 182 return mName; 183 } 184 getId()185 public int getId() { 186 return mId; 187 } 188 setCpuTime(long cpuTime)189 public void setCpuTime(long cpuTime) { 190 mCpuTime = cpuTime; 191 } 192 getCpuTime()193 public long getCpuTime() { 194 return mCpuTime; 195 } 196 setGlobalStartTime(long globalStartTime)197 public void setGlobalStartTime(long globalStartTime) { 198 mGlobalStartTime = globalStartTime; 199 } 200 getGlobalStartTime()201 public long getGlobalStartTime() { 202 return mGlobalStartTime; 203 } 204 setLastEventTime(long lastEventTime)205 public void setLastEventTime(long lastEventTime) { 206 mLastEventTime = lastEventTime; 207 } 208 getLastEventTime()209 public long getLastEventTime() { 210 return mLastEventTime; 211 } 212 setGlobalEndTime(long globalEndTime)213 public void setGlobalEndTime(long globalEndTime) { 214 mGlobalEndTime = globalEndTime; 215 } 216 getGlobalEndTime()217 public long getGlobalEndTime() { 218 return mGlobalEndTime; 219 } 220 setLastContextSwitch(Call lastContextSwitch)221 public void setLastContextSwitch(Call lastContextSwitch) { 222 mLastContextSwitch = lastContextSwitch; 223 } 224 getLastContextSwitch()225 public Call getLastContextSwitch() { 226 return mLastContextSwitch; 227 } 228 } 229