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

Commit ed7546f3 authored by Eric Miao's avatar Eric Miao
Browse files

Report Post-GC memory metrics

Bug: 331243037
Flag: android.app.report_postgc_memory_metrics

This makes use of ProcfsMemoryUtil.java, and so part of the change is to
move ProcfsMemoryUtil to com.android.internal.os so it can be shared.

This also registers the callback to report memory metrics in VMRuntime
when a post-GC event happens.

Change-Id: Idbe67f306935fefa8f3e4b4ef4fe656a61a4ede6
parent 3b56cb92
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -237,6 +237,7 @@ import com.android.internal.os.DebugStore;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SafeZipPathValidatorCallback;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.policy.DecorView;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
@@ -7675,6 +7676,16 @@ public final class ActivityThread extends ClientTransactionHandler
                }
            }
        });

        // Register callback to report native memory metrics post GC cleanup
        if (Flags.reportPostgcMemoryMetrics() &&
            com.android.libcore.readonly.Flags.postCleanupApis()) {
            VMRuntime.addPostCleanupCallback(new Runnable() {
                @Override public void run() {
                    MetricsLoggerWrapper.logPostGcMemorySnapshot();
                }
            });
        }
    }

    @UnsupportedAppUsage
+10 −0
Original line number Diff line number Diff line
package: "android.app"
container: "system"

flag {
     namespace: "system_performance"
     name: "report_postgc_memory_metrics"
     is_exported: false
     description: "Controls whether to report memory metrics post GC cleanup"
     bug: "331243037"
}
+66 −8
Original line number Diff line number Diff line
@@ -13,9 +13,9 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server.stats.pull;
package com.android.internal.os;

import static android.os.Process.PROC_OUT_STRING;
import static android.os.Process.*;

import android.annotation.Nullable;
import android.os.Process;
@@ -23,6 +23,7 @@ import android.util.SparseArray;

public final class ProcfsMemoryUtil {
    private static final int[] CMDLINE_OUT = new int[] { PROC_OUT_STRING };
    private static final int[] OOM_SCORE_ADJ_OUT = new int[] { PROC_NEWLINE_TERM | PROC_OUT_LONG };
    private static final String[] STATUS_KEYS = new String[] {
            "Uid:",
            "VmHWM:",
@@ -38,17 +39,34 @@ public final class ProcfsMemoryUtil {
    private ProcfsMemoryUtil() {}

    /**
     * Reads memory stats of a process from procfs. Returns values of the VmHWM, VmRss, AnonRSS,
     * VmSwap, RssShmem fields in /proc/pid/status in kilobytes or null if not available.
     * Reads memory stats of a process from procfs.
     *
     * Returns values of the VmHWM, VmRss, AnonRSS, VmSwap, RssShmem fields in
     * /proc/pid/status in kilobytes or null if not available.
     */
    @Nullable
    public static MemorySnapshot readMemorySnapshotFromProcfs(int pid) {
        return readMemorySnapshotFromProcfs("/proc/" + pid + "/status");
    }

    /**
     * Reads memory stats of the current process from procfs.
     *
     * Returns values of the VmHWM, VmRss, AnonRSS, VmSwap, RssShmem fields in
     * /proc/self/status in kilobytes or null if not available.
     */
    @Nullable
    public static MemorySnapshot readMemorySnapshotFromProcfs() {
        return readMemorySnapshotFromProcfs("/proc/self/status");
    }

    private static MemorySnapshot readMemorySnapshotFromProcfs(String path) {
        long[] output = new long[STATUS_KEYS.length];
        output[0] = -1;
        output[3] = -1;
        output[4] = -1;
        output[5] = -1;
        Process.readProcLines("/proc/" + pid + "/status", STATUS_KEYS, output);
        Process.readProcLines(path, STATUS_KEYS, output);
        if (output[0] == -1 || output[3] == -1 || output[4] == -1 || output[5] == -1) {
            // Could not open or parse file.
            return null;
@@ -70,13 +88,53 @@ public final class ProcfsMemoryUtil {
     * if the file is not available.
     */
    public static String readCmdlineFromProcfs(int pid) {
        return readCmdlineFromProcfs("/proc/" + pid + "/cmdline");
    }

    /**
     * Reads cmdline of the current process from procfs.
     *
     * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
     * if the file is not available.
     */
    public static String readCmdlineFromProcfs() {
        return readCmdlineFromProcfs("/proc/self/cmdline");
    }

    private static String readCmdlineFromProcfs(String path) {
        String[] cmdline = new String[1];
        if (!Process.readProcFile("/proc/" + pid + "/cmdline", CMDLINE_OUT, cmdline, null, null)) {
        if (!Process.readProcFile(path, CMDLINE_OUT, cmdline, null, null)) {
            return "";
        }
        return cmdline[0];
    }

    /**
     * Reads oom_score_adj of a process from procfs
     *
     * Returns content of /proc/pid/oom_score_adj. Defaults to 0 if reading fails.
     */
    public static int readOomScoreAdjFromProcfs(int pid) {
        return readOomScoreAdjFromProcfs("/proc/" + pid + "/oom_score_adj");
    }

    /**
     * Reads oom_score_adj of the current process from procfs
     *
     * Returns content of /proc/pid/oom_score_adj. Defaults to 0 if reading fails.
     */
    public static int readOomScoreAdjFromProcfs() {
        return readOomScoreAdjFromProcfs("/proc/self/oom_score_adj");
    }

    private static int readOomScoreAdjFromProcfs(String path) {
        long[] oom_score_adj = new long[1];
        if (Process.readProcFile(path, OOM_SCORE_ADJ_OUT, null, oom_score_adj, null)) {
            return (int)oom_score_adj[0];
        }
        return 0;
    }

    /**
     * Scans all /proc/pid/cmdline entries and returns a mapping between pid and cmdline.
     */
@@ -109,7 +167,7 @@ public final class ProcfsMemoryUtil {

    /** Reads and parses selected entries of /proc/vmstat. */
    @Nullable
    static VmStat readVmStat() {
    public static VmStat readVmStat() {
        long[] vmstat = new long[VMSTAT_KEYS.length];
        vmstat[0] = -1;
        Process.readProcLines("/proc/vmstat", VMSTAT_KEYS, vmstat);
@@ -121,7 +179,7 @@ public final class ProcfsMemoryUtil {
        return result;
    }

    static final class VmStat {
    public static final class VmStat {
        public int oomKillCount;
    }
}
+48 −0
Original line number Diff line number Diff line
@@ -16,9 +16,15 @@

package com.android.internal.os.logging;

import android.app.Application;
import android.os.Process;
import android.util.Log;
import android.view.WindowManager.LayoutParams;

import com.android.internal.os.ProcfsMemoryUtil;
import com.android.internal.util.FrameworkStatsLog;
import java.util.Collection;
import libcore.util.NativeAllocationRegistry;

/**
 * Used to wrap different logging calls in one, so that client side code base is clean and more
@@ -49,4 +55,46 @@ public class MetricsLoggerWrapper {
            }
        }
    }

    public static void logPostGcMemorySnapshot() {
        if (!com.android.libcore.Flags.nativeMetrics()) {
            return;
        }
        int pid = Process.myPid();
        String processName = Application.getProcessName();
        Collection<NativeAllocationRegistry.Metrics> metrics =
            NativeAllocationRegistry.getMetrics();
        int nMetrics = metrics.size();

        String[] classNames = new String[nMetrics];
        long[] mallocedCount = new long[nMetrics];
        long[] mallocedBytes = new long[nMetrics];
        long[] nonmallocedCount = new long[nMetrics];
        long[] nonmallocedBytes = new long[nMetrics];

        int i = 0;
        for (NativeAllocationRegistry.Metrics m : metrics) {
            classNames[i] = m.getClassName();
            mallocedCount[i] = m.getMallocedCount();
            mallocedBytes[i] = m.getMallocedBytes();
            nonmallocedCount[i] = m.getNonmallocedCount();
            nonmallocedBytes[i] = m.getNonmallocedBytes();
            i++;
        }

        ProcfsMemoryUtil.MemorySnapshot m = ProcfsMemoryUtil.readMemorySnapshotFromProcfs();
        int oom_score_adj = ProcfsMemoryUtil.readOomScoreAdjFromProcfs();
        FrameworkStatsLog.write(FrameworkStatsLog.POSTGC_MEMORY_SNAPSHOT,
            m.uid, processName, pid,
            oom_score_adj,
            m.rssInKilobytes,
            m.anonRssInKilobytes,
            m.swapInKilobytes,
            m.anonRssInKilobytes + m.swapInKilobytes,
            classNames,
            mallocedCount,
            mallocedBytes,
            nonmallocedCount,
            nonmallocedBytes);
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.am.ProcessRecord.TAG;
import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
import static com.android.internal.os.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;

import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -58,7 +58,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.modules.expresslog.Counter;
import com.android.server.ResourcePressureUtil;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
import com.android.internal.os.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.wm.WindowProcessController;

import java.io.File;
Loading