summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorFyodor Kupolov <fkupolov@google.com>2018-04-18 17:26:43 -0700
committerFyodor Kupolov <fkupolov@google.com>2018-04-20 16:12:41 -0700
commit3f3af617ae9fab797248a9a855fe396c0d2ab590 (patch)
treeaa3ea0144523b6d5255d0b7e0735fd798f4d7852 /core/java
parent5e12ebfffd813fc7035c9eef60220914dc92482f (diff)
Enabled aggregated per-uid stats collection by default
Enabled collection of number of calls per-uid. It has relatively small overhead. Memory impact is minimal and cpu overhead is also small - 250 ns vs 1500 ns with detailed tracking Detailed tracking is disabled by default. Controlled by persist.sys.binder_calls_detailed_tracking Added commands to reset and enable/disable detailed stats: dumpsys binder_calls_stats --reset dumpsys binder_calls_stats --enable-detailed-tracking dumpsys binder_calls_stats --disable-detailed-tracking Test: manual Bug: 75318418 Change-Id: I7c1280c025001b6d2b46e4a37bad841712b6da2f
Diffstat (limited to 'core/java')
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java142
1 files changed, 79 insertions, 63 deletions
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 2c48506494bc..7eefe59d4696 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -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,32 +72,31 @@ 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);
}
- // 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
- if (callStat == null) {
- callStat = new CallStat(s.mCallStat.className, s.mCallStat.msg);
- uidEntry.mCallStats.put(callStat, callStat);
+ 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
+ if (callStat == null) {
+ callStat = new CallStat(s.mCallStat.className, s.mCallStat.msg);
+ uidEntry.mCallStats.put(callStat, callStat);
+ }
+ callStat.callCount++;
+ callStat.time += duration;
}
+
uidEntry.time += duration;
uidEntry.callCount++;
- callStat.callCount++;
- callStat.time += duration;
}
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,20 +125,10 @@ public class BinderCallsStats {
totalCallsCount += e.callCount;
}
}
- pw.println("Binder call stats:");
- pw.println(" Raw data (uid,call_desc,time):");
- entries.sort((o1, o2) -> {
- if (o1.time < o2.time) {
- return 1;
- } else if (o1.time > o2.time) {
- return -1;
- }
- return 0;
- });
- StringBuilder sb = new StringBuilder();
- for (UidEntry uidEntry : entries) {
- List<CallStat> callStats = new ArrayList<>(uidEntry.mCallStats.keySet());
- callStats.sort((o1, o2) -> {
+ if (mDetailedTracking) {
+ pw.println("Binder call stats:");
+ pw.println(" Raw data (uid,call_desc,time):");
+ entries.sort((o1, o2) -> {
if (o1.time < o2.time) {
return 1;
} else if (o1.time > o2.time) {
@@ -148,44 +136,72 @@ public class BinderCallsStats {
}
return 0;
});
- for (CallStat e : callStats) {
- sb.setLength(0);
- sb.append(" ")
- .append(uidEntry.uid).append(",").append(e).append(',').append(e.time);
- pw.println(sb);
+ StringBuilder sb = new StringBuilder();
+ for (UidEntry uidEntry : entries) {
+ List<CallStat> callStats = new ArrayList<>(uidEntry.mCallStats.keySet());
+ callStats.sort((o1, o2) -> {
+ if (o1.time < o2.time) {
+ return 1;
+ } else if (o1.time > o2.time) {
+ return -1;
+ }
+ return 0;
+ });
+ for (CallStat e : callStats) {
+ sb.setLength(0);
+ sb.append(" ")
+ .append(uidEntry.uid).append(",").append(e).append(',').append(e.time);
+ pw.println(sb);
+ }
+ }
+ pw.println();
+ 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(" %7d: %11d %3.0f%% %8d",
+ uidTotal.getKey(), uidTotal.getValue(),
+ 100d * uidTotal.getValue() / totalCallsTime, callCount));
+ }
+ pw.println();
+ pw.println(String.format(" Summary: total_time=%d, "
+ + "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));
}
}
- pw.println();
- pw.println(" Per UID Summary(UID: time, total_time_percentage, 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",
- uidTotal.getKey(), uidTotal.getValue(),
- 100d * uidTotal.getValue() / totalCallsTime, callCount));
- }
- pw.println();
- pw.println(String.format(" Summary: total_time=%d, "
- + "calls_count=%d, avg_call_time=%.0f",
- totalCallsTime, totalCallsCount,
- (double)totalCallsTime / totalCallsCount));
}
- 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