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

Commit d701e951 authored by Rafal Slawik's avatar Rafal Slawik Committed by Android (Google) Code Review
Browse files

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

parents 4b4a138f d616982c
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;
    }
}