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

Commit db0f2ad5 authored by Rafal Slawik's avatar Rafal Slawik Committed by android-build-merger
Browse files

Merge "Read process allocation sizes on system ion heap" into qt-dev am: d701e951

am: 7fbd34f0

Change-Id: I1960b78da31cd94caf77511692ff7ab250ea51e2
parents 0bda5734 7fbd34f0
Loading
Loading
Loading
Loading
+90 −0
Original line number Diff line number Diff line
@@ -26,12 +26,17 @@ import android.os.SystemProperties;
import android.system.Os;
import android.system.OsConstants;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.VisibleForTesting;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@@ -76,6 +81,8 @@ public final class MemoryStatUtil {

    private static final Pattern ION_HEAP_SIZE_IN_BYTES =
            Pattern.compile("\n\\s*total\\s*(\\d+)\\s*\n");
    private static final Pattern PROCESS_ION_HEAP_SIZE_IN_BYTES =
            Pattern.compile("\n\\s+\\S+\\s+(\\d+)\\s+(\\d+)");

    private static final int PGFAULT_INDEX = 9;
    private static final int PGMAJFAULT_INDEX = 11;
@@ -147,6 +154,16 @@ public final class MemoryStatUtil {
        return parseIonHeapSizeFromDebugfs(readFileContents(DEBUG_SYSTEM_ION_HEAP_FILE));
    }

    /**
     * Reads process allocation sizes on the system ion heap from debugfs.
     *
     * Returns values of allocation sizes in bytes on the system ion heap from
     * /sys/kernel/debug/ion/heaps/system.
     */
    public static List<IonAllocations> readProcessSystemIonHeapSizesFromDebugfs() {
        return parseProcessIonHeapSizesFromDebugfs(readFileContents(DEBUG_SYSTEM_ION_HEAP_FILE));
    }

    private static String readFileContents(String path) {
        final File file = new File(path);
        if (!file.exists()) {
@@ -262,6 +279,43 @@ public final class MemoryStatUtil {
        return tryParseLong(ION_HEAP_SIZE_IN_BYTES, contents);
    }

    /**
     * Parses per-process allocation sizes on the ion heap from the contents of a file under
     * /sys/kernel/debug/ion/heaps in debugfs.
     */
    @VisibleForTesting
    static List<IonAllocations> parseProcessIonHeapSizesFromDebugfs(String contents) {
        if (contents == null || contents.isEmpty()) {
            return Collections.emptyList();
        }

        final Matcher m = PROCESS_ION_HEAP_SIZE_IN_BYTES.matcher(contents);
        final SparseArray<IonAllocations> entries = new SparseArray<>();
        while (m.find()) {
            try {
                final int pid = Integer.parseInt(m.group(1));
                final long sizeInBytes = Long.parseLong(m.group(2));
                IonAllocations allocations = entries.get(pid);
                if (allocations == null) {
                    allocations = new IonAllocations();
                    entries.put(pid, allocations);
                }
                allocations.pid = pid;
                allocations.totalSizeInBytes += sizeInBytes;
                allocations.count += 1;
                allocations.maxSizeInBytes = Math.max(allocations.maxSizeInBytes, sizeInBytes);
            } catch (NumberFormatException e) {
                Slog.e(TAG, "Failed to parse value", e);
            }
        }

        final List<IonAllocations> result = new ArrayList<>(entries.size());
        for (int i = 0; i < entries.size(); i++) {
            result.add(entries.valueAt(i));
        }
        return result;
    }

    /**
     * Returns whether per-app memcg is available on device.
     */
@@ -299,4 +353,40 @@ public final class MemoryStatUtil {
        /** Device time when the processes started. */
        public long startTimeNanos;
    }

    /** Summary information about process ion allocations. */
    public static final class IonAllocations {
        /** PID these allocations belong to. */
        public int pid;
        /** Size of all individual allocations added together. */
        public long totalSizeInBytes;
        /** Number of allocations. */
        public int count;
        /** Size of the largest allocation. */
        public long maxSizeInBytes;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            IonAllocations that = (IonAllocations) o;
            return pid == that.pid && totalSizeInBytes == that.totalSizeInBytes
                    && count == that.count && maxSizeInBytes == that.maxSizeInBytes;
        }

        @Override
        public int hashCode() {
            return Objects.hash(pid, totalSizeInBytes, count, maxSizeInBytes);
        }

        @Override
        public String toString() {
            return "IonAllocations{"
                    + "pid=" + pid
                    + ", totalSizeInBytes=" + totalSizeInBytes
                    + ", count=" + count
                    + ", maxSizeInBytes=" + maxSizeInBytes
                    + '}';
        }
    }
}
+12 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
import static com.android.server.am.MemoryStatUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.am.MemoryStatUtil.readRssHighWaterMarkFromProcfs;
import static com.android.server.am.MemoryStatUtil.readSystemIonHeapSizeFromDebugfs;

@@ -137,6 +138,7 @@ import com.android.server.BinderCallsStatsService;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.am.MemoryStatUtil.IonAllocations;
import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.role.RoleManagerInternal;
import com.android.server.storage.DiskStatsFileLogger;
@@ -1274,7 +1276,16 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
    private void pullProcessSystemIonHeapSize(
            int tagId, long elapsedNanos, long wallClockNanos,
            List<StatsLogEventWrapper> pulledData) {
        // TODO(b/130526489): Read from debugfs.
        List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs();
        for (IonAllocations allocations : result) {
            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
            e.writeInt(getUidForPid(allocations.pid));
            e.writeString(readCmdlineFromProcfs(allocations.pid));
            e.writeInt((int) (allocations.totalSizeInBytes / 1024));
            e.writeInt(allocations.count);
            e.writeInt((int) (allocations.maxSizeInBytes / 1024));
            pulledData.add(e);
        }
    }

    private void pullBinderCallsStats(
+110 −25
Original line number Diff line number Diff line
@@ -23,13 +23,18 @@ import static com.android.server.am.MemoryStatUtil.parseCmdlineFromProcfs;
import static com.android.server.am.MemoryStatUtil.parseIonHeapSizeFromDebugfs;
import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs;
import static com.android.server.am.MemoryStatUtil.parseProcessIonHeapSizesFromDebugfs;
import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import androidx.test.filters.SmallTest;

import com.android.server.am.MemoryStatUtil.IonAllocations;

import org.junit.Test;

import java.io.ByteArrayOutputStream;
@@ -178,32 +183,70 @@ public class MemoryStatUtilTest {
            + "voluntary_ctxt_switches:\t903\n"
            + "nonvoluntary_ctxt_switches:\t104\n";

    // Repeated lines have been removed.
    private static final String DEBUG_SYSTEM_ION_HEAP_CONTENTS = String.join(
            "          client              pid             size\n",
            "----------------------------------------------------\n",
            " audio@2.0-servi              765             4096\n",
            " audio@2.0-servi              765            61440\n",
            " audio@2.0-servi              765             4096\n",
            "     voip_client               96             8192\n",
            "     voip_client               96             4096\n",
            "   system_server             1232         16728064\n",
            "  surfaceflinger              611         50642944\n",
            "----------------------------------------------------\n",
            "orphaned allocations (info is from last known client):\n",
            "----------------------------------------------------\n",
            "  total orphaned                0\n",
            "          total          55193600\n",
            "   deferred free                0\n",
            "----------------------------------------------------\n",
            "0 order 4 highmem pages in uncached pool = 0 total\n",
            "0 order 4 lowmem pages in uncached pool = 0 total\n",
            "1251 order 4 lowmem pages in cached pool = 81985536 total\n",
            "VMID 8: 0 order 4 highmem pages in secure pool = 0 total\n",
            "VMID  8: 0 order 4 lowmem pages in secure pool = 0 total\n",
            "--------------------------------------------\n",
            "uncached pool = 4096 cached pool = 83566592 secure pool = 0\n",
            "pool total (uncached + cached + secure) = 83570688\n",
            "--------------------------------------------\n");
            "\n",
            "          client              pid             size",
            "----------------------------------------------------",
            " audio@2.0-servi              765             4096",
            " audio@2.0-servi              765            61440",
            " audio@2.0-servi              765             4096",
            "     voip_client               96             8192",
            "     voip_client               96             4096",
            "   system_server             1232         16728064",
            "  surfaceflinger              611         50642944",
            "----------------------------------------------------",
            "orphaned allocations (info is from last known client):",
            "----------------------------------------------------",
            "  total orphaned                0",
            "          total          55193600",
            "   deferred free                0",
            "----------------------------------------------------",
            "0 order 4 highmem pages in uncached pool = 0 total",
            "0 order 4 lowmem pages in uncached pool = 0 total",
            "1251 order 4 lowmem pages in cached pool = 81985536 total",
            "VMID 8: 0 order 4 highmem pages in secure pool = 0 total",
            "VMID  8: 0 order 4 lowmem pages in secure pool = 0 total",
            "--------------------------------------------",
            "uncached pool = 4096 cached pool = 83566592 secure pool = 0",
            "pool total (uncached + cached + secure) = 83570688",
            "--------------------------------------------");

    // Repeated lines have been removed.
    private static final String DEBUG_SYSTEM_ION_HEAP_CONTENTS_SARGO = String.join(
            "\n",
            "          client              pid             size      page counts"
                    + "--------------------------------------------------       4K       8K      "
                    + "16K      32K      64K     128K     256K     512K       1M       2M       "
                    + "4M      >=8M",
            "   system_server             1705         58097664    13120      532        "
                    + "0        0        0        0        0        0        0        0        "
                    + "0        0M",
            " audio@2.0-servi              851            16384        0        2        0        "
                    + "0        0        0        0        0        0        0        "
                    + "0        0M",
            " audio@2.0-servi              851             4096        1        0        0       "
                    + " 0        0        0        0        0        0        0        0        "
                    + "0M",
            " audio@2.0-servi              851             4096        1        0      "
                    + "  0        0        0        0        0        0        0        0        "
                    + "0        0M",
            "----------------------------------------------------",
            "orphaned allocations (info is from last known client):",
            "----------------------------------------------------",
            "  total orphaned                0",
            "          total         159928320",
            "   deferred free                0",
            "----------------------------------------------------",
            "0 order 4 highmem pages in uncached pool = 0 total",
            "0 order 4 lowmem pages in uncached pool = 0 total",
            "1251 order 4 lowmem pages in cached pool = 81985536 total",
            "VMID 8: 0 order 4 highmem pages in secure pool = 0 total",
            "VMID  8: 0 order 4 lowmem pages in secure pool = 0 total",
            "--------------------------------------------",
            "uncached pool = 4096 cached pool = 83566592 secure pool = 0",
            "pool total (uncached + cached + secure) = 83570688",
            "--------------------------------------------");

    @Test
    public void testParseMemoryStatFromMemcg_parsesCorrectValues() {
@@ -323,5 +366,47 @@ public class MemoryStatUtilTest {
    @Test
    public void testParseIonHeapSizeFromDebugfs_correctValue() {
        assertEquals(55193600, parseIonHeapSizeFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS));

        assertEquals(159928320, parseIonHeapSizeFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS_SARGO));
    }

    @Test
    public void testParseProcessIonHeapSizesFromDebugfs_emptyContents() {
        assertEquals(0, parseProcessIonHeapSizesFromDebugfs("").size());

        assertEquals(0, parseProcessIonHeapSizesFromDebugfs(null).size());
    }

    @Test
    public void testParseProcessIonHeapSizesFromDebugfs_invalidValue() {
        assertEquals(0, parseProcessIonHeapSizesFromDebugfs("<<no-value>>").size());
    }

    @Test
    public void testParseProcessIonHeapSizesFromDebugfs_correctValue1() {
        assertThat(parseProcessIonHeapSizesFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS))
                .containsExactly(
                        createIonAllocations(765, 61440 + 4096 + 4096, 3, 61440),
                        createIonAllocations(96, 8192 + 4096, 2, 8192),
                        createIonAllocations(1232, 16728064, 1, 16728064),
                        createIonAllocations(611, 50642944, 1, 50642944));
    }

    @Test
    public void testParseProcessIonHeapSizesFromDebugfs_correctValue2() {
        assertThat(parseProcessIonHeapSizesFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS_SARGO))
                .containsExactly(
                        createIonAllocations(1705, 58097664, 1, 58097664),
                        createIonAllocations(851, 16384 + 4096 + 4096, 3, 16384));
    }

    private static IonAllocations createIonAllocations(int pid, long totalSizeInBytes, int count,
            long maxSizeInBytes) {
        IonAllocations allocations = new IonAllocations();
        allocations.pid = pid;
        allocations.totalSizeInBytes = totalSizeInBytes;
        allocations.count = count;
        allocations.maxSizeInBytes = maxSizeInBytes;
        return allocations;
    }
}