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

Commit 6e67ca77 authored by Lee Shombert's avatar Lee Shombert
Browse files

Improve PackageManager snapshot statistics

Bug: 184751735

This makes some small improvements to the snapshot statistics.
The change emphasizes long rebuild times over short snapshot
lifetimes.

1. The pm_snapshot_rebuild "elapsed" field is renamed "lifetime".
   This is the number of times the previous snapshot (the snapshot
   that was replaced by this rebuild)  was used.

2. The pm_snapshot_stats cumulative build time is now a long.
   Wrap-around of the 32-bit int was seen during testing.  Also, the
   "quick_rebuilds" has been renamed to "short_lived".

3. pm_snapshot_rebuild events are only logged for long rebuild times.
   Short lifetimes are still counted but do not generate their own
   events.  Also, any rebuild time that is greater than the current
   maximum rebuild time is logged, even if the number of logged events
   is greater than the limit.

4. Snapshot statistics are included in the package manager dump.   Two
   sets of statistics are presented: there is a set of 10, rolling
   over every minute, and a set of two, rolling over every week.
   The snapshot statistics are part of the default "package" dumpsys
   output and can be selected individually with "package snapshot".

5. The SnapshotStatistics class is now in its own file.  At the
   momement, the class has code that is specific to
   PackageManagerService, but it should be possible to make the class
   more generic in the future, if desired.

See the bug for sample output.

Test: manual steps -
 * Create a bug report and verify that the new statistics are present.
 * Verify that pm_snapshot_rebuild events are generated for long
   rebuild times.

Change-Id: I3197d6b76e86ecfcdaff36f47e8a6b5d4a6e456d
parent 41b21288
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -174,9 +174,9 @@ option java_package com.android.server
# Disk usage stats for verifying quota correctness
3121 pm_package_stats (manual_time|2|3),(quota_time|2|3),(manual_data|2|2),(quota_data|2|2),(manual_cache|2|2),(quota_cache|2|2)
# Snapshot statistics
3130 pm_snapshot_stats (build_count|1|1),(reuse_count|1|1),(big_builds|1|1),(quick_rebuilds|1|1),(max_build_time|1|3),(cumm_build_time|1|3)
3130 pm_snapshot_stats (build_count|1|1),(reuse_count|1|1),(big_builds|1|1),(short_lived|1|1),(max_build_time|1|3),(cumm_build_time|2|3)
# Snapshot rebuild instance
3131 pm_snapshot_rebuild (build_time|1|3),(elapsed|1|3)
3131 pm_snapshot_rebuild (build_time|1|3),(lifetime|1|3)

# ---------------------------
# InputMethodManagerService.java
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ public final class DumpState {
    public static final int DUMP_QUERIES = 1 << 26;
    public static final int DUMP_KNOWN_PACKAGES = 1 << 27;
    public static final int DUMP_PER_UID_READ_TIMEOUTS = 1 << 28;
    public static final int DUMP_SNAPSHOT_STATISTICS = 1 << 29;

    public static final int OPTION_SHOW_FILTERS = 1 << 0;
    public static final int OPTION_DUMP_ALL_COMPONENTS = 1 << 1;
+75 −133
Original line number Diff line number Diff line
@@ -1914,6 +1914,18 @@ public class PackageManagerService extends IPackageManager.Stub
     */
    private interface Computer {
        /**
         * Administrative statistics: record that the snapshot has been used.  Every call
         * to use() increments the usage counter.
         */
        void use();
        /**
         * Fetch the snapshot usage counter.
         * @return The number of times this snapshot was used.
         */
        int getUsed();
        @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
                int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid,
                int userId, boolean resolveForStart, boolean allowDynamicSplits);
@@ -2065,6 +2077,9 @@ public class PackageManagerService extends IPackageManager.Stub
     */
    private static class ComputerEngine implements Computer {
        // The administrative use counter.
        private int mUsed = 0;
        // Cached attributes.  The names in this class are the same as the
        // names in PackageManagerService; see that class for documentation.
        protected final Settings mSettings;
@@ -2157,6 +2172,20 @@ public class PackageManagerService extends IPackageManager.Stub
            mService = args.service;
        }
        /**
         * Record that the snapshot was used.
         */
        public void use() {
            mUsed++;
        }
        /**
         * Return the usage counter.
         */
        public int getUsed() {
            return mUsed;
        }
        public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
                String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
                int filterCallingUid, int userId, boolean resolveForStart,
@@ -4885,121 +4914,11 @@ public class PackageManagerService extends IPackageManager.Stub
     */
    private final Object mSnapshotLock = new Object();
    // A counter of all queries that hit the current snapshot.
    @GuardedBy("mSnapshotLock")
    private int mSnapshotHits = 0;
    // A class to record snapshot statistics.
    private static class SnapshotStatistics {
        // A build time is "big" if it takes longer than 5ms.
        private static final long SNAPSHOT_BIG_BUILD_TIME_NS = TimeUnit.MILLISECONDS.toNanos(5);
        // A snapshot is in quick succession to the previous snapshot if it less than
        // 100ms since the previous snapshot.
        private static final long SNAPSHOT_QUICK_REBUILD_INTERVAL_NS =
                TimeUnit.MILLISECONDS.toNanos(100);
        // The interval between snapshot statistics logging, in ns.
        private static final long SNAPSHOT_LOG_INTERVAL_NS = TimeUnit.MINUTES.toNanos(10);
        // The throttle parameters for big build reporting.  Do not report more than this
        // many events in a single log interval.
        private static final int SNAPSHOT_BUILD_REPORT_LIMIT = 10;
        // The time the snapshot statistics were last logged.
        private long mStatisticsSent = 0;
        // The number of build events logged since the last periodic log.
        private int mLoggedBuilds = 0;
        // The time of the last build.
        private long mLastBuildTime = 0;
        // The number of times the snapshot has been rebuilt since the statistics were
        // last logged.
        private int mRebuilds = 0;
        // The number of times the snapshot has been used since it was rebuilt.
        private int mReused = 0;
        // The number of "big" build times since the last log.  "Big" is defined by
        // SNAPSHOT_BIG_BUILD_TIME.
        private int mBigBuilds = 0;
        // The number of quick rebuilds.  "Quick" is defined by
        // SNAPSHOT_QUICK_REBUILD_INTERVAL_NS.
        private int mQuickRebuilds = 0;
        // The time take to build a snapshot.  This is cumulative over the rebuilds recorded
        // in mRebuilds, so the average time to build a snapshot is given by
        // mBuildTimeNs/mRebuilds.
        private int mBuildTimeNs = 0;
        // The maximum build time since the last log.
        private long mMaxBuildTimeNs = 0;
        // The constant that converts ns to ms.  This is the divisor.
        private final long NS_TO_MS = TimeUnit.MILLISECONDS.toNanos(1);
        // Convert ns to an int ms.  The maximum range of this method is about 24 days.
        // There is no expectation that an event will take longer than that.
        private int nsToMs(long ns) {
            return (int) (ns / NS_TO_MS);
        }
        // The single method records a rebuild.  The "now" parameter is passed in because
        // the caller needed it to computer the duration, so pass it in to avoid
        // recomputing it.
        private void rebuild(long now, long done, int hits) {
            if (mStatisticsSent == 0) {
                mStatisticsSent = now;
            }
            final long elapsed = now - mLastBuildTime;
            final long duration = done - now;
            mLastBuildTime = now;
            if (mMaxBuildTimeNs < duration) {
                mMaxBuildTimeNs = duration;
            }
            mRebuilds++;
            mReused += hits;
            mBuildTimeNs += duration;
            boolean log_build = false;
            if (duration > SNAPSHOT_BIG_BUILD_TIME_NS) {
                log_build = true;
                mBigBuilds++;
            }
            if (elapsed < SNAPSHOT_QUICK_REBUILD_INTERVAL_NS) {
                log_build = true;
                mQuickRebuilds++;
            }
            if (log_build && mLoggedBuilds < SNAPSHOT_BUILD_REPORT_LIMIT) {
                EventLogTags.writePmSnapshotRebuild(nsToMs(duration), nsToMs(elapsed));
                mLoggedBuilds++;
            }
            final long log_interval = now - mStatisticsSent;
            if (log_interval >= SNAPSHOT_LOG_INTERVAL_NS) {
                EventLogTags.writePmSnapshotStats(mRebuilds, mReused,
                                                  mBigBuilds, mQuickRebuilds,
                                                  nsToMs(mMaxBuildTimeNs),
                                                  nsToMs(mBuildTimeNs));
                mStatisticsSent = now;
                mRebuilds = 0;
                mReused = 0;
                mBuildTimeNs = 0;
                mMaxBuildTimeNs = 0;
                mBigBuilds = 0;
                mQuickRebuilds = 0;
                mLoggedBuilds = 0;
            }
        }
    }
    // Snapshot statistics.
    @GuardedBy("mLock")
    private final SnapshotStatistics mSnapshotStatistics = new SnapshotStatistics();
    /**
     * The snapshot statistics.  These are collected to track performance and to identify
     * situations in which the snapshots are misbehaving.
     */
    private final SnapshotStatistics mSnapshotStatistics;
    // The snapshot disable/enable switch.  An image with the flag set true uses snapshots
    // and an image with the flag set false does not use snapshots.
@@ -5033,10 +4952,9 @@ public class PackageManagerService extends IPackageManager.Stub
            Computer c = mSnapshotComputer;
            if (sSnapshotCorked && (c != null)) {
                // Snapshots are corked, which means new ones should not be built right now.
                c.use();
                return c;
            }
            // Deliberately capture the value pre-increment
            final int hits = mSnapshotHits++;
            if (sSnapshotInvalid || (c == null)) {
                // The snapshot is invalid if it is marked as invalid or if it is null.  If it
                // is null, then it is currently being rebuilt by rebuildSnapshot().
@@ -5046,7 +4964,7 @@ public class PackageManagerService extends IPackageManager.Stub
                    // self-consistent (the lock is being held) and is current as of the time
                    // this function is entered.
                    if (sSnapshotInvalid) {
                        rebuildSnapshot(hits);
                        rebuildSnapshot();
                    }
                    // Guaranteed to be non-null.  mSnapshotComputer is only be set to null
@@ -5056,6 +4974,7 @@ public class PackageManagerService extends IPackageManager.Stub
                    c = mSnapshotComputer;
                }
            }
            c.use();
            return c;
        }
    }
@@ -5065,16 +4984,16 @@ public class PackageManagerService extends IPackageManager.Stub
     * threads from using the invalid computer until it is rebuilt.
     */
    @GuardedBy("mLock")
    private void rebuildSnapshot(int hits) {
        final long now = System.nanoTime();
    private void rebuildSnapshot() {
        final long now = SystemClock.currentTimeMicro();
        final int hits = mSnapshotComputer == null ? -1 : mSnapshotComputer.getUsed();
        mSnapshotComputer = null;
        sSnapshotInvalid = false;
        final Snapshot args = new Snapshot(Snapshot.SNAPPED);
        mSnapshotComputer = new ComputerEngine(args);
        final long done = System.nanoTime();
        final long done = SystemClock.currentTimeMicro();
        mSnapshotStatistics.rebuild(now, done, hits);
        mSnapshotHits = 0;
    }
    /**
@@ -6327,6 +6246,7 @@ public class PackageManagerService extends IPackageManager.Stub
        mSnapshotEnabled = false;
        mLiveComputer = createLiveComputer();
        mSnapshotComputer = null;
        mSnapshotStatistics = null;
        mPackages.putAll(testParams.packages);
        mEnableFreeCacheV2 = testParams.enableFreeCacheV2;
@@ -6479,6 +6399,7 @@ public class PackageManagerService extends IPackageManager.Stub
        mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
        mDomainVerificationManager.setConnection(mDomainVerificationConnection);
        synchronized (mLock) {
            // Create the computer as soon as the state objects have been installed.  The
            // cached computer is the same as the live computer until the end of the
            // constructor, at which time the invalidation method updates it.  The cache is
@@ -6487,9 +6408,11 @@ public class PackageManagerService extends IPackageManager.Stub
            mSnapshotEnabled = SNAPSHOT_ENABLED;
            sSnapshotCorked = true;
            sSnapshotInvalid = true;
            mSnapshotStatistics = new SnapshotStatistics();
            mLiveComputer = createLiveComputer();
            mSnapshotComputer = null;
            registerObserver();
        }
        // CHECKSTYLE:OFF IndentationCheck
        synchronized (mInstallLock) {
@@ -23957,6 +23880,7 @@ public class PackageManagerService extends IPackageManager.Stub
                pw.println("    dexopt: dump dexopt state");
                pw.println("    compiler-stats: dump compiler statistics");
                pw.println("    service-permissions: dump permissions required by services");
                pw.println("    snapshot: dump snapshot statistics");
                pw.println("    known-packages: dump known packages");
                pw.println("    <package.name>: info about given package");
                return;
@@ -24105,6 +24029,8 @@ public class PackageManagerService extends IPackageManager.Stub
                dumpState.setDump(DumpState.DUMP_KNOWN_PACKAGES);
            } else if ("t".equals(cmd) || "timeouts".equals(cmd)) {
                dumpState.setDump(DumpState.DUMP_PER_UID_READ_TIMEOUTS);
            } else if ("snapshot".equals(cmd)) {
                dumpState.setDump(DumpState.DUMP_SNAPSHOT_STATISTICS);
            } else if ("write".equals(cmd)) {
                synchronized (mLock) {
                    writeSettingsLPrTEMP();
@@ -24433,6 +24359,22 @@ public class PackageManagerService extends IPackageManager.Stub
                pw.println(")");
            }
        }
        if (!checkin && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)) {
            pw.println("Snapshot statistics");
            if (!mSnapshotEnabled) {
                pw.println("  Snapshots disabled");
            } else {
                int hits = 0;
                synchronized (mSnapshotLock) {
                    if (mSnapshotComputer != null) {
                        hits = mSnapshotComputer.getUsed();
                    }
                }
                final long now = SystemClock.currentTimeMicro();
                mSnapshotStatistics.dump(pw, "  ", now, hits, true);
            }
        }
    }
    /**
+622 −0

File added.

Preview size limit exceeded, changes collapsed.