Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f913ae21 authored by Misha Wagner's avatar Misha Wagner
Browse files

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
parent 44993614
Loading
Loading
Loading
Loading
+105 −27
Original line number Diff line number Diff line
@@ -38,16 +38,25 @@ public class CacheOomRanker {
    private static final boolean DEFAULT_USE_OOM_RE_RANKING = false;
    @VisibleForTesting
    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
    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
    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
    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 =
            new ScoreComparator();
@@ -66,15 +75,21 @@ public class CacheOomRanker {

    @GuardedBy("mPhenotypeFlagLock")
    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.
    @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.
    @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.
    @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.
    @GuardedBy("mPhenotypeFlagLock")
@@ -93,6 +108,8 @@ public class CacheOomRanker {
                                updateUseOomReranking();
                            } else if (KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK.equals(name)) {
                                updateNumberToReRank();
                            } else if (KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS.equals(name)) {
                                updatePreserveTopNApps();
                            } else if (KEY_OOM_RE_RANKING_LRU_WEIGHT.equals(name)) {
                                updateLruWeight();
                            } else if (KEY_OOM_RE_RANKING_USES_WEIGHT.equals(name)) {
@@ -159,6 +176,19 @@ public class CacheOomRanker {
        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")
    private void updateLruWeight() {
        mLruWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -183,6 +213,33 @@ public class CacheOomRanker {
     */
    @GuardedBy({"mService", "mProcLock"})
    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 usesWeight;
        float rssWeight;
@@ -202,52 +259,67 @@ public class CacheOomRanker {
            return;
        }

        int numProcessesEvaluated = 0;
        // Collect the least recently used processes to re-rank, only rank cached
        // processes further down the list than mLruProcessServiceStart.
        int cachedProcessPos = 0;
        for (int i = 0; i < lruProcessServiceStart
                && cachedProcessPos < scoredProcessRecords.length; ++i) {
            ProcessRecord app = lruList.get(i);
        int numProcessesReRanked = 0;
        while (numProcessesEvaluated < lruProcessServiceStart
                && numProcessesReRanked < scoredProcessRecords.length) {
            ProcessRecord process = lruList.get(numProcessesEvaluated);
            // Processes that will be assigned a cached oom adj score.
            if (!app.isKilledByAm() && app.getThread() != null && app.mState.getCurAdj()
                    >= ProcessList.UNKNOWN_ADJ) {
                scoredProcessRecords[cachedProcessPos].proc = app;
                scoredProcessRecords[cachedProcessPos].score = 0.0f;
                lruPositions[cachedProcessPos] = i;
                ++cachedProcessPos;
            if (appCanBeReRanked(process)) {
                scoredProcessRecords[numProcessesReRanked].proc = process;
                scoredProcessRecords[numProcessesReRanked].score = 0.0f;
                lruPositions[numProcessesReRanked] = numProcessesEvaluated;
                ++numProcessesReRanked;
            }
            ++numProcessesEvaluated;
        }

        // TODO maybe ensure a certain number above this in the cache before re-ranking.
        if (cachedProcessPos < scoredProcessRecords.length)  {
            // Ignore we don't have enough processes to worry about re-ranking.
            return;
        // Count how many apps we're not re-ranking (up to mPreserveTopNApps).
        int numProcessesNotReRanked = 0;
        while (numProcessesEvaluated < lruProcessServiceStart
                && 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.
        if (lruWeight > 0.0f) {
            // This doesn't use the LRU list ordering as after the first re-ranking
            // 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);
        }
        if (rssWeight > 0.0f) {
            synchronized (mService.mAppProfiler.mProfilerLock) {
                Arrays.sort(scoredProcessRecords, LAST_RSS_COMPARATOR);
                Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked, LAST_RSS_COMPARATOR);
            }
            addToScore(scoredProcessRecords, rssWeight);
        }
        if (usesWeight > 0.0f) {
            Arrays.sort(scoredProcessRecords, CACHE_USE_COMPARATOR);
            Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked, CACHE_USE_COMPARATOR);
            addToScore(scoredProcessRecords, usesWeight);
        }

        // 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) {
            boolean printedHeader = false;
            for (int i = 0; i < scoredProcessRecords.length; ++i) {
            for (int i = 0; i < numProcessesReRanked; ++i) {
                if (scoredProcessRecords[i].proc.getPid()
                        != lruList.get(lruPositions[i]).getPid()) {
                    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);
            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) {
        for (int i = 1; i < scores.length; ++i) {
            scores[i].score += i * weight;
+210 −14

File changed.

Preview size limit exceeded, changes collapsed.