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

Commit f1cca18a authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Try to improve PSS collection.

The goal is to collect PSS data from processes when they
are in as stable a state as possible.  We now have tables
for the durations to use for PSS collection based on
process state, and scheduling of collection is all driven
by process state changes.

Change-Id: I95e076f6971b9c093118e53dc8240fb3f5bad3b2
parent 5d3dff1d
Loading
Loading
Loading
Loading
+59 −60
Original line number Diff line number Diff line
@@ -229,6 +229,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
    static final boolean DEBUG_USER_LEAVING = localLOGV || false;
    static final boolean DEBUG_VISBILITY = localLOGV || false;
    static final boolean DEBUG_PSS = localLOGV || false;
    static final boolean VALIDATE_TOKENS = true;
    static final boolean SHOW_ACTIVITY_START_TIME = true;
@@ -269,24 +270,13 @@ public final class ActivityManagerService extends ActivityManagerNative
    // The minimum amount of time between successive GC requests for a process.
    static final int GC_MIN_INTERVAL = 60*1000;
    // The minimum amount of time between successive PSS requests for a process.
    static final int PSS_MIN_INTERVAL = 2*60*1000;
    // The amount of time we will sample PSS of the current top process while the
    // screen is on.
    static final int PSS_TOP_INTERVAL = 2*60*1000;
    // The amount of time we will sample PSS of any processes that more at least as
    // important as perceptible while the screen is on.
    static final int PSS_PERCEPTIBLE_INTERVAL = 10*60*1000;
    // The maximum amount of time for a process to be around until we will take
    // a PSS snapshot on its next oom change.
    static final int PSS_MAX_INTERVAL = 30*60*1000;
    // The minimum amount of time between successive PSS requests for a process.
    static final int FULL_PSS_MIN_INTERVAL = 10*60*1000;
    // The minimum amount of time between successive PSS requests for a process
    // when the request is due to the memory state being lowered.
    static final int FULL_PSS_LOWERED_INTERVAL = 2*60*1000;
    // The rate at which we check for apps using excessive power -- 15 mins.
    static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000;
@@ -1497,27 +1487,26 @@ public final class ActivityManagerService extends ActivityManagerNative
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case COLLECT_PSS_BG_MSG: {
                int i=0;
                int i=0, num=0;
                long start = SystemClock.uptimeMillis();
                long[] tmp = new long[1];
                do {
                    ProcessRecord proc;
                    int oomAdj;
                    int procState;
                    int pid;
                    synchronized (ActivityManagerService.this) {
                        if (i >= mPendingPssProcesses.size()) {
                            Slog.i(TAG, "Collected PSS of " + i + " processes in "
                                    + (SystemClock.uptimeMillis()-start) + "ms");
                            if (DEBUG_PSS) Slog.i(TAG, "Collected PSS of " + num + " of " + i
                                    + " processes in " + (SystemClock.uptimeMillis()-start) + "ms");
                            mPendingPssProcesses.clear();
                            return;
                        }
                        proc = mPendingPssProcesses.get(i);
                        if (proc.thread != null) {
                            oomAdj = proc.setAdj;
                        procState = proc.pssProcState;
                        if (proc.thread != null && procState == proc.setProcState) {
                            pid = proc.pid;
                        } else {
                            proc = null;
                            oomAdj = 0;
                            pid = 0;
                        }
                        i++;
@@ -1525,7 +1514,10 @@ public final class ActivityManagerService extends ActivityManagerNative
                    if (proc != null) {
                        long pss = Debug.getPss(pid, tmp);
                        synchronized (ActivityManagerService.this) {
                            if (proc.thread != null && proc.setAdj == oomAdj && proc.pid == pid) {
                            if (proc.thread != null && proc.setProcState == procState
                                    && proc.pid == pid) {
                                num++;
                                proc.lastPssTime = SystemClock.uptimeMillis();
                                proc.baseProcessTracker.addPss(pss, tmp[0], true);
                            }
                        }
@@ -4770,7 +4762,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                                            boolean sticky, int sendingUser) {
                                        synchronized (ActivityManagerService.this) {
                                            requestPssAllProcsLocked(SystemClock.uptimeMillis(),
                                                    true);
                                                    true, false);
                                        }
                                    }
                                },
@@ -14173,35 +14165,41 @@ public final class ActivityManagerService extends ActivityManagerNative
    /**
     * Schedule PSS collection of a process.
     */
    void requestPssLocked(ProcessRecord proc, long now, boolean always) {
        if (!always && now < (proc.lastPssTime+PSS_MIN_INTERVAL)) {
            return;
        }
    void requestPssLocked(ProcessRecord proc, int procState) {
        if (mPendingPssProcesses.contains(proc)) {
            return;
        }
        proc.lastPssTime = now;
        if (mPendingPssProcesses.size() == 0) {
            mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
        }
        if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of: " + proc);
        proc.pssProcState = procState;
        mPendingPssProcesses.add(proc);
    }
    /**
     * Schedule PSS collection of all processes.
     */
    void requestPssAllProcsLocked(long now, boolean always) {
        if (!always && now < (mLastFullPssTime+FULL_PSS_MIN_INTERVAL)) {
    void requestPssAllProcsLocked(long now, boolean always, boolean memLowered) {
        if (!always) {
            if (now < (mLastFullPssTime +
                    (memLowered ? FULL_PSS_LOWERED_INTERVAL : FULL_PSS_MIN_INTERVAL))) {
                return;
            }
        }
        if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of all procs!  memLowered=" + memLowered);
        mLastFullPssTime = now;
        mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
        mPendingPssProcesses.clear();
        for (int i=mLruProcesses.size()-1; i>=0; i--) {
            ProcessRecord app = mLruProcesses.get(i);
            app.lastPssTime = now;
            if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
                app.pssProcState = app.setProcState;
                app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
                        mSleeping, now);
                mPendingPssProcesses.add(app);
            }
        }
        mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
    }
@@ -14459,32 +14457,11 @@ public final class ActivityManagerService extends ActivityManagerNative
            app.setRawAdj = app.curRawAdj;
        }
        if (!mSleeping) {
            if (app == TOP_APP && now > (app.lastPssTime+PSS_TOP_INTERVAL)) {
                // For the current top application we will very aggressively collect
                // PSS data to have a good measure of memory use while in the foreground.
                requestPssLocked(app, now, true);
            } else if (app.curAdj <= ProcessList.PERCEPTIBLE_APP_ADJ
                    && now > (app.lastPssTime+PSS_TOP_INTERVAL)) {
                // For any unkillable processes, we will more regularly collect their PSS
                // since they have a significant impact on the memory state of the device.
                requestPssLocked(app, now, true);
            }
        }
        if (app.curAdj != app.setAdj) {
            if (Process.setOomAdj(app.pid, app.curAdj)) {
                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
                    TAG, "Set " + app.pid + " " + app.processName +
                    " adj " + app.curAdj + ": " + app.adjType);
                if (app.setAdj == ProcessList.SERVICE_ADJ
                        && app.curAdj == ProcessList.SERVICE_B_ADJ) {
                    // If a service is dropping to the B list, it has been running for
                    // a while, take a PSS snapshot.
                    requestPssLocked(app, now, false);
                } else if (now > (app.lastPssTime+PSS_MAX_INTERVAL)) {
                    requestPssLocked(app, now, true);
                }
                app.setAdj = app.curAdj;
            } else {
                success = false;
@@ -14542,19 +14519,39 @@ public final class ActivityManagerService extends ActivityManagerNative
                }
            }
        }
        if (app.setProcState < 0 || ProcessList.procStatesDifferForMem(app.curProcState,
                app.setProcState)) {
            if (DEBUG_PSS) Slog.d(TAG, "Process state change from " + app.setProcState
                    + " to " + app.curProcState + ": " + app);
            app.lastStateTime = now;
            app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
                    mSleeping, now);
        } else {
            if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
                    && now > (app.lastStateTime+ProcessList.PSS_MIN_TIME_FROM_STATE_CHANGE))) {
                requestPssLocked(app, app.setProcState);
                app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
                        mSleeping, now);
            }
        }
        if (app.setProcState != app.curProcState) {
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
                    "Proc state change of " + app.processName
                    + " to " + app.curProcState);
            app.setProcState = app.curProcState;
            app.procStateChanged = true;
            if (!doingAll) {
                app.setProcessTrackerState(mProcessTracker.getMemFactorLocked(), now);
                setProcessTrackerState(app, mProcessTracker.getMemFactorLocked(), now);
            } else {
                app.procStateChanged = true;
            }
        }
        return success;
    }
    private final void setProcessTrackerState(ProcessRecord proc, int memFactor, long now) {
        proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
    }
    private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
        if (app.thread == null) {
@@ -14835,7 +14832,8 @@ public final class ActivityManagerService extends ActivityManagerNative
            for (int i=N-1; i>=0; i--) {
                ProcessRecord app = mLruProcesses.get(i);
                if (allChanged || app.procStateChanged) {
                    app.setProcessTrackerState(trackerMemFactor, now);
                    setProcessTrackerState(app, trackerMemFactor, now);
                    app.procStateChanged = false;
                }
                if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
                        && !app.killedBackground) {
@@ -14924,7 +14922,8 @@ public final class ActivityManagerService extends ActivityManagerNative
            for (int i=N-1; i>=0; i--) {
                ProcessRecord app = mLruProcesses.get(i);
                if (allChanged || app.procStateChanged) {
                    app.setProcessTrackerState(ProcessTracker.ADJ_MEM_FACTOR_NORMAL, now);
                    setProcessTrackerState(app, trackerMemFactor, now);
                    app.procStateChanged = false;
                }
                if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
                        || app.systemNoUi) && app.pendingUiClean) {
@@ -14952,7 +14951,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        if (allChanged) {
            requestPssAllProcsLocked(now, false);
            requestPssAllProcsLocked(now, false, mProcessTracker.isMemFactorLowered());
        }
        if (mProcessTracker.shouldWriteNowLocked(now)) {
+0 −1
Original line number Diff line number Diff line
@@ -1783,7 +1783,6 @@ public final class ActivityStackSupervisor {
        if (allResumedActivitiesIdle()) {
            if (r != null) {
                mService.scheduleAppGcsLocked();
                mService.requestPssLocked(r.app, SystemClock.uptimeMillis(), false);
            }

            if (mLaunchingActivity.isHeld()) {
+100 −0
Original line number Diff line number Diff line
@@ -278,6 +278,106 @@ final class ProcessList {
        return (totalProcessLimit*2)/3;
    }

    // The minimum amount of time after a state change it is safe ro collect PSS.
    public static final int PSS_MIN_TIME_FROM_STATE_CHANGE = 15*1000;

    // The maximum amount of time we want to go between PSS collections.
    public static final int PSS_MAX_INTERVAL = 30*60*1000;

    // The minimum amount of time between successive PSS requests for *all* processes.
    public static final int PSS_ALL_INTERVAL = 10*60*1000;

    // The minimum amount of time between successive PSS requests for a process.
    private static final int PSS_SHORT_INTERVAL = 2*60*1000;

    // The amount of time until PSS when a process first becomes top.
    private static final int PSS_FIRST_TOP_INTERVAL = 15*1000;

    // The amount of time until PSS when a process first becomes cached.
    private static final int PSS_FIRST_CACHED_INTERVAL = 5*60*1000;

    // The amount of time until PSS when an important process stays in the same state.
    private static final int PSS_SAME_IMPORTANT_INTERVAL = 15*60*1000;

    // The amount of time until PSS when a service process stays in the same state.
    private static final int PSS_SAME_SERVICE_INTERVAL = 20*60*1000;

    // The amount of time until PSS when a cached process stays in the same state.
    private static final int PSS_SAME_CACHED_INTERVAL = 30*60*1000;

    public static final int PROC_MEM_PERSISTENT = 0;
    public static final int PROC_MEM_TOP = 1;
    public static final int PROC_MEM_IMPORTANT = 2;
    public static final int PROC_MEM_SERVICE = 3;
    public static final int PROC_MEM_CACHED = 4;

    private static final int[] sProcStateToProcMem = new int[] {
        PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT
        PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT_UI
        PROC_MEM_TOP,                   // ActivityManager.PROCESS_STATE_TOP
        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_BACKUP
        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
        PROC_MEM_SERVICE,               // ActivityManager.PROCESS_STATE_SERVICE
        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_RECEIVER
        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_HOME
        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
        PROC_MEM_CACHED,                // ActivityManager.PROCESS_STATE_CACHED_EMPTY
    };

    private static final long[] sFirstAwakePssTimes = new long[] {
        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_PERSISTENT
        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_PERSISTENT_UI
        PSS_FIRST_TOP_INTERVAL,         // ActivityManager.PROCESS_STATE_TOP
        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_BACKUP
        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_SERVICE
        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_RECEIVER
        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_HOME
        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
        PSS_FIRST_CACHED_INTERVAL,      // ActivityManager.PROCESS_STATE_CACHED_EMPTY
    };

    private static final long[] sSameAwakePssTimes = new long[] {
        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT
        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT_UI
        PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_TOP
        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_BACKUP
        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
        PSS_SAME_SERVICE_INTERVAL,      // ActivityManager.PROCESS_STATE_SERVICE
        PSS_SAME_SERVICE_INTERVAL,      // ActivityManager.PROCESS_STATE_RECEIVER
        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_HOME
        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
        PSS_SAME_CACHED_INTERVAL,       // ActivityManager.PROCESS_STATE_CACHED_EMPTY
    };

    public static boolean procStatesDifferForMem(int procState1, int procState2) {
        return sProcStateToProcMem[procState1] != sProcStateToProcMem[procState2];
    }

    public static long computeNextPssTime(int procState, boolean first, boolean sleeping,
            long now) {
        final long[] table = sleeping
                ? (first
                        ? sFirstAwakePssTimes
                        : sSameAwakePssTimes)
                : (first
                        ? sFirstAwakePssTimes
                        : sSameAwakePssTimes);
        return now + table[procState];
    }

    long getMemLevel(int adjustment) {
        for (int i=0; i<mOomAdj.length; i++) {
            if (adjustment <= mOomAdj[i]) {
+15 −8
Original line number Diff line number Diff line
@@ -62,7 +62,9 @@ final class ProcessRecord {
    boolean starting;           // True if the process is being started
    long lastActivityTime;      // For managing the LRU list
    long lruWeight;             // Weight for ordering in LRU list
    long lastPssTime;           // Last time we requested PSS data
    long lastPssTime;           // Last time we retrieved PSS data
    long nextPssTime;           // Next time we want to request PSS data
    long lastStateTime;         // Last time setProcState changed
    int maxAdj;                 // Maximum OOM adjustment for this process
    int curRawAdj;              // Current OOM unlimited adjustment for this process
    int setRawAdj;              // Last set OOM unlimited adjustment for this process
@@ -75,6 +77,7 @@ final class ProcessRecord {
    int curProcState = -1;      // Currently computed process state: ActivityManager.PROCESS_STATE_*
    int repProcState = -1;      // Last reported process state
    int setProcState = -1;      // Last set process state in process tracker
    int pssProcState = -1;      // The proc state we are currently requesting pss for
    boolean serviceb;           // Process currently is on the service B list
    boolean keeping;            // Actively running code so don't kill due to that?
    boolean setIsForeground;    // Running foreground UI when last set?
@@ -223,10 +226,18 @@ final class ProcessRecord {
                pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
        pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
                pw.print(" repProcState="); pw.print(repProcState);
                pw.print(" setProcState="); pw.println(setProcState);
                pw.print(" pssProcState="); pw.print(pssProcState);
                pw.print(" setProcState="); pw.print(setProcState);
                pw.print(" lastStateTime=");
                TimeUtils.formatDuration(lastStateTime, now, pw);
                pw.println();
        pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
                pw.print(" lruSeq="); pw.print(lruSeq);
                pw.print(" lastPssTime="); pw.println(lastPssTime);
                pw.print(" lastPssTime=");
                TimeUtils.formatDuration(lastPssTime, now, pw);
                pw.print(" nextPssTime=");
                TimeUtils.formatDuration(nextPssTime, now, pw);
                pw.println();
        if (hasShownUi || pendingUiClean || hasAboveClient) {
            pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
                    pw.print(" pendingUiClean="); pw.print(pendingUiClean);
@@ -354,7 +365,7 @@ final class ProcessRecord {
        curAdj = setAdj = -100;
        persistent = false;
        removed = false;
        lastPssTime = SystemClock.uptimeMillis();
        lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
    }

    public void setPid(int _pid) {
@@ -499,10 +510,6 @@ final class ProcessRecord {
        }
    }

    public void setProcessTrackerState(int memFactor, long now) {
        baseProcessTracker.setState(repProcState, memFactor, now, pkgList);
    }

    /*
     *  Delete all packages from list except the package indicated in info
     */
+8 −0
Original line number Diff line number Diff line
@@ -188,6 +188,8 @@ public final class ProcessTracker {
    State mState;
    boolean mCommitPending;
    boolean mShuttingDown;
    int mLastMemOnlyState = -1;
    boolean mMemFactorLowered;

    final ReentrantLock mWriteLock = new ReentrantLock();

@@ -1822,7 +1824,13 @@ public final class ProcessTracker {
        return ss;
    }

    public boolean isMemFactorLowered() {
        return mMemFactorLowered;
    }

    public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
        mMemFactorLowered = memFactor < mLastMemOnlyState;
        mLastMemOnlyState = memFactor;
        if (screenOn) {
            memFactor += ADJ_SCREEN_ON;
        }