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

Commit d49a4099 authored by Siim Sammul's avatar Siim Sammul Committed by Android (Google) Code Review
Browse files

Merge "Add sharding to BinderCallsStats collection and make it configurable....

Merge "Add sharding to BinderCallsStats collection and make it configurable. The hash code of the callsession will be used to select which apis will be collected for based on the configured modulo. This is needed to reduce the amount of data collected from public devices." into sc-dev
parents f369b89e 91223d54
Loading
Loading
Loading
Loading
+70 −4
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
    public static final boolean DEFAULT_IGNORE_BATTERY_STATUS = false;
    public static final boolean DEFAULT_COLLECT_LATENCY_DATA = true;
    public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 1500;
    public static final int SHARDING_MODULO_DEFAULT = 1;
    private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";

    private static class OverflowBinder extends Binder {}
@@ -107,6 +108,12 @@ public class BinderCallsStats implements BinderInternal.Observer {
    private boolean mIgnoreBatteryStatus = DEFAULT_IGNORE_BATTERY_STATUS;
    private boolean mCollectLatencyData = DEFAULT_COLLECT_LATENCY_DATA;

    // Controls how many APIs will be collected per device. 1 means all APIs, 10 means every 10th
    // API will be collected.
    private int mShardingModulo = SHARDING_MODULO_DEFAULT;
    // Controls which shards will be collected on this device.
    private int mShardingOffset;

    private CachedDeviceState.Readonly mDeviceState;
    private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch;

@@ -178,6 +185,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
        this.mRandom = injector.getRandomGenerator();
        this.mCallStatsObserverHandler = injector.getHandler();
        this.mLatencyObserver = injector.getLatencyObserver(processSource);
        this.mShardingOffset = mRandom.nextInt(mShardingModulo);
    }

    public void setDeviceState(@NonNull CachedDeviceState.Readonly deviceState) {
@@ -343,6 +351,19 @@ public class BinderCallsStats implements BinderInternal.Observer {
        }
    }

    private boolean shouldExport(ExportedCallStat e, boolean applySharding) {
        if (!applySharding) {
            return true;
        }

        int hash = e.binderClass.hashCode();
        hash = 31 * hash + e.transactionCode;
        hash = 31 * hash + e.callingUid;
        hash = 31 * hash + (e.screenInteractive ? 1231 : 1237);

        return (hash + mShardingOffset) % mShardingModulo == 0;
    }

    private UidEntry getUidEntry(int uid) {
        UidEntry uidEntry = mUidEntries.get(uid);
        if (uidEntry == null) {
@@ -424,6 +445,15 @@ public class BinderCallsStats implements BinderInternal.Observer {
     * This method is expensive to call.
     */
    public ArrayList<ExportedCallStat> getExportedCallStats() {
        return getExportedCallStats(false);
    }

    /**
     * This method is expensive to call.
     * Exports call stats and applies sharding if requested.
     */
    @VisibleForTesting
    public ArrayList<ExportedCallStat> getExportedCallStats(boolean applySharding) {
        // We do not collect all the data if detailed tracking is off.
        if (!mDetailedTracking) {
            return new ArrayList<>();
@@ -435,7 +465,10 @@ public class BinderCallsStats implements BinderInternal.Observer {
            for (int entryIdx = 0; entryIdx < uidEntriesSize; entryIdx++) {
                final UidEntry entry = mUidEntries.valueAt(entryIdx);
                for (CallStat stat : entry.getCallStatsList()) {
                    resultCallStats.add(getExportedCallStat(entry.workSourceUid, stat));
                    ExportedCallStat e = getExportedCallStat(entry.workSourceUid, stat);
                    if (shouldExport(e, applySharding)) {
                        resultCallStats.add(e);
                    }
                }
            }
        }
@@ -450,6 +483,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
            resultCallStats.add(
                    createDebugEntry("battery_time_millis", mBatteryStopwatch.getMillis()));
            resultCallStats.add(createDebugEntry("sampling_interval", mPeriodicSamplingInterval));
            resultCallStats.add(createDebugEntry("sharding_modulo", mShardingModulo));
        }

        return resultCallStats;
@@ -459,11 +493,24 @@ public class BinderCallsStats implements BinderInternal.Observer {
     * This method is expensive to call.
     */
    public ArrayList<ExportedCallStat> getExportedCallStats(int workSourceUid) {
        return getExportedCallStats(workSourceUid, false);
    }

    /**
     * This method is expensive to call.
     * Exports call stats and applies sharding if requested.
     */
    @VisibleForTesting
    public ArrayList<ExportedCallStat> getExportedCallStats(
                int workSourceUid, boolean applySharding) {
        ArrayList<ExportedCallStat> resultCallStats = new ArrayList<>();
        synchronized (mLock) {
            final UidEntry entry = getUidEntry(workSourceUid);
            for (CallStat stat : entry.getCallStatsList()) {
                resultCallStats.add(getExportedCallStat(workSourceUid, stat));
                ExportedCallStat e = getExportedCallStat(workSourceUid, stat);
                if (shouldExport(e, applySharding)) {
                    resultCallStats.add(e);
                }
            }
        }

@@ -555,6 +602,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
        pw.print("On battery time (ms): ");
        pw.println(mBatteryStopwatch != null ? mBatteryStopwatch.getMillis() : 0);
        pw.println("Sampling interval period: " + mPeriodicSamplingInterval);
        pw.println("Sharding modulo: " + mShardingModulo);

        final String datasetSizeDesc = verbose ? "" : "(top 90% by cpu time) ";
        final StringBuilder sb = new StringBuilder();
@@ -566,9 +614,9 @@ public class BinderCallsStats implements BinderInternal.Observer {
                + "call_count):");
        final List<ExportedCallStat> exportedCallStats;
        if (workSourceUid != Process.INVALID_UID) {
            exportedCallStats = getExportedCallStats(workSourceUid);
            exportedCallStats = getExportedCallStats(workSourceUid, true);
        } else {
            exportedCallStats = getExportedCallStats();
            exportedCallStats = getExportedCallStats(true);
        }
        exportedCallStats.sort(BinderCallsStats::compareByCpuDesc);
        for (ExportedCallStat e : exportedCallStats) {
@@ -784,6 +832,23 @@ public class BinderCallsStats implements BinderInternal.Observer {
        }
    }

    /** Updates the sharding modulo. */
    public void setShardingModulo(int shardingModulo) {
        if (shardingModulo <= 0) {
            Slog.w(TAG, "Ignored invalid sharding modulo (value must be positive): "
                    + shardingModulo);
            return;
        }

        synchronized (mLock) {
            if (shardingModulo != mShardingModulo) {
                mShardingModulo = shardingModulo;
                mShardingOffset = mRandom.nextInt(shardingModulo);
                reset();
            }
        }
    }

    /** Whether to collect latency histograms. */
    public void setCollectLatencyData(boolean collectLatencyData) {
        mCollectLatencyData = collectLatencyData;
@@ -1104,6 +1169,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
        public static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid";
        public static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count";
        public static final String SETTINGS_IGNORE_BATTERY_STATUS_KEY = "ignore_battery_status";
        public static final String SETTINGS_SHARDING_MODULO_KEY = "sharding_modulo";
        // Settings for BinderLatencyObserver.
        public static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_latency_data";
        public static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY =
+32 −1
Original line number Diff line number Diff line
@@ -241,6 +241,34 @@ public class BinderCallsStatsTest {
        assertEquals(10, callStats.maxCpuTimeMicros);
    }

    @Test
    public void testSharding() {
        TestBinderCallsStats bcs = new TestBinderCallsStats();
        bcs.setShardingModulo(2);

        Binder binder = new Binder();
        CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
        bcs.time += 10;
        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);

        callSession = bcs.callStarted(binder, 2 /* another method */, WORKSOURCE_UID);
        bcs.time += 10;
        bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);


        SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
        assertEquals(1, uidEntries.size());
        BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID);
        assertEquals(2, uidEntry.callCount);
        assertEquals(2, uidEntry.recordedCallCount);

        List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
        assertEquals(2, callStatsList.size());

        assertEquals(1, bcs.getExportedCallStats(true).size());
        assertEquals(2, bcs.getExportedCallStats(false).size());
    }

    private static class BinderWithGetTransactionName extends Binder {
        public static String getDefaultTransactionName(int code) {
            return "resolved";
@@ -669,7 +697,7 @@ public class BinderCallsStatsTest {
        bcs.setAddDebugEntries(true);
        bcs.setSamplingInterval(10);
        ArrayList<BinderCallsStats.ExportedCallStat> callStats = bcs.getExportedCallStats();
        assertEquals(4, callStats.size());
        assertEquals(5, callStats.size());
        BinderCallsStats.ExportedCallStat debugEntry1 = callStats.get(0);
        assertEquals("", debugEntry1.className);
        assertEquals("__DEBUG_start_time_millis", debugEntry1.methodName);
@@ -685,6 +713,9 @@ public class BinderCallsStatsTest {
        BinderCallsStats.ExportedCallStat debugEntry4 = callStats.get(3);
        assertEquals("__DEBUG_sampling_interval", debugEntry4.methodName);
        assertEquals(10, debugEntry4.latencyMicros);
        BinderCallsStats.ExportedCallStat debugEntry5 = callStats.get(4);
        assertEquals("__DEBUG_sharding_modulo", debugEntry5.methodName);
        assertEquals(1, debugEntry5.latencyMicros);
    }

    @Test
+5 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_IGNORE_BATTERY_STATUS_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_MAX_CALL_STATS_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_SAMPLING_INTERVAL_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_SHARDING_MODULO_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_TRACK_DIRECT_CALLING_UID_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY;

@@ -188,6 +189,10 @@ public class BinderCallsStatsService extends Binder {
            mBinderCallsStats.setIgnoreBatteryStatus(
                    mParser.getBoolean(SETTINGS_IGNORE_BATTERY_STATUS_KEY,
                    BinderCallsStats.DEFAULT_IGNORE_BATTERY_STATUS));
            mBinderCallsStats.setShardingModulo(mParser.getInt(
                    SETTINGS_SHARDING_MODULO_KEY,
                    BinderCallsStats.SHARDING_MODULO_DEFAULT));

            mBinderCallsStats.setCollectLatencyData(
                    mParser.getBoolean(SETTINGS_COLLECT_LATENCY_DATA_KEY,
                    BinderCallsStats.DEFAULT_COLLECT_LATENCY_DATA));