Loading core/java/com/android/internal/os/BinderCallsStats.java +29 −8 Original line number Diff line number Diff line Loading @@ -67,7 +67,10 @@ public class BinderCallsStats implements BinderInternal.Observer { private static final int MAX_EXCEPTION_COUNT_SIZE = 50; private static final String EXCEPTION_COUNT_OVERFLOW_NAME = "overflow"; // Whether to collect all the data: cpu + exceptions + reply/request sizes. private boolean mDetailedTracking = DETAILED_TRACKING_DEFAULT; // Sampling period to control how often to track CPU usage. 1 means all calls, 100 means ~1 out // of 100 requests. private int mPeriodicSamplingInterval = PERIODIC_SAMPLING_INTERVAL_DEFAULT; @GuardedBy("mLock") private final SparseArray<UidEntry> mUidEntries = new SparseArray<>(); Loading Loading @@ -177,7 +180,7 @@ public class BinderCallsStats implements BinderInternal.Observer { s.exceptionThrown = false; s.cpuTimeStarted = -1; s.timeStarted = -1; if (mDetailedTracking || shouldRecordDetailedData()) { if (shouldRecordDetailedData()) { s.cpuTimeStarted = getThreadTimeMicro(); s.timeStarted = getElapsedRealtimeMicro(); } Loading Loading @@ -224,14 +227,14 @@ public class BinderCallsStats implements BinderInternal.Observer { final UidEntry uidEntry = getUidEntry(callingUid); uidEntry.callCount++; final CallStat callStat = uidEntry.getOrCreate( s.binderClass, s.transactionCode, mScreenInteractive); callStat.callCount++; if (recordCall) { uidEntry.cpuTimeMicros += duration; uidEntry.recordedCallCount++; final CallStat callStat = uidEntry.getOrCreate( s.binderClass, s.transactionCode, mScreenInteractive); callStat.callCount++; callStat.recordedCallCount++; callStat.cpuTimeMicros += duration; callStat.maxCpuTimeMicros = Math.max(callStat.maxCpuTimeMicros, duration); Loading @@ -245,6 +248,14 @@ public class BinderCallsStats implements BinderInternal.Observer { callStat.maxReplySizeBytes = Math.max(callStat.maxReplySizeBytes, parcelReplySize); } } else { // Only record the total call count if we already track data for this key. // It helps to keep the memory usage down when sampling is enabled. final CallStat callStat = uidEntry.get( s.binderClass, s.transactionCode, mScreenInteractive); if (callStat != null) { callStat.callCount++; } } } } Loading Loading @@ -459,7 +470,7 @@ public class BinderCallsStats implements BinderInternal.Observer { pw.println(String.format(" %6d %s", entry.second, entry.first)); } if (!mDetailedTracking && mPeriodicSamplingInterval != 1) { if (mPeriodicSamplingInterval != 1) { pw.println(""); pw.println("/!\\ Displayed data is sampled. See sampling interval at the top."); } Loading Loading @@ -488,6 +499,9 @@ public class BinderCallsStats implements BinderInternal.Observer { return mRandom.nextInt() % mPeriodicSamplingInterval == 0; } /** * Sets to true to collect all the data. */ public void setDetailedTracking(boolean enabled) { synchronized (mLock) { if (enabled != mDetailedTracking) { Loading Loading @@ -546,7 +560,8 @@ public class BinderCallsStats implements BinderInternal.Observer { // 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. // Roughly the real number of total calls. We only track only track the API call count once // at least one non-sampled count happened. public long callCount; // Total CPU of all for all the recorded calls. // Approximate total CPU usage can be computed by Loading Loading @@ -620,13 +635,19 @@ public class BinderCallsStats implements BinderInternal.Observer { private Map<CallStatKey, CallStat> mCallStats = new ArrayMap<>(); private CallStatKey mTempKey = new CallStatKey(); CallStat getOrCreate(Class<? extends Binder> binderClass, int transactionCode, @Nullable CallStat get(Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { // Use a global temporary key to avoid creating new objects for every lookup. mTempKey.binderClass = binderClass; mTempKey.transactionCode = transactionCode; mTempKey.screenInteractive = screenInteractive; CallStat mapCallStat = mCallStats.get(mTempKey); return mCallStats.get(mTempKey); } CallStat getOrCreate(Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { CallStat mapCallStat = get(binderClass, transactionCode, screenInteractive); // Only create CallStat if it's a new entry, otherwise update existing instance if (mapCallStat == null) { mapCallStat = new CallStat(binderClass, transactionCode, screenInteractive); Loading core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +3 −9 Original line number Diff line number Diff line Loading @@ -90,7 +90,7 @@ public class BinderCallsStatsTest { assertEquals(1, uidEntry.recordedCallCount); // Still sampled even for another API. callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(2, callStatsList.size()); assertEquals(1, callStatsList.size()); } @Test Loading Loading @@ -221,20 +221,13 @@ public class BinderCallsStatsTest { assertEquals(10, uidEntry.cpuTimeMicros); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(2, callStatsList.size()); assertEquals(1, 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); } private static class BinderWithGetTransactionName extends Binder { Loading Loading @@ -586,6 +579,7 @@ public class BinderCallsStatsTest { }; } }); setSamplingInterval(1); } @Override Loading Loading
core/java/com/android/internal/os/BinderCallsStats.java +29 −8 Original line number Diff line number Diff line Loading @@ -67,7 +67,10 @@ public class BinderCallsStats implements BinderInternal.Observer { private static final int MAX_EXCEPTION_COUNT_SIZE = 50; private static final String EXCEPTION_COUNT_OVERFLOW_NAME = "overflow"; // Whether to collect all the data: cpu + exceptions + reply/request sizes. private boolean mDetailedTracking = DETAILED_TRACKING_DEFAULT; // Sampling period to control how often to track CPU usage. 1 means all calls, 100 means ~1 out // of 100 requests. private int mPeriodicSamplingInterval = PERIODIC_SAMPLING_INTERVAL_DEFAULT; @GuardedBy("mLock") private final SparseArray<UidEntry> mUidEntries = new SparseArray<>(); Loading Loading @@ -177,7 +180,7 @@ public class BinderCallsStats implements BinderInternal.Observer { s.exceptionThrown = false; s.cpuTimeStarted = -1; s.timeStarted = -1; if (mDetailedTracking || shouldRecordDetailedData()) { if (shouldRecordDetailedData()) { s.cpuTimeStarted = getThreadTimeMicro(); s.timeStarted = getElapsedRealtimeMicro(); } Loading Loading @@ -224,14 +227,14 @@ public class BinderCallsStats implements BinderInternal.Observer { final UidEntry uidEntry = getUidEntry(callingUid); uidEntry.callCount++; final CallStat callStat = uidEntry.getOrCreate( s.binderClass, s.transactionCode, mScreenInteractive); callStat.callCount++; if (recordCall) { uidEntry.cpuTimeMicros += duration; uidEntry.recordedCallCount++; final CallStat callStat = uidEntry.getOrCreate( s.binderClass, s.transactionCode, mScreenInteractive); callStat.callCount++; callStat.recordedCallCount++; callStat.cpuTimeMicros += duration; callStat.maxCpuTimeMicros = Math.max(callStat.maxCpuTimeMicros, duration); Loading @@ -245,6 +248,14 @@ public class BinderCallsStats implements BinderInternal.Observer { callStat.maxReplySizeBytes = Math.max(callStat.maxReplySizeBytes, parcelReplySize); } } else { // Only record the total call count if we already track data for this key. // It helps to keep the memory usage down when sampling is enabled. final CallStat callStat = uidEntry.get( s.binderClass, s.transactionCode, mScreenInteractive); if (callStat != null) { callStat.callCount++; } } } } Loading Loading @@ -459,7 +470,7 @@ public class BinderCallsStats implements BinderInternal.Observer { pw.println(String.format(" %6d %s", entry.second, entry.first)); } if (!mDetailedTracking && mPeriodicSamplingInterval != 1) { if (mPeriodicSamplingInterval != 1) { pw.println(""); pw.println("/!\\ Displayed data is sampled. See sampling interval at the top."); } Loading Loading @@ -488,6 +499,9 @@ public class BinderCallsStats implements BinderInternal.Observer { return mRandom.nextInt() % mPeriodicSamplingInterval == 0; } /** * Sets to true to collect all the data. */ public void setDetailedTracking(boolean enabled) { synchronized (mLock) { if (enabled != mDetailedTracking) { Loading Loading @@ -546,7 +560,8 @@ public class BinderCallsStats implements BinderInternal.Observer { // 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. // Roughly the real number of total calls. We only track only track the API call count once // at least one non-sampled count happened. public long callCount; // Total CPU of all for all the recorded calls. // Approximate total CPU usage can be computed by Loading Loading @@ -620,13 +635,19 @@ public class BinderCallsStats implements BinderInternal.Observer { private Map<CallStatKey, CallStat> mCallStats = new ArrayMap<>(); private CallStatKey mTempKey = new CallStatKey(); CallStat getOrCreate(Class<? extends Binder> binderClass, int transactionCode, @Nullable CallStat get(Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { // Use a global temporary key to avoid creating new objects for every lookup. mTempKey.binderClass = binderClass; mTempKey.transactionCode = transactionCode; mTempKey.screenInteractive = screenInteractive; CallStat mapCallStat = mCallStats.get(mTempKey); return mCallStats.get(mTempKey); } CallStat getOrCreate(Class<? extends Binder> binderClass, int transactionCode, boolean screenInteractive) { CallStat mapCallStat = get(binderClass, transactionCode, screenInteractive); // Only create CallStat if it's a new entry, otherwise update existing instance if (mapCallStat == null) { mapCallStat = new CallStat(binderClass, transactionCode, screenInteractive); Loading
core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +3 −9 Original line number Diff line number Diff line Loading @@ -90,7 +90,7 @@ public class BinderCallsStatsTest { assertEquals(1, uidEntry.recordedCallCount); // Still sampled even for another API. callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(2, callStatsList.size()); assertEquals(1, callStatsList.size()); } @Test Loading Loading @@ -221,20 +221,13 @@ public class BinderCallsStatsTest { assertEquals(10, uidEntry.cpuTimeMicros); List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); assertEquals(2, callStatsList.size()); assertEquals(1, 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); } private static class BinderWithGetTransactionName extends Binder { Loading Loading @@ -586,6 +579,7 @@ public class BinderCallsStatsTest { }; } }); setSamplingInterval(1); } @Override Loading