Allow CacheOomRanker to rerank when there's <8 processes in the cache.
This allows us to increase the number of process we rerank without losing the impact of the reranking. This would also mean that the top apps in the cache get reranked more often, so we also add a flag to prevent the top N processes from being re-ranked. Discussed with vvaldes@ offline: this is closer to the logic in the simulations that decided the weights, so this logic change shouldn't break any assumptions of the model. Test: atest FrameworksMockingServicesTests:CacheOomRankerTest Bug: 191357172 Change-Id: I0533da0a70cfe7ed1b48e4f98be24a46f17f7845
This commit is contained in:
@@ -38,16 +38,25 @@ public class CacheOomRanker {
|
|||||||
private static final boolean DEFAULT_USE_OOM_RE_RANKING = false;
|
private static final boolean DEFAULT_USE_OOM_RE_RANKING = false;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK = "oom_re_ranking_number_to_re_rank";
|
static final String KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK = "oom_re_ranking_number_to_re_rank";
|
||||||
@VisibleForTesting static final int DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK = 8;
|
@VisibleForTesting
|
||||||
|
static final int DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK = 8;
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS =
|
||||||
|
"oom_re_ranking_preserve_top_n_apps";
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int DEFAULT_PRESERVE_TOP_N_APPS = 3;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String KEY_OOM_RE_RANKING_LRU_WEIGHT = "oom_re_ranking_lru_weight";
|
static final String KEY_OOM_RE_RANKING_LRU_WEIGHT = "oom_re_ranking_lru_weight";
|
||||||
@VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_LRU_WEIGHT = 0.35f;
|
@VisibleForTesting
|
||||||
|
static final float DEFAULT_OOM_RE_RANKING_LRU_WEIGHT = 0.35f;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String KEY_OOM_RE_RANKING_USES_WEIGHT = "oom_re_ranking_uses_weight";
|
static final String KEY_OOM_RE_RANKING_USES_WEIGHT = "oom_re_ranking_uses_weight";
|
||||||
@VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_USES_WEIGHT = 0.5f;
|
@VisibleForTesting
|
||||||
|
static final float DEFAULT_OOM_RE_RANKING_USES_WEIGHT = 0.5f;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String KEY_OOM_RE_RANKING_RSS_WEIGHT = "oom_re_ranking_rss_weight";
|
static final String KEY_OOM_RE_RANKING_RSS_WEIGHT = "oom_re_ranking_rss_weight";
|
||||||
@VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_RSS_WEIGHT = 0.15f;
|
@VisibleForTesting
|
||||||
|
static final float DEFAULT_OOM_RE_RANKING_RSS_WEIGHT = 0.15f;
|
||||||
|
|
||||||
private static final Comparator<RankedProcessRecord> SCORED_PROCESS_RECORD_COMPARATOR =
|
private static final Comparator<RankedProcessRecord> SCORED_PROCESS_RECORD_COMPARATOR =
|
||||||
new ScoreComparator();
|
new ScoreComparator();
|
||||||
@@ -66,15 +75,21 @@ public class CacheOomRanker {
|
|||||||
|
|
||||||
@GuardedBy("mPhenotypeFlagLock")
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
private boolean mUseOomReRanking = DEFAULT_USE_OOM_RE_RANKING;
|
private boolean mUseOomReRanking = DEFAULT_USE_OOM_RE_RANKING;
|
||||||
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
|
@VisibleForTesting
|
||||||
|
int mPreserveTopNApps = DEFAULT_PRESERVE_TOP_N_APPS;
|
||||||
// Weight to apply to the LRU ordering.
|
// Weight to apply to the LRU ordering.
|
||||||
@GuardedBy("mPhenotypeFlagLock")
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
@VisibleForTesting float mLruWeight = DEFAULT_OOM_RE_RANKING_LRU_WEIGHT;
|
@VisibleForTesting
|
||||||
|
float mLruWeight = DEFAULT_OOM_RE_RANKING_LRU_WEIGHT;
|
||||||
// Weight to apply to the ordering by number of times the process has been added to the cache.
|
// Weight to apply to the ordering by number of times the process has been added to the cache.
|
||||||
@GuardedBy("mPhenotypeFlagLock")
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
@VisibleForTesting float mUsesWeight = DEFAULT_OOM_RE_RANKING_USES_WEIGHT;
|
@VisibleForTesting
|
||||||
|
float mUsesWeight = DEFAULT_OOM_RE_RANKING_USES_WEIGHT;
|
||||||
// Weight to apply to the ordering by RSS used by the processes.
|
// Weight to apply to the ordering by RSS used by the processes.
|
||||||
@GuardedBy("mPhenotypeFlagLock")
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
@VisibleForTesting float mRssWeight = DEFAULT_OOM_RE_RANKING_RSS_WEIGHT;
|
@VisibleForTesting
|
||||||
|
float mRssWeight = DEFAULT_OOM_RE_RANKING_RSS_WEIGHT;
|
||||||
|
|
||||||
// Positions to replace in the lru list.
|
// Positions to replace in the lru list.
|
||||||
@GuardedBy("mPhenotypeFlagLock")
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
@@ -93,6 +108,8 @@ public class CacheOomRanker {
|
|||||||
updateUseOomReranking();
|
updateUseOomReranking();
|
||||||
} else if (KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK.equals(name)) {
|
} else if (KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK.equals(name)) {
|
||||||
updateNumberToReRank();
|
updateNumberToReRank();
|
||||||
|
} else if (KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS.equals(name)) {
|
||||||
|
updatePreserveTopNApps();
|
||||||
} else if (KEY_OOM_RE_RANKING_LRU_WEIGHT.equals(name)) {
|
} else if (KEY_OOM_RE_RANKING_LRU_WEIGHT.equals(name)) {
|
||||||
updateLruWeight();
|
updateLruWeight();
|
||||||
} else if (KEY_OOM_RE_RANKING_USES_WEIGHT.equals(name)) {
|
} else if (KEY_OOM_RE_RANKING_USES_WEIGHT.equals(name)) {
|
||||||
@@ -159,6 +176,19 @@ public class CacheOomRanker {
|
|||||||
return mScoredProcessRecords == null ? 0 : mScoredProcessRecords.length;
|
return mScoredProcessRecords == null ? 0 : mScoredProcessRecords.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
|
private void updatePreserveTopNApps() {
|
||||||
|
int preserveTopNApps = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
|
KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS, DEFAULT_PRESERVE_TOP_N_APPS);
|
||||||
|
if (preserveTopNApps < 0) {
|
||||||
|
Slog.w(OomAdjuster.TAG,
|
||||||
|
"Found negative value for preserveTopNApps, setting to default: "
|
||||||
|
+ preserveTopNApps);
|
||||||
|
preserveTopNApps = DEFAULT_PRESERVE_TOP_N_APPS;
|
||||||
|
}
|
||||||
|
mPreserveTopNApps = preserveTopNApps;
|
||||||
|
}
|
||||||
|
|
||||||
@GuardedBy("mPhenotypeFlagLock")
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
private void updateLruWeight() {
|
private void updateLruWeight() {
|
||||||
mLruWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
mLruWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
@@ -183,6 +213,33 @@ public class CacheOomRanker {
|
|||||||
*/
|
*/
|
||||||
@GuardedBy({"mService", "mProcLock"})
|
@GuardedBy({"mService", "mProcLock"})
|
||||||
void reRankLruCachedAppsLSP(ArrayList<ProcessRecord> lruList, int lruProcessServiceStart) {
|
void reRankLruCachedAppsLSP(ArrayList<ProcessRecord> lruList, int lruProcessServiceStart) {
|
||||||
|
// The lruList is a list of processes ordered by how recently they were used. The
|
||||||
|
// least-recently-used apps are at the beginning of the list. We keep track of two
|
||||||
|
// indices in the lruList:
|
||||||
|
//
|
||||||
|
// getNumberToReRank=5, preserveTopNApps=3, lruProcessServiceStart=7,
|
||||||
|
// lruList=
|
||||||
|
// 0: app A ^
|
||||||
|
// 1: app B | These apps are re-ranked, as they are the first five apps (see
|
||||||
|
// 2: app C | getNumberToReRank), excluding...
|
||||||
|
// 3: app D v
|
||||||
|
// 4: app E ^
|
||||||
|
// 5: app F | The three most-recently-used apps in the cache (see preserveTopNApps).
|
||||||
|
// 6: app G v
|
||||||
|
// 7: service A ^
|
||||||
|
// 8: service B | Everything beyond lruProcessServiceStart is ignored, as these aren't
|
||||||
|
// 9: service C | apps.
|
||||||
|
// 10: activity A |
|
||||||
|
// ... |
|
||||||
|
//
|
||||||
|
// `numProcessesEvaluated` moves across the apps (indices 0-6) or until we've found enough
|
||||||
|
// apps to re-rank, and made sure none of them are in the top `preserveTopNApps` apps.
|
||||||
|
// Re-ranked apps are copied into `scoredProcessRecords`, where the re-ranking calculation
|
||||||
|
// happens.
|
||||||
|
//
|
||||||
|
// Note that some apps in the `lruList` can be skipped, if they don't pass
|
||||||
|
//`appCanBeReRanked`.
|
||||||
|
|
||||||
float lruWeight;
|
float lruWeight;
|
||||||
float usesWeight;
|
float usesWeight;
|
||||||
float rssWeight;
|
float rssWeight;
|
||||||
@@ -202,52 +259,67 @@ public class CacheOomRanker {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int numProcessesEvaluated = 0;
|
||||||
// Collect the least recently used processes to re-rank, only rank cached
|
// Collect the least recently used processes to re-rank, only rank cached
|
||||||
// processes further down the list than mLruProcessServiceStart.
|
// processes further down the list than mLruProcessServiceStart.
|
||||||
int cachedProcessPos = 0;
|
int numProcessesReRanked = 0;
|
||||||
for (int i = 0; i < lruProcessServiceStart
|
while (numProcessesEvaluated < lruProcessServiceStart
|
||||||
&& cachedProcessPos < scoredProcessRecords.length; ++i) {
|
&& numProcessesReRanked < scoredProcessRecords.length) {
|
||||||
ProcessRecord app = lruList.get(i);
|
ProcessRecord process = lruList.get(numProcessesEvaluated);
|
||||||
// Processes that will be assigned a cached oom adj score.
|
// Processes that will be assigned a cached oom adj score.
|
||||||
if (!app.isKilledByAm() && app.getThread() != null && app.mState.getCurAdj()
|
if (appCanBeReRanked(process)) {
|
||||||
>= ProcessList.UNKNOWN_ADJ) {
|
scoredProcessRecords[numProcessesReRanked].proc = process;
|
||||||
scoredProcessRecords[cachedProcessPos].proc = app;
|
scoredProcessRecords[numProcessesReRanked].score = 0.0f;
|
||||||
scoredProcessRecords[cachedProcessPos].score = 0.0f;
|
lruPositions[numProcessesReRanked] = numProcessesEvaluated;
|
||||||
lruPositions[cachedProcessPos] = i;
|
++numProcessesReRanked;
|
||||||
++cachedProcessPos;
|
|
||||||
}
|
}
|
||||||
|
++numProcessesEvaluated;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO maybe ensure a certain number above this in the cache before re-ranking.
|
// Count how many apps we're not re-ranking (up to mPreserveTopNApps).
|
||||||
if (cachedProcessPos < scoredProcessRecords.length) {
|
int numProcessesNotReRanked = 0;
|
||||||
// Ignore we don't have enough processes to worry about re-ranking.
|
while (numProcessesEvaluated < lruProcessServiceStart
|
||||||
return;
|
&& numProcessesNotReRanked < mPreserveTopNApps) {
|
||||||
|
ProcessRecord process = lruList.get(numProcessesEvaluated);
|
||||||
|
if (appCanBeReRanked(process)) {
|
||||||
|
numProcessesNotReRanked++;
|
||||||
|
}
|
||||||
|
numProcessesEvaluated++;
|
||||||
|
}
|
||||||
|
// Exclude the top `mPreserveTopNApps` apps from re-ranking.
|
||||||
|
if (numProcessesNotReRanked < mPreserveTopNApps) {
|
||||||
|
numProcessesReRanked -= mPreserveTopNApps - numProcessesNotReRanked;
|
||||||
|
if (numProcessesReRanked < 0) {
|
||||||
|
numProcessesReRanked = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add scores for each of the weighted features we want to rank based on.
|
// Add scores for each of the weighted features we want to rank based on.
|
||||||
if (lruWeight > 0.0f) {
|
if (lruWeight > 0.0f) {
|
||||||
// This doesn't use the LRU list ordering as after the first re-ranking
|
// This doesn't use the LRU list ordering as after the first re-ranking
|
||||||
// that will no longer be lru.
|
// that will no longer be lru.
|
||||||
Arrays.sort(scoredProcessRecords, LAST_ACTIVITY_TIME_COMPARATOR);
|
Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked,
|
||||||
|
LAST_ACTIVITY_TIME_COMPARATOR);
|
||||||
addToScore(scoredProcessRecords, lruWeight);
|
addToScore(scoredProcessRecords, lruWeight);
|
||||||
}
|
}
|
||||||
if (rssWeight > 0.0f) {
|
if (rssWeight > 0.0f) {
|
||||||
synchronized (mService.mAppProfiler.mProfilerLock) {
|
synchronized (mService.mAppProfiler.mProfilerLock) {
|
||||||
Arrays.sort(scoredProcessRecords, LAST_RSS_COMPARATOR);
|
Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked, LAST_RSS_COMPARATOR);
|
||||||
}
|
}
|
||||||
addToScore(scoredProcessRecords, rssWeight);
|
addToScore(scoredProcessRecords, rssWeight);
|
||||||
}
|
}
|
||||||
if (usesWeight > 0.0f) {
|
if (usesWeight > 0.0f) {
|
||||||
Arrays.sort(scoredProcessRecords, CACHE_USE_COMPARATOR);
|
Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked, CACHE_USE_COMPARATOR);
|
||||||
addToScore(scoredProcessRecords, usesWeight);
|
addToScore(scoredProcessRecords, usesWeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-rank by the new combined score.
|
// Re-rank by the new combined score.
|
||||||
Arrays.sort(scoredProcessRecords, SCORED_PROCESS_RECORD_COMPARATOR);
|
Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked,
|
||||||
|
SCORED_PROCESS_RECORD_COMPARATOR);
|
||||||
|
|
||||||
if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) {
|
if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) {
|
||||||
boolean printedHeader = false;
|
boolean printedHeader = false;
|
||||||
for (int i = 0; i < scoredProcessRecords.length; ++i) {
|
for (int i = 0; i < numProcessesReRanked; ++i) {
|
||||||
if (scoredProcessRecords[i].proc.getPid()
|
if (scoredProcessRecords[i].proc.getPid()
|
||||||
!= lruList.get(lruPositions[i]).getPid()) {
|
!= lruList.get(lruPositions[i]).getPid()) {
|
||||||
if (!printedHeader) {
|
if (!printedHeader) {
|
||||||
@@ -260,12 +332,18 @@ public class CacheOomRanker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < scoredProcessRecords.length; ++i) {
|
for (int i = 0; i < numProcessesReRanked; ++i) {
|
||||||
lruList.set(lruPositions[i], scoredProcessRecords[i].proc);
|
lruList.set(lruPositions[i], scoredProcessRecords[i].proc);
|
||||||
scoredProcessRecords[i].proc = null;
|
scoredProcessRecords[i].proc = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean appCanBeReRanked(ProcessRecord process) {
|
||||||
|
return !process.isKilledByAm()
|
||||||
|
&& process.getThread() != null
|
||||||
|
&& process.mState.getCurAdj() >= ProcessList.UNKNOWN_ADJ;
|
||||||
|
}
|
||||||
|
|
||||||
private static void addToScore(RankedProcessRecord[] scores, float weight) {
|
private static void addToScore(RankedProcessRecord[] scores, float weight) {
|
||||||
for (int i = 1; i < scores.length; ++i) {
|
for (int i = 1; i < scores.length; ++i) {
|
||||||
scores[i].score += i * weight;
|
scores[i].score += i * weight;
|
||||||
|
|||||||
@@ -142,6 +142,15 @@ public class CacheOomRankerTest {
|
|||||||
assertThat(mCacheOomRanker.getNumberToReRank())
|
assertThat(mCacheOomRanker.getNumberToReRank())
|
||||||
.isEqualTo(CacheOomRanker.DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK + 2);
|
.isEqualTo(CacheOomRanker.DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK + 2);
|
||||||
|
|
||||||
|
mExecutor.init();
|
||||||
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
|
CacheOomRanker.KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS,
|
||||||
|
Integer.toString(CacheOomRanker.DEFAULT_PRESERVE_TOP_N_APPS + 1),
|
||||||
|
false);
|
||||||
|
mExecutor.waitForLatch();
|
||||||
|
assertThat(mCacheOomRanker.mPreserveTopNApps)
|
||||||
|
.isEqualTo(CacheOomRanker.DEFAULT_PRESERVE_TOP_N_APPS + 1);
|
||||||
|
|
||||||
mExecutor.init();
|
mExecutor.init();
|
||||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
CacheOomRanker.KEY_OOM_RE_RANKING_LRU_WEIGHT,
|
CacheOomRanker.KEY_OOM_RE_RANKING_LRU_WEIGHT,
|
||||||
@@ -173,6 +182,7 @@ public class CacheOomRankerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void reRankLruCachedApps_lruImpactsOrdering() throws InterruptedException {
|
public void reRankLruCachedApps_lruImpactsOrdering() throws InterruptedException {
|
||||||
setConfig(/* numberToReRank= */ 5,
|
setConfig(/* numberToReRank= */ 5,
|
||||||
|
/* preserveTopNApps= */ 0,
|
||||||
/* usesWeight= */ 0.0f,
|
/* usesWeight= */ 0.0f,
|
||||||
/* pssWeight= */ 0.0f,
|
/* pssWeight= */ 0.0f,
|
||||||
/* lruWeight= */1.0f);
|
/* lruWeight= */1.0f);
|
||||||
@@ -211,6 +221,7 @@ public class CacheOomRankerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void reRankLruCachedApps_rssImpactsOrdering() throws InterruptedException {
|
public void reRankLruCachedApps_rssImpactsOrdering() throws InterruptedException {
|
||||||
setConfig(/* numberToReRank= */ 6,
|
setConfig(/* numberToReRank= */ 6,
|
||||||
|
/* preserveTopNApps= */ 0,
|
||||||
/* usesWeight= */ 0.0f,
|
/* usesWeight= */ 0.0f,
|
||||||
/* pssWeight= */ 1.0f,
|
/* pssWeight= */ 1.0f,
|
||||||
/* lruWeight= */ 0.0f);
|
/* lruWeight= */ 0.0f);
|
||||||
@@ -251,6 +262,7 @@ public class CacheOomRankerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void reRankLruCachedApps_usesImpactsOrdering() throws InterruptedException {
|
public void reRankLruCachedApps_usesImpactsOrdering() throws InterruptedException {
|
||||||
setConfig(/* numberToReRank= */ 4,
|
setConfig(/* numberToReRank= */ 4,
|
||||||
|
/* preserveTopNApps= */ 0,
|
||||||
/* usesWeight= */ 1.0f,
|
/* usesWeight= */ 1.0f,
|
||||||
/* pssWeight= */ 0.0f,
|
/* pssWeight= */ 0.0f,
|
||||||
/* lruWeight= */ 0.0f);
|
/* lruWeight= */ 0.0f);
|
||||||
@@ -286,23 +298,24 @@ public class CacheOomRankerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void reRankLruCachedApps_notEnoughProcesses() throws InterruptedException {
|
public void reRankLruCachedApps_fewProcesses() throws InterruptedException {
|
||||||
setConfig(/* numberToReRank= */ 4,
|
setConfig(/* numberToReRank= */ 4,
|
||||||
|
/* preserveTopNApps= */ 0,
|
||||||
/* usesWeight= */ 1.0f,
|
/* usesWeight= */ 1.0f,
|
||||||
/* pssWeight= */ 0.0f,
|
/* pssWeight= */ 0.0f,
|
||||||
/* lruWeight= */ 0.0f);
|
/* lruWeight= */ 0.0f);
|
||||||
|
|
||||||
ProcessList list = new ProcessList();
|
ProcessList list = new ProcessList();
|
||||||
ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
|
ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
|
||||||
ProcessRecord unknownAdj1 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
|
NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
|
||||||
processList.add(unknownAdj1);
|
processList.add(used1000);
|
||||||
ProcessRecord unknownAdj2 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
|
NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
|
||||||
processList.add(unknownAdj2);
|
processList.add(used2000);
|
||||||
ProcessRecord unknownAdj3 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
|
NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
|
||||||
processList.add(unknownAdj3);
|
processList.add(used10);
|
||||||
ProcessRecord foregroundAdj = nextProcessRecord(ProcessList.FOREGROUND_APP_ADJ,
|
ProcessRecord foregroundAdj = nextProcessRecord(ProcessList.FOREGROUND_APP_ADJ,
|
||||||
NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
|
NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
|
||||||
processList.add(foregroundAdj);
|
processList.add(foregroundAdj);
|
||||||
@@ -314,17 +327,156 @@ public class CacheOomRankerTest {
|
|||||||
processList.add(systemAdj);
|
processList.add(systemAdj);
|
||||||
list.setLruProcessServiceStartLSP(processList.size());
|
list.setLruProcessServiceStartLSP(processList.size());
|
||||||
|
|
||||||
// 6 Processes but only 3 in eligible for cache so no re-ranking.
|
|
||||||
mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
|
mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
|
||||||
|
|
||||||
// All positions unchanged.
|
// 6 processes, only 3 in eligible for cache, so only those are re-ranked.
|
||||||
assertThat(processList).containsExactly(unknownAdj1, unknownAdj2, unknownAdj3,
|
assertThat(processList).containsExactly(used10, used1000, used2000,
|
||||||
foregroundAdj, serviceAdj, systemAdj).inOrder();
|
foregroundAdj, serviceAdj, systemAdj).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void reRankLruCachedApps_notEnoughNonServiceProcesses() throws InterruptedException {
|
public void reRankLruCachedApps_fewNonServiceProcesses() throws InterruptedException {
|
||||||
setConfig(/* numberToReRank= */ 4,
|
setConfig(/* numberToReRank= */ 4,
|
||||||
|
/* preserveTopNApps= */ 0,
|
||||||
|
/* usesWeight= */ 1.0f,
|
||||||
|
/* pssWeight= */ 0.0f,
|
||||||
|
/* lruWeight= */ 0.0f);
|
||||||
|
|
||||||
|
ProcessList list = new ProcessList();
|
||||||
|
ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
|
||||||
|
ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
|
||||||
|
processList.add(used1000);
|
||||||
|
ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
|
||||||
|
processList.add(used2000);
|
||||||
|
ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
|
||||||
|
processList.add(used10);
|
||||||
|
ProcessRecord service1 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
|
||||||
|
processList.add(service1);
|
||||||
|
ProcessRecord service2 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
|
||||||
|
processList.add(service2);
|
||||||
|
ProcessRecord service3 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
|
||||||
|
processList.add(service3);
|
||||||
|
list.setLruProcessServiceStartLSP(3);
|
||||||
|
|
||||||
|
mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
|
||||||
|
|
||||||
|
// Services unchanged, rest re-ranked.
|
||||||
|
assertThat(processList).containsExactly(used10, used1000, used2000, service1, service2,
|
||||||
|
service3).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void reRankLruCachedApps_manyProcessesThenFew() throws InterruptedException {
|
||||||
|
setConfig(/* numberToReRank= */ 6,
|
||||||
|
/* preserveTopNApps= */ 0,
|
||||||
|
/* usesWeight= */ 1.0f,
|
||||||
|
/* pssWeight= */ 0.0f,
|
||||||
|
/* lruWeight= */ 0.0f);
|
||||||
|
|
||||||
|
ProcessList set1List = new ProcessList();
|
||||||
|
ArrayList<ProcessRecord> set1ProcessList = set1List.getLruProcessesLSP();
|
||||||
|
ProcessRecord set1Used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
|
||||||
|
set1ProcessList.add(set1Used1000);
|
||||||
|
ProcessRecord set1Used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
|
||||||
|
set1ProcessList.add(set1Used2000);
|
||||||
|
ProcessRecord set1Used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
|
||||||
|
set1ProcessList.add(set1Used10);
|
||||||
|
ProcessRecord set1Uses20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
|
||||||
|
set1ProcessList.add(set1Uses20);
|
||||||
|
ProcessRecord set1Uses500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
|
||||||
|
set1ProcessList.add(set1Uses500);
|
||||||
|
ProcessRecord set1Uses200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
|
||||||
|
set1ProcessList.add(set1Uses200);
|
||||||
|
set1List.setLruProcessServiceStartLSP(set1ProcessList.size());
|
||||||
|
|
||||||
|
mCacheOomRanker.reRankLruCachedAppsLSP(set1ProcessList,
|
||||||
|
set1List.getLruProcessServiceStartLOSP());
|
||||||
|
assertThat(set1ProcessList).containsExactly(set1Used10, set1Uses20, set1Uses200,
|
||||||
|
set1Uses500, set1Used1000, set1Used2000).inOrder();
|
||||||
|
|
||||||
|
ProcessList set2List = new ProcessList();
|
||||||
|
ArrayList<ProcessRecord> set2ProcessList = set2List.getLruProcessesLSP();
|
||||||
|
ProcessRecord set2Used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
|
||||||
|
set2ProcessList.add(set2Used1000);
|
||||||
|
ProcessRecord set2Used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
|
||||||
|
set2ProcessList.add(set2Used2000);
|
||||||
|
ProcessRecord set2Used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
|
||||||
|
set2ProcessList.add(set2Used10);
|
||||||
|
ProcessRecord set2ForegroundAdj = nextProcessRecord(ProcessList.FOREGROUND_APP_ADJ,
|
||||||
|
NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
|
||||||
|
set2ProcessList.add(set2ForegroundAdj);
|
||||||
|
ProcessRecord set2ServiceAdj = nextProcessRecord(ProcessList.SERVICE_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
|
||||||
|
set2ProcessList.add(set2ServiceAdj);
|
||||||
|
ProcessRecord set2SystemAdj = nextProcessRecord(ProcessList.SYSTEM_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
|
||||||
|
set2ProcessList.add(set2SystemAdj);
|
||||||
|
set2List.setLruProcessServiceStartLSP(set2ProcessList.size());
|
||||||
|
|
||||||
|
mCacheOomRanker.reRankLruCachedAppsLSP(set2ProcessList,
|
||||||
|
set2List.getLruProcessServiceStartLOSP());
|
||||||
|
assertThat(set2ProcessList).containsExactly(set2Used10, set2Used1000, set2Used2000,
|
||||||
|
set2ForegroundAdj, set2ServiceAdj, set2SystemAdj).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void reRankLruCachedApps_preservesTopNApps() throws InterruptedException {
|
||||||
|
setConfig(/* numberToReRank= */ 6,
|
||||||
|
/* preserveTopNApps= */ 3,
|
||||||
|
/* usesWeight= */ 1.0f,
|
||||||
|
/* pssWeight= */ 0.0f,
|
||||||
|
/* lruWeight= */ 0.0f);
|
||||||
|
|
||||||
|
ProcessList list = new ProcessList();
|
||||||
|
ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
|
||||||
|
ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
|
||||||
|
processList.add(used1000);
|
||||||
|
ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
|
||||||
|
processList.add(used2000);
|
||||||
|
ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
|
||||||
|
processList.add(used10);
|
||||||
|
// Preserving the top 3 processes, so these should not be re-ranked.
|
||||||
|
ProcessRecord used20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
|
||||||
|
processList.add(used20);
|
||||||
|
ProcessRecord used500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
|
||||||
|
processList.add(used500);
|
||||||
|
ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
|
||||||
|
processList.add(used200);
|
||||||
|
list.setLruProcessServiceStartLSP(processList.size());
|
||||||
|
|
||||||
|
mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
|
||||||
|
|
||||||
|
// First 3 ordered by uses, then last processes position unchanged.
|
||||||
|
assertThat(processList).containsExactly(used10, used1000, used2000, used20, used500,
|
||||||
|
used200).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void reRankLruCachedApps_preservesTopNApps_allAppsUnchanged()
|
||||||
|
throws InterruptedException {
|
||||||
|
setConfig(/* numberToReRank= */ 6,
|
||||||
|
/* preserveTopNApps= */ 100,
|
||||||
/* usesWeight= */ 1.0f,
|
/* usesWeight= */ 1.0f,
|
||||||
/* pssWeight= */ 0.0f,
|
/* pssWeight= */ 0.0f,
|
||||||
/* lruWeight= */ 0.0f);
|
/* lruWeight= */ 0.0f);
|
||||||
@@ -349,22 +501,66 @@ public class CacheOomRankerTest {
|
|||||||
ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
|
||||||
processList.add(used200);
|
processList.add(used200);
|
||||||
list.setLruProcessServiceStartLSP(3);
|
list.setLruProcessServiceStartLSP(processList.size());
|
||||||
|
|
||||||
mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
|
mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
|
||||||
|
|
||||||
// All positions unchanged.
|
// Nothing reordered, as we preserve the top 100 apps.
|
||||||
assertThat(processList).containsExactly(used1000, used2000, used10, used20, used500,
|
assertThat(processList).containsExactly(used1000, used2000, used10, used20, used500,
|
||||||
used200).inOrder();
|
used200).inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setConfig(int numberToReRank, float usesWeight, float pssWeight, float lruWeight)
|
@Test
|
||||||
|
public void reRankLruCachedApps_preservesTopNApps_negativeReplacedWithDefault()
|
||||||
|
throws InterruptedException {
|
||||||
|
setConfig(/* numberToReRank= */ 6,
|
||||||
|
/* preserveTopNApps= */ -100,
|
||||||
|
/* usesWeight= */ 1.0f,
|
||||||
|
/* pssWeight= */ 0.0f,
|
||||||
|
/* lruWeight= */ 0.0f);
|
||||||
|
|
||||||
|
ProcessList list = new ProcessList();
|
||||||
|
ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
|
||||||
|
ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
|
||||||
|
processList.add(used1000);
|
||||||
|
ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
|
||||||
|
processList.add(used2000);
|
||||||
|
ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
|
||||||
|
processList.add(used10);
|
||||||
|
// Negative preserveTopNApps interpreted as the default (3), so the last three are unranked.
|
||||||
|
ProcessRecord used20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
|
||||||
|
processList.add(used20);
|
||||||
|
ProcessRecord used500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
|
||||||
|
processList.add(used500);
|
||||||
|
ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
|
||||||
|
NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
|
||||||
|
processList.add(used200);
|
||||||
|
list.setLruProcessServiceStartLSP(processList.size());
|
||||||
|
|
||||||
|
mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
|
||||||
|
|
||||||
|
// First 3 apps re-ranked, as preserveTopNApps is interpreted as 3.
|
||||||
|
assertThat(processList).containsExactly(used10, used1000, used2000, used20, used500,
|
||||||
|
used200).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setConfig(int numberToReRank, int preserveTopNApps, float usesWeight,
|
||||||
|
float pssWeight, float lruWeight)
|
||||||
throws InterruptedException {
|
throws InterruptedException {
|
||||||
mExecutor.init(4);
|
mExecutor.init(4);
|
||||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
CacheOomRanker.KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK,
|
CacheOomRanker.KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK,
|
||||||
Integer.toString(numberToReRank),
|
Integer.toString(numberToReRank),
|
||||||
false);
|
false);
|
||||||
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
|
CacheOomRanker.KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS,
|
||||||
|
Integer.toString(preserveTopNApps),
|
||||||
|
false);
|
||||||
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
CacheOomRanker.KEY_OOM_RE_RANKING_LRU_WEIGHT,
|
CacheOomRanker.KEY_OOM_RE_RANKING_LRU_WEIGHT,
|
||||||
Float.toString(lruWeight),
|
Float.toString(lruWeight),
|
||||||
|
|||||||
Reference in New Issue
Block a user