Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17e78cef authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Improve binder calls stats sampling."

parents 35863cda 34ad8af0
Loading
Loading
Loading
Loading
+29 −8
Original line number Diff line number Diff line
@@ -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<>();
@@ -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();
        }
@@ -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);
@@ -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++;
                }
            }
        }
    }
@@ -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.");
        }
@@ -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) {
@@ -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
@@ -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);
+3 −9
Original line number Diff line number Diff line
@@ -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
@@ -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 {
@@ -586,6 +579,7 @@ public class BinderCallsStatsTest {
                    };
                }
            });
            setSamplingInterval(1);
        }

        @Override