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

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

Merge "Enabled aggregated per-uid stats collection by default" into pi-dev

parents 4f4882f2 3f3af617
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -69,7 +69,6 @@ public class BinderCallsStatsPerfTest {
        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        Binder b = new Binder();
        mBinderCallsStats = new BinderCallsStats(false);
        assertNull(mBinderCallsStats.callStarted(b, 0));
        while (state.keepRunning()) {
            BinderCallsStats.CallSession s = mBinderCallsStats.callStarted(b, 0);
            mBinderCallsStats.callEnded(s);
+79 −63
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;

@@ -40,23 +41,21 @@ public class BinderCallsStats {
    private static final int CALL_SESSIONS_POOL_SIZE = 100;
    private static final BinderCallsStats sInstance = new BinderCallsStats();

    private volatile boolean mTrackingEnabled = false;
    private volatile boolean mDetailedTracking = false;
    @GuardedBy("mLock")
    private final SparseArray<UidEntry> mUidEntries = new SparseArray<>();
    private final Queue<CallSession> mCallSessionsPool = new ConcurrentLinkedQueue<>();
    private final Object mLock = new Object();

    private BinderCallsStats() {
    }

    @VisibleForTesting
    public BinderCallsStats(boolean trackingEnabled) {
        mTrackingEnabled = trackingEnabled;
    public BinderCallsStats(boolean detailedTracking) {
        mDetailedTracking = detailedTracking;
    }

    public CallSession callStarted(Binder binder, int code) {
        if (!mTrackingEnabled) {
            return null;
        }

        return callStarted(binder.getClass().getName(), code);
    }

@@ -73,21 +72,18 @@ public class BinderCallsStats {
    }

    public void callEnded(CallSession s) {
        if (!mTrackingEnabled) {
            return;
        }
        Preconditions.checkNotNull(s);
        final long cpuTimeNow = getThreadTimeMicro();
        final long duration = cpuTimeNow - s.mStarted;
        long duration = mDetailedTracking ? getThreadTimeMicro() - s.mStarted : 1;
        s.mCallingUId = Binder.getCallingUid();

        synchronized (mUidEntries) {
        synchronized (mLock) {
            UidEntry uidEntry = mUidEntries.get(s.mCallingUId);
            if (uidEntry == null) {
                uidEntry = new UidEntry(s.mCallingUId);
                mUidEntries.put(s.mCallingUId, uidEntry);
            }

            if (mDetailedTracking) {
                // Find CallDesc entry and update its total time
                CallStat callStat = uidEntry.mCallStats.get(s.mCallStat);
                // Only create CallStat if it's a new entry, otherwise update existing instance
@@ -95,11 +91,13 @@ public class BinderCallsStats {
                    callStat = new CallStat(s.mCallStat.className, s.mCallStat.msg);
                    uidEntry.mCallStats.put(callStat, callStat);
                }
            uidEntry.time += duration;
            uidEntry.callCount++;
                callStat.callCount++;
                callStat.time += duration;
            }

            uidEntry.time += duration;
            uidEntry.callCount++;
        }
        if (mCallSessionsPool.size() < CALL_SESSIONS_POOL_SIZE) {
            mCallSessionsPool.add(s);
        }
@@ -112,7 +110,7 @@ public class BinderCallsStats {
        long totalCallsTime = 0;
        int uidEntriesSize = mUidEntries.size();
        List<UidEntry> entries = new ArrayList<>();
        synchronized (mUidEntries) {
        synchronized (mLock) {
            for (int i = 0; i < uidEntriesSize; i++) {
                UidEntry e = mUidEntries.valueAt(i);
                entries.add(e);
@@ -127,6 +125,7 @@ public class BinderCallsStats {
                totalCallsCount += e.callCount;
            }
        }
        if (mDetailedTracking) {
            pw.println("Binder call stats:");
            pw.println("  Raw data (uid,call_desc,time):");
            entries.sort((o1, o2) -> {
@@ -156,12 +155,12 @@ public class BinderCallsStats {
                }
            }
            pw.println();
        pw.println("  Per UID Summary(UID: time, total_time_percentage, calls_count):");
            pw.println("  Per UID Summary(UID: time, % of total_time, calls_count):");
            List<Map.Entry<Integer, Long>> uidTotals = new ArrayList<>(uidTimeMap.entrySet());
            uidTotals.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue()));
            for (Map.Entry<Integer, Long> uidTotal : uidTotals) {
                Long callCount = uidCallCountMap.get(uidTotal.getKey());
            pw.println(String.format("    %5d: %11d %3.0f%% %8d",
                pw.println(String.format("    %7d: %11d %3.0f%% %8d",
                        uidTotal.getKey(), uidTotal.getValue(),
                        100d * uidTotal.getValue() / totalCallsTime, callCount));
            }
@@ -170,22 +169,39 @@ public class BinderCallsStats {
                            + "calls_count=%d, avg_call_time=%.0f",
                    totalCallsTime, totalCallsCount,
                    (double)totalCallsTime / totalCallsCount));
        } else {
            pw.println("  Per UID Summary(UID: calls_count, % of total calls_count):");
            List<Map.Entry<Integer, Long>> uidTotals = new ArrayList<>(uidTimeMap.entrySet());
            uidTotals.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue()));
            for (Map.Entry<Integer, Long> uidTotal : uidTotals) {
                Long callCount = uidCallCountMap.get(uidTotal.getKey());
                pw.println(String.format("    %7d: %8d %3.0f%%",
                        uidTotal.getKey(), callCount, 100d * uidTotal.getValue() / totalCallsTime));
            }
        }
    }

    private static long getThreadTimeMicro() {
        return SystemClock.currentThreadTimeMicro();
    private long getThreadTimeMicro() {
        // currentThreadTimeMicro is expensive, so we measure cpu time only if detailed tracking is
        // enabled
        return mDetailedTracking ? SystemClock.currentThreadTimeMicro() : 0;
    }

    public static BinderCallsStats getInstance() {
        return sInstance;
    }

    public void setTrackingEnabled(boolean enabled) {
        mTrackingEnabled = enabled;
    public void setDetailedTracking(boolean enabled) {
        if (enabled != mDetailedTracking) {
            reset();
            mDetailedTracking = enabled;
        }
    }

    public boolean isTrackingEnabled() {
        return mTrackingEnabled;
    public void reset() {
        synchronized (mLock) {
            mUidEntries.clear();
        }
    }

    private static class CallStat {
@@ -210,7 +226,7 @@ public class BinderCallsStats {

            CallStat callStat = (CallStat) o;

            return msg == callStat.msg && (className == callStat.className);
            return msg == callStat.msg && (className.equals(callStat.className));
        }

        @Override
+41 −9
Original line number Diff line number Diff line
@@ -30,26 +30,58 @@ public class BinderCallsStatsService extends Binder {

    private static final String TAG = "BinderCallsStatsService";

    private static final String PERSIST_SYS_BINDER_CPU_STATS_TRACKING
            = "persist.sys.binder_cpu_stats_tracking";
    private static final String PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING
            = "persist.sys.binder_calls_detailed_tracking";

    public static void start() {
        BinderCallsStatsService service = new BinderCallsStatsService();
        ServiceManager.addService("binder_calls_stats", service);
        // TODO Enable by default on eng/userdebug builds
        boolean trackingEnabledDefault = false;
        boolean trackingEnabled = SystemProperties.getBoolean(PERSIST_SYS_BINDER_CPU_STATS_TRACKING,
                trackingEnabledDefault);
        boolean detailedTrackingEnabled = SystemProperties.getBoolean(
                PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, false);

        if (trackingEnabled) {
        if (detailedTrackingEnabled) {
            Slog.i(TAG, "Enabled CPU usage tracking for binder calls. Controlled by "
                    + PERSIST_SYS_BINDER_CPU_STATS_TRACKING);
            BinderCallsStats.getInstance().setTrackingEnabled(true);
                    + PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING
                    + " or via dumpsys binder_calls_stats --enable-detailed-tracking");
            BinderCallsStats.getInstance().setDetailedTracking(true);
        }
    }

    public static void reset() {
        Slog.i(TAG, "Resetting stats");
        BinderCallsStats.getInstance().reset();
    }

    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (args != null) {
            for (final String arg : args) {
                if ("--reset".equals(arg)) {
                    reset();
                    pw.println("binder_calls_stats reset.");
                    return;
                } else if ("--enable-detailed-tracking".equals(arg)) {
                    SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, "1");
                    BinderCallsStats.getInstance().setDetailedTracking(true);
                    pw.println("Detailed tracking enabled");
                    return;
                } else if ("--disable-detailed-tracking".equals(arg)) {
                    SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, "");
                    BinderCallsStats.getInstance().setDetailedTracking(false);
                    pw.println("Detailed tracking disabled");
                    return;
                } else if ("-h".equals(arg)) {
                    pw.println("binder_calls_stats commands:");
                    pw.println("  --reset: Reset stats");
                    pw.println("  --enable-detailed-tracking: Enables detailed tracking");
                    pw.println("  --disable-detailed-tracking: Disables detailed tracking");
                    return;
                } else {
                    pw.println("Unknown option: " + arg);
                    return;
                }
            }
        }
        BinderCallsStats.getInstance().dump(pw);
    }
}