aboutsummaryrefslogtreecommitdiffstats
path: root/traceview/src
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-06-22 19:48:45 -0700
committerJeff Brown <jeffbrown@android.com>2011-06-27 12:10:53 -0700
commit069cdbf76cc71c62b47e1fedc5a2bd376502b50a (patch)
tree10459b97836f4f6870f99a64337d7e8e232974a3 /traceview/src
parent3300cca599a8e3c52e7c5f188864e35799b4e74f (diff)
downloadsdk-069cdbf76cc71c62b47e1fedc5a2bd376502b50a.zip
sdk-069cdbf76cc71c62b47e1fedc5a2bd376502b50a.tar.gz
sdk-069cdbf76cc71c62b47e1fedc5a2bd376502b50a.tar.bz2
Add support for tracking cpu and real time.
Enhanced TraceView to support extracting cpu and real time profile data from traces and plotting them accordingly. In contrast, the original thread-cpu algorithm incorrectly assumed that threads could not execute in parallel so it would produce inaccurate representations of the global execution timeline on SMP systems. To use this feature, Dalvik must be restarted with appropriate profiling options. Collect CPU time only (default). Global timeline must be inferred. adb shell setprop dalvik.vm.extra-opts -Xprofile:threadcpuclock Collect real time only. CPU usage information is not available. adb shell setprop dalvik.vm.extra-opts -Xprofile:wallclock Collect CPU time and real time information. Most accurate but requires a newer VM. adb shell setprop dalvik.vm.extra-opts -Xprofile:dualclock TraceView remains compatible with traces gathered on older devices and produces identical output when analyzing traces gathered with the thread-cpu clock. Added a feature that displays the exclusive and inclusive time information while hovering over a method. Added a feature that displays the time spent in a context switch by a simple 1 pixel underline within the body of the method call. This makes it much easier to identify long running methods that spend most of their time blocked on a wait. Fixed a bug in the way that the method call highlights were displayed which could cause them to be truncated down to a single-pixel width depending on the pixel alignment of the start and end of each segment. Change-Id: Id2e6d101d9c604a0029e0920127871f88013faa0
Diffstat (limited to 'traceview/src')
-rw-r--r--traceview/src/com/android/traceview/Call.java148
-rw-r--r--traceview/src/com/android/traceview/DmTraceReader.java578
-rw-r--r--traceview/src/com/android/traceview/MethodData.java149
-rw-r--r--traceview/src/com/android/traceview/ProfileData.java21
-rw-r--r--traceview/src/com/android/traceview/ProfileProvider.java189
-rw-r--r--traceview/src/com/android/traceview/ProfileSelf.java9
-rw-r--r--traceview/src/com/android/traceview/ProfileView.java10
-rw-r--r--traceview/src/com/android/traceview/ThreadData.java228
-rw-r--r--traceview/src/com/android/traceview/TimeBase.java71
-rw-r--r--traceview/src/com/android/traceview/TimeLineView.java182
-rw-r--r--traceview/src/com/android/traceview/TraceAction.java (renamed from traceview/src/com/android/traceview/QtraceReader.java)34
-rw-r--r--traceview/src/com/android/traceview/TraceReader.java22
12 files changed, 1030 insertions, 611 deletions
diff --git a/traceview/src/com/android/traceview/Call.java b/traceview/src/com/android/traceview/Call.java
index 40ac244..53f16cb 100644
--- a/traceview/src/com/android/traceview/Call.java
+++ b/traceview/src/com/android/traceview/Call.java
@@ -19,52 +19,30 @@ package com.android.traceview;
import org.eclipse.swt.graphics.Color;
class Call implements TimeLineView.Block {
-
- // Values for bits within the mFlags field.
- private static final int METHOD_ACTION_MASK = 0x3;
- private static final int IS_RECURSIVE = 0x10;
-
- private int mThreadId;
- private int mFlags;
- MethodData mMethodData;
-
- /** 0-based thread-local start time */
- long mThreadStartTime;
-
- /** global start time */
- long mGlobalStartTime;
+ final private ThreadData mThreadData;
+ final private MethodData mMethodData;
+ final Call mCaller; // the caller, or null if this is the root
- /** global end time */
- long mGlobalEndTime;
-
private String mName;
+ private boolean mIsRecursive;
- /**
- * This constructor is used for the root of a Call tree. The name is
- * the name of the corresponding thread.
- */
- Call(String name, MethodData methodData) {
- mName = name;
- mMethodData = methodData;
- }
+ long mGlobalStartTime;
+ long mGlobalEndTime;
- Call() {
- }
-
- Call(int threadId, MethodData methodData, long time, int methodAction) {
- mThreadId = threadId;
- mMethodData = methodData;
- mThreadStartTime = time;
- mFlags = methodAction & METHOD_ACTION_MASK;
- mName = methodData.getProfileName();
- }
-
- public void set(int threadId, MethodData methodData, long time, int methodAction) {
- mThreadId = threadId;
+ long mThreadStartTime;
+ long mThreadEndTime;
+
+ long mInclusiveRealTime; // real time spent in this call including its children
+ long mExclusiveRealTime; // real time spent in this call including its children
+
+ long mInclusiveCpuTime; // cpu time spent in this call including its children
+ long mExclusiveCpuTime; // cpu time spent in this call excluding its children
+
+ Call(ThreadData threadData, MethodData methodData, Call caller) {
+ mThreadData = threadData;
mMethodData = methodData;
- mThreadStartTime = time;
- mFlags = methodAction & METHOD_ACTION_MASK;
mName = methodData.getProfileName();
+ mCaller = caller;
}
public void updateName() {
@@ -87,20 +65,24 @@ class Call implements TimeLineView.Block {
return mGlobalEndTime;
}
- public Color getColor() {
- return mMethodData.getColor();
+ public long getExclusiveCpuTime() {
+ return mExclusiveCpuTime;
}
- public void addExclusiveTime(long elapsed) {
- mMethodData.addElapsedExclusive(elapsed);
- if ((mFlags & IS_RECURSIVE) == 0) {
- mMethodData.addTopExclusive(elapsed);
- }
+ public long getInclusiveCpuTime() {
+ return mInclusiveCpuTime;
+ }
+
+ public long getExclusiveRealTime() {
+ return mExclusiveRealTime;
}
- public void addInclusiveTime(long elapsed, Call parent) {
- boolean isRecursive = (mFlags & IS_RECURSIVE) != 0;
- mMethodData.addElapsedInclusive(elapsed, isRecursive, parent);
+ public long getInclusiveRealTime() {
+ return mInclusiveRealTime;
+ }
+
+ public Color getColor() {
+ return mMethodData.getColor();
}
public String getName() {
@@ -111,31 +93,71 @@ class Call implements TimeLineView.Block {
mName = name;
}
- int getThreadId() {
- return mThreadId;
+ public ThreadData getThreadData() {
+ return mThreadData;
+ }
+
+ public int getThreadId() {
+ return mThreadData.getId();
}
public MethodData getMethodData() {
return mMethodData;
}
- int getMethodAction() {
- return mFlags & METHOD_ACTION_MASK;
+ public boolean isContextSwitch() {
+ return mMethodData.getId() < 0;
}
- public void dump() {
- System.out.printf("%s [%d, %d]\n", mName, mGlobalStartTime, mGlobalEndTime);
+ public boolean isIgnoredBlock() {
+ // Ignore the top-level call or context switches within the top-level call.
+ return mCaller == null || isContextSwitch() && mCaller.mCaller == null;
}
- public void setRecursive(boolean isRecursive) {
- if (isRecursive) {
- mFlags |= IS_RECURSIVE;
- } else {
- mFlags &= ~IS_RECURSIVE;
- }
+ public TimeLineView.Block getParentBlock() {
+ return mCaller;
}
public boolean isRecursive() {
- return (mFlags & IS_RECURSIVE) != 0;
+ return mIsRecursive;
+ }
+
+ void setRecursive(boolean isRecursive) {
+ mIsRecursive = isRecursive;
+ }
+
+ void addCpuTime(long elapsedCpuTime) {
+ mExclusiveCpuTime += elapsedCpuTime;
+ mInclusiveCpuTime += elapsedCpuTime;
+ }
+
+ /**
+ * Record time spent in the method call.
+ */
+ void finish() {
+ if (mCaller != null) {
+ mCaller.mInclusiveCpuTime += mInclusiveCpuTime;
+ mCaller.mInclusiveRealTime += mInclusiveRealTime;
+ }
+
+ mMethodData.addElapsedExclusive(mExclusiveCpuTime, mExclusiveRealTime);
+ if (!mIsRecursive) {
+ mMethodData.addTopExclusive(mExclusiveCpuTime, mExclusiveRealTime);
+ }
+ mMethodData.addElapsedInclusive(mInclusiveCpuTime, mInclusiveRealTime,
+ mIsRecursive, mCaller);
+ }
+
+ public static final class TraceAction {
+ public static final int ACTION_ENTER = 0;
+ public static final int ACTION_EXIT = 1;
+
+ public final int mAction;
+ public final Call mCall;
+
+ public TraceAction(int action, Call call) {
+ mAction = action;
+ mCall = call;
+ }
}
}
diff --git a/traceview/src/com/android/traceview/DmTraceReader.java b/traceview/src/com/android/traceview/DmTraceReader.java
index dcf17a2..fbcd13e 100644
--- a/traceview/src/com/android/traceview/DmTraceReader.java
+++ b/traceview/src/com/android/traceview/DmTraceReader.java
@@ -35,25 +35,37 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DmTraceReader extends TraceReader {
-
- private int mVersionNumber = 0;
- private boolean mDebug = false;
private static final int TRACE_MAGIC = 0x574f4c53;
+
+ private static final int METHOD_TRACE_ENTER = 0x00; // method entry
+ private static final int METHOD_TRACE_EXIT = 0x01; // method exit
+ private static final int METHOD_TRACE_UNROLL = 0x02; // method exited by exception unrolling
+
+ // When in dual clock mode, we report that a context switch has occurred
+ // when skew between the real time and thread cpu clocks is more than this
+ // many microseconds.
+ private static final long MIN_CONTEXT_SWITCH_TIME_USEC = 100;
+
+ private enum ClockSource {
+ THREAD_CPU, WALL, DUAL,
+ };
+
+ private int mVersionNumber;
private boolean mRegression;
private ProfileProvider mProfileProvider;
private String mTraceFileName;
private MethodData mTopLevel;
private ArrayList<Call> mCallList;
- private ArrayList<Call> mSwitchList;
private HashMap<String, String> mPropertiesMap;
private HashMap<Integer, MethodData> mMethodMap;
private HashMap<Integer, ThreadData> mThreadMap;
private ThreadData[] mSortedThreads;
private MethodData[] mSortedMethods;
- private long mGlobalEndTime;
+ private long mTotalCpuTime;
+ private long mTotalRealTime;
private MethodData mContextSwitch;
- private int mOffsetToData;
- private byte[] mBytes = new byte[8];
+ private int mRecordSize;
+ private ClockSource mClockSource;
// A regex for matching the thread "id name" lines in the .key file
private static final Pattern mIdNamePattern = Pattern.compile("(\\d+)\t(.*)"); //$NON-NLS-1$
@@ -64,14 +76,15 @@ public class DmTraceReader extends TraceReader {
mPropertiesMap = new HashMap<String, String>();
mMethodMap = new HashMap<Integer, MethodData>();
mThreadMap = new HashMap<Integer, ThreadData>();
+ mCallList = new ArrayList<Call>();
// Create a single top-level MethodData object to hold the profile data
// for time spent in the unknown caller.
mTopLevel = new MethodData(0, "(toplevel)");
mContextSwitch = new MethodData(-1, "(context switch)");
mMethodMap.put(0, mTopLevel);
+ mMethodMap.put(-1, mContextSwitch);
generateTrees();
- // dumpTrees();
}
void generateTrees() {
@@ -92,38 +105,6 @@ public class DmTraceReader extends TraceReader {
return mProfileProvider;
}
- Call readCall(MappedByteBuffer buffer, Call call) {
- int threadId;
- int methodId;
- long time;
-
- try {
- if (mVersionNumber == 1)
- threadId = buffer.get();
- else
- threadId = buffer.getShort();
- methodId = buffer.getInt();
- time = buffer.getInt();
- } catch (BufferUnderflowException ex) {
- return null;
- }
-
- int methodAction = methodId & 0x03;
- methodId = methodId & ~0x03;
- MethodData methodData = mMethodMap.get(methodId);
- if (methodData == null) {
- String name = String.format("(0x%1$x)", methodId); //$NON-NLS-1$
- methodData = new MethodData(methodId, name);
- }
-
- if (call != null) {
- call.set(threadId, methodData, time, methodAction);
- } else {
- call = new Call(threadId, methodData, time, methodAction);
- }
- return call;
- }
-
private MappedByteBuffer mapFile(String filename, long offset) {
MappedByteBuffer buffer = null;
try {
@@ -151,165 +132,279 @@ public class DmTraceReader extends TraceReader {
magic, TRACE_MAGIC);
throw new RuntimeException();
}
+
// read version
int version = buffer.getShort();
-
+ if (version != mVersionNumber) {
+ System.err.printf(
+ "Error: version number mismatch; got %d in data header but %d in options\n",
+ version, mVersionNumber);
+ throw new RuntimeException();
+ }
+ if (version < 1 || version > 3) {
+ System.err.printf(
+ "Error: unsupported trace version number %d. "
+ + "Please use a newer version of TraceView to read this file.", version);
+ throw new RuntimeException();
+ }
+
// read offset
- mOffsetToData = buffer.getShort() - 16;
-
+ int offsetToData = buffer.getShort() - 16;
+
// read startWhen
buffer.getLong();
-
- // Skip over "mOffsetToData" bytes
- for (int ii = 0; ii < mOffsetToData; ii++) {
+
+ // read record size
+ if (version == 1) {
+ mRecordSize = 9;
+ } else if (version == 2) {
+ mRecordSize = 10;
+ } else {
+ mRecordSize = buffer.getShort();
+ offsetToData -= 2;
+ }
+
+ // Skip over offsetToData bytes
+ while (offsetToData-- > 0) {
buffer.get();
}
-
- // Save this position so that we can re-read the data later
- buffer.mark();
}
private void parseData(long offset) {
MappedByteBuffer buffer = mapFile(mTraceFileName, offset);
readDataFileHeader(buffer);
- parseDataPass1(buffer);
-
- buffer.reset();
- parseDataPass2(buffer);
- }
-
- private void parseDataPass1(MappedByteBuffer buffer) {
- mSwitchList = new ArrayList<Call>();
-
- // Read the first call so that we can set "prevThreadData"
- Call call = new Call();
- call = readCall(buffer, call);
- if (call == null)
- return;
- long callTime = call.mThreadStartTime;
- long prevCallTime = 0;
- ThreadData threadData = mThreadMap.get(call.getThreadId());
- if (threadData == null) {
- String name = String.format("[%1$d]", call.getThreadId()); //$NON-NLS-1$
- threadData = new ThreadData(call.getThreadId(), name, mTopLevel);
- mThreadMap.put(call.getThreadId(), threadData);
- }
- ThreadData prevThreadData = threadData;
- while (true) {
- // If a context switch occurred, then insert a placeholder "call"
- // record so that we can do something reasonable with the global
- // timestamps.
- if (prevThreadData != threadData) {
- Call switchEnter = new Call(prevThreadData.getId(),
- mContextSwitch, prevCallTime, 0);
- prevThreadData.setLastContextSwitch(switchEnter);
- mSwitchList.add(switchEnter);
- Call contextSwitch = threadData.getLastContextSwitch();
- if (contextSwitch != null) {
- long prevStartTime = contextSwitch.mThreadStartTime;
- long elapsed = callTime - prevStartTime;
- long beforeSwitch = elapsed / 2;
- long afterSwitch = elapsed - beforeSwitch;
- long exitTime = callTime - afterSwitch;
- contextSwitch.mThreadStartTime = prevStartTime + beforeSwitch;
- Call switchExit = new Call(threadData.getId(),
- mContextSwitch, exitTime, 1);
-
- mSwitchList.add(switchExit);
+
+ ArrayList<TraceAction> trace = null;
+ if (mClockSource == ClockSource.THREAD_CPU) {
+ trace = new ArrayList<TraceAction>();
+ }
+
+ final boolean haveThreadClock = mClockSource != ClockSource.WALL;
+ final boolean haveGlobalClock = mClockSource != ClockSource.THREAD_CPU;
+
+ // Parse all call records to obtain elapsed time information.
+ ThreadData prevThreadData = null;
+ for (;;) {
+ int threadId;
+ int methodId;
+ long threadTime, globalTime;
+ try {
+ int recordSize = mRecordSize;
+
+ if (mVersionNumber == 1) {
+ threadId = buffer.get();
+ recordSize -= 1;
+ } else {
+ threadId = buffer.getShort();
+ recordSize -= 2;
}
- prevThreadData = threadData;
- }
- // Read the next call
- call = readCall(buffer, call);
- if (call == null) {
+ methodId = buffer.getInt();
+ recordSize -= 4;
+
+ switch (mClockSource) {
+ case WALL:
+ threadTime = 0;
+ globalTime = buffer.getInt();
+ recordSize -= 4;
+ break;
+ case DUAL:
+ threadTime = buffer.getInt();
+ globalTime = buffer.getInt();
+ recordSize -= 8;
+ break;
+ default:
+ case THREAD_CPU:
+ threadTime = buffer.getInt();
+ globalTime = 0;
+ recordSize -= 4;
+ break;
+ }
+
+ while (recordSize-- > 0) {
+ buffer.get();
+ }
+ } catch (BufferUnderflowException ex) {
break;
}
- prevCallTime = callTime;
- callTime = call.mThreadStartTime;
- threadData = mThreadMap.get(call.getThreadId());
- if (threadData == null) {
- String name = String.format("[%d]", call.getThreadId());
- threadData = new ThreadData(call.getThreadId(), name, mTopLevel);
- mThreadMap.put(call.getThreadId(), threadData);
+ int methodAction = methodId & 0x03;
+ methodId = methodId & ~0x03;
+ MethodData methodData = mMethodMap.get(methodId);
+ if (methodData == null) {
+ String name = String.format("(0x%1$x)", methodId); //$NON-NLS-1$
+ methodData = new MethodData(methodId, name);
+ mMethodMap.put(methodId, methodData);
}
- }
- }
- void parseDataPass2(MappedByteBuffer buffer) {
- mCallList = new ArrayList<Call>();
+ ThreadData threadData = mThreadMap.get(threadId);
+ if (threadData == null) {
+ String name = String.format("[%1$d]", threadId); //$NON-NLS-1$
+ threadData = new ThreadData(threadId, name, mTopLevel);
+ mThreadMap.put(threadId, threadData);
+ }
- // Read the first call so that we can set "prevThreadData"
- Call call = readCall(buffer, null);
- long callTime = call.mThreadStartTime;
- long prevCallTime = callTime;
- ThreadData threadData = mThreadMap.get(call.getThreadId());
- ThreadData prevThreadData = threadData;
- threadData.setGlobalStartTime(0);
-
- int nthContextSwitch = 0;
+ long elapsedGlobalTime = 0;
+ if (haveGlobalClock) {
+ if (!threadData.mHaveGlobalTime) {
+ threadData.mGlobalStartTime = globalTime;
+ threadData.mHaveGlobalTime = true;
+ } else {
+ elapsedGlobalTime = globalTime - threadData.mGlobalEndTime;
+ }
+ threadData.mGlobalEndTime = globalTime;
+ }
- // Assign a global timestamp to each event.
- long globalTime = 0;
- while (true) {
- long elapsed = callTime - prevCallTime;
- if (threadData != prevThreadData) {
- // Get the next context switch. This one is entered
- // by the previous thread.
- Call contextSwitch = mSwitchList.get(nthContextSwitch++);
- mCallList.add(contextSwitch);
- elapsed = contextSwitch.mThreadStartTime - prevCallTime;
- globalTime += elapsed;
- elapsed = 0;
- contextSwitch.mGlobalStartTime = globalTime;
- prevThreadData.handleCall(contextSwitch, globalTime);
-
- if (!threadData.isEmpty()) {
- // This context switch is exited by the current thread.
- contextSwitch = mSwitchList.get(nthContextSwitch++);
- mCallList.add(contextSwitch);
- contextSwitch.mGlobalStartTime = globalTime;
- elapsed = callTime - contextSwitch.mThreadStartTime;
- threadData.handleCall(contextSwitch, globalTime);
+ if (haveThreadClock) {
+ long elapsedThreadTime = 0;
+ if (!threadData.mHaveThreadTime) {
+ threadData.mThreadStartTime = threadTime;
+ threadData.mThreadCurrentTime = threadTime;
+ threadData.mHaveThreadTime = true;
+ } else {
+ elapsedThreadTime = threadTime - threadData.mThreadEndTime;
+ }
+ threadData.mThreadEndTime = threadTime;
+
+ if (!haveGlobalClock) {
+ // Detect context switches whenever execution appears to switch from one
+ // thread to another. This assumption is only valid on uniprocessor
+ // systems (which is why we now have a dual clock mode).
+ // We represent context switches in the trace by pushing a call record
+ // with MethodData mContextSwitch onto the stack of the previous
+ // thread. We arbitrarily set the start and end time of the context
+ // switch such that the context switch occurs in the middle of the thread
+ // time and itself accounts for zero thread time.
+ if (prevThreadData != null && prevThreadData != threadData) {
+ // Begin context switch from previous thread.
+ Call switchCall = prevThreadData.enter(mContextSwitch, trace);
+ switchCall.mThreadStartTime = prevThreadData.mThreadEndTime;
+ mCallList.add(switchCall);
+
+ // Return from context switch to current thread.
+ Call top = threadData.top();
+ if (top.getMethodData() == mContextSwitch) {
+ threadData.exit(mContextSwitch, trace);
+ long beforeSwitch = elapsedThreadTime / 2;
+ top.mThreadStartTime += beforeSwitch;
+ top.mThreadEndTime = top.mThreadStartTime;
+ }
+ }
+ prevThreadData = threadData;
+ } else {
+ // If we have a global clock, then we can detect context switches (or blocking
+ // calls or cpu suspensions or clock anomalies) by comparing global time to
+ // thread time for successive calls that occur on the same thread.
+ // As above, we represent the context switch using a special method call.
+ long sleepTime = elapsedGlobalTime - elapsedThreadTime;
+ if (sleepTime > MIN_CONTEXT_SWITCH_TIME_USEC) {
+ Call switchCall = threadData.enter(mContextSwitch, trace);
+ long beforeSwitch = elapsedThreadTime / 2;
+ long afterSwitch = elapsedThreadTime - beforeSwitch;
+ switchCall.mGlobalStartTime = globalTime - elapsedGlobalTime + beforeSwitch;
+ switchCall.mGlobalEndTime = globalTime - afterSwitch;
+ switchCall.mThreadStartTime = threadTime - afterSwitch;
+ switchCall.mThreadEndTime = switchCall.mThreadStartTime;
+ threadData.exit(mContextSwitch, trace);
+ mCallList.add(switchCall);
+ }
}
- // If the thread's global start time has not been set yet,
- // then set it.
- if (threadData.getGlobalStartTime() == -1)
- threadData.setGlobalStartTime(globalTime);
- prevThreadData = threadData;
+ // Add thread CPU time.
+ Call top = threadData.top();
+ top.addCpuTime(elapsedThreadTime);
}
- globalTime += elapsed;
- call.mGlobalStartTime = globalTime;
-
- threadData.handleCall(call, globalTime);
- mCallList.add(call);
-
- // Read the next call
- call = readCall(buffer, null);
- if (call == null) {
- break;
+ switch (methodAction) {
+ case METHOD_TRACE_ENTER: {
+ Call call = threadData.enter(methodData, trace);
+ if (haveGlobalClock) {
+ call.mGlobalStartTime = globalTime;
+ }
+ if (haveThreadClock) {
+ call.mThreadStartTime = threadTime;
+ }
+ mCallList.add(call);
+ break;
+ }
+ case METHOD_TRACE_EXIT:
+ case METHOD_TRACE_UNROLL: {
+ Call call = threadData.exit(methodData, trace);
+ if (call != null) {
+ if (haveGlobalClock) {
+ call.mGlobalEndTime = globalTime;
+ }
+ if (haveThreadClock) {
+ call.mThreadEndTime = threadTime;
+ }
+ }
+ break;
+ }
+ default:
+ throw new RuntimeException("Unrecognized method action: " + methodAction);
}
- prevCallTime = callTime;
- callTime = call.mThreadStartTime;
- threadData = mThreadMap.get(call.getThreadId());
}
- // Allow each thread to do any cleanup of the call stack.
- // Also add the elapsed time for each thread to the toplevel
- // method's inclusive time.
- for (int id : mThreadMap.keySet()) {
- threadData = mThreadMap.get(id);
- long endTime = threadData.endTrace();
- if (endTime > 0)
- mTopLevel.addElapsedInclusive(endTime, false, null);
+ // Exit any pending open-ended calls.
+ for (ThreadData threadData : mThreadMap.values()) {
+ threadData.endTrace(trace);
+ }
+
+ // Recreate the global timeline from thread times, if needed.
+ if (!haveGlobalClock) {
+ long globalTime = 0;
+ prevThreadData = null;
+ for (TraceAction traceAction : trace) {
+ Call call = traceAction.mCall;
+ ThreadData threadData = call.getThreadData();
+
+ if (traceAction.mAction == TraceAction.ACTION_ENTER) {
+ long threadTime = call.mThreadStartTime;
+ globalTime += call.mThreadStartTime - threadData.mThreadCurrentTime;
+ call.mGlobalStartTime = globalTime;
+ if (!threadData.mHaveGlobalTime) {
+ threadData.mHaveGlobalTime = true;
+ threadData.mGlobalStartTime = globalTime;
+ }
+ threadData.mThreadCurrentTime = threadTime;
+ } else if (traceAction.mAction == TraceAction.ACTION_EXIT) {
+ long threadTime = call.mThreadEndTime;
+ globalTime += call.mThreadEndTime - threadData.mThreadCurrentTime;
+ call.mGlobalEndTime = globalTime;
+ threadData.mGlobalEndTime = globalTime;
+ threadData.mThreadCurrentTime = threadTime;
+ } // else, ignore ACTION_INCOMPLETE calls, nothing to do
+ prevThreadData = threadData;
+ }
+ }
+
+ // Finish updating all calls and calculate the total time spent.
+ for (int i = mCallList.size() - 1; i >= 0; i--) {
+ Call call = mCallList.get(i);
+
+ // Calculate exclusive real-time by subtracting inclusive real time
+ // accumulated by children from the total span.
+ long realTime = call.mGlobalEndTime - call.mGlobalStartTime;
+ call.mExclusiveRealTime = Math.max(realTime - call.mInclusiveRealTime, 0);
+ call.mInclusiveRealTime = realTime;
+
+ call.finish();
+ }
+ mTotalCpuTime = 0;
+ mTotalRealTime = 0;
+ for (ThreadData threadData : mThreadMap.values()) {
+ Call rootCall = threadData.getRootCall();
+ threadData.updateRootCallTimeBounds();
+ rootCall.finish();
+ mTotalCpuTime += rootCall.mInclusiveCpuTime;
+ mTotalRealTime += rootCall.mInclusiveRealTime;
}
- mGlobalEndTime = globalTime;
-
if (mRegression) {
+ System.out.format("totalCpuTime %dus\n", mTotalCpuTime);
+ System.out.format("totalRealTime %dus\n", mTotalRealTime);
+
+ dumpThreadTimes();
dumpCallTimes();
}
}
@@ -353,7 +448,7 @@ public class DmTraceReader extends TraceReader {
continue;
}
if (line.equals("*end")) {
- return offset;
+ break;
}
}
switch (mode) {
@@ -372,6 +467,11 @@ public class DmTraceReader extends TraceReader {
break;
}
}
+
+ if (mClockSource == null) {
+ mClockSource = ClockSource.THREAD_CPU;
+ }
+ return offset;
}
void parseOption(String line) {
@@ -380,6 +480,16 @@ public class DmTraceReader extends TraceReader {
String key = tokens[0];
String value = tokens[1];
mPropertiesMap.put(key, value);
+
+ if (key.equals("clock")) {
+ if (value.equals("thread-cpu")) {
+ mClockSource = ClockSource.THREAD_CPU;
+ } else if (value.equals("wall")) {
+ mClockSource = ClockSource.WALL;
+ } else if (value.equals("dual")) {
+ mClockSource = ClockSource.DUAL;
+ }
+ }
}
}
@@ -435,38 +545,30 @@ public class DmTraceReader extends TraceReader {
}
private void analyzeData() {
+ final TimeBase timeBase = getPreferredTimeBase();
+
// Sort the threads into decreasing cpu time
Collection<ThreadData> tv = mThreadMap.values();
mSortedThreads = tv.toArray(new ThreadData[tv.size()]);
Arrays.sort(mSortedThreads, new Comparator<ThreadData>() {
public int compare(ThreadData td1, ThreadData td2) {
- if (td2.getCpuTime() > td1.getCpuTime())
+ if (timeBase.getTime(td2) > timeBase.getTime(td1))
return 1;
- if (td2.getCpuTime() < td1.getCpuTime())
+ if (timeBase.getTime(td2) < timeBase.getTime(td1))
return -1;
return td2.getName().compareTo(td1.getName());
}
});
- // Analyze the call tree so that we can label the "worst" children.
- // Also set all the root pointers in each node in the call tree.
- long sum = 0;
- for (ThreadData t : mSortedThreads) {
- if (t.isEmpty() == false) {
- Call root = t.getCalltreeRoot();
- root.mGlobalStartTime = t.getGlobalStartTime();
- }
- }
-
// Sort the methods into decreasing inclusive time
Collection<MethodData> mv = mMethodMap.values();
MethodData[] methods;
methods = mv.toArray(new MethodData[mv.size()]);
Arrays.sort(methods, new Comparator<MethodData>() {
public int compare(MethodData md1, MethodData md2) {
- if (md2.getElapsedInclusive() > md1.getElapsedInclusive())
+ if (timeBase.getElapsedInclusiveTime(md2) > timeBase.getElapsedInclusiveTime(md1))
return 1;
- if (md2.getElapsedInclusive() < md1.getElapsedInclusive())
+ if (timeBase.getElapsedInclusiveTime(md2) < timeBase.getElapsedInclusiveTime(md1))
return -1;
return md1.getName().compareTo(md2.getName());
}
@@ -475,7 +577,7 @@ public class DmTraceReader extends TraceReader {
// Count the number of methods with non-zero inclusive time
int nonZero = 0;
for (MethodData md : methods) {
- if (md.getElapsedInclusive() == 0)
+ if (timeBase.getElapsedInclusiveTime(md) == 0)
break;
nonZero += 1;
}
@@ -484,7 +586,7 @@ public class DmTraceReader extends TraceReader {
mSortedMethods = new MethodData[nonZero];
int ii = 0;
for (MethodData md : methods) {
- if (md.getElapsedInclusive() == 0)
+ if (timeBase.getElapsedInclusiveTime(md) == 0)
break;
md.setRank(ii);
mSortedMethods[ii++] = md;
@@ -492,7 +594,7 @@ public class DmTraceReader extends TraceReader {
// Let each method analyze its profile data
for (MethodData md : mSortedMethods) {
- md.analyzeData();
+ md.analyzeData(timeBase);
}
// Update all the calls to include the method rank in
@@ -522,67 +624,65 @@ public class DmTraceReader extends TraceReader {
// entire execution of the thread.
for (ThreadData threadData : mSortedThreads) {
if (!threadData.isEmpty() && threadData.getId() != 0) {
- Call call = new Call(threadData.getId(), mTopLevel,
- threadData.getGlobalStartTime(), 0);
- call.mGlobalStartTime = threadData.getGlobalStartTime();
- call.mGlobalEndTime = threadData.getGlobalEndTime();
- record = new TimeLineView.Record(threadData, call);
+ record = new TimeLineView.Record(threadData, threadData.getRootCall());
timeRecs.add(record);
}
}
for (Call call : mCallList) {
- if (call.getMethodAction() != 0 || call.getThreadId() == 0)
- continue;
- ThreadData threadData = mThreadMap.get(call.getThreadId());
- record = new TimeLineView.Record(threadData, call);
+ record = new TimeLineView.Record(call.getThreadData(), call);
timeRecs.add(record);
}
-
+
if (mRegression) {
dumpTimeRecs(timeRecs);
System.exit(0);
}
return timeRecs;
}
-
+
+ private void dumpThreadTimes() {
+ System.out.print("\nThread Times\n");
+ System.out.print("id t-start t-end g-start g-end name\n");
+ for (ThreadData threadData : mThreadMap.values()) {
+ System.out.format("%2d %8d %8d %8d %8d %s\n",
+ threadData.getId(),
+ threadData.mThreadStartTime, threadData.mThreadEndTime,
+ threadData.mGlobalStartTime, threadData.mGlobalEndTime,
+ threadData.getName());
+ }
+ }
+
private void dumpCallTimes() {
- String action;
-
- System.out.format("id thread global start,end method\n");
+ System.out.print("\nCall Times\n");
+ System.out.print("id t-start t-end g-start g-end excl. incl. method\n");
for (Call call : mCallList) {
- if (call.getMethodAction() == 0) {
- action = "+";
- } else {
- action = " ";
- }
- long callTime = call.mThreadStartTime;
- System.out.format("%2d %6d %8d %8d %s %s\n",
- call.getThreadId(), callTime, call.mGlobalStartTime,
- call.mGlobalEndTime, action, call.getMethodData().getName());
-// if (call.getMethodAction() == 0 && call.getGlobalEndTime() < call.getGlobalStartTime()) {
-// System.out.printf("endtime %d < startTime %d\n",
-// call.getGlobalEndTime(), call.getGlobalStartTime());
-// }
+ System.out.format("%2d %8d %8d %8d %8d %8d %8d %s\n",
+ call.getThreadId(), call.mThreadStartTime, call.mThreadEndTime,
+ call.mGlobalStartTime, call.mGlobalEndTime,
+ call.mExclusiveCpuTime, call.mInclusiveCpuTime,
+ call.getMethodData().getName());
}
}
private void dumpMethodStats() {
- System.out.format("\nExclusive Inclusive Calls Method\n");
+ System.out.print("\nMethod Stats\n");
+ System.out.print("Excl Cpu Incl Cpu Excl Real Incl Real Calls Method\n");
for (MethodData md : mSortedMethods) {
System.out.format("%9d %9d %9s %s\n",
- md.getElapsedExclusive(), md.getElapsedInclusive(),
+ md.getElapsedExclusiveCpuTime(), md.getElapsedInclusiveCpuTime(),
+ md.getElapsedExclusiveRealTime(), md.getElapsedInclusiveRealTime(),
md.getCalls(), md.getProfileName());
}
}
private void dumpTimeRecs(ArrayList<TimeLineView.Record> timeRecs) {
- System.out.format("\nid thread global start,end method\n");
+ System.out.print("\nTime Records\n");
+ System.out.print("id t-start t-end g-start g-end method\n");
for (TimeLineView.Record record : timeRecs) {
Call call = (Call) record.block;
- long callTime = call.mThreadStartTime;
- System.out.format("%2d %6d %8d %8d %s\n",
- call.getThreadId(), callTime,
+ System.out.format("%2d %8d %8d %8d %8d %s\n",
+ call.getThreadId(), call.mThreadStartTime, call.mThreadEndTime,
call.mGlobalStartTime, call.mGlobalEndTime,
call.getMethodData().getName());
}
@@ -608,12 +708,48 @@ public class DmTraceReader extends TraceReader {
}
@Override
- public long getEndTime() {
- return mGlobalEndTime;
+ public long getTotalCpuTime() {
+ return mTotalCpuTime;
+ }
+
+ @Override
+ public long getTotalRealTime() {
+ return mTotalRealTime;
+ }
+
+ @Override
+ public boolean haveCpuTime() {
+ return mClockSource != ClockSource.WALL;
+ }
+
+ @Override
+ public boolean haveRealTime() {
+ return mClockSource != ClockSource.THREAD_CPU;
}
@Override
public HashMap<String, String> getProperties() {
return mPropertiesMap;
}
+
+ @Override
+ public TimeBase getPreferredTimeBase() {
+ if (mClockSource == ClockSource.WALL) {
+ return TimeBase.REAL_TIME;
+ }
+ return TimeBase.CPU_TIME;
+ }
+
+ @Override
+ public String getClockSource() {
+ switch (mClockSource) {
+ case THREAD_CPU:
+ return "cpu time";
+ case WALL:
+ return "real time";
+ case DUAL:
+ return "real time, dual clock";
+ }
+ return null;
+ }
}
diff --git a/traceview/src/com/android/traceview/MethodData.java b/traceview/src/com/android/traceview/MethodData.java
index d54b72b..47f6df4 100644
--- a/traceview/src/com/android/traceview/MethodData.java
+++ b/traceview/src/com/android/traceview/MethodData.java
@@ -36,9 +36,12 @@ public class MethodData {
private String mProfileName;
private String mPathname;
private int mLineNumber;
- private long mElapsedExclusive;
- private long mElapsedInclusive;
- private long mTopExclusive;
+ private long mElapsedExclusiveCpuTime;
+ private long mElapsedInclusiveCpuTime;
+ private long mTopExclusiveCpuTime;
+ private long mElapsedExclusiveRealTime;
+ private long mElapsedInclusiveRealTime;
+ private long mTopExclusiveRealTime;
private int[] mNumCalls = new int[2]; // index 0=normal, 1=recursive
private Color mColor;
private Color mFadedColor;
@@ -81,16 +84,6 @@ public class MethodData {
computeProfileName();
}
- private Comparator<ProfileData> mByElapsedInclusive = new Comparator<ProfileData>() {
- public int compare(ProfileData pd1, ProfileData pd2) {
- if (pd2.getElapsedInclusive() > pd1.getElapsedInclusive())
- return 1;
- if (pd2.getElapsedInclusive() < pd1.getElapsedInclusive())
- return -1;
- return 0;
- }
- };
-
public double addWeight(int x, int y, double weight) {
if (mX == x && mY == y)
mWeight += weight;
@@ -115,13 +108,16 @@ public class MethodData {
computeProfileName();
}
- public void addElapsedExclusive(long time) {
- mElapsedExclusive += time;
+ public void addElapsedExclusive(long cpuTime, long realTime) {
+ mElapsedExclusiveCpuTime += cpuTime;
+ mElapsedExclusiveRealTime += realTime;
}
- public void addElapsedInclusive(long time, boolean isRecursive, Call parent) {
+ public void addElapsedInclusive(long cpuTime, long realTime,
+ boolean isRecursive, Call parent) {
if (isRecursive == false) {
- mElapsedInclusive += time;
+ mElapsedInclusiveCpuTime += cpuTime;
+ mElapsedInclusiveRealTime += realTime;
mNumCalls[0] += 1;
} else {
mNumCalls[1] += 1;
@@ -131,27 +127,27 @@ public class MethodData {
return;
// Find the child method in the parent
- MethodData parentMethod = parent.mMethodData;
+ MethodData parentMethod = parent.getMethodData();
if (parent.isRecursive()) {
- parentMethod.mRecursiveChildren = updateInclusive(time,
+ parentMethod.mRecursiveChildren = updateInclusive(cpuTime, realTime,
parentMethod, this, false,
parentMethod.mRecursiveChildren);
} else {
- parentMethod.mChildren = updateInclusive(time,
+ parentMethod.mChildren = updateInclusive(cpuTime, realTime,
parentMethod, this, false, parentMethod.mChildren);
}
// Find the parent method in the child
if (isRecursive) {
- mRecursiveParents = updateInclusive(time, this, parentMethod, true,
+ mRecursiveParents = updateInclusive(cpuTime, realTime, this, parentMethod, true,
mRecursiveParents);
} else {
- mParents = updateInclusive(time, this, parentMethod, true,
+ mParents = updateInclusive(cpuTime, realTime, this, parentMethod, true,
mParents);
}
}
- private HashMap<Integer, ProfileData> updateInclusive(long time,
+ private HashMap<Integer, ProfileData> updateInclusive(long cpuTime, long realTime,
MethodData contextMethod, MethodData elementMethod,
boolean elementIsParent, HashMap<Integer, ProfileData> map) {
if (map == null) {
@@ -159,30 +155,30 @@ public class MethodData {
} else {
ProfileData profileData = map.get(elementMethod.mId);
if (profileData != null) {
- profileData.addElapsedInclusive(time);
+ profileData.addElapsedInclusive(cpuTime, realTime);
return map;
}
}
ProfileData elementData = new ProfileData(contextMethod,
elementMethod, elementIsParent);
- elementData.setElapsedInclusive(time);
+ elementData.setElapsedInclusive(cpuTime, realTime);
elementData.setNumCalls(1);
map.put(elementMethod.mId, elementData);
return map;
}
- public void analyzeData() {
+ public void analyzeData(TimeBase timeBase) {
// Sort the parents and children into decreasing inclusive time
ProfileData[] sortedParents;
ProfileData[] sortedChildren;
ProfileData[] sortedRecursiveParents;
ProfileData[] sortedRecursiveChildren;
- sortedParents = sortProfileData(mParents);
- sortedChildren = sortProfileData(mChildren);
- sortedRecursiveParents = sortProfileData(mRecursiveParents);
- sortedRecursiveChildren = sortProfileData(mRecursiveChildren);
+ sortedParents = sortProfileData(mParents, timeBase);
+ sortedChildren = sortProfileData(mChildren, timeBase);
+ sortedRecursiveParents = sortProfileData(mRecursiveParents, timeBase);
+ sortedRecursiveChildren = sortProfileData(mRecursiveChildren, timeBase);
// Add "self" time to the top of the sorted children
sortedChildren = addSelf(sortedChildren);
@@ -215,7 +211,8 @@ public class MethodData {
// Create and return a ProfileData[] array that is a sorted copy
// of the given HashMap values.
- private ProfileData[] sortProfileData(HashMap<Integer, ProfileData> map) {
+ private ProfileData[] sortProfileData(HashMap<Integer, ProfileData> map,
+ final TimeBase timeBase) {
if (map == null)
return null;
@@ -224,7 +221,15 @@ public class MethodData {
ProfileData[] sorted = values.toArray(new ProfileData[values.size()]);
// Sort the array by elapsed inclusive time
- Arrays.sort(sorted, mByElapsedInclusive);
+ Arrays.sort(sorted, new Comparator<ProfileData>() {
+ public int compare(ProfileData pd1, ProfileData pd2) {
+ if (timeBase.getElapsedInclusiveTime(pd2) > timeBase.getElapsedInclusiveTime(pd1))
+ return 1;
+ if (timeBase.getElapsedInclusiveTime(pd2) < timeBase.getElapsedInclusiveTime(pd1))
+ return -1;
+ return 0;
+ }
+ });
return sorted;
}
@@ -240,12 +245,17 @@ public class MethodData {
return pdata;
}
- public void addTopExclusive(long time) {
- mTopExclusive += time;
+ public void addTopExclusive(long cpuTime, long realTime) {
+ mTopExclusiveCpuTime += cpuTime;
+ mTopExclusiveRealTime += realTime;
}
- public long getTopExclusive() {
- return mTopExclusive;
+ public long getTopExclusiveCpuTime() {
+ return mTopExclusiveCpuTime;
+ }
+
+ public long getTopExclusiveRealTime() {
+ return mTopExclusiveRealTime;
}
public int getId() {
@@ -329,12 +339,20 @@ public class MethodData {
return getName();
}
- public long getElapsedExclusive() {
- return mElapsedExclusive;
+ public long getElapsedExclusiveCpuTime() {
+ return mElapsedExclusiveCpuTime;
+ }
+
+ public long getElapsedExclusiveRealTime() {
+ return mElapsedExclusiveRealTime;
}
- public long getElapsedInclusive() {
- return mElapsedInclusive;
+ public long getElapsedInclusiveCpuTime() {
+ return mElapsedInclusiveCpuTime;
+ }
+
+ public long getElapsedInclusiveRealTime() {
+ return mElapsedInclusiveRealTime;
}
public void setFadedColor(Color fadedColor) {
@@ -379,17 +397,31 @@ public class MethodData {
int result = md1.getName().compareTo(md2.getName());
return (mDirection == Direction.INCREASING) ? result : -result;
}
- if (mColumn == Column.BY_INCLUSIVE) {
- if (md2.getElapsedInclusive() > md1.getElapsedInclusive())
+ if (mColumn == Column.BY_INCLUSIVE_CPU_TIME) {
+ if (md2.getElapsedInclusiveCpuTime() > md1.getElapsedInclusiveCpuTime())
+ return (mDirection == Direction.INCREASING) ? -1 : 1;
+ if (md2.getElapsedInclusiveCpuTime() < md1.getElapsedInclusiveCpuTime())
+ return (mDirection == Direction.INCREASING) ? 1 : -1;
+ return md1.getName().compareTo(md2.getName());
+ }
+ if (mColumn == Column.BY_EXCLUSIVE_CPU_TIME) {
+ if (md2.getElapsedExclusiveCpuTime() > md1.getElapsedExclusiveCpuTime())
+ return (mDirection == Direction.INCREASING) ? -1 : 1;
+ if (md2.getElapsedExclusiveCpuTime() < md1.getElapsedExclusiveCpuTime())
+ return (mDirection == Direction.INCREASING) ? 1 : -1;
+ return md1.getName().compareTo(md2.getName());
+ }
+ if (mColumn == Column.BY_INCLUSIVE_REAL_TIME) {
+ if (md2.getElapsedInclusiveRealTime() > md1.getElapsedInclusiveRealTime())
return (mDirection == Direction.INCREASING) ? -1 : 1;
- if (md2.getElapsedInclusive() < md1.getElapsedInclusive())
+ if (md2.getElapsedInclusiveRealTime() < md1.getElapsedInclusiveRealTime())
return (mDirection == Direction.INCREASING) ? 1 : -1;
return md1.getName().compareTo(md2.getName());
}
- if (mColumn == Column.BY_EXCLUSIVE) {
- if (md2.getElapsedExclusive() > md1.getElapsedExclusive())
+ if (mColumn == Column.BY_EXCLUSIVE_REAL_TIME) {
+ if (md2.getElapsedExclusiveRealTime() > md1.getElapsedExclusiveRealTime())
return (mDirection == Direction.INCREASING) ? -1 : 1;
- if (md2.getElapsedExclusive() < md1.getElapsedExclusive())
+ if (md2.getElapsedExclusiveRealTime() < md1.getElapsedExclusiveRealTime())
return (mDirection == Direction.INCREASING) ? 1 : -1;
return md1.getName().compareTo(md2.getName());
}
@@ -399,10 +431,25 @@ public class MethodData {
return md1.getName().compareTo(md2.getName());
return (mDirection == Direction.INCREASING) ? result : -result;
}
- if (mColumn == Column.BY_TIME_PER_CALL) {
- double time1 = md1.getElapsedInclusive();
+ if (mColumn == Column.BY_CPU_TIME_PER_CALL) {
+ double time1 = md1.getElapsedInclusiveCpuTime();
+ time1 = time1 / md1.getTotalCalls();
+ double time2 = md2.getElapsedInclusiveCpuTime();
+ time2 = time2 / md2.getTotalCalls();
+ double diff = time1 - time2;
+ int result = 0;
+ if (diff < 0)
+ result = -1;
+ else if (diff > 0)
+ result = 1;
+ if (result == 0)
+ return md1.getName().compareTo(md2.getName());
+ return (mDirection == Direction.INCREASING) ? result : -result;
+ }
+ if (mColumn == Column.BY_REAL_TIME_PER_CALL) {
+ double time1 = md1.getElapsedInclusiveRealTime();
time1 = time1 / md1.getTotalCalls();
- double time2 = md2.getElapsedInclusive();
+ double time2 = md2.getElapsedInclusiveRealTime();
time2 = time2 / md2.getTotalCalls();
double diff = time1 - time2;
int result = 0;
@@ -449,7 +496,9 @@ public class MethodData {
}
public static enum Column {
- BY_NAME, BY_EXCLUSIVE, BY_INCLUSIVE, BY_CALLS, BY_TIME_PER_CALL
+ BY_NAME, BY_EXCLUSIVE_CPU_TIME, BY_EXCLUSIVE_REAL_TIME,
+ BY_INCLUSIVE_CPU_TIME, BY_INCLUSIVE_REAL_TIME, BY_CALLS,
+ BY_REAL_TIME_PER_CALL, BY_CPU_TIME_PER_CALL,
};
public static enum Direction {
diff --git a/traceview/src/com/android/traceview/ProfileData.java b/traceview/src/com/android/traceview/ProfileData.java
index f0c1d61..e3c47fb 100644
--- a/traceview/src/com/android/traceview/ProfileData.java
+++ b/traceview/src/com/android/traceview/ProfileData.java
@@ -24,7 +24,8 @@ public class ProfileData {
/** mContext is either the parent or child of mElement */
protected MethodData mContext;
protected boolean mElementIsParent;
- protected long mElapsedInclusive;
+ protected long mElapsedInclusiveCpuTime;
+ protected long mElapsedInclusiveRealTime;
protected int mNumCalls;
public ProfileData() {
@@ -45,17 +46,23 @@ public class ProfileData {
return mElement;
}
- public void addElapsedInclusive(long elapsedInclusive) {
- mElapsedInclusive += elapsedInclusive;
+ public void addElapsedInclusive(long cpuTime, long realTime) {
+ mElapsedInclusiveCpuTime += cpuTime;
+ mElapsedInclusiveRealTime += realTime;
mNumCalls += 1;
}
- public void setElapsedInclusive(long elapsedInclusive) {
- mElapsedInclusive = elapsedInclusive;
+ public void setElapsedInclusive(long cpuTime, long realTime) {
+ mElapsedInclusiveCpuTime = cpuTime;
+ mElapsedInclusiveRealTime = realTime;
}
- public long getElapsedInclusive() {
- return mElapsedInclusive;
+ public long getElapsedInclusiveCpuTime() {
+ return mElapsedInclusiveCpuTime;
+ }
+
+ public long getElapsedInclusiveRealTime() {
+ return mElapsedInclusiveRealTime;
}
public void setNumCalls(int numCalls) {
diff --git a/traceview/src/com/android/traceview/ProfileProvider.java b/traceview/src/com/android/traceview/ProfileProvider.java
index fe5c832..63a1da6 100644
--- a/traceview/src/com/android/traceview/ProfileProvider.java
+++ b/traceview/src/com/android/traceview/ProfileProvider.java
@@ -44,26 +44,40 @@ class ProfileProvider implements ITreeContentProvider {
private TraceReader mReader;
private Image mSortUp;
private Image mSortDown;
- private String mColumnNames[] = { "Name", "Incl %", "Inclusive", "Excl %",
- "Exclusive", "Calls+Recur\nCalls/Total", "Time/Call" };
- private int mColumnWidths[] = { 370, 70, 70, 70, 70, 90, 70 };
- private int mColumnAlignments[] = { SWT.LEFT, SWT.RIGHT, SWT.RIGHT,
- SWT.RIGHT, SWT.RIGHT, SWT.CENTER, SWT.RIGHT };
+ private String mColumnNames[] = { "Name",
+ "Incl Cpu Time %", "Incl Cpu Time", "Excl Cpu Time %", "Excl Cpu Time",
+ "Incl Real Time %", "Incl Real Time", "Excl Real Time %", "Excl Real Time",
+ "Calls+Recur\nCalls/Total", "Cpu Time/Call", "Real Time/Call" };
+ private int mColumnWidths[] = { 370,
+ 100, 100, 100, 100,
+ 100, 100, 100, 100,
+ 100, 100, 100 };
+ private int mColumnAlignments[] = { SWT.LEFT,
+ SWT.RIGHT, SWT.RIGHT, SWT.RIGHT, SWT.RIGHT,
+ SWT.RIGHT, SWT.RIGHT, SWT.RIGHT, SWT.RIGHT,
+ SWT.CENTER, SWT.RIGHT, SWT.RIGHT };
private static final int COL_NAME = 0;
- private static final int COL_INCLUSIVE_PER = 1;
- private static final int COL_INCLUSIVE = 2;
- private static final int COL_EXCLUSIVE_PER = 3;
- private static final int COL_EXCLUSIVE = 4;
- private static final int COL_CALLS = 5;
- private static final int COL_TIME_PER_CALL = 6;
- private long mTotalTime;
+ private static final int COL_INCLUSIVE_CPU_TIME_PER = 1;
+ private static final int COL_INCLUSIVE_CPU_TIME = 2;
+ private static final int COL_EXCLUSIVE_CPU_TIME_PER = 3;
+ private static final int COL_EXCLUSIVE_CPU_TIME = 4;
+ private static final int COL_INCLUSIVE_REAL_TIME_PER = 5;
+ private static final int COL_INCLUSIVE_REAL_TIME = 6;
+ private static final int COL_EXCLUSIVE_REAL_TIME_PER = 7;
+ private static final int COL_EXCLUSIVE_REAL_TIME = 8;
+ private static final int COL_CALLS = 9;
+ private static final int COL_CPU_TIME_PER_CALL = 10;
+ private static final int COL_REAL_TIME_PER_CALL = 11;
+ private long mTotalCpuTime;
+ private long mTotalRealTime;
private Pattern mUppercase;
private int mPrevMatchIndex = -1;
public ProfileProvider(TraceReader reader) {
mRoots = reader.getMethods();
mReader = reader;
- mTotalTime = reader.getEndTime();
+ mTotalCpuTime = reader.getTotalCpuTime();
+ mTotalRealTime = reader.getTotalRealTime();
Display display = Display.getCurrent();
InputStream in = getClass().getClassLoader().getResourceAsStream(
"icons/sort_up.png");
@@ -126,7 +140,22 @@ class ProfileProvider implements ITreeContentProvider {
}
public int[] getColumnWidths() {
- return mColumnWidths;
+ int[] widths = Arrays.copyOf(mColumnWidths, mColumnWidths.length);
+ if (!mReader.haveCpuTime()) {
+ widths[COL_EXCLUSIVE_CPU_TIME] = 0;
+ widths[COL_EXCLUSIVE_CPU_TIME_PER] = 0;
+ widths[COL_INCLUSIVE_CPU_TIME] = 0;
+ widths[COL_INCLUSIVE_CPU_TIME_PER] = 0;
+ widths[COL_CPU_TIME_PER_CALL] = 0;
+ }
+ if (!mReader.haveRealTime()) {
+ widths[COL_EXCLUSIVE_REAL_TIME] = 0;
+ widths[COL_EXCLUSIVE_REAL_TIME_PER] = 0;
+ widths[COL_INCLUSIVE_REAL_TIME] = 0;
+ widths[COL_INCLUSIVE_REAL_TIME_PER] = 0;
+ widths[COL_REAL_TIME_PER_CALL] = 0;
+ }
+ return widths;
}
public int[] getColumnAlignments() {
@@ -201,31 +230,58 @@ class ProfileProvider implements ITreeContentProvider {
MethodData md = (MethodData) element;
if (col == COL_NAME)
return md.getProfileName();
- if (col == COL_EXCLUSIVE) {
- double val = md.getElapsedExclusive();
+ if (col == COL_EXCLUSIVE_CPU_TIME) {
+ double val = md.getElapsedExclusiveCpuTime();
+ val = traceUnits.getScaledValue(val);
+ return String.format("%.3f", val);
+ }
+ if (col == COL_EXCLUSIVE_CPU_TIME_PER) {
+ double val = md.getElapsedExclusiveCpuTime();
+ double per = val * 100.0 / mTotalCpuTime;
+ return String.format("%.1f%%", per);
+ }
+ if (col == COL_INCLUSIVE_CPU_TIME) {
+ double val = md.getElapsedInclusiveCpuTime();
val = traceUnits.getScaledValue(val);
return String.format("%.3f", val);
}
- if (col == COL_EXCLUSIVE_PER) {
- double val = md.getElapsedExclusive();
- double per = val * 100.0 / mTotalTime;
+ if (col == COL_INCLUSIVE_CPU_TIME_PER) {
+ double val = md.getElapsedInclusiveCpuTime();
+ double per = val * 100.0 / mTotalCpuTime;
return String.format("%.1f%%", per);
}
- if (col == COL_INCLUSIVE) {
- double val = md.getElapsedInclusive();
+ if (col == COL_EXCLUSIVE_REAL_TIME) {
+ double val = md.getElapsedExclusiveRealTime();
val = traceUnits.getScaledValue(val);
return String.format("%.3f", val);
}
- if (col == COL_INCLUSIVE_PER) {
- double val = md.getElapsedInclusive();
- double per = val * 100.0 / mTotalTime;
+ if (col == COL_EXCLUSIVE_REAL_TIME_PER) {
+ double val = md.getElapsedExclusiveRealTime();
+ double per = val * 100.0 / mTotalRealTime;
+ return String.format("%.1f%%", per);
+ }
+ if (col == COL_INCLUSIVE_REAL_TIME) {
+ double val = md.getElapsedInclusiveRealTime();
+ val = traceUnits.getScaledValue(val);
+ return String.format("%.3f", val);
+ }
+ if (col == COL_INCLUSIVE_REAL_TIME_PER) {
+ double val = md.getElapsedInclusiveRealTime();
+ double per = val * 100.0 / mTotalRealTime;
return String.format("%.1f%%", per);
}
if (col == COL_CALLS)
return md.getCalls();
- if (col == COL_TIME_PER_CALL) {
+ if (col == COL_CPU_TIME_PER_CALL) {
int numCalls = md.getTotalCalls();
- double val = md.getElapsedInclusive();
+ double val = md.getElapsedInclusiveCpuTime();
+ val = val / numCalls;
+ val = traceUnits.getScaledValue(val);
+ return String.format("%.3f", val);
+ }
+ if (col == COL_REAL_TIME_PER_CALL) {
+ int numCalls = md.getTotalCalls();
+ double val = md.getElapsedInclusiveRealTime();
val = val / numCalls;
val = traceUnits.getScaledValue(val);
return String.format("%.3f", val);
@@ -234,16 +290,29 @@ class ProfileProvider implements ITreeContentProvider {
ProfileSelf ps = (ProfileSelf) element;
if (col == COL_NAME)
return ps.getProfileName();
- if (col == COL_INCLUSIVE) {
- double val = ps.getElapsedInclusive();
+ if (col == COL_INCLUSIVE_CPU_TIME) {
+ double val = ps.getElapsedInclusiveCpuTime();
+ val = traceUnits.getScaledValue(val);
+ return String.format("%.3f", val);
+ }
+ if (col == COL_INCLUSIVE_CPU_TIME_PER) {
+ double total;
+ double val = ps.getElapsedInclusiveCpuTime();
+ MethodData context = ps.getContext();
+ total = context.getElapsedInclusiveCpuTime();
+ double per = val * 100.0 / total;
+ return String.format("%.1f%%", per);
+ }
+ if (col == COL_INCLUSIVE_REAL_TIME) {
+ double val = ps.getElapsedInclusiveRealTime();
val = traceUnits.getScaledValue(val);
return String.format("%.3f", val);
}
- if (col == COL_INCLUSIVE_PER) {
+ if (col == COL_INCLUSIVE_REAL_TIME_PER) {
double total;
- double val = ps.getElapsedInclusive();
+ double val = ps.getElapsedInclusiveRealTime();
MethodData context = ps.getContext();
- total = context.getElapsedInclusive();
+ total = context.getElapsedInclusiveRealTime();
double per = val * 100.0 / total;
return String.format("%.1f%%", per);
}
@@ -252,16 +321,29 @@ class ProfileProvider implements ITreeContentProvider {
ProfileData pd = (ProfileData) element;
if (col == COL_NAME)
return pd.getProfileName();
- if (col == COL_INCLUSIVE) {
- double val = pd.getElapsedInclusive();
+ if (col == COL_INCLUSIVE_CPU_TIME) {
+ double val = pd.getElapsedInclusiveCpuTime();
val = traceUnits.getScaledValue(val);
return String.format("%.3f", val);
}
- if (col == COL_INCLUSIVE_PER) {
+ if (col == COL_INCLUSIVE_CPU_TIME_PER) {
double total;
- double val = pd.getElapsedInclusive();
+ double val = pd.getElapsedInclusiveCpuTime();
MethodData context = pd.getContext();
- total = context.getElapsedInclusive();
+ total = context.getElapsedInclusiveCpuTime();
+ double per = val * 100.0 / total;
+ return String.format("%.1f%%", per);
+ }
+ if (col == COL_INCLUSIVE_REAL_TIME) {
+ double val = pd.getElapsedInclusiveRealTime();
+ val = traceUnits.getScaledValue(val);
+ return String.format("%.3f", val);
+ }
+ if (col == COL_INCLUSIVE_REAL_TIME_PER) {
+ double total;
+ double val = pd.getElapsedInclusiveRealTime();
+ MethodData context = pd.getContext();
+ total = context.getElapsedInclusiveRealTime();
double per = val * 100.0 / total;
return String.format("%.1f%%", per);
}
@@ -330,23 +412,38 @@ class ProfileProvider implements ITreeContentProvider {
// Sort names alphabetically
sorter.setColumn(MethodData.Sorter.Column.BY_NAME);
Arrays.sort(mRoots, sorter);
- } else if (name == mColumnNames[COL_EXCLUSIVE]) {
- sorter.setColumn(MethodData.Sorter.Column.BY_EXCLUSIVE);
+ } else if (name == mColumnNames[COL_EXCLUSIVE_CPU_TIME]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_EXCLUSIVE_CPU_TIME);
+ Arrays.sort(mRoots, sorter);
+ } else if (name == mColumnNames[COL_EXCLUSIVE_CPU_TIME_PER]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_EXCLUSIVE_CPU_TIME);
Arrays.sort(mRoots, sorter);
- } else if (name == mColumnNames[COL_EXCLUSIVE_PER]) {
- sorter.setColumn(MethodData.Sorter.Column.BY_EXCLUSIVE);
+ } else if (name == mColumnNames[COL_INCLUSIVE_CPU_TIME]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_INCLUSIVE_CPU_TIME);
Arrays.sort(mRoots, sorter);
- } else if (name == mColumnNames[COL_INCLUSIVE]) {
- sorter.setColumn(MethodData.Sorter.Column.BY_INCLUSIVE);
+ } else if (name == mColumnNames[COL_INCLUSIVE_CPU_TIME_PER]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_INCLUSIVE_CPU_TIME);
Arrays.sort(mRoots, sorter);
- } else if (name == mColumnNames[COL_INCLUSIVE_PER]) {
- sorter.setColumn(MethodData.Sorter.Column.BY_INCLUSIVE);
+ } else if (name == mColumnNames[COL_EXCLUSIVE_REAL_TIME]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_EXCLUSIVE_REAL_TIME);
+ Arrays.sort(mRoots, sorter);
+ } else if (name == mColumnNames[COL_EXCLUSIVE_REAL_TIME_PER]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_EXCLUSIVE_REAL_TIME);
+ Arrays.sort(mRoots, sorter);
+ } else if (name == mColumnNames[COL_INCLUSIVE_REAL_TIME]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_INCLUSIVE_REAL_TIME);
+ Arrays.sort(mRoots, sorter);
+ } else if (name == mColumnNames[COL_INCLUSIVE_REAL_TIME_PER]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_INCLUSIVE_REAL_TIME);
Arrays.sort(mRoots, sorter);
} else if (name == mColumnNames[COL_CALLS]) {
sorter.setColumn(MethodData.Sorter.Column.BY_CALLS);
Arrays.sort(mRoots, sorter);
- } else if (name == mColumnNames[COL_TIME_PER_CALL]) {
- sorter.setColumn(MethodData.Sorter.Column.BY_TIME_PER_CALL);
+ } else if (name == mColumnNames[COL_CPU_TIME_PER_CALL]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_CPU_TIME_PER_CALL);
+ Arrays.sort(mRoots, sorter);
+ } else if (name == mColumnNames[COL_REAL_TIME_PER_CALL]) {
+ sorter.setColumn(MethodData.Sorter.Column.BY_REAL_TIME_PER_CALL);
Arrays.sort(mRoots, sorter);
}
MethodData.Sorter.Direction direction = sorter.getDirection();
diff --git a/traceview/src/com/android/traceview/ProfileSelf.java b/traceview/src/com/android/traceview/ProfileSelf.java
index 3a4f3d9..45543b2 100644
--- a/traceview/src/com/android/traceview/ProfileSelf.java
+++ b/traceview/src/com/android/traceview/ProfileSelf.java
@@ -28,7 +28,12 @@ public class ProfileSelf extends ProfileData {
}
@Override
- public long getElapsedInclusive() {
- return mElement.getTopExclusive();
+ public long getElapsedInclusiveCpuTime() {
+ return mElement.getTopExclusiveCpuTime();
+ }
+
+ @Override
+ public long getElapsedInclusiveRealTime() {
+ return mElement.getTopExclusiveRealTime();
}
}
diff --git a/traceview/src/com/android/traceview/ProfileView.java b/traceview/src/com/android/traceview/ProfileView.java
index 506efca..8889b13 100644
--- a/traceview/src/com/android/traceview/ProfileView.java
+++ b/traceview/src/com/android/traceview/ProfileView.java
@@ -279,7 +279,7 @@ public class ProfileView extends Composite implements Observer {
}
if (name == "Call") {
Call call = (Call) selection.getValue();
- MethodData md = call.mMethodData;
+ MethodData md = call.getMethodData();
highlightMethod(md, true);
return;
}
@@ -304,9 +304,11 @@ public class ProfileView extends Composite implements Observer {
mTreeViewer.setSelection(sel, true);
Tree tree = mTreeViewer.getTree();
TreeItem[] items = tree.getSelection();
- tree.setTopItem(items[0]);
- // workaround a Mac bug by adding showItem().
- tree.showItem(items[0]);
+ if (items.length != 0) {
+ tree.setTopItem(items[0]);
+ // workaround a Mac bug by adding showItem().
+ tree.showItem(items[0]);
+ }
}
private void expandNode(MethodData md) {
diff --git a/traceview/src/com/android/traceview/ThreadData.java b/traceview/src/com/android/traceview/ThreadData.java
index 54ea891..f71e9c2 100644
--- a/traceview/src/com/android/traceview/ThreadData.java
+++ b/traceview/src/com/android/traceview/ThreadData.java
@@ -23,158 +23,130 @@ class ThreadData implements TimeLineView.Row {
private int mId;
private String mName;
- private long mGlobalStartTime = -1;
- private long mGlobalEndTime = -1;
- private long mLastEventTime;
- private long mCpuTime;
- private Call mRoot;
- private Call mCurrent;
- private Call mLastContextSwitch;
+ 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>();
-
- // True if no calls have ever been added to this thread
- private boolean mIsEmpty;
+
+ 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);
- mRoot = new Call(mName, topLevel);
- mCurrent = mRoot;
mIsEmpty = true;
- }
-
- public boolean isEmpty() {
- return mIsEmpty;
+ mRootCall = new Call(this, topLevel, null);
+ mRootCall.setName(mName);
+ mStack.add(mRootCall);
}
public String getName() {
return mName;
}
- public Call getCalltreeRoot() {
- return mRoot;
+ public Call getRootCall() {
+ return mRootCall;
+ }
+
+ /**
+ * Returns true if no calls have ever been recorded for this thread.
+ */
+ public boolean isEmpty() {
+ return mIsEmpty;
}
- void handleCall(Call call, long globalTime) {
- mIsEmpty = false;
- long currentTime = call.mThreadStartTime;
- if (currentTime < mLastEventTime) {
- System.err
- .printf(
- "ThreadData: '%1$s' call time (%2$d) is less than previous time (%3$d) for thread '%4$s'\n",
- call.getName(), currentTime, mLastEventTime, mName);
- System.exit(1);
+ Call enter(MethodData method, ArrayList<TraceAction> trace) {
+ if (mIsEmpty) {
+ mIsEmpty = false;
+ if (trace != null) {
+ trace.add(new TraceAction(TraceAction.ACTION_ENTER, mRootCall));
+ }
}
- long elapsed = currentTime - mLastEventTime;
- mCpuTime += elapsed;
- if (call.getMethodAction() == 0) {
- // This is a method entry.
- enter(call, elapsed);
- } else {
- // This is a method exit.
- exit(call, elapsed, globalTime);
+
+ Call caller = top();
+ Call call = new Call(this, method, caller);
+ mStack.add(call);
+
+ if (trace != null) {
+ trace.add(new TraceAction(TraceAction.ACTION_ENTER, call));
}
- mLastEventTime = currentTime;
- mGlobalEndTime = globalTime;
- }
- private void enter(Call c, long elapsed) {
- Call caller = mCurrent;
- push(c);
-
- // Check the stack for a matching method to determine if this call
- // is recursive.
- MethodData md = c.mMethodData;
- Integer num = mStackMethods.get(md);
+ Integer num = mStackMethods.get(method);
if (num == null) {
num = 0;
} else if (num > 0) {
- c.setRecursive(true);
+ call.setRecursive(true);
}
- num += 1;
- mStackMethods.put(md, num);
- mCurrent = c;
+ mStackMethods.put(method, num + 1);
- // Add the elapsed time to the caller's exclusive time
- caller.addExclusiveTime(elapsed);
+ return call;
}
- private void exit(Call c, long elapsed, long globalTime) {
- mCurrent.mGlobalEndTime = globalTime;
- Call top = pop();
- if (top == null) {
- return;
+ Call exit(MethodData method, ArrayList<TraceAction> trace) {
+ Call call = top();
+ if (call.mCaller == null) {
+ return null;
}
- if (mCurrent.mMethodData != c.mMethodData) {
- String error = "Method exit (" + c.getName()
- + ") does not match current method (" + mCurrent.getName()
+ if (call.getMethodData() != method) {
+ String error = "Method exit (" + method.getName()
+ + ") does not match current method (" + call.getMethodData().getName()
+ ")";
throw new RuntimeException(error);
- } else {
- long duration = c.mThreadStartTime - mCurrent.mThreadStartTime;
- Call caller = top();
- mCurrent.addExclusiveTime(elapsed);
- mCurrent.addInclusiveTime(duration, caller);
- if (caller == null) {
- caller = mRoot;
- }
- mCurrent = caller;
}
- }
- public void push(Call c) {
- mStack.add(c);
- }
+ mStack.remove(mStack.size() - 1);
- public Call pop() {
- ArrayList<Call> stack = mStack;
- if (stack.size() == 0)
- return null;
- Call top = stack.get(stack.size() - 1);
- stack.remove(stack.size() - 1);
-
- // Decrement the count on the method in the hash table and remove
- // the entry when it goes to zero.
- MethodData md = top.mMethodData;
- Integer num = mStackMethods.get(md);
+ if (trace != null) {
+ trace.add(new TraceAction(TraceAction.ACTION_EXIT, call));
+ }
+
+ Integer num = mStackMethods.get(method);
if (num != null) {
- num -= 1;
- if (num <= 0) {
- mStackMethods.remove(md);
+ if (num == 1) {
+ mStackMethods.remove(method);
} else {
- mStackMethods.put(md, num);
+ mStackMethods.put(method, num - 1);
}
}
- return top;
+
+ return call;
}
- public Call top() {
- ArrayList<Call> stack = mStack;
- if (stack.size() == 0)
- return null;
- return stack.get(stack.size() - 1);
+ Call top() {
+ return mStack.get(mStack.size() - 1);
}
- public long endTrace() {
- // If we have calls on the stack when the trace ends, then clean up
- // the stack and compute the inclusive time of the methods by pretending
- // that we are exiting from their methods now.
- while (mCurrent != mRoot) {
- long duration = mLastEventTime - mCurrent.mThreadStartTime;
- pop();
- Call caller = top();
- mCurrent.addInclusiveTime(duration, caller);
- mCurrent.mGlobalEndTime = mGlobalEndTime;
- if (caller == null) {
- caller = mRoot;
+ 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));
}
- mCurrent = caller;
}
- return mLastEventTime;
+ mStack.clear();
+ mStackMethods.clear();
+ }
+
+ void updateRootCallTimeBounds() {
+ if (!mIsEmpty) {
+ mRootCall.mGlobalStartTime = mGlobalStartTime;
+ mRootCall.mGlobalEndTime = mGlobalEndTime;
+ mRootCall.mThreadStartTime = mThreadStartTime;
+ mRootCall.mThreadEndTime = mThreadEndTime;
+ }
}
@Override
@@ -186,43 +158,11 @@ class ThreadData implements TimeLineView.Row {
return mId;
}
- public void setCpuTime(long cpuTime) {
- mCpuTime = cpuTime;
- }
-
public long getCpuTime() {
- return mCpuTime;
- }
-
- public void setGlobalStartTime(long globalStartTime) {
- mGlobalStartTime = globalStartTime;
- }
-
- public long getGlobalStartTime() {
- return mGlobalStartTime;
- }
-
- public void setLastEventTime(long lastEventTime) {
- mLastEventTime = lastEventTime;
- }
-
- public long getLastEventTime() {
- return mLastEventTime;
- }
-
- public void setGlobalEndTime(long globalEndTime) {
- mGlobalEndTime = globalEndTime;
- }
-
- public long getGlobalEndTime() {
- return mGlobalEndTime;
- }
-
- public void setLastContextSwitch(Call lastContextSwitch) {
- mLastContextSwitch = lastContextSwitch;
+ return mRootCall.mInclusiveCpuTime;
}
- public Call getLastContextSwitch() {
- return mLastContextSwitch;
+ public long getRealTime() {
+ return mRootCall.mInclusiveRealTime;
}
}
diff --git a/traceview/src/com/android/traceview/TimeBase.java b/traceview/src/com/android/traceview/TimeBase.java
new file mode 100644
index 0000000..b6b23cb
--- /dev/null
+++ b/traceview/src/com/android/traceview/TimeBase.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+interface TimeBase {
+ public static final TimeBase CPU_TIME = new CpuTimeBase();
+ public static final TimeBase REAL_TIME = new RealTimeBase();
+
+ public long getTime(ThreadData threadData);
+ public long getElapsedInclusiveTime(MethodData methodData);
+ public long getElapsedExclusiveTime(MethodData methodData);
+ public long getElapsedInclusiveTime(ProfileData profileData);
+
+ public static final class CpuTimeBase implements TimeBase {
+ @Override
+ public long getTime(ThreadData threadData) {
+ return threadData.getCpuTime();
+ }
+
+ @Override
+ public long getElapsedInclusiveTime(MethodData methodData) {
+ return methodData.getElapsedInclusiveCpuTime();
+ }
+
+ @Override
+ public long getElapsedExclusiveTime(MethodData methodData) {
+ return methodData.getElapsedExclusiveCpuTime();
+ }
+
+ @Override
+ public long getElapsedInclusiveTime(ProfileData profileData) {
+ return profileData.getElapsedInclusiveCpuTime();
+ }
+ }
+
+ public static final class RealTimeBase implements TimeBase {
+ @Override
+ public long getTime(ThreadData threadData) {
+ return threadData.getRealTime();
+ }
+
+ @Override
+ public long getElapsedInclusiveTime(MethodData methodData) {
+ return methodData.getElapsedInclusiveRealTime();
+ }
+
+ @Override
+ public long getElapsedExclusiveTime(MethodData methodData) {
+ return methodData.getElapsedExclusiveRealTime();
+ }
+
+ @Override
+ public long getElapsedInclusiveTime(ProfileData profileData) {
+ return profileData.getElapsedInclusiveRealTime();
+ }
+ }
+}
diff --git a/traceview/src/com/android/traceview/TimeLineView.java b/traceview/src/com/android/traceview/TimeLineView.java
index c9eb8e7..b04a411 100644
--- a/traceview/src/com/android/traceview/TimeLineView.java
+++ b/traceview/src/com/android/traceview/TimeLineView.java
@@ -54,10 +54,8 @@ import java.util.Observer;
public class TimeLineView extends Composite implements Observer {
private HashMap<String, RowData> mRowByName;
- private double mTotalElapsed;
private RowData[] mRows;
private Segment[] mSegments;
- private ArrayList<Segment> mSegmentList = new ArrayList<Segment>();
private HashMap<Integer, String> mThreadLabels;
private Timescale mTimescale;
private Surface mSurface;
@@ -89,19 +87,21 @@ public class TimeLineView extends Composite implements Observer {
private static final int rowYSpace = rowHeight + rowYMargin;
private static final int majorTickLength = 8;
private static final int minorTickLength = 4;
- private static final int timeLineOffsetY = 38;
+ private static final int timeLineOffsetY = 58;
private static final int tickToFontSpacing = 2;
/** start of first row */
- private static final int topMargin = 70;
+ private static final int topMargin = 90;
private int mMouseRow = -1;
private int mNumRows;
private int mStartRow;
private int mEndRow;
private TraceUnits mUnits;
+ private String mClockSource;
+ private boolean mHaveCpuTime;
+ private boolean mHaveRealTime;
private int mSmallFontWidth;
private int mSmallFontHeight;
- private int mMediumFontWidth;
private SelectionController mSelectionController;
private MethodData mHighlightMethodData;
private Call mHighlightCall;
@@ -118,6 +118,13 @@ public class TimeLineView extends Composite implements Observer {
public Color getColor();
public double addWeight(int x, int y, double weight);
public void clearWeight();
+ public long getExclusiveCpuTime();
+ public long getInclusiveCpuTime();
+ public long getExclusiveRealTime();
+ public long getInclusiveRealTime();
+ public boolean isContextSwitch();
+ public boolean isIgnoredBlock();
+ public Block getParentBlock();
}
public static interface Row {
@@ -142,6 +149,9 @@ public class TimeLineView extends Composite implements Observer {
this.mSelectionController = selectionController;
selectionController.addObserver(this);
mUnits = reader.getTraceUnits();
+ mClockSource = reader.getClockSource();
+ mHaveCpuTime = reader.haveCpuTime();
+ mHaveRealTime = reader.haveRealTime();
mThreadLabels = reader.getThreadLabels();
Display display = getDisplay();
@@ -169,11 +179,6 @@ public class TimeLineView extends Composite implements Observer {
mSmallFontWidth = gc.getFontMetrics().getAverageCharWidth();
mSmallFontHeight = gc.getFontMetrics().getHeight();
- if (mSetFonts) {
- gc.setFont(mFontRegistry.get("medium")); //$NON-NLS-1$
- }
- mMediumFontWidth = gc.getFontMetrics().getAverageCharWidth();
-
image.dispose();
gc.dispose();
@@ -403,6 +408,8 @@ public class TimeLineView extends Composite implements Observer {
}
});
+ ArrayList<Segment> segmentList = new ArrayList<Segment>();
+
// The records are sorted into increasing start time,
// so the minimum start time is the start time of the first record.
double minVal = 0;
@@ -415,6 +422,10 @@ public class TimeLineView extends Composite implements Observer {
for (Record rec : records) {
Row row = rec.row;
Block block = rec.block;
+ if (block.isIgnoredBlock()) {
+ continue;
+ }
+
String rowName = row.getName();
RowData rd = mRowByName.get(rowName);
if (rd == null) {
@@ -426,7 +437,6 @@ public class TimeLineView extends Composite implements Observer {
if (blockEndTime > rd.mEndTime) {
long start = Math.max(blockStartTime, rd.mEndTime);
rd.mElapsed += blockEndTime - start;
- mTotalElapsed += blockEndTime - start;
rd.mEndTime = blockEndTime;
}
if (blockEndTime > maxVal)
@@ -447,7 +457,7 @@ public class TimeLineView extends Composite implements Observer {
if (topStartTime < blockStartTime) {
Segment segment = new Segment(rd, top, topStartTime,
blockStartTime);
- mSegmentList.add(segment);
+ segmentList.add(segment);
}
// If this block starts where the previous (top) block ends,
@@ -457,7 +467,7 @@ public class TimeLineView extends Composite implements Observer {
rd.push(block);
} else {
// We may have to pop several frames here.
- popFrames(rd, top, blockStartTime);
+ popFrames(rd, top, blockStartTime, segmentList);
rd.push(block);
}
}
@@ -465,7 +475,7 @@ public class TimeLineView extends Composite implements Observer {
// Clean up the stack of each row
for (RowData rd : mRowByName.values()) {
Block top = rd.top();
- popFrames(rd, top, Integer.MAX_VALUE);
+ popFrames(rd, top, Integer.MAX_VALUE, segmentList);
}
mSurface.setRange(minVal, maxVal);
@@ -495,7 +505,7 @@ public class TimeLineView extends Composite implements Observer {
// Sort the blocks into increasing rows, and within rows into
// increasing start values.
- mSegments = mSegmentList.toArray(new Segment[mSegmentList.size()]);
+ mSegments = segmentList.toArray(new Segment[segmentList.size()]);
Arrays.sort(mSegments, new Comparator<Segment>() {
public int compare(Segment bd1, Segment bd2) {
RowData rd1 = bd1.mRowData;
@@ -524,13 +534,14 @@ public class TimeLineView extends Composite implements Observer {
}
}
- private void popFrames(RowData rd, Block top, long startTime) {
+ private static void popFrames(RowData rd, Block top, long startTime,
+ ArrayList<Segment> segmentList) {
long topEndTime = top.getEndTime();
long lastEndTime = top.getStartTime();
while (topEndTime <= startTime) {
if (topEndTime > lastEndTime) {
Segment segment = new Segment(rd, top, lastEndTime, topEndTime);
- mSegmentList.add(segment);
+ segmentList.add(segment);
lastEndTime = topEndTime;
}
rd.pop();
@@ -543,7 +554,7 @@ public class TimeLineView extends Composite implements Observer {
// If we get here, then topEndTime > startTime
if (lastEndTime < startTime) {
Segment bd = new Segment(rd, top, lastEndTime, startTime);
- mSegmentList.add(bd);
+ segmentList.add(bd);
}
}
@@ -648,7 +659,9 @@ public class TimeLineView extends Composite implements Observer {
private Cursor mZoomCursor;
private String mMethodName = null;
private Color mMethodColor = null;
+ private String mDetails;
private int mMethodStartY;
+ private int mDetailsStartY;
private int mMarkStartX;
private int mMarkEndX;
@@ -662,6 +675,7 @@ public class TimeLineView extends Composite implements Observer {
mZoomCursor = new Cursor(display, SWT.CURSOR_SIZEWE);
setCursor(mZoomCursor);
mMethodStartY = mSmallFontHeight + 1;
+ mDetailsStartY = mMethodStartY + mSmallFontHeight + 1;
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent pe) {
draw(pe.display, pe.gc);
@@ -680,7 +694,7 @@ public class TimeLineView extends Composite implements Observer {
public void setMarkEnd(int x) {
mMarkEndX = x;
}
-
+
public void setMethodName(String name) {
mMethodName = name;
}
@@ -688,7 +702,11 @@ public class TimeLineView extends Composite implements Observer {
public void setMethodColor(Color color) {
mMethodColor = color;
}
-
+
+ public void setDetails(String details) {
+ mDetails = details;
+ }
+
private void mouseMove(MouseEvent me) {
me.y = -1;
mSurface.mouseMove(me);
@@ -734,7 +752,10 @@ public class TimeLineView extends Composite implements Observer {
// Draw the method name and color, if needed
drawMethod(display, gcImage);
-
+
+ // Draw the details, if needed
+ drawDetails(display, gcImage);
+
// Draw the off-screen buffer to the screen
gc.drawImage(image, 0, 0);
@@ -771,7 +792,11 @@ public class TimeLineView extends Composite implements Observer {
// Display the maximum data value
double maxVal = mScaleInfo.getMaxVal();
info = mUnits.labelledString(maxVal);
- info = String.format(" max %s ", info); //$NON-NLS-1$
+ if (mClockSource != null) {
+ info = String.format(" max %s (%s)", info, mClockSource); //$NON-NLS-1$
+ } else {
+ info = String.format(" max %s ", info); //$NON-NLS-1$
+ }
Point extent = gc.stringExtent(info);
Point dim = getSize();
int x1 = dim.x - RightMargin - extent.x;
@@ -791,7 +816,17 @@ public class TimeLineView extends Composite implements Observer {
x1 += width + METHOD_BLOCK_MARGIN;
gc.drawString(mMethodName, x1, y1, true);
}
-
+
+ private void drawDetails(Display display, GC gc) {
+ if (mDetails == null) {
+ return;
+ }
+
+ int x1 = LeftMargin + 2 * mSmallFontWidth + METHOD_BLOCK_MARGIN;
+ int y1 = mDetailsStartY;
+ gc.drawString(mDetails, x1, y1, true);
+ }
+
private void drawTicks(Display display, GC gc) {
Point dim = getSize();
int y2 = majorTickLength + timeLineOffsetY;
@@ -1049,6 +1084,7 @@ public class TimeLineView extends Composite implements Observer {
String blockName = null;
Color blockColor = null;
+ String blockDetails = null;
if (mDebug) {
double pixelsPerRange = mScaleInfo.getPixelsPerRange();
@@ -1073,8 +1109,30 @@ public class TimeLineView extends Composite implements Observer {
if (mMouseRow == strip.mRowData.mRank) {
if (mMouse.x >= strip.mX
&& mMouse.x < strip.mX + strip.mWidth) {
- blockName = strip.mSegment.mBlock.getName();
+ Block block = strip.mSegment.mBlock;
+ blockName = block.getName();
blockColor = strip.mColor;
+ if (mHaveCpuTime) {
+ if (mHaveRealTime) {
+ blockDetails = String.format(
+ "excl cpu %s, incl cpu %s, "
+ + "excl real %s, incl real %s",
+ mUnits.labelledString(block.getExclusiveCpuTime()),
+ mUnits.labelledString(block.getInclusiveCpuTime()),
+ mUnits.labelledString(block.getExclusiveRealTime()),
+ mUnits.labelledString(block.getInclusiveRealTime()));
+ } else {
+ blockDetails = String.format(
+ "excl cpu %s, incl cpu %s",
+ mUnits.labelledString(block.getExclusiveCpuTime()),
+ mUnits.labelledString(block.getInclusiveCpuTime()));
+ }
+ } else {
+ blockDetails = String.format(
+ "excl real %s, incl real %s",
+ mUnits.labelledString(block.getExclusiveRealTime()),
+ mUnits.labelledString(block.getInclusiveRealTime()));
+ }
}
if (mMouseSelect.x >= strip.mX
&& mMouseSelect.x < strip.mX + strip.mWidth) {
@@ -1125,6 +1183,7 @@ public class TimeLineView extends Composite implements Observer {
if (blockName != null) {
mTimescale.setMethodName(blockName);
mTimescale.setMethodColor(blockColor);
+ mTimescale.setDetails(blockDetails);
mShowHighlightName = false;
} else if (mShowHighlightName) {
// Draw the highlighted method name
@@ -1136,10 +1195,12 @@ public class TimeLineView extends Composite implements Observer {
if (md != null) {
mTimescale.setMethodName(md.getProfileName());
mTimescale.setMethodColor(md.getColor());
+ mTimescale.setDetails(null);
}
} else {
mTimescale.setMethodName(null);
mTimescale.setMethodColor(null);
+ mTimescale.setDetails(null);
}
mTimescale.redraw();
@@ -1152,7 +1213,7 @@ public class TimeLineView extends Composite implements Observer {
}
private void drawHighlights(GC gc, Point dim) {
- int height = highlightHeight;
+ int height = mHighlightHeight;
if (height <= 0)
return;
for (Range range : mHighlightExclusive) {
@@ -1278,13 +1339,15 @@ public class TimeLineView extends Composite implements Observer {
long callEnd = -1;
RowData callRowData = null;
int prevMethodStart = -1;
+ int prevMethodEnd = -1;
int prevCallStart = -1;
+ int prevCallEnd = -1;
if (mHighlightCall != null) {
int callPixelStart = -1;
int callPixelEnd = -1;
- callStart = mHighlightCall.mGlobalStartTime;
- callEnd = mHighlightCall.mGlobalEndTime;
- callMethod = mHighlightCall.mMethodData;
+ callStart = mHighlightCall.getStartTime();
+ callEnd = mHighlightCall.getEndTime();
+ callMethod = mHighlightCall.getMethodData();
if (callStart >= minVal)
callPixelStart = mScaleInfo.valueToPixel(callStart);
if (callEnd <= maxVal)
@@ -1306,7 +1369,11 @@ public class TimeLineView extends Composite implements Observer {
continue;
if (segment.mStartTime >= maxVal)
continue;
+
Block block = segment.mBlock;
+
+ // Skip over blocks that were not assigned a color, including the
+ // top level block and others that have zero inclusive time.
Color color = block.getColor();
if (color == null)
continue;
@@ -1318,6 +1385,7 @@ public class TimeLineView extends Composite implements Observer {
int pixelStart = mScaleInfo.valueToPixel(recordStart);
int pixelEnd = mScaleInfo.valueToPixel(recordEnd);
int width = pixelEnd - pixelStart;
+ boolean isContextSwitch = segment.mIsContextSwitch;
RowData rd = segment.mRowData;
MethodData md = block.getMethodData();
@@ -1342,24 +1410,25 @@ public class TimeLineView extends Composite implements Observer {
if (mHighlightMethodData != null) {
if (mHighlightMethodData == md) {
- if (prevMethodStart != pixelStart) {
+ if (prevMethodStart != pixelStart || prevMethodEnd != pixelEnd) {
prevMethodStart = pixelStart;
+ prevMethodEnd = pixelEnd;
int rangeWidth = width;
if (rangeWidth == 0)
rangeWidth = 1;
mHighlightExclusive.add(new Range(pixelStart
+ LeftMargin, rangeWidth, y1, color));
- Call call = (Call) block;
- callStart = call.mGlobalStartTime;
+ callStart = block.getStartTime();
int callPixelStart = -1;
if (callStart >= minVal)
callPixelStart = mScaleInfo.valueToPixel(callStart);
- if (prevCallStart != callPixelStart) {
+ int callPixelEnd = -1;
+ callEnd = block.getEndTime();
+ if (callEnd <= maxVal)
+ callPixelEnd = mScaleInfo.valueToPixel(callEnd);
+ if (prevCallStart != callPixelStart || prevCallEnd != callPixelEnd) {
prevCallStart = callPixelStart;
- int callPixelEnd = -1;
- callEnd = call.mGlobalEndTime;
- if (callEnd <= maxVal)
- callPixelEnd = mScaleInfo.valueToPixel(callEnd);
+ prevCallEnd = callPixelEnd;
mHighlightInclusive.add(new Range(
callPixelStart + LeftMargin,
callPixelEnd + LeftMargin, y1, color));
@@ -1372,8 +1441,9 @@ public class TimeLineView extends Composite implements Observer {
if (segment.mStartTime >= callStart
&& segment.mEndTime <= callEnd && callMethod == md
&& callRowData == rd) {
- if (prevMethodStart != pixelStart) {
+ if (prevMethodStart != pixelStart || prevMethodEnd != pixelEnd) {
prevMethodStart = pixelStart;
+ prevMethodEnd = pixelEnd;
int rangeWidth = width;
if (rangeWidth == 0)
rangeWidth = 1;
@@ -1418,7 +1488,7 @@ public class TimeLineView extends Composite implements Observer {
// how much of the region [N - 0.5, N + 0.5] is covered
// by the segment.
double weight = computeWeight(recordStart, recordEnd,
- pixelStart);
+ isContextSwitch, pixelStart);
weight = block.addWeight(pixelStart, rd.mRank, weight);
if (weight > pix.mMaxWeight) {
pix.setFields(pixelStart, weight, segment, color,
@@ -1426,13 +1496,15 @@ public class TimeLineView extends Composite implements Observer {
}
} else {
int x1 = pixelStart + LeftMargin;
- Strip strip = new Strip(x1, y1, width, rowHeight, rd,
- segment, color);
+ Strip strip = new Strip(
+ x1, isContextSwitch ? y1 + rowHeight - 1 : y1,
+ width, isContextSwitch ? 1 : rowHeight,
+ rd, segment, color);
mStripList.add(strip);
}
} else {
double weight = computeWeight(recordStart, recordEnd,
- pixelStart);
+ isContextSwitch, pixelStart);
weight = block.addWeight(pixelStart, rd.mRank, weight);
if (weight > pix.mMaxWeight) {
pix.setFields(pixelStart, weight, segment, color, rd);
@@ -1444,7 +1516,7 @@ public class TimeLineView extends Composite implements Observer {
// Compute the weight for the next pixel
pixelStart += 1;
weight = computeWeight(recordStart, recordEnd,
- pixelStart);
+ isContextSwitch, pixelStart);
weight = block.addWeight(pixelStart, rd.mRank, weight);
pix.setFields(pixelStart, weight, segment, color, rd);
} else if (width > 1) {
@@ -1455,8 +1527,10 @@ public class TimeLineView extends Composite implements Observer {
pixelStart += 1;
width -= 1;
int x1 = pixelStart + LeftMargin;
- Strip strip = new Strip(x1, y1, width, rowHeight, rd,
- segment, color);
+ Strip strip = new Strip(
+ x1, isContextSwitch ? y1 + rowHeight - 1 : y1,
+ width, isContextSwitch ? 1 : rowHeight,
+ rd,segment, color);
mStripList.add(strip);
}
}
@@ -1483,7 +1557,11 @@ public class TimeLineView extends Composite implements Observer {
}
}
- private double computeWeight(double start, double end, int pixel) {
+ private double computeWeight(double start, double end,
+ boolean isContextSwitch, int pixel) {
+ if (isContextSwitch) {
+ return 0;
+ }
double pixelStartFraction = mScaleInfo.valueToPixelFraction(start);
double pixelEndFraction = mScaleInfo.valueToPixelFraction(end);
double leftEndPoint = Math.max(pixelStartFraction, pixel - 0.5);
@@ -1811,7 +1889,7 @@ public class TimeLineView extends Composite implements Observer {
} else {
mFadeColors = true;
mShowHighlightName = true;
- highlightHeight = highlightHeights[mHighlightStep];
+ mHighlightHeight = highlightHeights[mHighlightStep];
getDisplay().timerExec(HIGHLIGHT_TIMER_INTERVAL, mHighlightAnimator);
}
redraw();
@@ -1820,7 +1898,7 @@ public class TimeLineView extends Composite implements Observer {
private void clearHighlights() {
// System.out.printf("clearHighlights()\n");
mShowHighlightName = false;
- highlightHeight = 0;
+ mHighlightHeight = 0;
mHighlightMethodData = null;
mHighlightCall = null;
mFadeColors = false;
@@ -1900,7 +1978,7 @@ public class TimeLineView extends Composite implements Observer {
private static final int ZOOM_TIMER_INTERVAL = 10;
private static final int HIGHLIGHT_TIMER_INTERVAL = 50;
private static final int ZOOM_STEPS = 8; // must be even
- private int highlightHeight = 4;
+ private int mHighlightHeight = 4;
private final int[] highlightHeights = { 0, 2, 4, 5, 6, 5, 4, 2, 4, 5,
6 };
private final int HIGHLIGHT_STEPS = highlightHeights.length;
@@ -1989,7 +2067,12 @@ public class TimeLineView extends Composite implements Observer {
private static class Segment {
Segment(RowData rowData, Block block, long startTime, long endTime) {
mRowData = rowData;
- mBlock = block;
+ if (block.isContextSwitch()) {
+ mBlock = block.getParentBlock();
+ mIsContextSwitch = true;
+ } else {
+ mBlock = block;
+ }
mStartTime = startTime;
mEndTime = endTime;
}
@@ -1998,6 +2081,7 @@ public class TimeLineView extends Composite implements Observer {
private Block mBlock;
private long mStartTime;
private long mEndTime;
+ private boolean mIsContextSwitch;
}
private static class Strip {
diff --git a/traceview/src/com/android/traceview/QtraceReader.java b/traceview/src/com/android/traceview/TraceAction.java
index c4db4a2..6717300 100644
--- a/traceview/src/com/android/traceview/QtraceReader.java
+++ b/traceview/src/com/android/traceview/TraceAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -16,30 +16,16 @@
package com.android.traceview;
-import java.util.ArrayList;
-import java.util.HashMap;
+final class TraceAction {
+ public static final int ACTION_ENTER = 0;
+ public static final int ACTION_EXIT = 1;
+ public static final int ACTION_INCOMPLETE = 2;
-public class QtraceReader extends TraceReader {
- QtraceReader(String traceName) {
- }
-
- @Override
- public MethodData[] getMethods() {
- return null;
- }
-
- @Override
- public HashMap<Integer, String> getThreadLabels() {
- return null;
- }
-
- @Override
- public ArrayList<TimeLineView.Record> getThreadTimeRecords() {
- return null;
- }
+ public final int mAction;
+ public final Call mCall;
- @Override
- public ProfileProvider getProfileProvider() {
- return null;
+ public TraceAction(int action, Call call) {
+ mAction = action;
+ mCall = call;
}
}
diff --git a/traceview/src/com/android/traceview/TraceReader.java b/traceview/src/com/android/traceview/TraceReader.java
index e936629..fa76d27 100644
--- a/traceview/src/com/android/traceview/TraceReader.java
+++ b/traceview/src/com/android/traceview/TraceReader.java
@@ -45,10 +45,22 @@ public abstract class TraceReader {
return null;
}
- public long getEndTime() {
+ public long getTotalCpuTime() {
return 0;
}
+ public long getTotalRealTime() {
+ return 0;
+ }
+
+ public boolean haveCpuTime() {
+ return false;
+ }
+
+ public boolean haveRealTime() {
+ return false;
+ }
+
public HashMap<String, String> getProperties() {
return null;
}
@@ -56,4 +68,12 @@ public abstract class TraceReader {
public ProfileProvider getProfileProvider() {
return null;
}
+
+ public TimeBase getPreferredTimeBase() {
+ return TimeBase.CPU_TIME;
+ }
+
+ public String getClockSource() {
+ return null;
+ }
}