blob: 05e54e8a15e6b3f3f958fc267fbe99ffdeb881cf [file] [log] [blame]
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.traceview;
import java.util.ArrayList;
import java.util.HashMap;
class ThreadData implements TimeLineView.Row {
private int mId;
private String mName;
private boolean mIsEmpty;
private Call mRootCall;
private ArrayList<Call> mStack = new ArrayList<Call>();
// This is a hash of all the methods that are currently on the stack.
private HashMap<MethodData, Integer> mStackMethods = new HashMap<MethodData, Integer>();
boolean mHaveGlobalTime;
long mGlobalStartTime;
long mGlobalEndTime;
boolean mHaveThreadTime;
long mThreadStartTime;
long mThreadEndTime;
long mThreadCurrentTime; // only used while parsing thread-cpu clock
ThreadData(int id, String name, MethodData topLevel) {
mId = id;
mName = String.format("[%d] %s", id, name);
mIsEmpty = true;
mRootCall = new Call(this, topLevel, null);
mRootCall.setName(mName);
mStack.add(mRootCall);
}
@Override
public String getName() {
return mName;
}
public Call getRootCall() {
return mRootCall;
}
/**
* Returns true if no calls have ever been recorded for this thread.
*/
public boolean isEmpty() {
return mIsEmpty;
}
Call enter(MethodData method, ArrayList<TraceAction> trace) {
if (mIsEmpty) {
mIsEmpty = false;
if (trace != null) {
trace.add(new TraceAction(TraceAction.ACTION_ENTER, mRootCall));
}
}
Call caller = top();
Call call = new Call(this, method, caller);
mStack.add(call);
if (trace != null) {
trace.add(new TraceAction(TraceAction.ACTION_ENTER, call));
}
Integer num = mStackMethods.get(method);
if (num == null) {
num = 0;
} else if (num > 0) {
call.setRecursive(true);
}
mStackMethods.put(method, num + 1);
return call;
}
Call exit(MethodData method, ArrayList<TraceAction> trace) {
Call call = top();
if (call.mCaller == null) {
return null;
}
if (call.getMethodData() != method) {
String error = "Method exit (" + method.getName()
+ ") does not match current method (" + call.getMethodData().getName()
+ ")";
throw new RuntimeException(error);
}
mStack.remove(mStack.size() - 1);
if (trace != null) {
trace.add(new TraceAction(TraceAction.ACTION_EXIT, call));
}
Integer num = mStackMethods.get(method);
if (num != null) {
if (num == 1) {
mStackMethods.remove(method);
} else {
mStackMethods.put(method, num - 1);
}
}
return call;
}
Call top() {
return mStack.get(mStack.size() - 1);
}
void endTrace(ArrayList<TraceAction> trace) {
for (int i = mStack.size() - 1; i >= 1; i--) {
Call call = mStack.get(i);
call.mGlobalEndTime = mGlobalEndTime;
call.mThreadEndTime = mThreadEndTime;
if (trace != null) {
trace.add(new TraceAction(TraceAction.ACTION_INCOMPLETE, call));
}
}
mStack.clear();
mStackMethods.clear();
}
void updateRootCallTimeBounds() {
if (!mIsEmpty) {
mRootCall.mGlobalStartTime = mGlobalStartTime;
mRootCall.mGlobalEndTime = mGlobalEndTime;
mRootCall.mThreadStartTime = mThreadStartTime;
mRootCall.mThreadEndTime = mThreadEndTime;
}
}
@Override
public String toString() {
return mName;
}
@Override
public int getId() {
return mId;
}
public long getCpuTime() {
return mRootCall.mInclusiveCpuTime;
}
public long getRealTime() {
return mRootCall.mInclusiveRealTime;
}
}