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

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

Merge "Move ion stats reading code under stats"

parents 8f59c413 23628e08
Loading
Loading
Loading
Loading
+0 −117
Original line number Diff line number Diff line
@@ -26,17 +26,12 @@ 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;

@@ -61,8 +56,6 @@ public final class MemoryStatUtil {
    private static final String PROC_STATUS_FILE_FMT = "/proc/%d/status";
    /** Path to procfs cmdline file. Used with pid: /proc/pid/cmdline. */
    private static final String PROC_CMDLINE_FILE_FMT = "/proc/%d/cmdline";
    /** Path to debugfs file for the system ion heap. */
    private static final String DEBUG_SYSTEM_ION_HEAP_FILE = "/sys/kernel/debug/ion/heaps/system";

    private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
    private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
@@ -79,11 +72,6 @@ public final class MemoryStatUtil {
    private static final Pattern PROCFS_SWAP_IN_KILOBYTES =
            Pattern.compile("VmSwap:\\s*(\\d+)\\s*kB");

    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;
    private static final int START_TIME_INDEX = 21;
@@ -144,26 +132,6 @@ public final class MemoryStatUtil {
        return parseCmdlineFromProcfs(readFileContents(path));
    }

    /**
     * Reads size of the system ion heap from debugfs.
     *
     * Returns value of the total size in bytes of the system ion heap from
     * /sys/kernel/debug/ion/heaps/system.
     */
    public static long readSystemIonHeapSizeFromDebugfs() {
        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()) {
@@ -265,55 +233,6 @@ public final class MemoryStatUtil {
        return cmdline.substring(0, firstNullByte);
    }

    /**
     * Parses the ion heap size from the contents of a file under /sys/kernel/debug/ion/heaps in
     * debugfs. The returned value is in bytes.
     */
    @VisibleForTesting
    static long parseIonHeapSizeFromDebugfs(String contents) {
        if (contents == null || contents.isEmpty()) {
            return 0;
        }
        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.
     */
@@ -351,40 +270,4 @@ 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
                    + '}';
        }
    }
}
+167 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server.stats;

import android.os.FileUtils;
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.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** Utility methods for reading ion memory stats. */
final class IonMemoryUtil {
    private static final String TAG = "IonMemoryUtil";

    /** Path to debugfs file for the system ion heap. */
    private static final String DEBUG_SYSTEM_ION_HEAP_FILE = "/sys/kernel/debug/ion/heaps/system";

    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 IonMemoryUtil() {}

    /**
     * Reads size of the system ion heap from debugfs.
     *
     * Returns value of the total size in bytes of the system ion heap from
     * /sys/kernel/debug/ion/heaps/system.
     */
    static long readSystemIonHeapSizeFromDebugfs() {
        return parseIonHeapSizeFromDebugfs(readFile(DEBUG_SYSTEM_ION_HEAP_FILE));
    }

    /**
     * Parses the ion heap size from the contents of a file under /sys/kernel/debug/ion/heaps in
     * debugfs. The returned value is in bytes.
     */
    @VisibleForTesting
    static long parseIonHeapSizeFromDebugfs(String contents) {
        if (contents.isEmpty()) {
            return 0;
        }
        final Matcher matcher = ION_HEAP_SIZE_IN_BYTES.matcher(contents);
        try {
            return matcher.find() ? Long.parseLong(matcher.group(1)) : 0;
        } catch (NumberFormatException e) {
            Slog.e(TAG, "Failed to parse value", e);
            return 0;
        }
    }

    /**
     * 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.
     */
    static List<IonAllocations> readProcessSystemIonHeapSizesFromDebugfs() {
        return parseProcessIonHeapSizesFromDebugfs(readFile(DEBUG_SYSTEM_ION_HEAP_FILE));
    }

    /**
     * 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.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;
    }

    private static String readFile(String path) {
        try {
            final File file = new File(path);
            return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */);
        } catch (IOException e) {
            Slog.e(TAG, "Failed to read file", e);
            return "";
        }
    }

    /** Summary information about process ion allocations. */
    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
                    + '}';
        }
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -27,9 +27,9 @@ 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;
import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -138,9 +138,9 @@ 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.stats.IonMemoryUtil.IonAllocations;
import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;

+0 −132
Original line number Diff line number Diff line
@@ -20,21 +20,15 @@ import static com.android.server.am.MemoryStatUtil.BYTES_IN_KILOBYTE;
import static com.android.server.am.MemoryStatUtil.JIFFY_NANOS;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
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;
@@ -183,71 +177,6 @@ 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(
            "\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() {
        MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS);
@@ -348,65 +277,4 @@ public class MemoryStatUtilTest {
        output.write(bytes, 0, bytes.length);
        return output.toString();
    }

    @Test
    public void testParseIonHeapSizeFromDebugfs_emptyContents() {
        assertEquals(0, parseIonHeapSizeFromDebugfs(""));

        assertEquals(0, parseIonHeapSizeFromDebugfs(null));
    }

    @Test
    public void testParseIonHeapSizeFromDebugfs_invalidValue() {
        assertEquals(0, parseIonHeapSizeFromDebugfs("<<no-value>>"));

        assertEquals(0, parseIonHeapSizeFromDebugfs("\ntotal 12345678901234567890\n"));
    }

    @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;
    }
}
+158 −0

File added.

Preview size limit exceeded, changes collapsed.