summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java4
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java239
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java108
3 files changed, 187 insertions, 164 deletions
diff --git a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
index e126fb807b99..2b8b8f2c611a 100644
--- a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
@@ -23,6 +23,8 @@ import android.support.test.runner.AndroidJUnit4;
import com.android.internal.os.BinderCallsStats;
+import java.util.Random;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -45,7 +47,7 @@ public class BinderCallsStatsPerfTest {
@Before
public void setUp() {
- mBinderCallsStats = new BinderCallsStats();
+ mBinderCallsStats = new BinderCallsStats(new Random());
}
@After
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index f87c081fd04f..63c7dd0e0cb3 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -38,6 +38,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
+import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.ToDoubleFunction;
@@ -57,7 +58,7 @@ public class BinderCallsStats {
private static final int MAX_EXCEPTION_COUNT_SIZE = 50;
private static final String EXCEPTION_COUNT_OVERFLOW_NAME = "overflow";
private static final CallSession NOT_ENABLED = new CallSession();
- private static final BinderCallsStats sInstance = new BinderCallsStats();
+ private static final BinderCallsStats sInstance = new BinderCallsStats(new Random());
private volatile boolean mEnabled = ENABLED_DEFAULT;
private volatile boolean mDetailedTracking = DETAILED_TRACKING_DEFAULT;
@@ -68,12 +69,12 @@ public class BinderCallsStats {
private final ArrayMap<String, Integer> mExceptionCounts = new ArrayMap<>();
private final Queue<CallSession> mCallSessionsPool = new ConcurrentLinkedQueue<>();
private final Object mLock = new Object();
+ private final Random mRandom;
private long mStartTime = System.currentTimeMillis();
- @GuardedBy("mLock")
- private UidEntry mSampledEntries = new UidEntry(-1);
@VisibleForTesting // Use getInstance() instead.
- public BinderCallsStats() {
+ public BinderCallsStats(Random random) {
+ this.mRandom = random;
}
public CallSession callStarted(Binder binder, int code) {
@@ -82,7 +83,7 @@ public class BinderCallsStats {
private CallSession callStarted(String className, int code, @Nullable String methodName) {
if (!mEnabled) {
- return NOT_ENABLED;
+ return NOT_ENABLED;
}
CallSession s = mCallSessionsPool.poll();
@@ -98,16 +99,12 @@ public class BinderCallsStats {
s.timeStarted = -1;
synchronized (mLock) {
- if (mDetailedTracking) {
- s.cpuTimeStarted = getThreadTimeMicro();
- s.timeStarted = getElapsedRealtimeMicro();
- } else {
- s.sampledCallStat = mSampledEntries.getOrCreate(s.callStat);
- if (s.sampledCallStat.callCount % mPeriodicSamplingInterval == 0) {
- s.cpuTimeStarted = getThreadTimeMicro();
- s.timeStarted = getElapsedRealtimeMicro();
- }
+ if (!mDetailedTracking && !shouldTrackCall()) {
+ return s;
}
+
+ s.cpuTimeStarted = getThreadTimeMicro();
+ s.timeStarted = getElapsedRealtimeMicro();
}
return s;
}
@@ -115,7 +112,7 @@ public class BinderCallsStats {
public void callEnded(CallSession s, int parcelRequestSize, int parcelReplySize) {
Preconditions.checkNotNull(s);
if (s == NOT_ENABLED) {
- return;
+ return;
}
processCallEnded(s, parcelRequestSize, parcelReplySize);
@@ -128,60 +125,42 @@ public class BinderCallsStats {
private void processCallEnded(CallSession s, int parcelRequestSize, int parcelReplySize) {
synchronized (mLock) {
if (!mEnabled) {
- return;
+ return;
}
- long duration;
- long latencyDuration;
- if (mDetailedTracking) {
- duration = getThreadTimeMicro() - s.cpuTimeStarted;
- latencyDuration = getElapsedRealtimeMicro() - s.timeStarted;
- } else {
- CallStat cs = s.sampledCallStat;
- // Non-negative time signals beginning of the new sampling interval
- if (s.cpuTimeStarted >= 0) {
- duration = getThreadTimeMicro() - s.cpuTimeStarted;
- latencyDuration = getElapsedRealtimeMicro() - s.timeStarted;
- } else {
- // callCount is always incremented, but time only once per sampling interval
- long samplesCount = cs.callCount / mPeriodicSamplingInterval + 1;
- duration = cs.cpuTimeMicros / samplesCount;
- latencyDuration = cs.latencyMicros / samplesCount;
- }
- }
-
- int callingUid = getCallingUid();
-
+ final int callingUid = getCallingUid();
UidEntry uidEntry = mUidEntries.get(callingUid);
if (uidEntry == null) {
uidEntry = new UidEntry(callingUid);
mUidEntries.put(callingUid, uidEntry);
}
-
- CallStat callStat;
- if (mDetailedTracking) {
- // Find CallStat entry and update its total time
- callStat = uidEntry.getOrCreate(s.callStat);
- callStat.exceptionCount += s.exceptionThrown ? 1 : 0;
- callStat.maxRequestSizeBytes =
- Math.max(callStat.maxRequestSizeBytes, parcelRequestSize);
- callStat.maxReplySizeBytes =
- Math.max(callStat.maxReplySizeBytes, parcelReplySize);
- } else {
- // update sampled timings in the beginning of each interval
- callStat = s.sampledCallStat;
- }
+ uidEntry.callCount++;
+ CallStat callStat = uidEntry.getOrCreate(s.callStat);
callStat.callCount++;
- callStat.methodName = s.callStat.methodName;
- if (s.cpuTimeStarted >= 0) {
+
+ // Non-negative time signals we need to record data for this call.
+ final boolean recordCall = s.cpuTimeStarted >= 0;
+ if (recordCall) {
+ final long duration = getThreadTimeMicro() - s.cpuTimeStarted;
+ final long latencyDuration = getElapsedRealtimeMicro() - s.timeStarted;
+ uidEntry.cpuTimeMicros += duration;
+ uidEntry.recordedCallCount++;
+
+ callStat.recordedCallCount++;
+ callStat.methodName = s.callStat.methodName;
callStat.cpuTimeMicros += duration;
callStat.maxCpuTimeMicros = Math.max(callStat.maxCpuTimeMicros, duration);
callStat.latencyMicros += latencyDuration;
- callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration);
+ callStat.maxLatencyMicros =
+ Math.max(callStat.maxLatencyMicros, latencyDuration);
+ if (mDetailedTracking) {
+ callStat.exceptionCount += s.exceptionThrown ? 1 : 0;
+ callStat.maxRequestSizeBytes =
+ Math.max(callStat.maxRequestSizeBytes, parcelRequestSize);
+ callStat.maxReplySizeBytes =
+ Math.max(callStat.maxReplySizeBytes, parcelReplySize);
+ }
}
-
- uidEntry.cpuTimeMicros += duration;
- uidEntry.callCount++;
}
}
@@ -195,28 +174,28 @@ public class BinderCallsStats {
public void callThrewException(CallSession s, Exception exception) {
Preconditions.checkNotNull(s);
if (!mEnabled) {
- return;
+ return;
}
s.exceptionThrown = true;
try {
String className = exception.getClass().getName();
synchronized (mLock) {
if (mExceptionCounts.size() >= MAX_EXCEPTION_COUNT_SIZE) {
- className = EXCEPTION_COUNT_OVERFLOW_NAME;
+ className = EXCEPTION_COUNT_OVERFLOW_NAME;
}
Integer count = mExceptionCounts.get(className);
mExceptionCounts.put(className, count == null ? 1 : count + 1);
}
} catch (RuntimeException e) {
- // Do not propagate the exception. We do not want to swallow original exception.
- Log.wtf(TAG, "Unexpected exception while updating mExceptionCounts", e);
+ // Do not propagate the exception. We do not want to swallow original exception.
+ Log.wtf(TAG, "Unexpected exception while updating mExceptionCounts", e);
}
}
public ArrayList<ExportedCallStat> getExportedCallStats() {
// We do not collect all the data if detailed tracking is off.
if (!mDetailedTracking) {
- return new ArrayList<ExportedCallStat>();
+ return new ArrayList<ExportedCallStat>();
}
ArrayList<ExportedCallStat> resultCallStats = new ArrayList<>();
@@ -229,11 +208,12 @@ public class BinderCallsStats {
exported.uid = entry.uid;
exported.className = stat.className;
exported.methodName = stat.methodName == null
- ? String.valueOf(stat.msg) : stat.methodName;
+ ? String.valueOf(stat.msg) : stat.methodName;
exported.cpuTimeMicros = stat.cpuTimeMicros;
exported.maxCpuTimeMicros = stat.maxCpuTimeMicros;
exported.latencyMicros = stat.latencyMicros;
exported.maxLatencyMicros = stat.maxLatencyMicros;
+ exported.recordedCallCount = stat.recordedCallCount;
exported.callCount = stat.callCount;
exported.maxRequestSizeBytes = stat.maxRequestSizeBytes;
exported.maxReplySizeBytes = stat.maxReplySizeBytes;
@@ -254,14 +234,16 @@ public class BinderCallsStats {
private void dumpLocked(PrintWriter pw, Map<Integer,String> appIdToPkgNameMap, boolean verbose) {
if (!mEnabled) {
- pw.println("Binder calls stats disabled.");
- return;
+ pw.println("Binder calls stats disabled.");
+ return;
}
long totalCallsCount = 0;
+ long totalRecordedCallsCount = 0;
long totalCpuTime = 0;
pw.print("Start time: ");
pw.println(DateFormat.format("yyyy-MM-dd HH:mm:ss", mStartTime));
+ pw.println("Sampling interval period: " + mPeriodicSamplingInterval);
List<UidEntry> entries = new ArrayList<>();
int uidEntriesSize = mUidEntries.size();
@@ -269,70 +251,53 @@ public class BinderCallsStats {
UidEntry e = mUidEntries.valueAt(i);
entries.add(e);
totalCpuTime += e.cpuTimeMicros;
+ totalRecordedCallsCount += e.recordedCallCount;
totalCallsCount += e.callCount;
}
entries.sort(Comparator.<UidEntry>comparingDouble(value -> value.cpuTimeMicros).reversed());
String datasetSizeDesc = verbose ? "" : "(top 90% by cpu time) ";
StringBuilder sb = new StringBuilder();
- if (mDetailedTracking) {
- pw.println("Per-UID raw data " + datasetSizeDesc
- + "(package/uid, call_desc, cpu_time_micros, max_cpu_time_micros, "
- + "latency_time_micros, max_latency_time_micros, exception_count, "
- + "max_request_size_bytes, max_reply_size_bytes, call_count):");
- List<UidEntry> topEntries = verbose ? entries
- : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9);
- for (UidEntry uidEntry : topEntries) {
- for (CallStat e : uidEntry.getCallStatsList()) {
- sb.setLength(0);
- sb.append(" ")
- .append(uidToString(uidEntry.uid, appIdToPkgNameMap))
- .append(",").append(e)
- .append(',').append(e.cpuTimeMicros)
- .append(',').append(e.maxCpuTimeMicros)
- .append(',').append(e.latencyMicros)
- .append(',').append(e.maxLatencyMicros)
- .append(',').append(e.exceptionCount)
- .append(',').append(e.maxRequestSizeBytes)
- .append(',').append(e.maxReplySizeBytes)
- .append(',').append(e.callCount);
- pw.println(sb);
- }
- }
- pw.println();
- } else {
- pw.println("Sampled stats " + datasetSizeDesc
- + "(call_desc, cpu_time, call_count, exception_count):");
- List<CallStat> sampledStatsList = mSampledEntries.getCallStatsList();
- // Show all if verbose, otherwise 90th percentile
- if (!verbose) {
- sampledStatsList = getHighestValues(sampledStatsList,
- value -> value.cpuTimeMicros, 0.9);
- }
- for (CallStat e : sampledStatsList) {
+ List<UidEntry> topEntries = verbose ? entries
+ : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9);
+ pw.println("Per-UID raw data " + datasetSizeDesc
+ + "(package/uid, call_desc, cpu_time_micros, max_cpu_time_micros, "
+ + "latency_time_micros, max_latency_time_micros, exception_count, "
+ + "max_request_size_bytes, max_reply_size_bytes, recorded_call_count, "
+ + "call_count):");
+ for (UidEntry uidEntry : topEntries) {
+ for (CallStat e : uidEntry.getCallStatsList()) {
sb.setLength(0);
- sb.append(" ").append(e)
- .append(',').append(e.cpuTimeMicros * mPeriodicSamplingInterval)
- .append(',').append(e.callCount)
- .append(',').append(e.exceptionCount);
+ sb.append(" ")
+ .append(uidToString(uidEntry.uid, appIdToPkgNameMap))
+ .append(',').append(e)
+ .append(',').append(e.cpuTimeMicros)
+ .append(',').append(e.maxCpuTimeMicros)
+ .append(',').append(e.latencyMicros)
+ .append(',').append(e.maxLatencyMicros)
+ .append(',').append(mDetailedTracking ? e.exceptionCount : '_')
+ .append(',').append(mDetailedTracking ? e.maxRequestSizeBytes : '_')
+ .append(',').append(mDetailedTracking ? e.maxReplySizeBytes : '_')
+ .append(',').append(e.recordedCallCount)
+ .append(',').append(e.callCount);
pw.println(sb);
}
- pw.println();
}
+ pw.println();
pw.println("Per-UID Summary " + datasetSizeDesc
- + "(cpu_time, % of total cpu_time, call_count, exception_count, package/uid):");
+ + "(cpu_time, % of total cpu_time, recorded_call_count, call_count, package/uid):");
List<UidEntry> summaryEntries = verbose ? entries
: getHighestValues(entries, value -> value.cpuTimeMicros, 0.9);
for (UidEntry entry : summaryEntries) {
String uidStr = uidToString(entry.uid, appIdToPkgNameMap);
- pw.println(String.format(" %10d %3.0f%% %8d %3d %s",
- entry.cpuTimeMicros, 100d * entry.cpuTimeMicros / totalCpuTime, entry.callCount,
- entry.exceptionCount, uidStr));
+ pw.println(String.format(" %10d %3.0f%% %8d %8d %s",
+ entry.cpuTimeMicros, 100d * entry.cpuTimeMicros / totalCpuTime,
+ entry.recordedCallCount, entry.callCount, uidStr));
}
pw.println();
pw.println(String.format(" Summary: total_cpu_time=%d, "
- + "calls_count=%d, avg_call_cpu_time=%.0f",
- totalCpuTime, totalCallsCount, (double)totalCpuTime / totalCallsCount));
+ + "calls_count=%d, avg_call_cpu_time=%.0f",
+ totalCpuTime, totalCallsCount, (double)totalCpuTime / totalRecordedCallsCount));
pw.println();
pw.println("Exceptions thrown (exception_count, class_name):");
@@ -340,10 +305,15 @@ public class BinderCallsStats {
// We cannot use new ArrayList(Collection) constructor because MapCollections does not
// implement toArray method.
mExceptionCounts.entrySet().iterator().forEachRemaining(
- (e) -> exceptionEntries.add(Pair.create(e.getKey(), e.getValue())));
+ (e) -> exceptionEntries.add(Pair.create(e.getKey(), e.getValue())));
exceptionEntries.sort((e1, e2) -> Integer.compare(e2.second, e1.second));
for (Pair<String, Integer> entry : exceptionEntries) {
- pw.println(String.format(" %6d %s", entry.second, entry.first));
+ pw.println(String.format(" %6d %s", entry.second, entry.first));
+ }
+
+ if (!mDetailedTracking && mPeriodicSamplingInterval != 1) {
+ pw.println("");
+ pw.println("/!\\ Displayed data is sampled. See sampling interval at the top.");
}
}
@@ -366,16 +336,20 @@ public class BinderCallsStats {
return SystemClock.elapsedRealtimeNanos() / 1000;
}
+ private boolean shouldTrackCall() {
+ return mRandom.nextInt() % mPeriodicSamplingInterval == 0;
+ }
+
public static BinderCallsStats getInstance() {
return sInstance;
}
public void setDetailedTracking(boolean enabled) {
synchronized (mLock) {
- if (enabled != mDetailedTracking) {
- mDetailedTracking = enabled;
- reset();
- }
+ if (enabled != mDetailedTracking) {
+ mDetailedTracking = enabled;
+ reset();
+ }
}
}
@@ -401,7 +375,6 @@ public class BinderCallsStats {
synchronized (mLock) {
mUidEntries.clear();
mExceptionCounts.clear();
- mSampledEntries.mCallStats.clear();
mStartTime = System.currentTimeMillis();
}
}
@@ -418,6 +391,7 @@ public class BinderCallsStats {
public long latencyMicros;
public long maxLatencyMicros;
public long callCount;
+ public long recordedCallCount;
public long maxRequestSizeBytes;
public long maxReplySizeBytes;
public long exceptionCount;
@@ -430,11 +404,21 @@ public class BinderCallsStats {
// Method name might be null when we cannot resolve the transaction code. For instance, if
// the binder was not generated by AIDL.
public @Nullable String methodName;
+ // Number of calls for which we collected data for. We do not record data for all the calls
+ // when sampling is on.
+ public long recordedCallCount;
+ // Real number of total calls.
+ public long callCount;
+ // Total CPU of all for all the recorded calls.
+ // Approximate total CPU usage can be computed by
+ // cpuTimeMicros * callCount / recordedCallCount
public long cpuTimeMicros;
public long maxCpuTimeMicros;
+ // Total latency of all for all the recorded calls.
+ // Approximate average latency can be computed by
+ // latencyMicros * callCount / recordedCallCount
public long latencyMicros;
public long maxLatencyMicros;
- public long callCount;
// The following fields are only computed if mDetailedTracking is set.
public long maxRequestSizeBytes;
public long maxReplySizeBytes;
@@ -455,7 +439,6 @@ public class BinderCallsStats {
}
CallStat callStat = (CallStat) o;
-
return msg == callStat.msg && (className.equals(callStat.className));
}
@@ -477,15 +460,20 @@ public class BinderCallsStats {
long timeStarted;
boolean exceptionThrown;
final CallStat callStat = new CallStat();
- CallStat sampledCallStat;
}
@VisibleForTesting
public static class UidEntry {
int uid;
- public long cpuTimeMicros;
+ // Number of calls for which we collected data for. We do not record data for all the calls
+ // when sampling is on.
+ public long recordedCallCount;
+ // Real number of total calls.
public long callCount;
- public int exceptionCount;
+ // Total CPU of all for all the recorded calls.
+ // Approximate total CPU usage can be computed by
+ // cpuTimeMicros * callCount / recordedCallCount
+ public long cpuTimeMicros;
UidEntry(int uid) {
this.uid = uid;
@@ -551,11 +539,6 @@ public class BinderCallsStats {
}
@VisibleForTesting
- public UidEntry getSampledEntries() {
- return mSampledEntries;
- }
-
- @VisibleForTesting
public ArrayMap<String, Integer> getExceptionCounts() {
return mExceptionCounts;
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index d46c1543e0f0..07e2af8d4c66 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -33,6 +33,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Random;
import static org.junit.Assert.assertEquals;
@@ -48,6 +49,7 @@ public class BinderCallsStatsTest {
public void testDetailedOff() {
TestBinderCallsStats bcs = new TestBinderCallsStats();
bcs.setDetailedTracking(false);
+ bcs.setSamplingInterval(5);
Binder binder = new Binder();
BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
@@ -58,44 +60,31 @@ public class BinderCallsStatsTest {
assertEquals(1, uidEntries.size());
BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
Assert.assertNotNull(uidEntry);
+ List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
assertEquals(1, uidEntry.callCount);
+ assertEquals(1, uidEntry.recordedCallCount);
assertEquals(10, uidEntry.cpuTimeMicros);
- assertEquals("Detailed tracking off - no entries should be returned",
- 0, uidEntry.getCallStatsList().size());
-
- BinderCallsStats.UidEntry sampledEntries = bcs.getSampledEntries();
- List<BinderCallsStats.CallStat> sampledCallStatsList = sampledEntries.getCallStatsList();
- assertEquals(1, sampledCallStatsList.size());
-
-
- assertEquals(1, sampledCallStatsList.get(0).callCount);
- assertEquals(10, sampledCallStatsList.get(0).cpuTimeMicros);
- assertEquals(binder.getClass().getName(), sampledCallStatsList.get(0).className);
- assertEquals(1, sampledCallStatsList.get(0).msg);
+ assertEquals(binder.getClass().getName(), callStatsList.get(0).className);
+ assertEquals(1, callStatsList.get(0).msg);
+ // CPU usage is sampled, should not be tracked here.
callSession = bcs.callStarted(binder, 1);
bcs.time += 20;
bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
-
- uidEntry = bcs.getUidEntries().get(TEST_UID);
assertEquals(2, uidEntry.callCount);
- // When sampling is enabled, cpu time is only measured for the first transaction in the
- // sampling interval, for others an average duration of previous transactions is used as
- // approximation
- assertEquals(20, uidEntry.cpuTimeMicros);
- sampledCallStatsList = sampledEntries.getCallStatsList();
- assertEquals(1, sampledCallStatsList.size());
+ assertEquals(1, uidEntry.recordedCallCount);
+ assertEquals(10, uidEntry.cpuTimeMicros);
+ assertEquals(1, callStatsList.size());
callSession = bcs.callStarted(binder, 2);
bcs.time += 50;
bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
uidEntry = bcs.getUidEntries().get(TEST_UID);
assertEquals(3, uidEntry.callCount);
-
- // This is the first transaction of a new type, so the real CPU time will be measured
- assertEquals(70, uidEntry.cpuTimeMicros);
- sampledCallStatsList = sampledEntries.getCallStatsList();
- assertEquals(2, sampledCallStatsList.size());
+ assertEquals(1, uidEntry.recordedCallCount);
+ // Still sampled even for another API.
+ callStatsList = uidEntry.getCallStatsList();
+ assertEquals(2, callStatsList.size());
}
@Test
@@ -116,10 +105,6 @@ public class BinderCallsStatsTest {
assertEquals(10, uidEntry.cpuTimeMicros);
assertEquals(1, uidEntry.getCallStatsList().size());
- BinderCallsStats.UidEntry sampledEntries = bcs.getSampledEntries();
- assertEquals("Sampling is not used when detailed tracking on",
- 0, bcs.getSampledEntries().getCallStatsList().size());
-
List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
assertEquals(1, callStatsList.get(0).callCount);
assertEquals(10, callStatsList.get(0).cpuTimeMicros);
@@ -216,13 +201,57 @@ public class BinderCallsStatsTest {
BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
Assert.assertNotNull(uidEntry);
assertEquals(3, uidEntry.callCount);
- assertEquals(70, uidEntry.cpuTimeMicros);
- assertEquals("Detailed tracking off - no entries should be returned",
- 0, uidEntry.getCallStatsList().size());
+ assertEquals(60 /* 10 + 50 */, uidEntry.cpuTimeMicros);
+
+ List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
+ assertEquals(1, callStatsList.size());
+ BinderCallsStats.CallStat callStats = callStatsList.get(0);
+ assertEquals(3, callStats.callCount);
+ assertEquals(2, callStats.recordedCallCount);
+ assertEquals(60, callStats.cpuTimeMicros);
+ assertEquals(50, callStats.maxCpuTimeMicros);
+ assertEquals(0, callStats.maxRequestSizeBytes);
+ assertEquals(0, callStats.maxReplySizeBytes);
+ }
+
+ @Test
+ public void testSamplingWithDifferentApis() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ bcs.setDetailedTracking(false);
+ bcs.setSamplingInterval(2);
+
+ Binder binder = new Binder();
+ BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
+ callSession = bcs.callStarted(binder, 2 /* another method */);
+ bcs.time += 1000; // shoud be ignored.
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
+
- BinderCallsStats.UidEntry sampledEntries = bcs.getSampledEntries();
- List<BinderCallsStats.CallStat> sampledCallStatsList = sampledEntries.getCallStatsList();
- assertEquals(1, sampledCallStatsList.size());
+ SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
+ assertEquals(1, uidEntries.size());
+ BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
+ assertEquals(2, uidEntry.callCount);
+ assertEquals(1, uidEntry.recordedCallCount);
+ assertEquals(10, uidEntry.cpuTimeMicros);
+
+ List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
+ assertEquals(2, callStatsList.size());
+
+ BinderCallsStats.CallStat callStats = callStatsList.get(0);
+ assertEquals(1, callStats.callCount);
+ assertEquals(1, callStats.recordedCallCount);
+ assertEquals(10, callStats.cpuTimeMicros);
+ assertEquals(10, callStats.maxCpuTimeMicros);
+
+ // Only call count should is tracked, rest is sampled.
+ callStats = callStatsList.get(1);
+ assertEquals(1, callStats.callCount);
+ assertEquals(0, callStats.recordedCallCount);
+ assertEquals(0, callStats.cpuTimeMicros);
+ assertEquals(0, callStats.maxCpuTimeMicros);
}
@Test
@@ -374,6 +403,7 @@ public class BinderCallsStatsTest {
assertEquals(20, stat.latencyMicros);
assertEquals(20, stat.maxLatencyMicros);
assertEquals(1, stat.callCount);
+ assertEquals(1, stat.recordedCallCount);
assertEquals(REQUEST_SIZE, stat.maxRequestSizeBytes);
assertEquals(REPLY_SIZE, stat.maxReplySizeBytes);
assertEquals(0, stat.exceptionCount);
@@ -385,6 +415,14 @@ public class BinderCallsStatsTest {
long elapsedTime = 0;
TestBinderCallsStats() {
+ // Make random generator not random.
+ super(new Random() {
+ int mCallCount = 0;
+
+ public int nextInt() {
+ return mCallCount++;
+ }
+ });
}
@Override