From 57dc86afc0392c268073828d6947f6d0c082bbc8 Mon Sep 17 00:00:00 2001 From: Richard Gaywood Date: Thu, 12 Mar 2020 17:57:10 +0000 Subject: [PATCH] Implement procsstats data agggregation Aggregation of procstats data is done to a subset of total possible process states; this reduces total data footprint. Change-Id: Ia1528c5ca33bafcb992e34d5fec53156d357b9e1 Test: make, flash (code not yet invoked) Bug: 145203981 Merged-In: Ia1528c5ca33bafcb992e34d5fec53156d357b9e1 (cherry picked from commit 1651ad3c3a9896c5cd4b8cde3b7d6192d50284ae) --- .../internal/app/procstats/DumpUtils.java | 7 + .../internal/app/procstats/ProcessState.java | 135 +++++++++++++++--- .../internal/app/procstats/PssTable.java | 17 ++- 3 files changed, 137 insertions(+), 22 deletions(-) diff --git a/core/java/com/android/internal/app/procstats/DumpUtils.java b/core/java/com/android/internal/app/procstats/DumpUtils.java index ea41618a982f4..fc5381e13dd29 100644 --- a/core/java/com/android/internal/app/procstats/DumpUtils.java +++ b/core/java/com/android/internal/app/procstats/DumpUtils.java @@ -539,4 +539,11 @@ public final class DumpUtils { // Pack screen & process state using bit shifting return (procStateIndex << 8) | screenStateIndex; } + + /** Print aggregated tags generated via {@code #aggregateCurrentProcessState}. */ + public static void printAggregatedProcStateTagProto(ProtoOutputStream proto, long screenId, + long stateId, int state) { + proto.write(screenId, ADJ_SCREEN_PROTO_ENUMS[state >> 8]); + proto.write(stateId, STATE_PROTO_ENUMS[state]); + } } diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java index a6bed5bdfedce..fa9785c6a21eb 100644 --- a/core/java/com/android/internal/app/procstats/ProcessState.java +++ b/core/java/com/android/internal/app/procstats/ProcessState.java @@ -16,22 +16,6 @@ package com.android.internal.app.procstats; -import android.os.Parcel; -import android.os.SystemClock; -import android.os.UserHandle; -import android.service.procstats.ProcessStatsProto; -import android.service.procstats.ProcessStatsStateProto; -import android.util.ArrayMap; -import android.util.DebugUtils; -import android.util.Log; -import android.util.LongSparseArray; -import android.util.Slog; -import android.util.SparseLongArray; -import android.util.TimeUtils; -import android.util.proto.ProtoOutputStream; -import android.util.proto.ProtoUtils; - - import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE; import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT; import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM; @@ -60,6 +44,21 @@ import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE; import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING; import static com.android.internal.app.procstats.ProcessStats.STATE_TOP; +import android.os.Parcel; +import android.os.SystemClock; +import android.os.UserHandle; +import android.service.procstats.ProcessStatsProto; +import android.service.procstats.ProcessStatsStateProto; +import android.util.ArrayMap; +import android.util.DebugUtils; +import android.util.Log; +import android.util.LongSparseArray; +import android.util.Slog; +import android.util.SparseLongArray; +import android.util.TimeUtils; +import android.util.proto.ProtoOutputStream; +import android.util.proto.ProtoUtils; + import com.android.internal.app.procstats.ProcessStats.PackageState; import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder; import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection; @@ -1418,4 +1417,108 @@ public final class ProcessState { proto.end(token); } + + /** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */ + public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId, + String procName, int uid, long now) { + // Group proc stats by aggregated type (only screen state + process state) + SparseLongArray durationByState = new SparseLongArray(); + boolean didCurState = false; + for (int i = 0; i < mDurations.getKeyCount(); i++) { + final int key = mDurations.getKeyAt(i); + final int type = SparseMappingTable.getIdFromKey(key); + final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type); + + long time = mDurations.getValue(key); + if (mCurCombinedState == type) { + didCurState = true; + time += now - mStartTime; + } + int index = durationByState.indexOfKey(aggregatedType); + if (index >= 0) { + durationByState.put(aggregatedType, time + durationByState.valueAt(aggregatedType)); + } else { + durationByState.put(aggregatedType, time); + } + } + if (!didCurState && mCurCombinedState != STATE_NOTHING) { + final int aggregatedType = DumpUtils.aggregateCurrentProcessState(mCurCombinedState); + int index = durationByState.indexOfKey(aggregatedType); + if (index >= 0) { + durationByState.put(aggregatedType, + (now - mStartTime) + durationByState.valueAt(index)); + } else { + durationByState.put(aggregatedType, now - mStartTime); + } + } + + // Now we have total durations, aggregate the RSS values + SparseLongArray meanRssByState = new SparseLongArray(); + SparseLongArray maxRssByState = new SparseLongArray(); + // compute weighted averages and max-of-max + for (int i = 0; i < mPssTable.getKeyCount(); i++) { + final int key = mPssTable.getKeyAt(i); + final int type = SparseMappingTable.getIdFromKey(key); + if (durationByState.indexOfKey(type) < 0) { + // state without duration should not have stats! + continue; + } + final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type); + + long[] rssMeanAndMax = mPssTable.getRssMeanAndMax(key); + + // compute mean * duration, then store sum of that in meanRssByState + long meanTimesDuration = rssMeanAndMax[0] * mDurations.getValue(key); + if (meanRssByState.indexOfKey(aggregatedType) >= 0) { + meanRssByState.put(aggregatedType, + meanTimesDuration + meanRssByState.get(aggregatedType)); + } else { + meanRssByState.put(aggregatedType, meanTimesDuration); + } + + // accumulate max-of-maxes in maxRssByState + if (maxRssByState.indexOfKey(aggregatedType) >= 0 + && maxRssByState.get(aggregatedType) < rssMeanAndMax[1]) { + maxRssByState.put(aggregatedType, rssMeanAndMax[1]); + } else if (maxRssByState.indexOfKey(aggregatedType) < 0) { + maxRssByState.put(aggregatedType, rssMeanAndMax[1]); + } + } + + // divide the means by the durations to get the weighted mean-of-means + for (int i = 0; i < durationByState.size(); i++) { + int aggregatedKey = durationByState.keyAt(i); + if (meanRssByState.indexOfKey(aggregatedKey) < 0) { + // these data structures should be consistent + continue; + } + meanRssByState.put(aggregatedKey, + meanRssByState.get(aggregatedKey) / durationByState.get(aggregatedKey)); + } + + // build the output + final long token = proto.start(fieldId); + proto.write(ProcessStatsProto.PROCESS, procName); + proto.write(ProcessStatsProto.UID, uid); + + for (int i = 0; i < durationByState.size(); i++) { + final int aggregatedKey = mPssTable.getKeyAt(i); + + final long stateToken = proto.start(ProcessStatsProto.STATES); + DumpUtils.printAggregatedProcStateTagProto(proto, + ProcessStatsStateProto.SCREEN_STATE, + ProcessStatsStateProto.PROCESS_STATE, + durationByState.keyAt(i)); + proto.write(ProcessStatsStateProto.DURATION_MS, durationByState.valueAt(i)); + + ProtoUtils.toAggStatsProto(proto, ProcessStatsStateProto.RSS, + 0, /* do not output a minimum value */ + meanRssByState.get(aggregatedKey), + maxRssByState.get(aggregatedKey)); + + proto.end(stateToken); + } + + proto.end(token); + } } diff --git a/core/java/com/android/internal/app/procstats/PssTable.java b/core/java/com/android/internal/app/procstats/PssTable.java index fc93c3a0094e3..a6bae6e05dbc9 100644 --- a/core/java/com/android/internal/app/procstats/PssTable.java +++ b/core/java/com/android/internal/app/procstats/PssTable.java @@ -16,17 +16,17 @@ package com.android.internal.app.procstats; +import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE; +import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT; +import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM; +import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM; import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_AVERAGE; import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MAXIMUM; import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM; import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT; -import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM; -import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE; -import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM; -import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM; import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE; import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM; -import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT; +import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM; import android.service.procstats.ProcessStatsStateProto; import android.util.proto.ProtoOutputStream; @@ -133,7 +133,6 @@ public class PssTable extends SparseMappingTable.Table { } if (stats[statsIndex + PSS_RSS_MINIMUM] > minRss) { - stats[statsIndex + PSS_RSS_MINIMUM] = minRss; } stats[statsIndex + PSS_RSS_AVERAGE] = (long)(((stats[statsIndex + PSS_RSS_AVERAGE] @@ -167,4 +166,10 @@ public class PssTable extends SparseMappingTable.Table { stats[statsIndex + PSS_RSS_AVERAGE], stats[statsIndex + PSS_RSS_MAXIMUM]); } + + long[] getRssMeanAndMax(int key) { + final long[] stats = getArrayForKey(key); + final int statsIndex = SparseMappingTable.getIndexFromKey(key); + return new long[]{stats[statsIndex + PSS_RSS_AVERAGE], stats[statsIndex + PSS_RSS_MAXIMUM]}; + } }