summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Siim Sammul <siims@google.com> 2021-05-24 13:09:19 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-05-24 13:09:19 +0000
commitd49a40998aa13d4bc8ffbfd7893c9198b7727f8a (patch)
tree5ea46b09e5b3e313be5c7129bc8bb3be2a6fe2ae
parentf369b89e37df4f2e01794a2ceead1812a994af63 (diff)
parent91223d54e53a3a9619f71ade8f2724e15f2752ff (diff)
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
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java74
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java33
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java5
3 files changed, 107 insertions, 5 deletions
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 57e1bf79622c..6f911cbd6121 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -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 =
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 e2e672ea6f68..55943a0dc319 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -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
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index 0bd331b737c6..b87184aa5582 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -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));