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

Commit 5a51e004 authored by Misha Wagner's avatar Misha Wagner
Browse files

Add atom to StatsCompanionService for retrieving per-thread CPU usage data

N.B.: This calls CpuThreadProcReader synchronously in
StatsCompanionService::pullData. This call takes approximately 50.079ms on a
Pixel 2.

Bug: 111534779
Test: `adb shell cmd stats pull-source 10035` returns correct data

Change-Id: I6fe6d178e28669f10ba9c076cbf19dc443d171c9
parent 0c6b2afb
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -150,7 +150,7 @@ message Atom {
    }

    // Pulled events will start at field 10000.
    // Next: 10037
    // Next: 10038
    oneof pulled {
        WifiBytesTransfer wifi_bytes_transfer = 10000;
        WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -189,6 +189,7 @@ message Atom {
        ProcStats proc_stats_pkg_proc = 10034;
        ProcessCpuTime process_cpu_time = 10035;
        NativeProcessMemoryState native_process_memory_state = 10036;
        CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
    }

    // DO NOT USE field numbers above 100,000 in AOSP.
@@ -3121,3 +3122,29 @@ message ProcessCpuTime {
    // Process cpu time in system space, cumulative from boot/process start
    optional int64 system_time_millis = 4;
}

/**
 * Pulls the CPU usage for each thread.
 *
 * Read from /proc/$PID/task/$TID/time_in_state files.
 *
 * TODO(mishaw): This is an experimental atom. Issues with big/little CPU frequencies, and
 * time_in_state files not being present on some phones, have not been addressed. These should be
 * considered before a public release.
 */
message CpuTimePerThreadFreq {
    // UID that owns the process.
    optional int32 uid = 1 [(is_uid) = true];
    // ID of the process.
    optional uint32 process_id = 2;
    // ID of the thread.
    optional uint32 thread_id = 3;
    // Name of the process taken from `/proc/$PID/cmdline`.
    optional string process_name = 4;
    // Name of the thread taken from `/proc/$PID/task/$TID/comm`
    optional string thread_name = 5;
    // What frequency the CPU was running at, in KHz
    optional uint32 frequency_khz = 6;
    // Time spent in frequency in milliseconds, since thread start.
    optional uint32 time_millis = 7;
}
+5 −0
Original line number Diff line number Diff line
@@ -234,6 +234,11 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
            {{} /* additive fields */, {} /* non additive fields */,
             5 * NS_PER_SEC /* min cool-down in seconds*/,
             new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}},
        {android::util::CPU_TIME_PER_THREAD_FREQ,
         {{7},
          {2, 3, 4, 5, 6},
          1 * NS_PER_SEC,
          new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}},
};

StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
+48 −0
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.os.BinderCallsStats.ExportedCallStat;
import com.android.internal.os.KernelCpuSpeedReader;
import com.android.internal.os.KernelCpuThreadReader;
import com.android.internal.os.KernelUidCpuActiveTimeReader;
import com.android.internal.os.KernelUidCpuClusterTimeReader;
import com.android.internal.os.KernelUidCpuFreqTimeReader;
@@ -191,6 +192,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
            new KernelUidCpuClusterTimeReader();
    private StoragedUidIoStatsReader mStoragedUidIoStatsReader =
            new StoragedUidIoStatsReader();
    @Nullable
    private final KernelCpuThreadReader mKernelCpuThreadReader;

    private static IThermalService sThermalService;
    private File mBaseDir =
@@ -265,6 +268,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
        handlerThread.start();
        mHandler = new CompanionHandler(handlerThread.getLooper());

        mKernelCpuThreadReader = KernelCpuThreadReader.create();
    }

    @Override
@@ -1445,6 +1449,46 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
        }
    }

    private void pullCpuTimePerThreadFreq(int tagId, long elapsedNanos, long wallClockNanos,
            List<StatsLogEventWrapper> pulledData) {
        if (this.mKernelCpuThreadReader == null) {
            return;
        }
        KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = this.mKernelCpuThreadReader
                .getCurrentProcessCpuUsage();
        if (processCpuUsage == null) {
            return;
        }
        int[] cpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz();
        for (KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage
                : processCpuUsage.threadCpuUsages) {
            if (threadCpuUsage.usageTimesMillis.length != cpuFrequencies.length) {
                Slog.w(TAG, "Unexpected number of usage times,"
                        + " expected " + cpuFrequencies.length
                        + " but got " + threadCpuUsage.usageTimesMillis.length);
                continue;
            }

            for (int i = 0; i < threadCpuUsage.usageTimesMillis.length; i++) {
                // Do not report CPU usage at a frequency when it's zero
                if (threadCpuUsage.usageTimesMillis[i] == 0) {
                    continue;
                }

                StatsLogEventWrapper e =
                        new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
                e.writeInt(processCpuUsage.uid);
                e.writeInt(processCpuUsage.processId);
                e.writeInt(threadCpuUsage.threadId);
                e.writeString(processCpuUsage.processName);
                e.writeString(threadCpuUsage.threadName);
                e.writeInt(cpuFrequencies[i]);
                e.writeInt(threadCpuUsage.usageTimesMillis[i]);
                pulledData.add(e);
            }
        }
    }

    /**
     * Pulls various data.
     */
@@ -1583,6 +1627,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
                pullProcessCpuTime(tagId, elapsedNanos, wallClockNanos, ret);
                break;
            }
            case StatsLog.CPU_TIME_PER_THREAD_FREQ: {
                pullCpuTimePerThreadFreq(tagId, elapsedNanos, wallClockNanos, ret);
                break;
            }
            default:
                Slog.w(TAG, "No such tagId data as " + tagId);
                return null;