summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-02-06 13:41:06 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-02-06 13:41:06 -0800
commit4c8649b8ad2d97def7e4734e554b426c7aade07c (patch)
tree5e709847f3531ba84a1ff8b07c527874df96fe45
parentd5adc1d1f86dc53816a770c52621774091c0a876 (diff)
parentf2d5f7f127efd4fa8ca9e7aef6ae2099257b1d4b (diff)
Merge "Refactor compaction stats related code to its own classes" into main
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java14
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java1
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java452
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java1
-rw-r--r--services/core/java/com/android/server/am/compaction/AggregatedCompactionStats.java124
-rw-r--r--services/core/java/com/android/server/am/compaction/AggregatedProcessCompactionStats.java23
-rw-r--r--services/core/java/com/android/server/am/compaction/AggregatedSourceCompactionStats.java27
-rw-r--r--services/core/java/com/android/server/am/compaction/CompactionStatsManager.java320
-rw-r--r--services/core/java/com/android/server/am/compaction/OWNERS5
-rw-r--r--services/core/java/com/android/server/am/compaction/SingleCompactionStats.java94
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java82
11 files changed, 700 insertions, 443 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7db63a5c4a11..f34016905502 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10430,9 +10430,7 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized(this) {
mConstants.dump(pw);
- synchronized (mProcLock) {
- mOomAdjuster.dumpCachedAppOptimizerSettings(pw);
- }
+ mOomAdjuster.dumpCachedAppOptimizerSettings(pw);
mOomAdjuster.dumpCacheOomRankerSettings(pw);
pw.println();
if (dumpAll) {
@@ -10806,7 +10804,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|| DUMP_RECENTS_CMD.equals(cmd) || DUMP_RECENTS_SHORT_CMD.equals(cmd)
|| DUMP_TOP_RESUMED_ACTIVITY.equals(cmd)
|| DUMP_VISIBLE_ACTIVITIES.equals(cmd)) {
- mAtmInternal.dump(cmd, fd, pw, args, opti, /* dumpAll= */ true , dumpClient,
+ mAtmInternal.dump(cmd, fd, pw, args, opti, /* dumpAll= */ true, dumpClient,
dumpPackage, dumpDisplayId);
} else if ("binder-proxies".equals(cmd)) {
if (opti >= args.length) {
@@ -10896,7 +10894,8 @@ public class ActivityManagerService extends IActivityManager.Stub
name = args[opti];
opti++;
newArgs = new String[args.length - opti];
- if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
+ if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
+ args.length - opti);
}
if (!mCpHelper.dumpProvider(fd, pw, name, newArgs, 0, dumpAll)) {
pw.println("No providers match: " + name);
@@ -10919,7 +10918,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
args.length - opti);
}
- int[] users = dumpUserId == UserHandle.USER_ALL ? null : new int[] { dumpUserId };
+ int[] users = dumpUserId == UserHandle.USER_ALL ? null : new int[]{dumpUserId};
if (!mServices.dumpService(fd, pw, name, users, newArgs, 0, dumpAll)) {
pw.println("No services match: " + name);
pw.println("Use -h for help.");
@@ -10948,9 +10947,10 @@ public class ActivityManagerService extends IActivityManager.Stub
mConstants.dump(pw);
}
synchronized (mProcLock) {
- mOomAdjuster.dumpCachedAppOptimizerSettings(pw);
mOomAdjuster.dumpCacheOomRankerSettings(pw);
}
+ } else if ("cao".equals(cmd)) {
+ mOomAdjuster.dumpCachedAppOptimizerSettings(pw);
} else if ("timers".equals(cmd)) {
AnrTimer.dump(pw, true);
} else if ("services".equals(cmd) || "s".equals(cmd)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index c237897f1229..5c2bd0a0e90f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -4344,6 +4344,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" lru: raw LRU process list");
pw.println(" binder-proxies: stats on binder objects and IPCs");
pw.println(" settings: currently applied config settings");
+ pw.println(" cao: cached app optimizer state");
pw.println(" timers: the current ANR timer state");
pw.println(" service [COMP_SPEC]: service client-side state");
pw.println(" package [PACKAGE_NAME]: all state related to given package");
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index ce526e510053..b677297dfef2 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -85,6 +85,8 @@ import com.android.internal.os.BinderfsStatsReader;
import com.android.internal.os.ProcLocksReader;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.ServiceThread;
+import com.android.server.am.compaction.CompactionStatsManager;
+import com.android.server.am.compaction.SingleCompactionStats;
import dalvik.annotation.optimization.NeverCompile;
@@ -94,11 +96,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.EnumMap;
import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -343,12 +341,6 @@ public class CachedAppOptimizer {
// on swap resources as file.
static final double COMPACT_DOWNGRADE_FREE_SWAP_THRESHOLD = 0.2;
- // Size of history for the last 20 compactions for any process
- static final int LAST_COMPACTED_ANY_PROCESS_STATS_HISTORY_SIZE = 20;
-
- // Amount of processes supported to record for their last compaction.
- static final int LAST_COMPACTION_FOR_PROCESS_STATS_SIZE = 256;
-
static final int DO_FREEZE = 1;
static final int REPORT_UNFREEZE = 2;
@@ -521,6 +513,9 @@ public class CachedAppOptimizer {
// Handler on which compaction runs.
@VisibleForTesting
Handler mCompactionHandler;
+ @VisibleForTesting
+ CompactionStatsManager mCompactStatsManager;
+
private Handler mFreezeHandler;
@GuardedBy("mProcLock")
private boolean mFreezerOverride = false;
@@ -529,156 +524,6 @@ public class CachedAppOptimizer {
@VisibleForTesting volatile long mFreezerDebounceTimeout = DEFAULT_FREEZER_DEBOUNCE_TIMEOUT;
@VisibleForTesting volatile boolean mFreezerExemptInstPkg = DEFAULT_FREEZER_EXEMPT_INST_PKG;
- // Maps process ID to last compaction statistics for processes that we've fully compacted. Used
- // when evaluating throttles that we only consider for "full" compaction, so we don't store
- // data for "some" compactions. Uses LinkedHashMap to ensure insertion order is kept and
- // facilitate removal of the oldest entry.
- @VisibleForTesting
- @GuardedBy("mProcLock")
- LinkedHashMap<Integer, SingleCompactionStats> mLastCompactionStats =
- new LinkedHashMap<Integer, SingleCompactionStats>() {
- @Override
- protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > LAST_COMPACTION_FOR_PROCESS_STATS_SIZE;
- }
- };
-
- LinkedList<SingleCompactionStats> mCompactionStatsHistory =
- new LinkedList<SingleCompactionStats>() {
- @Override
- public boolean add(SingleCompactionStats e) {
- if (size() >= LAST_COMPACTED_ANY_PROCESS_STATS_HISTORY_SIZE) {
- this.remove();
- }
- return super.add(e);
- }
- };
-
- class AggregatedCompactionStats {
- // Throttling stats
- public long mFullCompactRequested;
- public long mSomeCompactRequested;
- public long mFullCompactPerformed;
- public long mSomeCompactPerformed;
- public long mProcCompactionsNoPidThrottled;
- public long mProcCompactionsOomAdjThrottled;
- public long mProcCompactionsTimeThrottled;
- public long mProcCompactionsRSSThrottled;
- public long mProcCompactionsMiscThrottled;
-
- // Memory stats
- public long mTotalDeltaAnonRssKBs;
- public long mTotalZramConsumedKBs;
- public long mTotalAnonMemFreedKBs;
- public long mSumOrigAnonRss;
- public double mMaxCompactEfficiency;
- public double mMaxSwapEfficiency;
-
- // Cpu time
- public long mTotalCpuTimeMillis;
-
- public long getThrottledSome() { return mSomeCompactRequested - mSomeCompactPerformed; }
-
- public long getThrottledFull() { return mFullCompactRequested - mFullCompactPerformed; }
-
- public void addMemStats(long anonRssSaved, long zramConsumed, long memFreed,
- long origAnonRss, long totalCpuTimeMillis) {
- final double compactEfficiency = memFreed / (double) origAnonRss;
- if (compactEfficiency > mMaxCompactEfficiency) {
- mMaxCompactEfficiency = compactEfficiency;
- }
- final double swapEfficiency = anonRssSaved / (double) origAnonRss;
- if (swapEfficiency > mMaxSwapEfficiency) {
- mMaxSwapEfficiency = swapEfficiency;
- }
- mTotalDeltaAnonRssKBs += anonRssSaved;
- mTotalZramConsumedKBs += zramConsumed;
- mTotalAnonMemFreedKBs += memFreed;
- mSumOrigAnonRss += origAnonRss;
- mTotalCpuTimeMillis += totalCpuTimeMillis;
- }
-
- @NeverCompile
- public void dump(PrintWriter pw) {
- long totalCompactRequested = mSomeCompactRequested + mFullCompactRequested;
- long totalCompactPerformed = mSomeCompactPerformed + mFullCompactPerformed;
- pw.println(" Performed / Requested:");
- pw.println(" Some: (" + mSomeCompactPerformed + "/" + mSomeCompactRequested + ")");
- pw.println(" Full: (" + mFullCompactPerformed + "/" + mFullCompactRequested + ")");
-
- long throttledSome = getThrottledSome();
- long throttledFull = getThrottledFull();
-
- if (throttledSome > 0 || throttledFull > 0) {
- pw.println(" Throttled:");
- pw.println(" Some: " + throttledSome + " Full: " + throttledFull);
- pw.println(" Throttled by Type:");
- final long compactionsThrottled = totalCompactRequested - totalCompactPerformed;
- // Any throttle that was not part of the previous categories
- final long unaccountedThrottled = compactionsThrottled
- - mProcCompactionsNoPidThrottled - mProcCompactionsOomAdjThrottled
- - mProcCompactionsTimeThrottled - mProcCompactionsRSSThrottled
- - mProcCompactionsMiscThrottled;
- pw.println(" NoPid: " + mProcCompactionsNoPidThrottled
- + " OomAdj: " + mProcCompactionsOomAdjThrottled + " Time: "
- + mProcCompactionsTimeThrottled + " RSS: " + mProcCompactionsRSSThrottled
- + " Misc: " + mProcCompactionsMiscThrottled
- + " Unaccounted: " + unaccountedThrottled);
- final double compactThrottlePercentage =
- (compactionsThrottled / (double) totalCompactRequested) * 100.0;
- pw.println(" Throttle Percentage: " + compactThrottlePercentage);
- }
-
- if (mFullCompactPerformed > 0) {
- pw.println(" -----Memory Stats----");
- pw.println(" Total Delta Anon RSS (KB) : " + mTotalDeltaAnonRssKBs);
- pw.println(" Total Physical ZRAM Consumed (KB): " + mTotalZramConsumedKBs);
- // Anon Mem Freed = Delta Anon RSS - ZRAM Consumed
- pw.println(" Total Anon Memory Freed (KB): " + mTotalAnonMemFreedKBs);
- pw.println(" Avg Swap Efficiency (KB) (Delta Anon RSS/Orig Anon RSS): "
- + (mTotalDeltaAnonRssKBs / (double) mSumOrigAnonRss));
- pw.println(" Max Swap Efficiency: " + mMaxSwapEfficiency);
- // This tells us how much anon memory we were able to free thanks to running
- // compaction
- pw.println(" Avg Compaction Efficiency (Anon Freed/Anon RSS): "
- + (mTotalAnonMemFreedKBs / (double) mSumOrigAnonRss));
- pw.println(" Max Compaction Efficiency: " + mMaxCompactEfficiency);
- // This tells us how effective is the compression algorithm in physical memory
- pw.println(" Avg Compression Ratio (1 - ZRAM Consumed/DeltaAnonRSS): "
- + (1.0 - mTotalZramConsumedKBs / (double) mTotalDeltaAnonRssKBs));
- long avgKBsPerProcCompact = mFullCompactPerformed > 0
- ? (mTotalAnonMemFreedKBs / mFullCompactPerformed)
- : 0;
- pw.println(" Avg Anon Mem Freed/Compaction (KB) : " + avgKBsPerProcCompact);
- double compactionCost =
- mTotalCpuTimeMillis / (mTotalAnonMemFreedKBs / 1024.0); // ms/MB
- pw.println(" Compaction Cost (ms/MB): " + compactionCost);
- }
- }
- }
-
- class AggregatedProcessCompactionStats extends AggregatedCompactionStats {
- public final String processName;
-
- AggregatedProcessCompactionStats(String processName) { this.processName = processName; }
- }
-
- class AggregatedSourceCompactionStats extends AggregatedCompactionStats {
- public final CompactSource sourceType;
-
- AggregatedSourceCompactionStats(CompactSource sourceType) { this.sourceType = sourceType; }
- }
-
- private final LinkedHashMap<String, AggregatedProcessCompactionStats> mPerProcessCompactStats =
- new LinkedHashMap<>(256);
- private final EnumMap<CompactSource, AggregatedSourceCompactionStats> mPerSourceCompactStats =
- new EnumMap<>(CompactSource.class);
- private long mTotalCompactionDowngrades;
- private long mSystemCompactionsPerformed;
- private long mSystemTotalMemFreed;
- private EnumMap<CancelCompactReason, Integer> mTotalCompactionsCancelled =
- new EnumMap<>(CancelCompactReason.class);
-
private final ProcessDependencies mProcessDependencies;
private final ProcLocksReader mProcLocksReader;
@@ -758,10 +603,15 @@ public class CachedAppOptimizer {
}
}
- @GuardedBy("mProcLock")
@NeverCompile
void dump(PrintWriter pw) {
- pw.println("CachedAppOptimizer settings");
+ dumpCompact(pw);
+ dumpFreezer(pw);
+ }
+
+ @NeverCompile
+ void dumpCompact(PrintWriter pw) {
+ pw.println("Compaction settings");
synchronized (mPhenotypeFlagLock) {
pw.println(" " + KEY_USE_COMPACTION + "=" + mUseCompaction);
pw.println(" " + KEY_COMPACT_THROTTLE_1 + "=" + mCompactThrottleSomeSome);
@@ -775,66 +625,30 @@ public class CachedAppOptimizer {
+ mFullAnonRssThrottleKb);
pw.println(" " + KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + "="
+ mFullDeltaRssThrottleKb);
- pw.println(" " + KEY_COMPACT_PROC_STATE_THROTTLE + "="
+ pw.println(" " + KEY_COMPACT_PROC_STATE_THROTTLE + "="
+ Arrays.toString(mProcStateThrottle.toArray(new Integer[0])));
+ }
- pw.println(" Per-Process Compaction Stats");
- long totalCompactPerformedSome = 0;
- long totalCompactPerformedFull = 0;
- for (AggregatedProcessCompactionStats stats : mPerProcessCompactStats.values()) {
- pw.println("-----" + stats.processName + "-----");
- totalCompactPerformedSome += stats.mSomeCompactPerformed;
- totalCompactPerformedFull += stats.mFullCompactPerformed;
- stats.dump(pw);
- pw.println();
- }
- pw.println();
- pw.println(" Per-Source Compaction Stats");
- for (AggregatedSourceCompactionStats stats : mPerSourceCompactStats.values()) {
- pw.println("-----" + stats.sourceType + "-----");
- stats.dump(pw);
- pw.println();
- }
- pw.println();
-
- pw.println("Total Compactions Performed by profile: " + totalCompactPerformedSome
- + " some, " + totalCompactPerformedFull + " full");
- pw.println("Total compactions downgraded: " + mTotalCompactionDowngrades);
- pw.println("Total compactions cancelled by reason: ");
- for (CancelCompactReason reason : mTotalCompactionsCancelled.keySet()) {
- pw.println(" " + reason + ": " + mTotalCompactionsCancelled.get(reason));
- }
- pw.println();
-
- pw.println(" System Compaction Memory Stats");
- pw.println(" Compactions Performed: " + mSystemCompactionsPerformed);
- pw.println(" Total Memory Freed (KB): " + mSystemTotalMemFreed);
- double avgKBsPerSystemCompact = mSystemCompactionsPerformed > 0
- ? mSystemTotalMemFreed / mSystemCompactionsPerformed
- : 0;
- pw.println(" Avg Mem Freed per Compact (KB): " + avgKBsPerSystemCompact);
- pw.println();
- pw.println(" Tracking last compaction stats for " + mLastCompactionStats.size()
- + " processes.");
- pw.println("Last Compaction per process stats:");
- pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs"
- + ",SwapEfficiency,CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,"
- + "oomAdjReason)");
- for (Map.Entry<Integer, SingleCompactionStats> entry :
- mLastCompactionStats.entrySet()) {
- SingleCompactionStats stats = entry.getValue();
- stats.dump(pw);
- }
- pw.println();
- pw.println("Last 20 Compactions Stats:");
- pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs,"
- + "SwapEfficiency,CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,"
- + "oomAdjReason)");
- for (SingleCompactionStats stats : mCompactionStatsHistory) {
- stats.dump(pw);
+ mCompactStatsManager.dump(pw);
+
+ synchronized (mProcLock) {
+ if (!mPendingCompactionProcesses.isEmpty()) {
+ pw.println(" Pending compactions:");
+ int size = mPendingCompactionProcesses.size();
+ for (int i = 0; i < size; i++) {
+ ProcessRecord app = mPendingCompactionProcesses.get(i);
+ pw.println(" pid: " + app.getPid() + ". name: " + app.processName
+ + ". hasPendingCompact: " + app.mOptRecord.hasPendingCompact());
+ }
}
- pw.println();
+ }
+ pw.println();
+ }
+ @NeverCompile
+ void dumpFreezer(PrintWriter pw) {
+ pw.println("Freezer settings");
+ synchronized (mPhenotypeFlagLock) {
pw.println(" " + KEY_USE_FREEZER + "=" + mUseFreezer);
pw.println(" " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate);
pw.println(" " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout);
@@ -858,16 +672,6 @@ public class CachedAppOptimizer {
+ " " + app.processName
+ (app.mOptRecord.isFreezeSticky() ? " (sticky)" : ""));
}
-
- if (!mPendingCompactionProcesses.isEmpty()) {
- pw.println(" Pending compactions:");
- size = mPendingCompactionProcesses.size();
- for (int i = 0; i < size; i++) {
- ProcessRecord app = mPendingCompactionProcesses.get(i);
- pw.println(" pid: " + app.getPid() + ". name: " + app.processName
- + ". hasPendingCompact: " + app.mOptRecord.hasPendingCompact());
- }
- }
}
}
}
@@ -877,26 +681,14 @@ public class CachedAppOptimizer {
ProcessRecord app, CompactProfile compactProfile, CompactSource source, boolean force) {
app.mOptRecord.setReqCompactSource(source);
app.mOptRecord.setReqCompactProfile(compactProfile);
- AggregatedSourceCompactionStats perSourceStats = getPerSourceAggregatedCompactStat(source);
- AggregatedCompactionStats perProcStats =
- getPerProcessAggregatedCompactStat(app.processName);
- switch (compactProfile) {
- case SOME:
- ++perProcStats.mSomeCompactRequested;
- ++perSourceStats.mSomeCompactRequested;
- break;
- case FULL:
- ++perProcStats.mFullCompactRequested;
- ++perSourceStats.mFullCompactRequested;
- break;
- default:
- Slog.e(TAG_AM,
- "Unimplemented compaction type, consider adding it.");
- return false;
+
+ if(compactProfile == null || compactProfile.equals(CompactProfile.NONE)) {
+ return false;
}
+ final String processName = (app.processName != null ? app.processName : "");
+ mCompactStatsManager.logCompactionRequested(source, compactProfile, processName);
if (!app.mOptRecord.hasPendingCompact()) {
- final String processName = (app.processName != null ? app.processName : "");
if (DEBUG_COMPACTION) {
Slog.d(TAG_AM,
"compactApp " + app.mOptRecord.getReqCompactSource().name() + " "
@@ -925,29 +717,6 @@ public class CachedAppOptimizer {
COMPACT_NATIVE_MSG, pid, compactProfile.ordinal()));
}
- private AggregatedProcessCompactionStats getPerProcessAggregatedCompactStat(
- String processName) {
- if (processName == null) {
- processName = "";
- }
- AggregatedProcessCompactionStats stats = mPerProcessCompactStats.get(processName);
- if (stats == null) {
- stats = new AggregatedProcessCompactionStats(processName);
- mPerProcessCompactStats.put(processName, stats);
- }
- return stats;
- }
-
- private AggregatedSourceCompactionStats getPerSourceAggregatedCompactStat(
- CompactSource source) {
- AggregatedSourceCompactionStats stats = mPerSourceCompactStats.get(source);
- if (stats == null) {
- stats = new AggregatedSourceCompactionStats(source);
- mPerSourceCompactStats.put(source, stats);
- }
- return stats;
- }
-
void compactAllSystem() {
if (useCompaction()) {
if (DEBUG_COMPACTION) {
@@ -1008,6 +777,7 @@ public class CachedAppOptimizer {
}
mCompactionHandler = new MemCompactionHandler();
+ mCompactStatsManager = CompactionStatsManager.getInstance();
Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
Process.THREAD_GROUP_SYSTEM);
@@ -1667,12 +1437,7 @@ public class CachedAppOptimizer {
cancelled = true;
}
if (cancelled) {
- if (mTotalCompactionsCancelled.containsKey(cancelReason)) {
- int count = mTotalCompactionsCancelled.get(cancelReason);
- mTotalCompactionsCancelled.put(cancelReason, count + 1);
- } else {
- mTotalCompactionsCancelled.put(cancelReason, 1);
- }
+ mCompactStatsManager.logCompactionCancelled(cancelReason);
if (DEBUG_COMPACTION) {
Slog.d(TAG_AM,
"Cancelled pending or running compactions for process: " +
@@ -1722,8 +1487,7 @@ public class CachedAppOptimizer {
// Downgrade compaction under swap memory pressure
if (swapFreePercent < COMPACT_DOWNGRADE_FREE_SWAP_THRESHOLD) {
profile = CompactProfile.SOME;
-
- ++mTotalCompactionDowngrades;
+ mCompactStatsManager.logCompactionDowngrade();
if (DEBUG_COMPACTION) {
Slog.d(TAG_AM,
"Downgraded compaction to "+ profile +" due to low swap."
@@ -1753,72 +1517,6 @@ public class CachedAppOptimizer {
}
}
- @VisibleForTesting
- static final class SingleCompactionStats {
- private static final float STATSD_SAMPLE_RATE = 0.1f;
- private static final Random mRandom = new Random();
- private final long[] mRssAfterCompaction;
- public CompactSource mSourceType;
- public String mProcessName;
- public final int mUid;
- public long mDeltaAnonRssKBs;
- public long mZramConsumedKBs;
- public long mAnonMemFreedKBs;
- public float mCpuTimeMillis;
- public long mOrigAnonRss;
- public int mProcState;
- public int mOomAdj;
- public @OomAdjReason int mOomAdjReason;
-
- SingleCompactionStats(long[] rss, CompactSource source, String processName,
- long deltaAnonRss, long zramConsumed, long anonMemFreed, long origAnonRss,
- long cpuTimeMillis, int procState, int oomAdj,
- @OomAdjReason int oomAdjReason, int uid) {
- mRssAfterCompaction = rss;
- mSourceType = source;
- mProcessName = processName;
- mUid = uid;
- mDeltaAnonRssKBs = deltaAnonRss;
- mZramConsumedKBs = zramConsumed;
- mAnonMemFreedKBs = anonMemFreed;
- mCpuTimeMillis = cpuTimeMillis;
- mOrigAnonRss = origAnonRss;
- mProcState = procState;
- mOomAdj = oomAdj;
- mOomAdjReason = oomAdjReason;
- }
-
- double getCompactEfficiency() { return mAnonMemFreedKBs / (double) mOrigAnonRss; }
-
- double getSwapEfficiency() { return mDeltaAnonRssKBs / (double) mOrigAnonRss; }
-
- double getCompactCost() {
- // mCpuTimeMillis / (anonMemFreedKBs/1024) and metric is in (ms/MB)
- return mCpuTimeMillis / (double) mAnonMemFreedKBs * 1024;
- }
-
- long[] getRssAfterCompaction() {
- return mRssAfterCompaction;
- }
-
- @NeverCompile
- void dump(PrintWriter pw) {
- pw.println(" (" + mProcessName + "," + mSourceType.name() + "," + mDeltaAnonRssKBs
- + "," + mZramConsumedKBs + "," + mAnonMemFreedKBs + ","
- + getSwapEfficiency() + "," + getCompactEfficiency()
- + "," + getCompactCost() + "," + mProcState + "," + mOomAdj + ","
- + OomAdjuster.oomAdjReasonToString(mOomAdjReason) + ")");
- }
-
- void sendStat() {
- if (mRandom.nextFloat() < STATSD_SAMPLE_RATE) {
- FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPACTED_V2, mUid, mProcState,
- mOomAdj, mDeltaAnonRssKBs, mZramConsumedKBs, mCpuTimeMillis, mOrigAnonRss,
- mOomAdjReason);
- }
- }
- }
-
private final class MemCompactionHandler extends Handler {
private MemCompactionHandler() {
super(mCachedAppOptimizerThread.getLooper());
@@ -1909,7 +1607,8 @@ public class CachedAppOptimizer {
private boolean shouldRssThrottleCompaction(
CompactProfile profile, int pid, String name, long[] rssBefore) {
long anonRssBefore = rssBefore[RSS_ANON_INDEX];
- SingleCompactionStats lastCompactionStats = mLastCompactionStats.get(pid);
+ SingleCompactionStats lastCompactionStats =
+ mCompactStatsManager.getLastCompactionStats(pid);
if (rssBefore[RSS_TOTAL_INDEX] == 0 && rssBefore[RSS_FILE_INDEX] == 0
&& rssBefore[RSS_ANON_INDEX] == 0 && rssBefore[RSS_SWAP_INDEX] == 0) {
@@ -1988,43 +1687,43 @@ public class CachedAppOptimizer {
oomAdjReason = opt.getLastOomAdjChangeReason();
}
- AggregatedSourceCompactionStats perSourceStats =
- getPerSourceAggregatedCompactStat(opt.getReqCompactSource());
- AggregatedProcessCompactionStats perProcessStats =
- getPerProcessAggregatedCompactStat(name);
-
long[] rssBefore;
if (pid == 0) {
// not a real process, either one being launched or one being killed
if (DEBUG_COMPACTION) {
Slog.d(TAG_AM, "Compaction failed, pid is 0");
}
- ++perSourceStats.mProcCompactionsNoPidThrottled;
- ++perProcessStats.mProcCompactionsNoPidThrottled;
+ mCompactStatsManager.logCompactionThrottled(
+ CompactionStatsManager.COMPACT_THROTTLE_REASON_NO_PID,
+ compactSource, name);
return;
}
if (!forceCompaction) {
if (shouldOomAdjThrottleCompaction(proc)) {
- ++perProcessStats.mProcCompactionsOomAdjThrottled;
- ++perSourceStats.mProcCompactionsOomAdjThrottled;
+ mCompactStatsManager.logCompactionThrottled(
+ CompactionStatsManager.COMPACT_THROTTLE_REASON_OOM_ADJ,
+ compactSource, name);
return;
}
if (shouldTimeThrottleCompaction(
proc, start, requestedProfile, compactSource)) {
- ++perProcessStats.mProcCompactionsTimeThrottled;
- ++perSourceStats.mProcCompactionsTimeThrottled;
+ mCompactStatsManager.logCompactionThrottled(
+ CompactionStatsManager.COMPACT_THROTTLE_REASON_TIME_TOO_SOON,
+ compactSource, name);
return;
}
if (shouldThrottleMiscCompaction(proc, procState)) {
- ++perProcessStats.mProcCompactionsMiscThrottled;
- ++perSourceStats.mProcCompactionsMiscThrottled;
+ mCompactStatsManager.logCompactionThrottled(
+ CompactionStatsManager.COMPACT_THROTTLE_REASON_PROC_STATE,
+ compactSource, name);
return;
}
rssBefore = mProcessDependencies.getRss(pid);
if (shouldRssThrottleCompaction(requestedProfile, pid, name, rssBefore)) {
- ++perProcessStats.mProcCompactionsRSSThrottled;
- ++perSourceStats.mProcCompactionsRSSThrottled;
+ mCompactStatsManager.logCompactionThrottled(
+ CompactionStatsManager.COMPACT_THROTTLE_REASON_DELTA_RSS,
+ compactSource, name);
return;
}
} else {
@@ -2065,40 +1764,19 @@ public class CachedAppOptimizer {
long deltaSwapRss = rssAfter[RSS_SWAP_INDEX] - rssBefore[RSS_SWAP_INDEX];
switch (opt.getReqCompactProfile()) {
case SOME:
- ++perSourceStats.mSomeCompactPerformed;
- ++perProcessStats.mSomeCompactPerformed;
+ mCompactStatsManager.logSomeCompactionPerformed(compactSource,
+ name);
break;
case FULL:
- ++perSourceStats.mFullCompactPerformed;
- ++perProcessStats.mFullCompactPerformed;
long anonRssSavings = -deltaAnonRss;
long zramConsumed = zramUsedKbAfter - zramUsedKbBefore;
long memFreed = anonRssSavings - zramConsumed;
long totalCpuTimeMillis = deltaCpuTimeNanos / 1000000;
long origAnonRss = rssBefore[RSS_ANON_INDEX];
-
- // Negative stats would skew averages and will likely be due to
- // noise of system doing other things so we put a floor at 0 to
- // avoid negative values.
- anonRssSavings = anonRssSavings > 0 ? anonRssSavings : 0;
- zramConsumed = zramConsumed > 0 ? zramConsumed : 0;
- memFreed = memFreed > 0 ? memFreed : 0;
-
- perProcessStats.addMemStats(anonRssSavings, zramConsumed, memFreed,
- origAnonRss, totalCpuTimeMillis);
- perSourceStats.addMemStats(anonRssSavings, zramConsumed, memFreed,
- origAnonRss, totalCpuTimeMillis);
- SingleCompactionStats memStats = new SingleCompactionStats(rssAfter,
- compactSource, name, anonRssSavings, zramConsumed, memFreed,
- origAnonRss, totalCpuTimeMillis, procState, newOomAdj,
- oomAdjReason, proc.uid);
- mLastCompactionStats.remove(pid);
- mLastCompactionStats.put(pid, memStats);
- mCompactionStatsHistory.add(memStats);
- if (!forceCompaction) {
- // Avoid polluting field metrics with forced compactions.
- memStats.sendStat();
- }
+ mCompactStatsManager.logFullCompactionPerformed(compactSource, name,
+ anonRssSavings, zramConsumed, memFreed, origAnonRss,
+ totalCpuTimeMillis, rssAfter, procState, newOomAdj,
+ oomAdjReason, proc.uid, pid, !forceCompaction);
break;
default:
// We likely missed adding this category, it needs to be added
@@ -2129,12 +1807,12 @@ public class CachedAppOptimizer {
break;
}
case COMPACT_SYSTEM_MSG: {
- ++mSystemCompactionsPerformed;
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactSystem");
long memFreedBefore = getMemoryFreedCompaction();
compactSystem();
long memFreedAfter = getMemoryFreedCompaction();
- mSystemTotalMemFreed += memFreedAfter - memFreedBefore;
+ long memFreed = memFreedAfter - memFreedBefore;
+ mCompactStatsManager.logSystemCompactionPerformed(memFreed);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 363ba82cb332..cd40905b01da 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -4057,7 +4057,6 @@ public class OomAdjuster {
+ " mNewNumServiceProcs=" + mNewNumServiceProcs);
}
- @GuardedBy("mProcLock")
void dumpCachedAppOptimizerSettings(PrintWriter pw) {
mCachedAppOptimizer.dump(pw);
}
diff --git a/services/core/java/com/android/server/am/compaction/AggregatedCompactionStats.java b/services/core/java/com/android/server/am/compaction/AggregatedCompactionStats.java
new file mode 100644
index 000000000000..836670cd10eb
--- /dev/null
+++ b/services/core/java/com/android/server/am/compaction/AggregatedCompactionStats.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am.compaction;
+
+import dalvik.annotation.optimization.NeverCompile;
+
+import java.io.PrintWriter;
+
+class AggregatedCompactionStats {
+ // Throttling stats
+ public long mFullCompactRequested;
+ public long mSomeCompactRequested;
+ public long mFullCompactPerformed;
+ public long mSomeCompactPerformed;
+ public long mProcCompactionsNoPidThrottled;
+ public long mProcCompactionsOomAdjThrottled;
+ public long mProcCompactionsTimeThrottled;
+ public long mProcCompactionsRSSThrottled;
+ public long mProcCompactionsMiscThrottled;
+
+ // Memory stats
+ public long mTotalDeltaAnonRssKBs;
+ public long mTotalZramConsumedKBs;
+ public long mTotalAnonMemFreedKBs;
+ public long mSumOrigAnonRss;
+ public double mMaxCompactEfficiency;
+ public double mMaxSwapEfficiency;
+
+ // Cpu time
+ public long mTotalCpuTimeMillis;
+
+ public long getThrottledSome() { return mSomeCompactRequested - mSomeCompactPerformed; }
+
+ public long getThrottledFull() { return mFullCompactRequested - mFullCompactPerformed; }
+
+ public void addMemStats(long anonRssSaved, long zramConsumed, long memFreed,
+ long origAnonRss, long totalCpuTimeMillis) {
+ final double compactEfficiency = memFreed / (double) origAnonRss;
+ if (compactEfficiency > mMaxCompactEfficiency) {
+ mMaxCompactEfficiency = compactEfficiency;
+ }
+ final double swapEfficiency = anonRssSaved / (double) origAnonRss;
+ if (swapEfficiency > mMaxSwapEfficiency) {
+ mMaxSwapEfficiency = swapEfficiency;
+ }
+ mTotalDeltaAnonRssKBs += anonRssSaved;
+ mTotalZramConsumedKBs += zramConsumed;
+ mTotalAnonMemFreedKBs += memFreed;
+ mSumOrigAnonRss += origAnonRss;
+ mTotalCpuTimeMillis += totalCpuTimeMillis;
+ }
+
+ @NeverCompile
+ public void dump(PrintWriter pw) {
+ long totalCompactRequested = mSomeCompactRequested + mFullCompactRequested;
+ long totalCompactPerformed = mSomeCompactPerformed + mFullCompactPerformed;
+ pw.println(" Performed / Requested:");
+ pw.println(" Some: (" + mSomeCompactPerformed + "/" + mSomeCompactRequested + ")");
+ pw.println(" Full: (" + mFullCompactPerformed + "/" + mFullCompactRequested + ")");
+
+ long throttledSome = getThrottledSome();
+ long throttledFull = getThrottledFull();
+
+ if (throttledSome > 0 || throttledFull > 0) {
+ pw.println(" Throttled:");
+ pw.println(" Some: " + throttledSome + " Full: " + throttledFull);
+ pw.println(" Throttled by Type:");
+ final long compactionsThrottled = totalCompactRequested - totalCompactPerformed;
+ // Any throttle that was not part of the previous categories
+ final long unaccountedThrottled = compactionsThrottled
+ - mProcCompactionsNoPidThrottled - mProcCompactionsOomAdjThrottled
+ - mProcCompactionsTimeThrottled - mProcCompactionsRSSThrottled
+ - mProcCompactionsMiscThrottled;
+ pw.println(" NoPid: " + mProcCompactionsNoPidThrottled
+ + " OomAdj: " + mProcCompactionsOomAdjThrottled + " Time: "
+ + mProcCompactionsTimeThrottled + " RSS: " + mProcCompactionsRSSThrottled
+ + " Misc: " + mProcCompactionsMiscThrottled
+ + " Unaccounted: " + unaccountedThrottled);
+ final double compactThrottlePercentage =
+ (compactionsThrottled / (double) totalCompactRequested) * 100.0;
+ pw.println(" Throttle Percentage: " + compactThrottlePercentage);
+ }
+
+ if (mFullCompactPerformed > 0) {
+ pw.println(" -----Memory Stats----");
+ pw.println(" Total Delta Anon RSS (KB) : " + mTotalDeltaAnonRssKBs);
+ pw.println(" Total Physical ZRAM Consumed (KB): " + mTotalZramConsumedKBs);
+ // Anon Mem Freed = Delta Anon RSS - ZRAM Consumed
+ pw.println(" Total Anon Memory Freed (KB): " + mTotalAnonMemFreedKBs);
+ pw.println(" Avg Swap Efficiency (KB) (Delta Anon RSS/Orig Anon RSS): "
+ + (mTotalDeltaAnonRssKBs / (double) mSumOrigAnonRss));
+ pw.println(" Max Swap Efficiency: " + mMaxSwapEfficiency);
+ // This tells us how much anon memory we were able to free thanks to running
+ // compaction
+ pw.println(" Avg Compaction Efficiency (Anon Freed/Anon RSS): "
+ + (mTotalAnonMemFreedKBs / (double) mSumOrigAnonRss));
+ pw.println(" Max Compaction Efficiency: " + mMaxCompactEfficiency);
+ // This tells us how effective is the compression algorithm in physical memory
+ pw.println(" Avg Compression Ratio (1 - ZRAM Consumed/DeltaAnonRSS): "
+ + (1.0 - mTotalZramConsumedKBs / (double) mTotalDeltaAnonRssKBs));
+ long avgKBsPerProcCompact = mFullCompactPerformed > 0
+ ? (mTotalAnonMemFreedKBs / mFullCompactPerformed)
+ : 0;
+ pw.println(" Avg Anon Mem Freed/Compaction (KB) : " + avgKBsPerProcCompact);
+ double compactionCost =
+ mTotalCpuTimeMillis / (mTotalAnonMemFreedKBs / 1024.0); // ms/MB
+ pw.println(" Compaction Cost (ms/MB): " + compactionCost);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/compaction/AggregatedProcessCompactionStats.java b/services/core/java/com/android/server/am/compaction/AggregatedProcessCompactionStats.java
new file mode 100644
index 000000000000..53019f93267a
--- /dev/null
+++ b/services/core/java/com/android/server/am/compaction/AggregatedProcessCompactionStats.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am.compaction;
+
+final class AggregatedProcessCompactionStats extends AggregatedCompactionStats {
+ public final String mProcessName;
+
+ public AggregatedProcessCompactionStats(String processName) { this.mProcessName = processName; }
+}
diff --git a/services/core/java/com/android/server/am/compaction/AggregatedSourceCompactionStats.java b/services/core/java/com/android/server/am/compaction/AggregatedSourceCompactionStats.java
new file mode 100644
index 000000000000..39a10d52a217
--- /dev/null
+++ b/services/core/java/com/android/server/am/compaction/AggregatedSourceCompactionStats.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am.compaction;
+
+import com.android.server.am.CachedAppOptimizer;
+
+final class AggregatedSourceCompactionStats extends AggregatedCompactionStats {
+ public final CachedAppOptimizer.CompactSource mSourceType;
+
+ public AggregatedSourceCompactionStats(CachedAppOptimizer.CompactSource sourceType) {
+ this.mSourceType = sourceType;
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/am/compaction/CompactionStatsManager.java b/services/core/java/com/android/server/am/compaction/CompactionStatsManager.java
new file mode 100644
index 000000000000..98368dacb86d
--- /dev/null
+++ b/services/core/java/com/android/server/am/compaction/CompactionStatsManager.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am.compaction;
+
+import android.annotation.IntDef;
+import android.app.ActivityManagerInternal;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.am.CachedAppOptimizer;
+
+import dalvik.annotation.optimization.NeverCompile;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.EnumMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+public final class CompactionStatsManager {
+ private static CompactionStatsManager sInstance;
+
+ private static String TAG = "CompactionStatsManager";
+
+ // Size of history for the last 20 compactions for any process
+ static final int LAST_COMPACTED_ANY_PROCESS_STATS_HISTORY_SIZE = 20;
+
+ // Amount of processes supported to record for their last compaction.
+ static final int LAST_COMPACTION_FOR_PROCESS_STATS_SIZE = 256;
+
+ public static final int COMPACT_THROTTLE_REASON_NO_PID = 0;
+ public static final int COMPACT_THROTTLE_REASON_OOM_ADJ = 1;
+ public static final int COMPACT_THROTTLE_REASON_TIME_TOO_SOON = 2;
+ public static final int COMPACT_THROTTLE_REASON_PROC_STATE = 3;
+ public static final int COMPACT_THROTTLE_REASON_DELTA_RSS = 4;
+ @IntDef(value = {
+ COMPACT_THROTTLE_REASON_NO_PID, COMPACT_THROTTLE_REASON_OOM_ADJ,
+ COMPACT_THROTTLE_REASON_TIME_TOO_SOON, COMPACT_THROTTLE_REASON_PROC_STATE,
+ COMPACT_THROTTLE_REASON_DELTA_RSS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CompactThrottleReason {}
+
+ private final LinkedHashMap<String, AggregatedProcessCompactionStats> mPerProcessCompactStats =
+ new LinkedHashMap<>(256);
+ private final EnumMap<CachedAppOptimizer.CompactSource, AggregatedSourceCompactionStats>
+ mPerSourceCompactStats =
+ new EnumMap<>(CachedAppOptimizer.CompactSource.class);
+
+ private long mTotalCompactionDowngrades;
+ private long mSystemCompactionsPerformed;
+ private long mSystemTotalMemFreed;
+ private EnumMap<CachedAppOptimizer.CancelCompactReason, Integer> mTotalCompactionsCancelled =
+ new EnumMap<>(CachedAppOptimizer.CancelCompactReason.class);
+
+ // Maps process ID to last compaction statistics for processes that we've fully compacted. Used
+ // when evaluating throttles that we only consider for "full" compaction, so we don't store
+ // data for "some" compactions. Uses LinkedHashMap to ensure insertion order is kept and
+ // facilitate removal of the oldest entry.
+ @VisibleForTesting
+ @GuardedBy("mProcLock")
+ LinkedHashMap<Integer, SingleCompactionStats> mLastCompactionStats =
+ new LinkedHashMap<Integer, SingleCompactionStats>() {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > LAST_COMPACTION_FOR_PROCESS_STATS_SIZE;
+ }
+ };
+
+ LinkedList<SingleCompactionStats> mCompactionStatsHistory =
+ new LinkedList<SingleCompactionStats>() {
+ @Override
+ public boolean add(SingleCompactionStats e) {
+ if (size() >= LAST_COMPACTED_ANY_PROCESS_STATS_HISTORY_SIZE) {
+ this.remove();
+ }
+ return super.add(e);
+ }
+ };
+
+ public static CompactionStatsManager getInstance() {
+ if (sInstance == null) {
+ sInstance = new CompactionStatsManager();
+ }
+ return sInstance;
+ }
+
+ public SingleCompactionStats getLastCompactionStats(int pid) {
+ return mLastCompactionStats.get(pid);
+ }
+
+ @VisibleForTesting
+ public LinkedHashMap<Integer, SingleCompactionStats> getLastCompactionStats() {
+ return mLastCompactionStats;
+ }
+
+ @VisibleForTesting
+ public void reinit() {
+ sInstance = new CompactionStatsManager();
+ }
+
+
+ public void logCompactionRequested(CachedAppOptimizer.CompactSource source,
+ CachedAppOptimizer.CompactProfile compactProfile, String processName) {
+ AggregatedSourceCompactionStats perSourceStats = getPerSourceAggregatedCompactStat(source);
+ AggregatedCompactionStats perProcStats =
+ getPerProcessAggregatedCompactStat(processName);
+
+ switch (compactProfile) {
+ case SOME:
+ ++perProcStats.mSomeCompactRequested;
+ ++perSourceStats.mSomeCompactRequested;
+ break;
+ case FULL:
+ ++perProcStats.mFullCompactRequested;
+ ++perSourceStats.mFullCompactRequested;
+ break;
+ default:
+ Slog.e(TAG,
+ "Stats cannot be logged for compaction type."+compactProfile);
+ }
+ }
+ public void logCompactionThrottled(@CompactThrottleReason int reason,
+ CachedAppOptimizer.CompactSource source, String processName) {
+ AggregatedSourceCompactionStats perSourceStats =
+ getPerSourceAggregatedCompactStat(source);
+ AggregatedProcessCompactionStats perProcessStats =
+ getPerProcessAggregatedCompactStat(processName);
+
+ switch(reason) {
+ case COMPACT_THROTTLE_REASON_NO_PID:
+ ++perSourceStats.mProcCompactionsNoPidThrottled;
+ ++perProcessStats.mProcCompactionsNoPidThrottled;
+ break;
+ case COMPACT_THROTTLE_REASON_OOM_ADJ:
+ ++perProcessStats.mProcCompactionsOomAdjThrottled;
+ ++perSourceStats.mProcCompactionsOomAdjThrottled;
+ break;
+ case COMPACT_THROTTLE_REASON_TIME_TOO_SOON:
+ ++perProcessStats.mProcCompactionsTimeThrottled;
+ ++perSourceStats.mProcCompactionsTimeThrottled;
+ break;
+ case COMPACT_THROTTLE_REASON_PROC_STATE:
+ ++perProcessStats.mProcCompactionsMiscThrottled;
+ ++perSourceStats.mProcCompactionsMiscThrottled;
+ break;
+ case COMPACT_THROTTLE_REASON_DELTA_RSS:
+ ++perProcessStats.mProcCompactionsRSSThrottled;
+ ++perSourceStats.mProcCompactionsRSSThrottled;
+ break;
+ default:
+ break;
+ }
+ }
+
+ public void logSomeCompactionPerformed(CachedAppOptimizer.CompactSource source,
+ String processName) {
+ AggregatedSourceCompactionStats perSourceStats =
+ getPerSourceAggregatedCompactStat(source);
+ AggregatedProcessCompactionStats perProcessStats =
+ getPerProcessAggregatedCompactStat(processName);
+
+ ++perSourceStats.mSomeCompactPerformed;
+ ++perProcessStats.mSomeCompactPerformed;
+ }
+
+ public void logFullCompactionPerformed(
+ CachedAppOptimizer.CompactSource source, String processName, long anonRssSavings,
+ long zramConsumed, long memFreed, long origAnonRss, long totalCpuTimeMillis,
+ long[] rssAfterCompact, int procState, int newOomAdj,
+ @ActivityManagerInternal.OomAdjReason int oomAdjReason, int uid, int pid,
+ boolean logFieldMetric) {
+ AggregatedSourceCompactionStats perSourceStats =
+ getPerSourceAggregatedCompactStat(source);
+ AggregatedProcessCompactionStats perProcessStats =
+ getPerProcessAggregatedCompactStat(processName);
+
+ ++perSourceStats.mFullCompactPerformed;
+ ++perProcessStats.mFullCompactPerformed;
+
+ // Negative stats would skew averages and will likely be due to
+ // noise of system doing other things so we put a floor at 0 to
+ // avoid negative values.
+ anonRssSavings = anonRssSavings > 0 ? anonRssSavings : 0;
+ zramConsumed = zramConsumed > 0 ? zramConsumed : 0;
+ memFreed = memFreed > 0 ? memFreed : 0;
+
+ perProcessStats.addMemStats(anonRssSavings, zramConsumed, memFreed,
+ origAnonRss, totalCpuTimeMillis);
+ perSourceStats.addMemStats(anonRssSavings, zramConsumed, memFreed,
+ origAnonRss, totalCpuTimeMillis);
+ SingleCompactionStats memStats = new SingleCompactionStats(rssAfterCompact,
+ source, processName, anonRssSavings, zramConsumed, memFreed,
+ origAnonRss, totalCpuTimeMillis, procState, newOomAdj,
+ oomAdjReason, uid);
+ mLastCompactionStats.remove(pid);
+ mLastCompactionStats.put(pid, memStats);
+ mCompactionStatsHistory.add(memStats);
+ if (!logFieldMetric) {
+ memStats.sendStat();
+ }
+ }
+
+ public void logCompactionDowngrade() {
+ ++mTotalCompactionDowngrades;
+ }
+
+ public void logSystemCompactionPerformed(long memFreed) {
+ ++mSystemCompactionsPerformed;
+ mSystemTotalMemFreed += memFreed;
+ }
+
+ public void logCompactionCancelled(CachedAppOptimizer.CancelCompactReason cancelReason) {
+ if (mTotalCompactionsCancelled.containsKey(cancelReason)) {
+ int count = mTotalCompactionsCancelled.get(cancelReason);
+ mTotalCompactionsCancelled.put(cancelReason, count + 1);
+ } else {
+ mTotalCompactionsCancelled.put(cancelReason, 1);
+ }
+ }
+
+ private AggregatedProcessCompactionStats getPerProcessAggregatedCompactStat(
+ String processName) {
+ if (processName == null) {
+ processName = "";
+ }
+ AggregatedProcessCompactionStats stats = mPerProcessCompactStats.get(processName);
+ if (stats == null) {
+ stats = new AggregatedProcessCompactionStats(processName);
+ mPerProcessCompactStats.put(processName, stats);
+ }
+ return stats;
+ }
+
+ private AggregatedSourceCompactionStats getPerSourceAggregatedCompactStat(
+ CachedAppOptimizer.CompactSource source) {
+ AggregatedSourceCompactionStats stats = mPerSourceCompactStats.get(source);
+ if (stats == null) {
+ stats = new AggregatedSourceCompactionStats(source);
+ mPerSourceCompactStats.put(source, stats);
+ }
+ return stats;
+ }
+
+ @NeverCompile
+ public void dump(PrintWriter pw) {
+ pw.println(" Per-Process Compaction Stats");
+ long totalCompactPerformedSome = 0;
+ long totalCompactPerformedFull = 0;
+ for (AggregatedProcessCompactionStats stats : mPerProcessCompactStats.values()) {
+ pw.println("-----" + stats.mProcessName + "-----");
+ totalCompactPerformedSome += stats.mSomeCompactPerformed;
+ totalCompactPerformedFull += stats.mFullCompactPerformed;
+ stats.dump(pw);
+ pw.println();
+ }
+ pw.println();
+ pw.println(" Per-Source Compaction Stats");
+ for (AggregatedSourceCompactionStats stats : mPerSourceCompactStats.values()) {
+ pw.println("-----" + stats.mSourceType + "-----");
+ stats.dump(pw);
+ pw.println();
+ }
+ pw.println();
+
+ pw.println("Total Compactions Performed by profile: " + totalCompactPerformedSome
+ + " some, " + totalCompactPerformedFull + " full");
+ pw.println("Total compactions downgraded: " + mTotalCompactionDowngrades);
+ pw.println("Total compactions cancelled by reason: ");
+ for (CachedAppOptimizer.CancelCompactReason reason : mTotalCompactionsCancelled.keySet()) {
+ pw.println(" " + reason + ": " + mTotalCompactionsCancelled.get(reason));
+ }
+ pw.println();
+
+ pw.println(" System Compaction Memory Stats");
+ pw.println(" Compactions Performed: " + mSystemCompactionsPerformed);
+ pw.println(" Total Memory Freed (KB): " + mSystemTotalMemFreed);
+ double avgKBsPerSystemCompact = mSystemCompactionsPerformed > 0
+ ? mSystemTotalMemFreed / mSystemCompactionsPerformed
+ : 0;
+ pw.println(" Avg Mem Freed per Compact (KB): " + avgKBsPerSystemCompact);
+ pw.println();
+ pw.println(" Tracking last compaction stats for " + mLastCompactionStats.size()
+ + " processes.");
+ pw.println("Last Compaction per process stats:");
+ pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs"
+ + ",SwapEfficiency,CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,"
+ + "oomAdjReason)");
+ for (Map.Entry<Integer, SingleCompactionStats> entry :
+ mLastCompactionStats.entrySet()) {
+ SingleCompactionStats stats = entry.getValue();
+ stats.dump(pw);
+ }
+ pw.println();
+ pw.println("Last 20 Compactions Stats:");
+ pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs,"
+ + "SwapEfficiency,CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,"
+ + "oomAdjReason)");
+ for (SingleCompactionStats stats : mCompactionStatsHistory) {
+ stats.dump(pw);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/compaction/OWNERS b/services/core/java/com/android/server/am/compaction/OWNERS
new file mode 100644
index 000000000000..54253b49daa3
--- /dev/null
+++ b/services/core/java/com/android/server/am/compaction/OWNERS
@@ -0,0 +1,5 @@
+edgararriaga@google.com
+shayba@google.com
+
+# Fallback
+include /PERFORMANCE_OWNERS
diff --git a/services/core/java/com/android/server/am/compaction/SingleCompactionStats.java b/services/core/java/com/android/server/am/compaction/SingleCompactionStats.java
new file mode 100644
index 000000000000..c20087ac973e
--- /dev/null
+++ b/services/core/java/com/android/server/am/compaction/SingleCompactionStats.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am.compaction;
+
+import android.app.ActivityManagerInternal;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.am.CachedAppOptimizer;
+import com.android.server.am.OomAdjuster;
+
+import dalvik.annotation.optimization.NeverCompile;
+
+import java.io.PrintWriter;
+import java.util.Random;
+
+public final class SingleCompactionStats {
+ private static final float STATSD_SAMPLE_RATE = 0.1f;
+ private static final Random mRandom = new Random();
+ private final long[] mRssAfterCompaction;
+ public CachedAppOptimizer.CompactSource mSourceType;
+ public String mProcessName;
+ public final int mUid;
+ public long mDeltaAnonRssKBs;
+ public long mZramConsumedKBs;
+ public long mAnonMemFreedKBs;
+ public float mCpuTimeMillis;
+ public long mOrigAnonRss;
+ public int mProcState;
+ public int mOomAdj;
+ public @ActivityManagerInternal.OomAdjReason int mOomAdjReason;
+
+ SingleCompactionStats(long[] rss, CachedAppOptimizer.CompactSource source, String processName,
+ long deltaAnonRss, long zramConsumed, long anonMemFreed, long origAnonRss,
+ long cpuTimeMillis, int procState, int oomAdj,
+ @ActivityManagerInternal.OomAdjReason int oomAdjReason, int uid) {
+ mRssAfterCompaction = rss;
+ mSourceType = source;
+ mProcessName = processName;
+ mUid = uid;
+ mDeltaAnonRssKBs = deltaAnonRss;
+ mZramConsumedKBs = zramConsumed;
+ mAnonMemFreedKBs = anonMemFreed;
+ mCpuTimeMillis = cpuTimeMillis;
+ mOrigAnonRss = origAnonRss;
+ mProcState = procState;
+ mOomAdj = oomAdj;
+ mOomAdjReason = oomAdjReason;
+ }
+
+ double getCompactEfficiency() { return mAnonMemFreedKBs / (double) mOrigAnonRss; }
+
+ double getSwapEfficiency() { return mDeltaAnonRssKBs / (double) mOrigAnonRss; }
+
+ double getCompactCost() {
+ // mCpuTimeMillis / (anonMemFreedKBs/1024) and metric is in (ms/MB)
+ return mCpuTimeMillis / (double) mAnonMemFreedKBs * 1024;
+ }
+
+ public long[] getRssAfterCompaction() {
+ return mRssAfterCompaction;
+ }
+
+ @NeverCompile
+ void dump(PrintWriter pw) {
+ pw.println(" (" + mProcessName + "," + mSourceType.name() + "," + mDeltaAnonRssKBs
+ + "," + mZramConsumedKBs + "," + mAnonMemFreedKBs + ","
+ + getSwapEfficiency() + "," + getCompactEfficiency()
+ + "," + getCompactCost() + "," + mProcState + "," + mOomAdj + ","
+ + OomAdjuster.oomAdjReasonToString(mOomAdjReason) + ")");
+ }
+
+ void sendStat() {
+ if (mRandom.nextFloat() < STATSD_SAMPLE_RATE) {
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPACTED_V2, mUid, mProcState,
+ mOomAdj, mDeltaAnonRssKBs, mZramConsumedKBs, mCpuTimeMillis, mOrigAnonRss,
+ mOomAdjReason);
+ }
+ }
+} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index d203de537b81..fa5847560782 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -142,6 +142,9 @@ public final class CachedAppOptimizerTest {
}, mProcessDependencies);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
+
+ mCachedAppOptimizerUnderTest.init();
+ mCachedAppOptimizerUnderTest.mCompactStatsManager.reinit();
}
@After
@@ -168,7 +171,6 @@ public final class CachedAppOptimizerTest {
@Test
public void init_setsDefaults() {
- mCachedAppOptimizerUnderTest.init();
synchronized (mCachedAppOptimizerUnderTest.mPhenotypeFlagLock) {
assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo(
CachedAppOptimizer.DEFAULT_USE_COMPACTION);
@@ -304,7 +306,6 @@ public final class CachedAppOptimizerTest {
assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo(
CachedAppOptimizer.DEFAULT_USE_COMPACTION);
// When we call init and change some the flag value...
- mCachedAppOptimizerUnderTest.init();
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_USE_COMPACTION, "true", false);
@@ -331,7 +332,6 @@ public final class CachedAppOptimizerTest {
// The freezer DeviceConfig property is read at boot only
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
CachedAppOptimizer.KEY_USE_FREEZER, "true", false);
- mCachedAppOptimizerUnderTest.init();
assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue();
mCountDown = new CountDownLatch(1);
@@ -363,7 +363,6 @@ public final class CachedAppOptimizerTest {
public void useCompaction_listensToDeviceConfigChangesBadValues() throws InterruptedException {
assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo(
CachedAppOptimizer.DEFAULT_USE_COMPACTION);
- mCachedAppOptimizerUnderTest.init();
// When we push an invalid flag value...
mCountDown = new CountDownLatch(1);
@@ -392,8 +391,6 @@ public final class CachedAppOptimizerTest {
@Test
public void compactThrottle_listensToDeviceConfigChanges() throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
-
// When we override new reasonable throttle values after init...
mCountDown = new CountDownLatch(8);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -440,8 +437,6 @@ public final class CachedAppOptimizerTest {
@Test
public void compactThrottle_listensToDeviceConfigChangesBadValues()
throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
-
// When one of the throttles is overridden with a bad value...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -526,8 +521,6 @@ public final class CachedAppOptimizerTest {
@Test
public void statsdSampleRate_listensToDeviceConfigChanges() throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
-
// When we override mCompactStatsdSampleRate with a reasonable value ...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -554,8 +547,6 @@ public final class CachedAppOptimizerTest {
@Test
public void statsdSampleRate_listensToDeviceConfigChangesBadValues()
throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
-
// When we override mCompactStatsdSampleRate with an unreasonable value ...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -580,8 +571,6 @@ public final class CachedAppOptimizerTest {
@Test
public void statsdSampleRate_listensToDeviceConfigChangesOutOfRangeValues()
throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
-
// When we override mCompactStatsdSampleRate with an value outside of [0..1]...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -624,8 +613,6 @@ public final class CachedAppOptimizerTest {
@Test
public void fullCompactionRssThrottleKb_listensToDeviceConfigChanges()
throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
-
// When we override mStatsdSampleRate with a reasonable value ...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -641,8 +628,6 @@ public final class CachedAppOptimizerTest {
@Test
public void fullCompactionRssThrottleKb_listensToDeviceConfigChangesBadValues()
throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
-
// When we override mStatsdSampleRate with an unreasonable value ...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -666,8 +651,6 @@ public final class CachedAppOptimizerTest {
@Test
public void fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChanges()
throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
-
// When we override mStatsdSampleRate with a reasonable value ...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -684,8 +667,6 @@ public final class CachedAppOptimizerTest {
@Test
public void fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChangesBadValues()
throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
-
// When we override mStatsdSampleRate with an unreasonable value ...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -709,7 +690,6 @@ public final class CachedAppOptimizerTest {
@Test
public void procStateThrottle_listensToDeviceConfigChanges()
throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false);
@@ -726,7 +706,6 @@ public final class CachedAppOptimizerTest {
@Test
public void procStateThrottle_listensToDeviceConfigChangesBadValues()
throws InterruptedException {
- mCachedAppOptimizerUnderTest.init();
Set<Integer> expected = new HashSet<>();
for (String s : TextUtils.split(
@@ -774,7 +753,6 @@ public final class CachedAppOptimizerTest {
public void processWithDeltaRSSTooSmall_notFullCompacted() throws Exception {
// Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set RSS
// throttle to 12000.
- mCachedAppOptimizerUnderTest.init();
setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true);
setFlag(CachedAppOptimizer.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, "12000", false);
initActivityManagerService();
@@ -810,9 +788,10 @@ public final class CachedAppOptimizerTest {
false);
waitForHandler();
// THEN process IS compacted.
- assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
- valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get(
- pid).getRssAfterCompaction();
+ assertThat(mCachedAppOptimizerUnderTest.mCompactStatsManager.getLastCompactionStats(pid))
+ .isNotNull();
+ valuesAfter = mCachedAppOptimizerUnderTest.mCompactStatsManager.getLastCompactionStats(pid)
+ .getRssAfterCompaction();
assertThat(valuesAfter).isEqualTo(rssAfter1);
// WHEN delta is below threshold (500).
@@ -828,9 +807,10 @@ public final class CachedAppOptimizerTest {
waitForHandler();
// THEN process IS NOT compacted - values after compaction for process 1 should remain the
// same as from the last compaction.
- assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
- valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get(
- pid).getRssAfterCompaction();
+ assertThat(mCachedAppOptimizerUnderTest.mCompactStatsManager.
+ getLastCompactionStats(pid)).isNotNull();
+ valuesAfter = mCachedAppOptimizerUnderTest.mCompactStatsManager.
+ getLastCompactionStats(pid).getRssAfterCompaction();
assertThat(valuesAfter).isEqualTo(rssAfter1);
// WHEN delta is above threshold (13000).
@@ -845,9 +825,10 @@ public final class CachedAppOptimizerTest {
false);
waitForHandler();
// THEN process IS compacted - values after compaction for process 1 should be updated.
- assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
- valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get(
- pid).getRssAfterCompaction();
+ assertThat(mCachedAppOptimizerUnderTest.
+ mCompactStatsManager.getLastCompactionStats(pid)).isNotNull();
+ valuesAfter = mCachedAppOptimizerUnderTest.
+ mCompactStatsManager.getLastCompactionStats(pid).getRssAfterCompaction();
assertThat(valuesAfter).isEqualTo(rssAfter3);
}
@@ -856,7 +837,7 @@ public final class CachedAppOptimizerTest {
public void processWithAnonRSSTooSmall_notFullCompacted() throws Exception {
// Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set RSS
// throttle to 8000.
- mCachedAppOptimizerUnderTest.init();
+
setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true);
setFlag(CachedAppOptimizer.KEY_COMPACT_FULL_RSS_THROTTLE_KB, "8000", false);
initActivityManagerService();
@@ -888,7 +869,8 @@ public final class CachedAppOptimizerTest {
false);
waitForHandler();
// THEN process IS NOT compacted.
- assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull();
+ assertThat(mCachedAppOptimizerUnderTest.
+ mCompactStatsManager.getLastCompactionStats(pid)).isNull();
// GIVEN we simulate RSS memory before above threshold.
mProcessDependencies.setRss(rssAboveThreshold);
@@ -899,9 +881,10 @@ public final class CachedAppOptimizerTest {
false);
waitForHandler();
// THEN process IS compacted.
- assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
- long[] valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get(
- pid).getRssAfterCompaction();
+ assertThat(mCachedAppOptimizerUnderTest.
+ mCompactStatsManager.getLastCompactionStats(pid)).isNotNull();
+ long[] valuesAfter = mCachedAppOptimizerUnderTest.mCompactStatsManager.
+ getLastCompactionStats(pid).getRssAfterCompaction();
assertThat(valuesAfter).isEqualTo(rssAboveThresholdAfter);
}
@@ -910,7 +893,6 @@ public final class CachedAppOptimizerTest {
public void processWithOomAdjTooSmall_notFullCompacted() throws Exception {
// Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set Min and
// Max OOM_Adj throttles.
- mCachedAppOptimizerUnderTest.init();
setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true);
setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, Long.toString(920), true);
setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, Long.toString(950), true);
@@ -934,9 +916,10 @@ public final class CachedAppOptimizerTest {
mCachedAppOptimizerUnderTest.onProcessFrozen(processRecord);
waitForHandler();
// THEN process IS compacted.
- assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
- long[] valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats
- .get(pid)
+ assertThat(mCachedAppOptimizerUnderTest.mCompactStatsManager
+ .getLastCompactionStats(pid)).isNotNull();
+ long[] valuesAfter = mCachedAppOptimizerUnderTest.mCompactStatsManager
+ .getLastCompactionStats(pid)
.getRssAfterCompaction();
assertThat(valuesAfter).isEqualTo(rssAfter);
}
@@ -944,7 +927,7 @@ public final class CachedAppOptimizerTest {
@SuppressWarnings("GuardedBy")
@Test
public void process_forceCompacted() throws Exception {
- mCachedAppOptimizerUnderTest.init();
+
setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true);
setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, Long.toString(920), true);
setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, Long.toString(950), true);
@@ -970,7 +953,8 @@ public final class CachedAppOptimizerTest {
false);
waitForHandler();
// the process is not compacted
- assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull();
+ assertThat(mCachedAppOptimizerUnderTest.mCompactStatsManager.
+ getLastCompactionStats(pid)).isNull();
// Compact process some
mCachedAppOptimizerUnderTest.compactApp(processRecord,
@@ -978,7 +962,8 @@ public final class CachedAppOptimizerTest {
false);
waitForHandler();
// the process is not compacted
- assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull();
+ assertThat(mCachedAppOptimizerUnderTest.mCompactStatsManager
+ .getLastCompactionStats(pid)).isNull();
processRecord.mState.setSetAdj(100);
processRecord.mState.setCurAdj(100);
@@ -989,9 +974,10 @@ public final class CachedAppOptimizerTest {
true);
waitForHandler();
// then process is compacted.
- assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
+ assertThat(mCachedAppOptimizerUnderTest
+ .mCompactStatsManager.getLastCompactionStats(pid)).isNotNull();
- mCachedAppOptimizerUnderTest.mLastCompactionStats.clear();
+ mCachedAppOptimizerUnderTest.mCompactStatsManager.getLastCompactionStats().clear();
if (CachedAppOptimizer.ENABLE_SHARED_AND_CODE_COMPACT) {
// We force a some compaction