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

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

Merge "Add thread atom that contains sum of filtered thread CPU usage"

parents b9fadbfc e51e5204
Loading
Loading
Loading
Loading
+56 −16
Original line number Diff line number Diff line
@@ -102,6 +102,16 @@ public class KernelCpuThreadReader {
     */
    private static final int ID_ERROR = -1;

    /**
     * Thread ID used when reporting CPU used by other threads
     */
    private static final int OTHER_THREADS_ID = -1;

    /**
     * Thread name used when reporting CPU used by other threads
     */
    private static final String OTHER_THREADS_NAME = "__OTHER_THREADS";

    /**
     * When checking whether to report data for a thread, we check the UID of the thread's owner
     * against this predicate
@@ -140,7 +150,8 @@ public class KernelCpuThreadReader {
    /**
     * Create with a path where `proc` is mounted. Used primarily for testing
     *
     * @param procPath where `proc` is mounted (to find, see {@code mount | grep ^proc})
     * @param procPath               where `proc` is mounted (to find, see {@code mount | grep
     *                               ^proc})
     * @param initialTimeInStatePath where the initial {@code time_in_state} file exists to define
     *                               format
     */
@@ -263,14 +274,24 @@ public class KernelCpuThreadReader {
                    + " and user ID " + uid);
        }

        int[] filteredThreadsCpuUsage = null;
        final Path allThreadsPath = processPath.resolve("task");
        final ArrayList<ThreadCpuUsage> threadCpuUsages = new ArrayList<>();
        try (DirectoryStream<Path> threadPaths = Files.newDirectoryStream(allThreadsPath)) {
            for (Path threadDirectory : threadPaths) {
                ThreadCpuUsage threadCpuUsage = getThreadCpuUsage(threadDirectory);
                if (threadCpuUsage != null) {
                    threadCpuUsages.add(threadCpuUsage);
                if (threadCpuUsage == null) {
                    continue;
                }
                if (mMinimumTotalCpuUsageMillis < totalCpuUsage(threadCpuUsage.usageTimesMillis)) {
                    if (filteredThreadsCpuUsage == null) {
                        filteredThreadsCpuUsage = new int[mFrequenciesKhz.length];
                    }
                    filteredThreadsCpuUsage =
                            sumCpuUsage(filteredThreadsCpuUsage, threadCpuUsage.usageTimesMillis);
                    continue;
                }
                threadCpuUsages.add(threadCpuUsage);
            }
        } catch (IOException e) {
            // Expected when a process finishes
@@ -282,6 +303,12 @@ public class KernelCpuThreadReader {
            return null;
        }

        // Add the filtered out thread CPU usage under an "other threads" ThreadCpuUsage
        if (filteredThreadsCpuUsage != null) {
            threadCpuUsages.add(new ThreadCpuUsage(
                    OTHER_THREADS_ID, OTHER_THREADS_NAME, filteredThreadsCpuUsage));
        }

        if (DEBUG) {
            Slog.d(TAG, "Read CPU usage of " + threadCpuUsages.size() + " threads");
        }
@@ -368,15 +395,6 @@ public class KernelCpuThreadReader {
        }
        int[] cpuUsages = mFrequencyBucketCreator.getBucketedValues(cpuUsagesLong);

        // Check if the total CPU usage below the threshold
        int totalCpuUsage = 0;
        for (int i = 0; i < cpuUsages.length; i++) {
            totalCpuUsage += cpuUsages[i];
        }
        if (totalCpuUsage < mMinimumTotalCpuUsageMillis) {
            return null;
        }

        return new ThreadCpuUsage(threadId, threadName, cpuUsages);
    }

@@ -423,6 +441,28 @@ public class KernelCpuThreadReader {
        }
    }

    /**
     * Get the sum of all CPU usage across all frequencies
     */
    private static int totalCpuUsage(int[] cpuUsage) {
        int total = 0;
        for (int i = 0; i < cpuUsage.length; i++) {
            total += cpuUsage[i];
        }
        return total;
    }

    /**
     * Add two CPU frequency usages together
     */
    private static int[] sumCpuUsage(int[] a, int[] b) {
        int[] summed = new int[a.length];
        for (int i = 0; i < a.length; i++) {
            summed[i] = a[i] + b[i];
        }
        return summed;
    }

    /**
     * Puts frequencies and usage times into buckets
     */
+46 −0
Original line number Diff line number Diff line
@@ -218,6 +218,51 @@ public class KernelCpuThreadReaderTest {

    }

    @Test
    public void testReader_otherThreads() throws IOException {
        final Path processPath = mProcDirectory.toPath().resolve("self");
        setupDirectory(
                processPath,
                new int[]{1, 2, 3},
                "process",
                new String[]{"thread1", "thread2", "thread3"},
                new int[]{1000, 2000},
                new int[][]{{0, 100}, {10, 0}, {0, 300}});
        final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
                8,
                i -> true,
                2000,
                mProcDirectory.toPath(),
                processPath.resolve("task/1/time_in_state"),
                new KernelCpuThreadReader.Injector() {
                    @Override
                    public int myPid() {
                        return 1000;
                    }

                    @Override
                    public int myUid() {
                        return 0;
                    }

                    @Override
                    public int getUidForPid(int pid) {
                        return 0;
                    }
                });
        checkResults(
                kernelCpuThreadReader.getCurrentProcessCpuUsage(),
                kernelCpuThreadReader.getCpuFrequenciesKhz(),
                0,
                1000,
                new int[]{-1, 3},
                "process",
                new String[]{"__OTHER_THREADS", "thread3"},
                new int[]{1000, 2000},
                new int[][]{{100, 1000}, {0, 3000}}
        );
    }

    private void setupDirectory(Path processPath, int[] threadIds, String processName,
            String[] threadNames, int[] cpuFrequencies, int[][] cpuTimes) throws IOException {
        // Make /proc/$PID
@@ -259,6 +304,7 @@ public class KernelCpuThreadReaderTest {
        assertEquals(processId, processCpuUsage.processId);
        assertEquals(uid, processCpuUsage.uid);
        assertEquals(processName, processCpuUsage.processName);
        assertEquals(threadIds.length, processCpuUsage.threadCpuUsages.size());

        // Sort the thread CPU usages to compare with test case
        final ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages =