Read current CPU frequencies and populate CpuInfo.
- CPU time in state file provides information on the time spent by CPU cores in a specific frequency since system bootup. This time is monotonically increasing since system bootup. - Use the time in state information to calculate the average frequency of a CPU core between two polling periods. - The unit tests require test files to read the CPU info. The test files in the test APK are not accessible by the implementation. Thus, copy the test files from the APK into the test app's cache directory during setup and remove them from the cache directory during teardown. Test: atest CpuInfoReaderTest Bug: 217422127 Bug: 242722241 (cherry-picked from commit c1057fef03d755e35e6d6723480dc7a9cbbeb3c8) Change-Id: Iadb234a56b48dcba3c8dc77411b175de5046ce89
This commit is contained in:
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
@@ -46,8 +47,12 @@ public final class CpuInfoReader {
|
||||
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_CPUFREQ_FILE = "cpuinfo_cur_freq";
|
||||
private static final String MAX_CPUFREQ_FILE = "cpuinfo_max_freq";
|
||||
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";
|
||||
@@ -60,6 +65,8 @@ public final class CpuInfoReader {
|
||||
+ "(?<irqClockTicks>[0-9]+)\\s(?<softirqClockTicks>[0-9]+)\\s"
|
||||
+ "(?<stealClockTicks>[0-9]+)\\s(?<guestClockTicks>[0-9]+)\\s"
|
||||
+ "(?<guestNiceClockTicks>[0-9]+)");
|
||||
private static final Pattern TIME_IN_STATE_PATTERN =
|
||||
Pattern.compile("(?<freqKHz>[0-9]+)\\s(?<time>[0-9]+)");
|
||||
private static final long MILLIS_PER_JIFFY = 1000L / Os.sysconf(OsConstants._SC_CLK_TCK);
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@@ -70,14 +77,16 @@ public final class CpuInfoReader {
|
||||
private @interface CpusetCategory{}
|
||||
|
||||
private final File mCpusetDir;
|
||||
private final File mCpuFreqDir;
|
||||
private final File mProcStatFile;
|
||||
private final SparseIntArray mCpusetCategoriesByCpus = new SparseIntArray();
|
||||
private final SparseArray<Long> mMaxCpuFrequenciesByCpus = new SparseArray<>();
|
||||
private final ArrayMap<String, ArrayMap<Long, Long>> mTimeInStateByPolicy = new ArrayMap<>();
|
||||
|
||||
private File mCpuFreqDir;
|
||||
private File mProcStatFile;
|
||||
private File[] mCpuFreqPolicyDirs;
|
||||
private SparseArray<CpuUsageStats> mCumulativeCpuUsageStats = new SparseArray<>();
|
||||
private boolean mIsEnabled;
|
||||
private boolean mHasTimeInStateFile;
|
||||
|
||||
public CpuInfoReader() {
|
||||
this(new File(CPUSET_DIR_PATH), new File(CPUFREQ_DIR_PATH), new File(PROC_STAT_FILE_PATH));
|
||||
@@ -115,6 +124,11 @@ public final class CpuInfoReader {
|
||||
mCpuFreqDir.getAbsolutePath());
|
||||
return false;
|
||||
}
|
||||
|
||||
// The Kernel must be configured to generate the `time_in_state` file. If the Kernel is not
|
||||
// configured to generate this file, this file won't be available for the entire system
|
||||
// uptime. Thus, check for the presence of this file only during init.
|
||||
mHasTimeInStateFile = new File(mCpuFreqPolicyDirs[0], TIME_IN_STATE_FILE).exists();
|
||||
mIsEnabled = true;
|
||||
return true;
|
||||
}
|
||||
@@ -129,8 +143,44 @@ public final class CpuInfoReader {
|
||||
Slogf.e(TAG, "Failed to read latest CPU usage stats");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// TODO(b/217422127): Read current CPU frequencies and populate the CpuInfo.
|
||||
return Collections.emptyList();
|
||||
SparseArray<Long> cpuFrequenciesByCpus = readCurrentCpuFrequencies();
|
||||
List<CpuInfo> cpuInfos = new ArrayList<>();
|
||||
for (int i = 0; i < cpuFrequenciesByCpus.size(); i++) {
|
||||
int cpu = cpuFrequenciesByCpus.keyAt(i);
|
||||
long curFrequency = cpuFrequenciesByCpus.valueAt(i);
|
||||
if (!mMaxCpuFrequenciesByCpus.contains(cpu) || !latestCpuUsageStats.contains(cpu)) {
|
||||
Slogf.w(TAG, "Missing max CPU frequency or CPU usage stats for CPU core %d", cpu);
|
||||
continue;
|
||||
}
|
||||
int cpuCategories = mCpusetCategoriesByCpus.get(cpu, -1);
|
||||
if (cpuCategories < 0) {
|
||||
Slogf.w(TAG, "Missing cpuset information for CPU core %d", cpu);
|
||||
continue;
|
||||
}
|
||||
cpuInfos.add(new CpuInfo(cpu, cpuCategories, curFrequency,
|
||||
mMaxCpuFrequenciesByCpus.get(cpu), latestCpuUsageStats.get(cpu)));
|
||||
}
|
||||
return cpuInfos;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setCpuFreqDir(File cpuFreqDir) {
|
||||
File[] cpuFreqPolicyDirs = cpuFreqDir.listFiles(
|
||||
file -> file.isDirectory() && file.getName().startsWith(POLICY_DIR_PREFIX));
|
||||
if (mCpuFreqPolicyDirs == null || mCpuFreqPolicyDirs.length == 0) {
|
||||
Slogf.w(TAG, "Failed to set CPU frequency directory. Missing policy directories at %s",
|
||||
mCpuFreqDir.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
mCpuFreqDir = cpuFreqDir;
|
||||
mCpuFreqPolicyDirs = cpuFreqPolicyDirs;
|
||||
Slogf.i(TAG, "Set CPU frequency directory to %s", cpuFreqDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setProcStatFile(File procStatFile) {
|
||||
mProcStatFile = procStatFile;
|
||||
Slogf.i(TAG, "Set proc stat file to %s", procStatFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
private void readCpusetCategories() {
|
||||
@@ -192,6 +242,77 @@ public final class CpuInfoReader {
|
||||
: readCpuFreqKHz(new File(policyDir, MAX_SCALING_FREQ_FILE));
|
||||
}
|
||||
|
||||
private SparseArray<Long> readCurrentCpuFrequencies() {
|
||||
SparseArray<Long> curCpuFrequenciesByCpus = new SparseArray<>();
|
||||
for (int i = 0; i < mCpuFreqPolicyDirs.length; i++) {
|
||||
File policyDir = mCpuFreqPolicyDirs[i];
|
||||
long curCpuFreqKHz = readCurrentCpuFrequency(policyDir);
|
||||
if (curCpuFreqKHz == 0) {
|
||||
Slogf.w(TAG, "Missing current frequency information at %s",
|
||||
policyDir.getAbsolutePath());
|
||||
continue;
|
||||
}
|
||||
File cpuCoresFile = new File(policyDir, AFFECTED_CPUS_FILE);
|
||||
List<Integer> cpuCores = readCpuCores(cpuCoresFile);
|
||||
if (cpuCores.isEmpty()) {
|
||||
Slogf.e(TAG, "Failed to read CPU cores from %s", cpuCoresFile.getAbsolutePath());
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < cpuCores.size(); j++) {
|
||||
curCpuFrequenciesByCpus.append(cpuCores.get(j), curCpuFreqKHz);
|
||||
}
|
||||
}
|
||||
return curCpuFrequenciesByCpus;
|
||||
}
|
||||
|
||||
private long readCurrentCpuFrequency(File policyDir) {
|
||||
ArrayMap<Long, Long> latestTimeInState = readTimeInState(policyDir);
|
||||
if (latestTimeInState == null) {
|
||||
long curCpuFreqKHz = readCpuFreqKHz(new File(policyDir, CUR_CPUFREQ_FILE));
|
||||
return curCpuFreqKHz > 0 ? curCpuFreqKHz :
|
||||
readCpuFreqKHz(new File(policyDir, CUR_SCALING_FREQ_FILE));
|
||||
}
|
||||
String policyDirName = policyDir.getName();
|
||||
if (mTimeInStateByPolicy.containsKey(policyDirName)) {
|
||||
ArrayMap<Long, Long> prevTimeInState = mTimeInStateByPolicy.get(policyDirName);
|
||||
ArrayMap<Long, Long> deltaTimeInState =
|
||||
calculateDeltaTimeInState(prevTimeInState, latestTimeInState);
|
||||
mTimeInStateByPolicy.put(policyDirName, latestTimeInState);
|
||||
return calculateAvgCpuFreq(deltaTimeInState);
|
||||
}
|
||||
mTimeInStateByPolicy.put(policyDirName, latestTimeInState);
|
||||
return calculateAvgCpuFreq(latestTimeInState);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ArrayMap<Long, Long> readTimeInState(File policyDir) {
|
||||
if (!mHasTimeInStateFile) {
|
||||
return null;
|
||||
}
|
||||
File timeInStateFile = new File(policyDir, TIME_IN_STATE_FILE);
|
||||
try {
|
||||
List<String> lines = Files.readAllLines(timeInStateFile.toPath());
|
||||
if (lines.isEmpty()) {
|
||||
Slogf.w(TAG, "Empty time in state file at %s", timeInStateFile.getAbsolutePath());
|
||||
return null;
|
||||
}
|
||||
ArrayMap<Long, Long> cpuTimeByFrequencies = new ArrayMap<>();
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
Matcher m = TIME_IN_STATE_PATTERN.matcher(lines.get(i).trim());
|
||||
if (!m.find()) {
|
||||
continue;
|
||||
}
|
||||
cpuTimeByFrequencies.put(Long.parseLong(m.group("freqKHz")),
|
||||
jiffyStrToMillis(m.group("time")));
|
||||
}
|
||||
return cpuTimeByFrequencies;
|
||||
} catch (Exception e) {
|
||||
Slogf.e(TAG, e, "Failed to read CPU time in state from file: %s",
|
||||
timeInStateFile.getAbsolutePath());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static long readCpuFreqKHz(File file) {
|
||||
if (!file.exists()) {
|
||||
Slogf.e(TAG, "CPU frequency file %s doesn't exist", file.getAbsolutePath());
|
||||
@@ -209,6 +330,37 @@ public final class CpuInfoReader {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static ArrayMap<Long, Long> calculateDeltaTimeInState(
|
||||
ArrayMap<Long, Long> prevTimeInState, ArrayMap<Long, Long> latestTimeInState) {
|
||||
ArrayMap<Long, Long> deltaTimeInState = new ArrayMap();
|
||||
for (int i = 0; i < latestTimeInState.size(); i++) {
|
||||
long freq = latestTimeInState.keyAt(i);
|
||||
long durationMillis = latestTimeInState.valueAt(i);
|
||||
long deltaDurationMillis;
|
||||
if (prevTimeInState.containsKey(freq)) {
|
||||
long prevDurationMillis = prevTimeInState.get(freq);
|
||||
deltaDurationMillis = durationMillis > prevDurationMillis
|
||||
? (durationMillis - prevDurationMillis) : durationMillis;
|
||||
} else {
|
||||
deltaDurationMillis = durationMillis;
|
||||
}
|
||||
deltaTimeInState.put(freq, deltaDurationMillis);
|
||||
}
|
||||
return deltaTimeInState;
|
||||
}
|
||||
|
||||
private static long calculateAvgCpuFreq(ArrayMap<Long, Long> timeInState) {
|
||||
double totalTimeInState = 0;
|
||||
for (int i = 0; i < timeInState.size(); i++) {
|
||||
totalTimeInState += timeInState.valueAt(i);
|
||||
}
|
||||
double avgFreqKHz = 0;
|
||||
for (int i = 0; i < timeInState.size(); i++) {
|
||||
avgFreqKHz += (timeInState.keyAt(i) * timeInState.valueAt(i)) / totalTimeInState;
|
||||
}
|
||||
return (long) avgFreqKHz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the list of CPU cores from the given file.
|
||||
*
|
||||
@@ -282,7 +434,7 @@ public final class CpuInfoReader {
|
||||
if (!m.find()) {
|
||||
continue;
|
||||
}
|
||||
cpuUsageStats.append(Integer.parseInt(Objects.requireNonNull(m.group("core"))),
|
||||
cpuUsageStats.append(Integer.parseInt(m.group("core")),
|
||||
new CpuUsageStats(jiffyStrToMillis(m.group("userClockTicks")),
|
||||
jiffyStrToMillis(m.group("niceClockTicks")),
|
||||
jiffyStrToMillis(m.group("sysClockTicks")),
|
||||
@@ -302,7 +454,7 @@ public final class CpuInfoReader {
|
||||
}
|
||||
|
||||
private static long jiffyStrToMillis(String jiffyStr) {
|
||||
return Long.parseLong(Objects.requireNonNull(jiffyStr)) * MILLIS_PER_JIFFY;
|
||||
return Long.parseLong(jiffyStr) * MILLIS_PER_JIFFY;
|
||||
}
|
||||
|
||||
/** Contains information for each CPU core on the system. */
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0-
|
||||
@@ -0,0 +1 @@
|
||||
"1.23
|
||||
@@ -0,0 +1 @@
|
||||
+2.5
|
||||
@@ -0,0 +1 @@
|
||||
0-
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
3000000
|
||||
@@ -0,0 +1 @@
|
||||
1000000
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,2 @@
|
||||
2,
|
||||
3
|
||||
@@ -0,0 +1,2 @@
|
||||
2,
|
||||
3
|
||||
@@ -0,0 +1 @@
|
||||
9
|
||||
@@ -0,0 +1 @@
|
||||
2
|
||||
@@ -0,0 +1,2 @@
|
||||
2,
|
||||
-3
|
||||
@@ -0,0 +1,2 @@
|
||||
0-
|
||||
1-2-3
|
||||
@@ -0,0 +1,12 @@
|
||||
cpu 6119889 1575038 10623107 81174407 250978 2293369 192710 16073 0 0
|
||||
cpu0 3224961 795093 5222705 40903695 132281 814674 42897 8195 0 0
|
||||
cpu1 2894928 779945 5400402 40270712 118696 1478694 149813 7878 0 0
|
||||
cpu2 2895928 corrupted 40271712 116696 1479694 147813 8878 0 0
|
||||
cpu3 3234961 785093 5212705 40913695 133281 813674 corrupted
|
||||
intr 1411620772 49 19 0 0 4 0 0 0 1 0 0 1497 3 0 0 0 1 0 0 0 0 459002 0 0 19479985 0 30742819 0 1 0 22977745 0 79 0 10 0 1578 2077 0 207913133 0 53571 0 43 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 142749 719664 0 4096981 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
ctxt 3289727889
|
||||
btime 1648158254
|
||||
processes 7700412
|
||||
procs_running 1
|
||||
procs_blocked 0
|
||||
softirq 190070910 9 21017845 30017 4408 64129752 0 672853 46618585 0 57597441
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
1230000
|
||||
@@ -0,0 +1 @@
|
||||
2500000
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,4 @@
|
||||
200000 500
|
||||
350000 500
|
||||
500000 1000
|
||||
2500000 100
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
1450000
|
||||
@@ -0,0 +1 @@
|
||||
2800000
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,4 @@
|
||||
200000 500
|
||||
350000 500
|
||||
500000 1000
|
||||
2800000 100
|
||||
@@ -0,0 +1 @@
|
||||
2,3
|
||||
@@ -0,0 +1 @@
|
||||
2-3
|
||||
@@ -0,0 +1 @@
|
||||
1000000
|
||||
@@ -0,0 +1 @@
|
||||
2000000
|
||||
@@ -0,0 +1,4 @@
|
||||
200000 500
|
||||
350000 500
|
||||
500000 1000
|
||||
2000000 100
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
1000000
|
||||
@@ -0,0 +1 @@
|
||||
2500000
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,4 @@
|
||||
200000 1500
|
||||
350000 1500
|
||||
500000 2000
|
||||
2500000 200
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
2800000
|
||||
@@ -0,0 +1 @@
|
||||
2800000
|
||||
@@ -0,0 +1,4 @@
|
||||
200000 1500
|
||||
350000 1500
|
||||
500000 2000
|
||||
2800000 200
|
||||
@@ -0,0 +1 @@
|
||||
2,3
|
||||
@@ -0,0 +1 @@
|
||||
2000000
|
||||
@@ -0,0 +1 @@
|
||||
2000000
|
||||
@@ -0,0 +1,4 @@
|
||||
200000 1500
|
||||
350000 1500
|
||||
500000 2000
|
||||
2000000 200
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
1230000
|
||||
@@ -0,0 +1 @@
|
||||
2500000
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
1450000
|
||||
@@ -0,0 +1 @@
|
||||
2800000
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
2,3
|
||||
@@ -0,0 +1 @@
|
||||
2-3
|
||||
@@ -0,0 +1 @@
|
||||
1000000
|
||||
@@ -0,0 +1 @@
|
||||
2000000
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
1000000
|
||||
@@ -0,0 +1 @@
|
||||
2500000
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
2800000
|
||||
@@ -0,0 +1 @@
|
||||
2800000
|
||||
@@ -0,0 +1 @@
|
||||
2,3
|
||||
@@ -0,0 +1 @@
|
||||
2000000
|
||||
@@ -0,0 +1 @@
|
||||
2000000
|
||||
@@ -0,0 +1,2 @@
|
||||
2
|
||||
3
|
||||
@@ -0,0 +1 @@
|
||||
0-3
|
||||
@@ -0,0 +1,12 @@
|
||||
cpu 6119889 1575038 10623107 81174407 250978 2293369 192710 16073 0 0
|
||||
cpu0 3224961 795093 5222705 40903695 132281 814674 42897 8195 0 0
|
||||
cpu1 2894928 779945 5400402 40270712 118696 1478694 149813 7878 0 0
|
||||
cpu2 2895928 778945 5401402 40271712 116696 1479694 147813 8878 0 0
|
||||
cpu3 3234961 785093 5212705 40913695 133281 813674 43897 7195 0 0
|
||||
intr 1411620772 49 19 0 0 4 0 0 0 1 0 0 1497 3 0 0 0 1 0 0 0 0 459002 0 0 19479985 0 30742819 0 1 0 22977745 0 79 0 10 0 1578 2077 0 207913133 0 53571 0 43 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 142749 719664 0 4096981 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
ctxt 3289727889
|
||||
btime 1648158254
|
||||
processes 7700412
|
||||
procs_running 1
|
||||
procs_blocked 0
|
||||
softirq 190070910 9 21017845 30017 4408 64129752 0 672853 46618585 0 57597441
|
||||
@@ -0,0 +1,12 @@
|
||||
cpu 6119889 1575038 10623107 81174407 250978 2293369 192710 16073 0 0
|
||||
cpu0 4224961 895093 6222705 51903695 242281 954674 50897 10295 0 0
|
||||
cpu1 2984928 879945 6400402 40370712 127696 1498694 159813 17878 0 0
|
||||
cpu2 3895928 978945 5401402 41271712 216696 3479694 247813 18878 0 0
|
||||
cpu3 3434961 885093 5312705 40923695 143281 823674 143897 7295 0 0
|
||||
intr 1411620772 49 19 0 0 4 0 0 0 1 0 0 1497 3 0 0 0 1 0 0 0 0 459002 0 0 19479985 0 30742819 0 1 0 22977745 0 79 0 10 0 1578 2077 0 207913133 0 53571 0 43 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 142749 719664 0 4096981 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
ctxt 3289727889
|
||||
btime 1648158254
|
||||
processes 7700412
|
||||
procs_running 1
|
||||
procs_blocked 0
|
||||
softirq 190070910 9 21017845 30017 4408 64129752 0 672853 46618585 0 57597441
|
||||
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.cpu;
|
||||
|
||||
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_BACKGROUND;
|
||||
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_TOP_APP;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.util.Slog;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.server.ExtendedMockitoTestCase;
|
||||
|
||||
import libcore.io.Streams;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>This class contains unit tests for the {@link CpuInfoReader}.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public final class CpuInfoReaderTest extends ExtendedMockitoTestCase {
|
||||
private static final String TAG = CpuInfoReaderTest.class.getSimpleName();
|
||||
private static final String ROOT_DIR_NAME = "CpuInfoReaderTest";
|
||||
private static final String VALID_CPUSET_DIR = "valid_cpuset";
|
||||
private static final String VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR =
|
||||
"valid_cpufreq_with_time_in_state";
|
||||
private static final String VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR =
|
||||
"valid_cpufreq_with_time_in_state_2";
|
||||
private static final String VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_DIR =
|
||||
"valid_cpufreq_without_time_in_state";
|
||||
private static final String VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_2_DIR =
|
||||
"valid_cpufreq_without_time_in_state_2";
|
||||
private static final String VALID_PROC_STAT = "valid_proc_stat";
|
||||
private static final String VALID_PROC_STAT_2 = "valid_proc_stat_2";
|
||||
private static final String CORRUPTED_CPUFREQ_DIR = "corrupted_cpufreq";
|
||||
private static final String CORRUPTED_CPUSET_DIR = "corrupted_cpuset";
|
||||
private static final String CORRUPTED_PROC_STAT = "corrupted_proc_stat";
|
||||
private static final String EMPTY_DIR = "empty_dir";
|
||||
private static final String EMPTY_FILE = "empty_file";
|
||||
|
||||
private final Context mContext =
|
||||
InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
private final File mCacheRoot = new File(mContext.getCacheDir(), ROOT_DIR_NAME);
|
||||
private final AssetManager mAssetManager = mContext.getAssets();
|
||||
|
||||
private CpuInfoReader mCpuInfoReader;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
copyAssets(ROOT_DIR_NAME, mContext.getCacheDir());
|
||||
assertWithMessage("Cache root dir %s", mCacheRoot.getAbsolutePath())
|
||||
.that(mCacheRoot.exists()).isTrue();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (!deleteDirectory(mCacheRoot)) {
|
||||
Slog.e(TAG, "Failed to delete cache root directory " + mCacheRoot.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCpuInfoWithTimeInState() throws Exception {
|
||||
mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
|
||||
getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
|
||||
mCpuInfoReader.init();
|
||||
List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
|
||||
List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 488_095, /* maxCpuFreqKHz= */ 2_500_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
|
||||
/* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
|
||||
/* idleTimeMillis= */ 409_036_950,
|
||||
/* iowaitTimeMillis= */ 1_322_810, /* irqTimeMillis= */ 8_146_740,
|
||||
/* softirqTimeMillis= */ 428_970, /* stealTimeMillis= */ 81_950,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 502_380, /* maxCpuFreqKHz= */ 2_800_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
|
||||
/* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
|
||||
/* idleTimeMillis= */ 402_707_120,
|
||||
/* iowaitTimeMillis= */ 1_186_960, /* irqTimeMillis= */ 14_786_940,
|
||||
/* softirqTimeMillis= */ 1_498_130, /* stealTimeMillis= */ 78_780,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 464_285, /* maxCpuFreqKHz= */ 2_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
|
||||
/* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
|
||||
/* idleTimeMillis= */ 402_717_120,
|
||||
/* iowaitTimeMillis= */ 1_166_960, /* irqTimeMillis= */ 14_796_940,
|
||||
/* softirqTimeMillis= */ 1_478_130, /* stealTimeMillis= */ 88_780,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 464_285, /* maxCpuFreqKHz= */ 2_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
|
||||
/* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
|
||||
/* idleTimeMillis= */ 409_136_950,
|
||||
/* iowaitTimeMillis= */ 1_332_810, /* irqTimeMillis= */ 8_136_740,
|
||||
/* softirqTimeMillis= */ 438_970, /* stealTimeMillis= */ 71_950,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)));
|
||||
|
||||
assertWithMessage("Cpu infos").that(actualCpuInfos)
|
||||
.containsExactlyElementsIn(expectedCpuInfos);
|
||||
|
||||
mCpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
|
||||
mCpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
|
||||
|
||||
actualCpuInfos = mCpuInfoReader.readCpuInfos();
|
||||
expectedCpuInfos = List.of(
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 419_354, /* maxCpuFreqKHz= */ 2_500_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
|
||||
/* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
|
||||
/* idleTimeMillis= */ 110_000_000,
|
||||
/* iowaitTimeMillis= */ 1_100_000, /* irqTimeMillis= */ 1_400_000,
|
||||
/* softirqTimeMillis= */ 80_000, /* stealTimeMillis= */ 21_000,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 429_032, /* maxCpuFreqKHz= */ 2_800_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
|
||||
/* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
|
||||
/* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
|
||||
/* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000,
|
||||
/* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
|
||||
/* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 403_225, /* maxCpuFreqKHz= */ 2_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
|
||||
/* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
|
||||
/* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
|
||||
/* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000,
|
||||
/* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
|
||||
/* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 403_225, /* maxCpuFreqKHz= */ 2_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
|
||||
/* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
|
||||
/* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
|
||||
/* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000,
|
||||
/* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0,
|
||||
/* guestNiceTimeMillis= */ 0)));
|
||||
|
||||
assertWithMessage("Second snapshot of cpu infos").that(actualCpuInfos)
|
||||
.containsExactlyElementsIn(expectedCpuInfos);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCpuInfoWithoutTimeInState() throws Exception {
|
||||
mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
|
||||
getCacheFile(VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_DIR),
|
||||
getCacheFile(VALID_PROC_STAT));
|
||||
mCpuInfoReader.init();
|
||||
List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
|
||||
List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 1_230_000, /* maxCpuFreqKHz= */ 2_500_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
|
||||
/* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
|
||||
/* idleTimeMillis= */ 409_036_950,
|
||||
/* iowaitTimeMillis= */ 1_322_810, /* irqTimeMillis= */ 8_146_740,
|
||||
/* softirqTimeMillis= */ 428_970, /* stealTimeMillis= */ 81_950,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 1_450_000, /* maxCpuFreqKHz= */ 2_800_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
|
||||
/* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
|
||||
/* idleTimeMillis= */ 402_707_120,
|
||||
/* iowaitTimeMillis= */ 1_186_960, /* irqTimeMillis= */ 14_786_940,
|
||||
/* softirqTimeMillis= */ 1_498_130, /* stealTimeMillis= */ 78_780,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 1_000_000, /* maxCpuFreqKHz= */ 2_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
|
||||
/* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
|
||||
/* idleTimeMillis= */ 402_717_120,
|
||||
/* iowaitTimeMillis= */ 1_166_960, /* irqTimeMillis= */ 14_796_940,
|
||||
/* softirqTimeMillis= */ 1_478_130, /* stealTimeMillis= */ 88_780,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 1_000_000, /* maxCpuFreqKHz= */ 2_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
|
||||
/* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
|
||||
/* idleTimeMillis= */ 409_136_950,
|
||||
/* iowaitTimeMillis= */ 1_332_810, /* irqTimeMillis= */ 8_136_740,
|
||||
/* softirqTimeMillis= */ 438_970, /* stealTimeMillis= */ 71_950,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)));
|
||||
|
||||
assertWithMessage("Cpu infos").that(actualCpuInfos)
|
||||
.containsExactlyElementsIn(expectedCpuInfos);
|
||||
|
||||
mCpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_2_DIR));
|
||||
mCpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
|
||||
|
||||
actualCpuInfos = mCpuInfoReader.readCpuInfos();
|
||||
expectedCpuInfos = List.of(
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 1_000_000, /* maxCpuFreqKHz= */ 2_500_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
|
||||
/* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
|
||||
/* idleTimeMillis= */ 110_000_000,
|
||||
/* iowaitTimeMillis= */ 1_100_000, /* irqTimeMillis= */ 1_400_000,
|
||||
/* softirqTimeMillis= */ 80_000, /* stealTimeMillis= */ 21_000,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 2_800_000, /* maxCpuFreqKHz= */ 2_800_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
|
||||
/* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
|
||||
/* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
|
||||
/* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000,
|
||||
/* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
|
||||
/* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 2_000_000, /* maxCpuFreqKHz= */ 2_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
|
||||
/* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
|
||||
/* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
|
||||
/* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000,
|
||||
/* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
|
||||
/* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 2_000_000, /* maxCpuFreqKHz= */ 2_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
|
||||
/* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
|
||||
/* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
|
||||
/* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000,
|
||||
/* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0,
|
||||
/* guestNiceTimeMillis= */ 0)));
|
||||
|
||||
assertWithMessage("Second snapshot of cpu infos").that(actualCpuInfos)
|
||||
.containsExactlyElementsIn(expectedCpuInfos);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCpuInfoWithCorruptedCpuset() throws Exception {
|
||||
mCpuInfoReader = new CpuInfoReader(getCacheFile(CORRUPTED_CPUSET_DIR),
|
||||
getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR),
|
||||
getCacheFile(VALID_PROC_STAT));
|
||||
mCpuInfoReader.init();
|
||||
List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
|
||||
List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 488_095, /* maxCpuFreqKHz= */ 2_500_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
|
||||
/* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
|
||||
/* idleTimeMillis= */ 409_036_950,
|
||||
/* iowaitTimeMillis= */ 1_322_810, /* irqTimeMillis= */ 8_146_740,
|
||||
/* softirqTimeMillis= */ 428_970, /* stealTimeMillis= */ 81_950,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 502_380, /* maxCpuFreqKHz= */ 2_800_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
|
||||
/* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
|
||||
/* idleTimeMillis= */ 402_707_120,
|
||||
/* iowaitTimeMillis= */ 1_186_960, /* irqTimeMillis= */ 14_786_940,
|
||||
/* softirqTimeMillis= */ 1_498_130, /* stealTimeMillis= */ 78_780,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 464_285, /* maxCpuFreqKHz= */ 2_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
|
||||
/* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
|
||||
/* idleTimeMillis= */ 402_717_120,
|
||||
/* iowaitTimeMillis= */ 1_166_960, /* irqTimeMillis= */ 14_796_940,
|
||||
/* softirqTimeMillis= */ 1_478_130, /* stealTimeMillis= */ 88_780,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)));
|
||||
|
||||
assertWithMessage("Cpu infos").that(actualCpuInfos)
|
||||
.containsExactlyElementsIn(expectedCpuInfos);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCpuInfoWithCorruptedCpufreq() throws Exception {
|
||||
mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
|
||||
getCacheFile(CORRUPTED_CPUFREQ_DIR), getCacheFile(VALID_PROC_STAT));
|
||||
mCpuInfoReader.init();
|
||||
List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
|
||||
List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 3_000_000, /* maxCpuFreqKHz= */ 1_000_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
|
||||
/* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
|
||||
/* idleTimeMillis= */ 402_707_120,
|
||||
/* iowaitTimeMillis= */ 1_186_960, /* irqTimeMillis= */ 14_786_940,
|
||||
/* softirqTimeMillis= */ 1_498_130, /* stealTimeMillis= */ 78_780,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 9, /* maxCpuFreqKHz= */ 2,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
|
||||
/* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
|
||||
/* idleTimeMillis= */ 402_717_120,
|
||||
/* iowaitTimeMillis= */ 1_166_960, /* irqTimeMillis= */ 14_796_940,
|
||||
/* softirqTimeMillis= */ 1_478_130, /* stealTimeMillis= */ 88_780,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
|
||||
/* curCpuFreqKHz= */ 9, /* maxCpuFreqKHz= */ 2,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
|
||||
/* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
|
||||
/* idleTimeMillis= */ 409_136_950,
|
||||
/* iowaitTimeMillis= */ 1_332_810, /* irqTimeMillis= */ 8_136_740,
|
||||
/* softirqTimeMillis= */ 438_970, /* stealTimeMillis= */ 71_950,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)));
|
||||
|
||||
assertWithMessage("Cpu infos").that(actualCpuInfos)
|
||||
.containsExactlyElementsIn(expectedCpuInfos);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCpuInfoCorruptedProcStat() throws Exception {
|
||||
mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
|
||||
getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR),
|
||||
getCacheFile(CORRUPTED_PROC_STAT));
|
||||
mCpuInfoReader.init();
|
||||
List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
|
||||
List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 488_095, /* maxCpuFreqKHz= */ 2_500_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
|
||||
/* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
|
||||
/* idleTimeMillis= */ 409_036_950,
|
||||
/* iowaitTimeMillis= */ 1_322_810, /* irqTimeMillis= */ 8_146_740,
|
||||
/* softirqTimeMillis= */ 428_970, /* stealTimeMillis= */ 81_950,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)),
|
||||
new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
|
||||
FLAG_CPUSET_CATEGORY_TOP_APP,
|
||||
/* curCpuFreqKHz= */ 502_380, /* maxCpuFreqKHz= */ 2_800_000,
|
||||
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
|
||||
/* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
|
||||
/* idleTimeMillis= */ 402_707_120,
|
||||
/* iowaitTimeMillis= */ 1_186_960, /* irqTimeMillis= */ 14_786_940,
|
||||
/* softirqTimeMillis= */ 1_498_130, /* stealTimeMillis= */ 78_780,
|
||||
/* guestTimeMillis= */ 0, /* guestNiceTimeMillis= */ 0)));
|
||||
|
||||
assertWithMessage("Cpu infos").that(actualCpuInfos)
|
||||
.containsExactlyElementsIn(expectedCpuInfos);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCpuInfoWithEmptyCpuset() throws Exception {
|
||||
File emptyDir = getCacheFile(EMPTY_DIR);
|
||||
assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue();
|
||||
mCpuInfoReader = new CpuInfoReader(emptyDir, getCacheFile(
|
||||
VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR),
|
||||
getCacheFile(VALID_PROC_STAT));
|
||||
|
||||
assertWithMessage("Init CPU reader info").that(mCpuInfoReader.init()).isFalse();
|
||||
|
||||
assertWithMessage("Cpu infos").that(mCpuInfoReader.readCpuInfos()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCpuInfoWithEmptyCpufreq() throws Exception {
|
||||
File emptyDir = getCacheFile(EMPTY_DIR);
|
||||
assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue();
|
||||
mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR), emptyDir,
|
||||
getCacheFile(VALID_PROC_STAT));
|
||||
|
||||
assertWithMessage("Init CPU reader info").that(mCpuInfoReader.init()).isFalse();
|
||||
|
||||
assertWithMessage("Cpu infos").that(mCpuInfoReader.readCpuInfos()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadCpuInfoWithEmptyProcStat() throws Exception {
|
||||
File emptyFile = getCacheFile(EMPTY_FILE);
|
||||
assertWithMessage("Create empty file %s", emptyFile).that(emptyFile.createNewFile())
|
||||
.isTrue();
|
||||
mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
|
||||
getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(EMPTY_FILE));
|
||||
|
||||
assertWithMessage("Cpu infos").that(mCpuInfoReader.readCpuInfos()).isEmpty();
|
||||
}
|
||||
|
||||
private File getCacheFile(String assetName) {
|
||||
return new File(mCacheRoot, assetName);
|
||||
}
|
||||
|
||||
private void copyAssets(String assetPath, File targetRoot) throws Exception {
|
||||
File target = new File(targetRoot, assetPath);
|
||||
String[] assets = mAssetManager.list(assetPath);
|
||||
if (assets == null || assets.length == 0) {
|
||||
try (InputStream in = mAssetManager.open(assetPath);
|
||||
OutputStream out = new FileOutputStream(target)) {
|
||||
Streams.copy(in, out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
assertWithMessage("Make target directory %s", target).that(target.mkdir()).isTrue();
|
||||
for (int i = 0; i < assets.length; i++) {
|
||||
copyAssets(String.format("%s%s%s", assetPath, File.separator, assets[i]), targetRoot);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean deleteDirectory(File rootDir) {
|
||||
if (!rootDir.exists() || !rootDir.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
for (File file : Objects.requireNonNull(rootDir.listFiles())) {
|
||||
if (file.isDirectory()) {
|
||||
deleteDirectory(file);
|
||||
} else if (!file.delete()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return rootDir.delete();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user