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

Commit ac70654f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Procstats: keep track of per-proc state active time"

parents 15640720 7aea7a4c
Loading
Loading
Loading
Loading
+230 −38
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ public final class AssociationState {
    private final ProcessStats.PackageState mPackageState;
    private final String mProcessName;
    private final String mName;
    private final DurationsTable mDurations;

    public final class SourceState {
        final SourceKey mKey;
@@ -49,8 +48,10 @@ public final class AssociationState {
        long mDuration;
        long mTrackingUptime;
        int mActiveCount;
        int mActiveProcState = ProcessStats.STATE_NOTHING;
        long mActiveStartUptime;
        long mActiveDuration;
        DurationsTable mDurations;

        SourceState(SourceKey key) {
            mKey = key;
@@ -77,13 +78,15 @@ public final class AssociationState {
                mProcState = procState;
            }
            if (procState < ProcessStats.STATE_HOME) {
                // If the proc state has become better than cached, then we want to
                // start tracking it to count when it is actually active.  If it drops
                // down to cached, we will clean it up when we later evaluate all currently
                // tracked associations in ProcessStats.updateTrackingAssociationsLocked().
                if (!mInTrackingList) {
                    mInTrackingList = true;
                    mTrackingUptime = now;
                    mProcessStats.mTrackingAssociations.add(this);
                }
            } else {
                stopTracking(now);
            }
        }

@@ -102,6 +105,22 @@ public final class AssociationState {
                    mActiveStartUptime = now;
                    mActiveCount++;
                }
                if (mActiveProcState != mProcState) {
                    if (mActiveProcState != ProcessStats.STATE_NOTHING) {
                        // Currently active proc state changed, need to store the duration
                        // so far and switch tracking to the new proc state.
                        final long duration = mActiveDuration + now - mActiveStartUptime;
                        if (duration != 0) {
                            if (mDurations == null) {
                                makeDurations();
                            }
                            mDurations.addDuration(mActiveProcState, duration);
                            mActiveDuration = 0;
                        }
                        mActiveStartUptime = now;
                    }
                    mActiveProcState = mProcState;
                }
            } else {
                Slog.wtf(TAG, "startActive while not tracking: " + this);
            }
@@ -112,15 +131,25 @@ public final class AssociationState {
                if (!mInTrackingList) {
                    Slog.wtf(TAG, "stopActive while not tracking: " + this);
                }
                mActiveDuration += now - mActiveStartUptime;
                final long duration = mActiveDuration + now - mActiveStartUptime;
                if (mDurations != null) {
                    mDurations.addDuration(mActiveProcState, duration);
                } else {
                    mActiveDuration = duration;
                }
                mActiveStartUptime = 0;
            }
        }

        void makeDurations() {
            mDurations = new DurationsTable(mProcessStats.mTableData);
        }

        void stopTracking(long now) {
            stopActive(now);
            if (mInTrackingList) {
                mInTrackingList = false;
                mProcState = ProcessStats.STATE_NOTHING;
                // Do a manual search for where to remove, since these objects will typically
                // be towards the end of the array.
                final ArrayList<SourceState> list = mProcessStats.mTrackingAssociations;
@@ -207,7 +236,6 @@ public final class AssociationState {
        mPackageState = packageState;
        mName = name;
        mProcessName = processName;
        mDurations = new DurationsTable(processStats.mTableData);
        mProc = proc;
    }

@@ -254,7 +282,6 @@ public final class AssociationState {
    }

    public void add(AssociationState other) {
        mDurations.addDurations(other.mDurations);
        for (int isrc = other.mSources.size() - 1; isrc >= 0; isrc--) {
            final SourceKey key = other.mSources.keyAt(isrc);
            final SourceState otherSrc = other.mSources.valueAt(isrc);
@@ -266,7 +293,48 @@ public final class AssociationState {
            mySrc.mCount += otherSrc.mCount;
            mySrc.mDuration += otherSrc.mDuration;
            mySrc.mActiveCount += otherSrc.mActiveCount;
            mySrc.mActiveDuration += otherSrc.mActiveDuration;
            if (otherSrc.mActiveDuration != 0 || otherSrc.mDurations != null) {
                // Only need to do anything if the other one has some duration data.
                if (mySrc.mDurations != null) {
                    // If the target already has multiple durations, just add in whatever
                    // we have in the other.
                    if (otherSrc.mDurations != null) {
                        mySrc.mDurations.addDurations(otherSrc.mDurations);
                    } else {
                        mySrc.mDurations.addDuration(otherSrc.mActiveProcState,
                                otherSrc.mActiveDuration);
                    }
                } else if (otherSrc.mDurations != null) {
                    // The other one has multiple durations, but we don't.  Expand to
                    // multiple durations and copy over.
                    mySrc.makeDurations();
                    mySrc.mDurations.addDurations(otherSrc.mDurations);
                    if (mySrc.mActiveDuration != 0) {
                        mySrc.mDurations.addDuration(mySrc.mActiveProcState, mySrc.mActiveDuration);
                        mySrc.mActiveDuration = 0;
                        mySrc.mActiveProcState = ProcessStats.STATE_NOTHING;
                    }
                } else if (mySrc.mActiveDuration != 0) {
                    // Both have a single inline duration...  we can either add them together,
                    // or need to expand to multiple durations.
                    if (mySrc.mActiveProcState == otherSrc.mActiveProcState) {
                        mySrc.mDuration += otherSrc.mDuration;
                    } else {
                        // The two have durations with different proc states, need to turn
                        // in to multiple durations.
                        mySrc.makeDurations();
                        mySrc.mDurations.addDuration(mySrc.mActiveProcState, mySrc.mActiveDuration);
                        mySrc.mDurations.addDuration(otherSrc.mActiveProcState,
                                otherSrc.mActiveDuration);
                        mySrc.mActiveDuration = 0;
                        mySrc.mActiveProcState = ProcessStats.STATE_NOTHING;
                    }
                } else {
                    // The other one has a duration, and we know the target doesn't.  Copy over.
                    mySrc.mActiveProcState = otherSrc.mActiveProcState;
                    mySrc.mActiveDuration = otherSrc.mActiveDuration;
                }
            }
        }
    }

@@ -275,7 +343,6 @@ public final class AssociationState {
    }

    public void resetSafely(long now) {
        mDurations.resetTable();
        if (!isInUse()) {
            mSources.clear();
        } else {
@@ -293,6 +360,7 @@ public final class AssociationState {
                        src.mActiveCount = 0;
                    }
                    src.mActiveDuration = 0;
                    src.mDurations = null;
                } else {
                    mSources.removeAt(isrc);
                }
@@ -301,7 +369,6 @@ public final class AssociationState {
    }

    public void writeToParcel(ProcessStats stats, Parcel out, long nowUptime) {
        mDurations.writeToParcel(out);
        final int NSRC = mSources.size();
        out.writeInt(NSRC);
        for (int isrc = 0; isrc < NSRC; isrc++) {
@@ -312,18 +379,22 @@ public final class AssociationState {
            out.writeInt(src.mCount);
            out.writeLong(src.mDuration);
            out.writeInt(src.mActiveCount);
            if (src.mDurations != null) {
                out.writeInt(1);
                src.mDurations.writeToParcel(out);
            } else {
                out.writeInt(0);
                out.writeInt(src.mActiveProcState);
                out.writeLong(src.mActiveDuration);
            }
        }
    }

    /**
     * Returns non-null if all else fine, else a String that describes the error that
     * caused it to fail.
     */
    public String readFromParcel(ProcessStats stats, Parcel in, int parcelVersion) {
        if (!mDurations.readFromParcel(in)) {
            return "Duration table corrupt";
        }
        final int NSRC = in.readInt();
        if (NSRC < 0 || NSRC > 100000) {
            return "Association with bad src count: " + NSRC;
@@ -336,7 +407,15 @@ public final class AssociationState {
            src.mCount = in.readInt();
            src.mDuration = in.readLong();
            src.mActiveCount = in.readInt();
            if (in.readInt() != 0) {
                src.makeDurations();
                if (!src.mDurations.readFromParcel(in)) {
                    return "Duration table corrupt: " + key + " <- " + src;
                }
            } else {
                src.mActiveProcState = in.readInt();
                src.mActiveDuration = in.readLong();
            }
            mSources.put(key, src);
        }
        return null;
@@ -351,7 +430,12 @@ public final class AssociationState {
                    src.mStartUptime = nowUptime;
                }
                if (src.mActiveStartUptime > 0) {
                    src.mActiveDuration += nowUptime - src.mActiveStartUptime;
                    final long duration = src.mActiveDuration + nowUptime - src.mActiveStartUptime;
                    if (src.mDurations != null) {
                        src.mDurations.addDuration(src.mActiveProcState, duration);
                    } else {
                        src.mActiveDuration = duration;
                    }
                    src.mActiveStartUptime = nowUptime;
                }
            }
@@ -359,7 +443,7 @@ public final class AssociationState {
    }

    public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix,
            long now, long totalTime, boolean dumpSummary, boolean dumpAll) {
            long now, long totalTime, boolean dumpDetails, boolean dumpAll) {
        if (dumpAll) {
            pw.print(prefix);
            pw.print("mNumActive=");
@@ -376,18 +460,18 @@ public final class AssociationState {
            UserHandle.formatUid(pw, key.mUid);
            pw.println(":");
            pw.print(prefixInner);
            pw.print("   Count ");
            pw.print("   Total count ");
            pw.print(src.mCount);
            long duration = src.mDuration;
            if (src.mNesting > 0) {
                duration += now - src.mStartUptime;
            }
            if (dumpAll) {
                pw.print(" / Duration ");
                pw.print(": Duration ");
                TimeUtils.formatDuration(duration, pw);
                pw.print(" / ");
            } else {
                pw.print(" / time ");
                pw.print(": time ");
            }
            DumpUtils.printPercent(pw, (double)duration/(double)totalTime);
            if (src.mNesting > 0) {
@@ -401,20 +485,53 @@ public final class AssociationState {
                pw.print(")");
            }
            pw.println();
            if (src.mActiveCount > 0) {
            if (src.mActiveCount > 0 || src.mDurations != null || src.mActiveDuration != 0
                    || src.mActiveStartUptime != 0) {
                pw.print(prefixInner);
                pw.print("   Active count ");
                pw.print(src.mActiveCount);
                duration = src.mActiveDuration;
                if (src.mActiveStartUptime > 0) {
                    duration += now - src.mActiveStartUptime;
                if (dumpDetails) {
                    if (dumpAll) {
                        pw.print(src.mDurations != null ? " (multi-field)" : " (inline)");
                    }
                    pw.println(":");
                    dumpTime(pw, prefixInner, src, totalTime, now, dumpDetails, dumpAll);
                } else {
                    pw.print(": ");
                    dumpActiveDurationSummary(pw, src, totalTime, now, dumpAll);
                    pw.println();
                }
            }
            if (dumpAll) {
                    pw.print(" / Duration ");
                if (src.mInTrackingList) {
                    pw.print(prefixInner);
                    pw.print("   mInTrackingList=");
                    pw.println(src.mInTrackingList);
                }
                if (src.mProcState != ProcessStats.STATE_NOTHING) {
                    pw.print(prefixInner);
                    pw.print("   mProcState=");
                    pw.print(DumpUtils.STATE_NAMES[src.mProcState]);
                    pw.print(" mProcStateSeq=");
                    pw.println(src.mProcStateSeq);
                }
            }
        }
    }

    void dumpActiveDurationSummary(PrintWriter pw, final SourceState src, long totalTime,
            long now, boolean dumpAll) {
        long duration = dumpTime(null, null, src, totalTime, now, false, false);
        final boolean isRunning = duration < 0;
        if (isRunning) {
            duration = -duration;
        }
        if (dumpAll) {
            pw.print("Duration ");
            TimeUtils.formatDuration(duration, pw);
            pw.print(" / ");
        } else {
                    pw.print(" / time ");
            pw.print("time ");
        }
        DumpUtils.printPercent(pw, (double) duration / (double) totalTime);
        if (src.mActiveStartUptime > 0) {
@@ -422,7 +539,64 @@ public final class AssociationState {
        }
        pw.println();
    }

    long dumpTime(PrintWriter pw, String prefix, final SourceState src, long overallTime, long now,
            boolean dumpDetails, boolean dumpAll) {
        long totalTime = 0;
        boolean isRunning = false;
        for (int iprocstate = 0; iprocstate < ProcessStats.STATE_COUNT; iprocstate++) {
            long time;
            if (src.mDurations != null) {
                time = src.mDurations.getValueForId((byte)iprocstate);
            } else {
                time = src.mActiveProcState == iprocstate ? src.mDuration : 0;
            }
            final String running;
            if (src.mActiveStartUptime != 0 && src.mActiveProcState == iprocstate) {
                running = " (running)";
                isRunning = true;
                time += now - src.mActiveStartUptime;
            } else {
                running = null;
            }
            if (time != 0) {
                if (pw != null) {
                    pw.print(prefix);
                    pw.print("  ");
                    pw.print(DumpUtils.STATE_LABELS[iprocstate]);
                    pw.print(": ");
                    if (dumpAll) {
                        pw.print("Duration ");
                        TimeUtils.formatDuration(time, pw);
                        pw.print(" / ");
                    } else {
                        pw.print("time ");
                    }
                    DumpUtils.printPercent(pw, (double) time / (double) overallTime);
                    if (running != null) {
                        pw.print(running);
                    }
                    pw.println();
                }
                totalTime += time;
            }
        }
        if (totalTime != 0 && pw != null) {
            pw.print(prefix);
            pw.print("  ");
            pw.print(DumpUtils.STATE_LABEL_TOTAL);
            pw.print(": ");
            if (dumpAll) {
                pw.print("Duration ");
                TimeUtils.formatDuration(totalTime, pw);
                pw.print(" / ");
            } else {
                pw.print("time ");
            }
            DumpUtils.printPercent(pw, (double) totalTime / (double) overallTime);
            pw.println();
        }
        return isRunning ? -totalTime : totalTime;
    }

    public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers,
@@ -454,12 +628,30 @@ public final class AssociationState {
            pw.print(duration);
            pw.print(",");
            pw.print(src.mActiveCount);
            duration = src.mActiveDuration;
            if (src.mActiveStartUptime > 0) {
                duration += now - src.mActiveStartUptime;
            final long timeNow = src.mActiveStartUptime != 0 ? (now-src.mActiveStartUptime) : 0;
            if (src.mDurations != null) {
                final int N = src.mDurations.getKeyCount();
                for (int i=0; i<N; i++) {
                    final int dkey = src.mDurations.getKeyAt(i);
                    duration = src.mDurations.getValue(dkey);
                    if (dkey == src.mActiveProcState) {
                        duration += timeNow;
                    }
                    final int procState = SparseMappingTable.getIdFromKey(dkey);
                    pw.print(",");
                    DumpUtils.printArrayEntry(pw, DumpUtils.STATE_TAGS,  procState, 1);
                    pw.print(':');
                    pw.print(duration);
                }
            } else {
                duration = src.mActiveDuration + timeNow;
                if (duration != 0) {
                    pw.print(",");
                    DumpUtils.printArrayEntry(pw, DumpUtils.STATE_TAGS,  src.mActiveProcState, 1);
                    pw.print(':');
                    pw.print(duration);
                }
            }
            pw.println();
        }
    }
+66 −45
Original line number Diff line number Diff line
@@ -48,6 +48,9 @@ import java.util.Objects;
 */
public final class DumpUtils {
    public static final String[] STATE_NAMES;
    public static final String[] STATE_LABELS;
    public static final String STATE_LABEL_TOTAL;
    public static final String STATE_LABEL_CACHED;
    public static final String[] STATE_NAMES_CSV;
    static final String[] STATE_TAGS;
    static final int[] STATE_PROTO_ENUMS;
@@ -70,6 +73,24 @@ public final class DumpUtils {
        STATE_NAMES[STATE_CACHED_ACTIVITY_CLIENT]   = "CchCAct";
        STATE_NAMES[STATE_CACHED_EMPTY]             = "CchEmty";

        STATE_LABELS = new String[STATE_COUNT];
        STATE_LABELS[STATE_PERSISTENT]              = "Persistent";
        STATE_LABELS[STATE_TOP]                     = "       Top";
        STATE_LABELS[STATE_IMPORTANT_FOREGROUND]    = "    Imp Fg";
        STATE_LABELS[STATE_IMPORTANT_BACKGROUND]    = "    Imp Bg";
        STATE_LABELS[STATE_BACKUP]                  = "    Backup";
        STATE_LABELS[STATE_SERVICE]                 = "   Service";
        STATE_LABELS[STATE_SERVICE_RESTARTING]      = "Service Rs";
        STATE_LABELS[STATE_RECEIVER]                = "  Receiver";
        STATE_LABELS[STATE_HEAVY_WEIGHT]            = " Heavy Wgt";
        STATE_LABELS[STATE_HOME]                    = "    (Home)";
        STATE_LABELS[STATE_LAST_ACTIVITY]           = "(Last Act)";
        STATE_LABELS[STATE_CACHED_ACTIVITY]         = " (Cch Act)";
        STATE_LABELS[STATE_CACHED_ACTIVITY_CLIENT]  = "(Cch CAct)";
        STATE_LABELS[STATE_CACHED_EMPTY]            = "(Cch Emty)";
        STATE_LABEL_CACHED                          = "  (Cached)";
        STATE_LABEL_TOTAL                           = "     TOTAL";

        STATE_NAMES_CSV = new String[STATE_COUNT];
        STATE_NAMES_CSV[STATE_PERSISTENT]               = "pers";
        STATE_NAMES_CSV[STATE_TOP]                      = "top";
+36 −32

File changed.

Preview size limit exceeded, changes collapsed.

+11 −20
Original line number Diff line number Diff line
@@ -158,7 +158,7 @@ public final class ProcessStats implements Parcelable {
    };

    // Current version of the parcel format.
    private static final int PARCEL_VERSION = 32;
    private static final int PARCEL_VERSION = 33;
    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
    private static final int MAGIC = 0x50535454;

@@ -1380,9 +1380,13 @@ public final class ProcessStats implements Parcelable {
        final int NUM = mTrackingAssociations.size();
        for (int i = NUM - 1; i >= 0; i--) {
            final AssociationState.SourceState act = mTrackingAssociations.get(i);
            if (act.mProcStateSeq != curSeq) {
            if (act.mProcStateSeq != curSeq || act.mProcState >= ProcessStats.STATE_HOME) {
                // If this association did not get touched the last time we computed
                // process states, or its state ended up down in cached, then we no
                // longer have a reason to track it at all.
                act.stopActive(now);
                act.mInTrackingList = false;
                act.mProcState = STATE_NOTHING;
                act.mProcState = ProcessStats.STATE_NOTHING;
                mTrackingAssociations.remove(i);
            } else {
                final ProcessState proc = act.getAssociationState().getProcess();
@@ -1407,7 +1411,7 @@ public final class ProcessStats implements Parcelable {
    }

    public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
            boolean dumpAll, boolean activeOnly) {
            boolean dumpDetails, boolean dumpAll, boolean activeOnly) {
        long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
                mStartTime, now);
        boolean sepNeeded = false;
@@ -1538,7 +1542,7 @@ public final class ProcessStats implements Parcelable {
                        pw.println(":");
                        pw.print("        Process: "); pw.println(asc.getProcessName());
                        asc.dumpStats(pw, "        ", "          ", "    ",
                                now, totalTime, dumpSummary, dumpAll);
                                now, totalTime, dumpDetails, dumpAll);
                    }
                }
            }
@@ -1632,21 +1636,8 @@ public final class ProcessStats implements Parcelable {
                    if (src.mActiveCount > 0) {
                        pw.print("    Active count ");
                        pw.print(src.mActiveCount);
                        long duration = src.mActiveDuration;
                        if (src.mActiveStartUptime > 0) {
                            duration += now - src.mActiveStartUptime;
                        }
                        if (dumpAll) {
                            pw.print(" / Duration ");
                            TimeUtils.formatDuration(duration, pw);
                            pw.print(" / ");
                        } else {
                            pw.print(" / time ");
                        }
                        DumpUtils.printPercent(pw, (double)duration/(double)totalTime);
                        if (src.mActiveStartUptime > 0) {
                            pw.print(" (running)");
                        }
                        pw.print(": ");
                        asc.dumpActiveDurationSummary(pw, src, totalTime, now, dumpAll);
                        pw.println();
                    }
                }
+7 −6
Original line number Diff line number Diff line
@@ -612,7 +612,8 @@ public final class ProcessStatsService extends IProcessStats.Stub {
            stats.dumpCheckinLocked(pw, reqPackage);
        } else {
            if (dumpDetails || dumpFullDetails) {
                stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll, activeOnly);
                stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll,
                        activeOnly);
            } else {
                stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
            }
@@ -974,8 +975,8 @@ public final class ProcessStatsService extends IProcessStats.Stub {
                if (checkedIn) pw.print(" (checked in)");
                pw.println(":");
                if (dumpDetails || dumpFullDetails) {
                    processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll,
                            activeOnly);
                    processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
                            dumpAll, activeOnly);
                    if (dumpAll) {
                        pw.print("  mFile="); pw.println(mFile.getBaseFile());
                    }
@@ -1030,7 +1031,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
                                // much crud.
                                if (dumpFullDetails) {
                                    processStats.dumpLocked(pw, reqPackage, now, false, false,
                                            activeOnly);
                                            false, activeOnly);
                                } else {
                                    processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
                                }
@@ -1060,8 +1061,8 @@ public final class ProcessStatsService extends IProcessStats.Stub {
                    }
                    pw.println("CURRENT STATS:");
                    if (dumpDetails || dumpFullDetails) {
                        mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll,
                                activeOnly);
                        mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
                                dumpAll, activeOnly);
                        if (dumpAll) {
                            pw.print("  mFile="); pw.println(mFile.getBaseFile());
                        }