Android 14 CpuMonitorService介绍

556 阅读3分钟

CpuMonitorService

  • 背景:Android 14 新增了一个系统服务,名字叫CpuMonitorService,主要用于监控CPU相关的使用情况,我们近今天介绍下它的用途

启动

  • CpuMonitorService在Systemserver初始化函数startCoreServices中启动,目前只有在debug相关版本上使能
if (Build.IS_DEBUGGABLE || Build.IS_ENG) {
  // Service for CPU monitor.
  t.traceBegin("CpuMonitorService");
  mSystemServiceManager.startService(CpuMonitorService.class);
  t.traceEnd();
}

运行时许图

  • CpuMonitorService 运行起来之后,会轮训读取CPU信息,下面时许图中的13~17 步会周期性执行,执行周期为1分钟。
private static final long DEBUG_MONITORING_INTERVAL_MILLISECONDS = TimeUnit.MINUTES.toMillis(1);

CPUmonitor.png

监控内容

CpuMonitorService 关注的系统目录有下面这些:

private static final String CPUFREQ_DIR_PATH = "/sys/devices/system/cpu/cpufreq";
private static final String POLICY_DIR_PREFIX = "policy";
private static final String RELATED_CPUS_FILE = "related_cpus";
private static final String AFFECTED_CPUS_FILE = "affected_cpus";
private static final String CUR_SCALING_FREQ_FILE = "scaling_cur_freq";
private static final String MAX_SCALING_FREQ_FILE = "scaling_max_freq";
private static final String TIME_IN_STATE_FILE = "stats/time_in_state";
private static final String CPUSET_DIR_PATH = "/dev/cpuset";
private static final String CPUSET_TOP_APP_DIR = "top-app";
private static final String CPUSET_BACKGROUND_DIR = "background";
private static final String CPUS_FILE = "cpus";
private static final String PROC_STAT_FILE_PATH = "/proc/stat";

CpuMonitorService可以提供哪些信息

  • 每个CPU是什么categories,这里categories指的是top-app还是background
writer.printf("Cpuset categories by CPU core:\n");
writer.increaseIndent();
for (int i = 0; i < mCpusetCategoriesByCpus.size(); i++) {
    writer.printf("CPU core id = %d, %s\n", mCpusetCategoriesByCpus.keyAt(i),
            toCpusetCategoriesStr(mCpusetCategoriesByCpus.valueAt(i)));
}
  • 每个CPU在什么policy下面,按照policy分类CPU
writer.println("Cpu frequency policy directories by policy id:");
writer.increaseIndent();
for (int i = 0; i < mCpuFreqPolicyDirsById.size(); i++) {
    writer.printf("Policy id = %d, Dir = %s\n", mCpuFreqPolicyDirsById.keyAt(i),
            mCpuFreqPolicyDirsById.valueAt(i));
}
  • 每个policy下面的最大频率,下面代码中的static代表的就是最大频率(静态的意思)
writer.println("Static cpu frequency policy infos by policy id:");
writer.increaseIndent();
for (int i = 0; i < mStaticPolicyInfoById.size(); i++) {
    writer.printf("Policy id = %d, %s\n", mStaticPolicyInfoById.keyAt(i),
            mStaticPolicyInfoById.valueAt(i));
}
  • 每个policy下面每个频率上运行的时间
writer.println("Cpu time in frequency state by policy id:");
writer.increaseIndent();
for (int i = 0; i < mTimeInStateByPolicyId.size(); i++) {
    writer.printf("Policy id = %d, Time(millis) in state by CPU frequency(KHz) = %s\n",
            mTimeInStateByPolicyId.keyAt(i), mTimeInStateByPolicyId.valueAt(i));
}
  • 最近一次获取的CPU info
writer.println("Last read CPU infos:");
writer.increaseIndent();
for (int i = 0; i < mLastReadCpuInfos.size(); i++) {
    writer.printf("%s\n", mLastReadCpuInfos.valueAt(i));
}


CpuInfo(relatedCpuCore, cpusetCategories, /* isOnline= */true,
        dynamicPolicyInfo.curCpuFreqKHz, staticPolicyInfo.maxCpuFreqKHz,
        dynamicPolicyInfo.avgTimeInStateCpuFreqKHz, usageStats);
        
        // usageStats 指的是/proc/stat下面的CPU信息 
  • CPU累计使用信息
writer.println("Latest cumulative CPU usage stats by CPU core:");
writer.increaseIndent();
for (int i = 0; i < mCumulativeCpuUsageStats.size(); i++) {
    writer.printf("CPU core id = %d, %s\n", mCumulativeCpuUsageStats.keyAt(i),
            mCumulativeCpuUsageStats.valueAt(i));
}

上面这些信息都可以通过dump 服务获得

重点变量和函数介绍

  • CpuMonitorService 中存在各种代表CPU信息的变量和读取CPU信息的各种函数,看代码时容易迷糊,我们列举一下为了方便查询,下面是变量名
参数含义
mCumulativeCpuUsageStats保存当前的cpu累计信息的cpuUsageStats结构体
mCpuFreqPolicyDirsById保存policy后面的整数,比如下面保存 0 4 7 sys/devices/system/cpu/cpufreq/policy0
mTimeInStateByPolicyIdmTimeInStateByPolicyId.put(policyId, latestTimeInState);保存的是id 和time_in_state 对应关系
dynamicPolicyInfoByIdDynamicPolicyInfo dynamicPolicyInfo = new DynamicPolicyInfo(curCpuFreqKHz,avgTimeInStateCpuFreqKHz, affectedCpuCores);dynamicPolicyInfoById.append(policyId, dynamicPolicyInfo);affectedCpuCores 代表“/sys/devices/system/cpu/cpufreq/policy0 # cat affected_cpus”
mStaticPolicyInfoById保存同一policy下面所有related CPU的最大频率
mCpusetCategoriesByCpus键值对,CPU id和对应的类别,这里的类别指的是FLAG_CPUSET_CATEGORY_TOP_APPFLAG_CPUSET_CATEGORY_BACKGROUND
函数含义
readCumulativeCpuUsageStats读取/proc/stat 并把结果保存到cpuUsageStats结构体
readDynamicPolicyInfo读取cpu当前频率,affectcpus ,平均频率并保存
populateCpuFreqPolicyDirsById读取"/sys/devices/system/cpu/cpufreq"目录下面policy后面的整数值,保存在mCpuFreqPolicyDirsById 中
readAvgTimeInStateCpuFrequency计算来两次差值之前的平均频率,调用的是calculateAvgCpuFreq
readTimeInState读取/sys/devices/system/cpu/cpufreq/policy0/stats/time_in_state的内容,并返回
calculateDeltaTimeInState算两次time in state的差值
calculateAvgCpuFreqfor (int i = 0; i < timeInState.size(); i++) {avgFreqKHz += (timeInState.keyAt(i) * timeInState.valueAt(i)) / totalTimeInState;}计算平均频率
readStaticPolicyInfo读取同一policy下面所有related CPU的最大频率,保存到mStaticPolicyInfoByIdStaticPolicyInfo staticPolicyInfo = new StaticPolicyInfo(maxCpuFreqKHz,relatedCpuCores);
readCpuInfos读取CPU 信息,返回cpuinfoCpuInfo cpuInfo = new CpuInfo(relatedCpuCore, cpusetCategories, /* isOnline= */true,dynamicPolicyInfo.curCpuFreqKHz, staticPolicyInfo.maxCpuFreqKHz,dynamicPolicyInfo.avgTimeInStateCpuFreqKHz, usageStats);cpuInfoByCpus.append(relatedCpuCore, cpuInfo);