Loading apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java +0 −1 Original line number Diff line number Diff line Loading @@ -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); Loading core/java/com/android/internal/os/BinderCallsStats.java +79 −63 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -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 Loading @@ -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); } Loading @@ -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); Loading @@ -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) -> { Loading Loading @@ -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)); } Loading @@ -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 { Loading @@ -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 Loading services/core/java/com/android/server/BinderCallsStatsService.java +41 −9 Original line number Diff line number Diff line Loading @@ -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); } } Loading
apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java +0 −1 Original line number Diff line number Diff line Loading @@ -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); Loading
core/java/com/android/internal/os/BinderCallsStats.java +79 −63 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -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 Loading @@ -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); } Loading @@ -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); Loading @@ -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) -> { Loading Loading @@ -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)); } Loading @@ -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 { Loading @@ -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 Loading
services/core/java/com/android/server/BinderCallsStatsService.java +41 −9 Original line number Diff line number Diff line Loading @@ -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); } }