From e69ade3545864e7271806d071825ec37486d5d37 Mon Sep 17 00:00:00 2001 From: Rafal Slawik Date: Tue, 8 Dec 2020 00:27:16 +0000 Subject: [PATCH] Combine uids for CpuTimePerUidFreq atom The puller for the atom frequently fails. We believe it is due to the size of the pulled atoms. No metric can be correctly build from this atom. To reduce the size, we apply transformations that we would likely perform when analyzing this data. We combine times for all shared app gids together and combine times for the same apps. We also exclude isolated uids which are frequently recycled and removed from the underlying data source. If these optimization do not help, we will need to introduce different atoms. Bug: 157535126 Test: cmd stats pull-source 10010 Change-Id: I0d9a18c78f456e1b0f9d7ad322f15354ead9f02b --- core/java/android/os/UserHandle.java | 8 ++++ .../stats/pull/StatsPullAtomService.java | 48 +++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index d6720248720a4..7e50ebc419dd2 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -222,6 +222,14 @@ public final class UserHandle implements Parcelable { } } + /** + * Whether a UID belongs to a shared app gid. + * @hide + */ + public static boolean isSharedAppGid(int uid) { + return getAppIdFromSharedAppGid(uid) != -1; + } + /** * Returns the user for a given uid. * @param uid A uid for an application running in a particular user. diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index cf20cf4c0c9f1..49f9b311d95c8 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -31,6 +31,7 @@ import static android.net.NetworkTemplate.buildTemplateMobileWithRatType; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.NetworkTemplate.getAllCollapsedRatTypes; import static android.os.Debug.getIonHeapsSizeKb; +import static android.os.Process.LAST_SHARED_APPLICATION_GID; import static android.os.Process.getUidForPid; import static android.os.storage.VolumeInfo.TYPE_PRIVATE; import static android.os.storage.VolumeInfo.TYPE_PUBLIC; @@ -1517,14 +1518,53 @@ public class StatsPullAtomService extends SystemService { } int pullCpuTimePerUidFreqLocked(int atomTag, List pulledData) { + // Aggregate times for the same uids. + SparseArray aggregated = new SparseArray<>(); mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> { - for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) { - if (cpuFreqTimeMs[freqIndex] >= MIN_CPU_TIME_PER_UID_FREQ) { - pulledData.add(FrameworkStatsLog.buildStatsEvent( - atomTag, uid, freqIndex, cpuFreqTimeMs[freqIndex])); + // For uids known to be aggregated from many entries allow mutating in place to avoid + // many copies. Otherwise, copy before aggregating. + boolean mutateInPlace = false; + if (UserHandle.isIsolated(uid)) { + // Skip individual isolated uids because they are recycled and quickly removed from + // the underlying data source. + return; + } else if (UserHandle.isSharedAppGid(uid)) { + // All shared app gids are accounted together. + uid = LAST_SHARED_APPLICATION_GID; + mutateInPlace = true; + } else if (UserHandle.isApp(uid)) { + // Apps are accounted under their app id. + uid = UserHandle.getAppId(uid); + } + + long[] aggCpuFreqTimeMs = aggregated.get(uid); + if (aggCpuFreqTimeMs != null) { + if (!mutateInPlace) { + aggCpuFreqTimeMs = Arrays.copyOf(aggCpuFreqTimeMs, cpuFreqTimeMs.length); + aggregated.put(uid, aggCpuFreqTimeMs); } + for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) { + aggCpuFreqTimeMs[freqIndex] += cpuFreqTimeMs[freqIndex]; + } + } else { + if (mutateInPlace) { + cpuFreqTimeMs = Arrays.copyOf(cpuFreqTimeMs, cpuFreqTimeMs.length); + } + aggregated.put(uid, cpuFreqTimeMs); } }); + + int size = aggregated.size(); + for (int i = 0; i < size; ++i) { + int uid = aggregated.keyAt(i); + long[] aggCpuFreqTimeMs = aggregated.valueAt(i); + for (int freqIndex = 0; freqIndex < aggCpuFreqTimeMs.length; ++freqIndex) { + if (aggCpuFreqTimeMs[freqIndex] >= MIN_CPU_TIME_PER_UID_FREQ) { + pulledData.add(FrameworkStatsLog.buildStatsEvent( + atomTag, uid, freqIndex, aggCpuFreqTimeMs[freqIndex])); + } + } + } return StatsManager.PULL_SUCCESS; }