diff options
| author | 2023-01-31 17:01:27 -0800 | |
|---|---|---|
| committer | 2023-03-16 23:35:26 +0000 | |
| commit | aabb81ecb58208e7c9151bea6ebc19f6060e7515 (patch) | |
| tree | 4b8223c771d41931d7769a00e28d093292986087 | |
| parent | f5549dfd720f6834f961663558e121a91418e96b (diff) | |
Update CpuInfoReader to compute normalized available CPU frequency.
- Guard against reading CpuInfos too frequently.
- Implement dump logic in CpuInfoReader.
- Guard against zero time value in the time_in_state file.
Test: atest CpuInfoReaderTest
Bug: 242722241
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:67bc88121775785907a3aebd87db7c4bdef5fff9)
Merged-In: I9fc109c43fe0bd5f1d16135ad3167325ae502e15
Change-Id: I9fc109c43fe0bd5f1d16135ad3167325ae502e15
| -rw-r--r-- | services/core/java/com/android/server/cpu/CpuInfoReader.java | 159 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java | 79 |
2 files changed, 190 insertions, 48 deletions
diff --git a/services/core/java/com/android/server/cpu/CpuInfoReader.java b/services/core/java/com/android/server/cpu/CpuInfoReader.java index ca97a9847b39..ce68edbb9fa1 100644 --- a/services/core/java/com/android/server/cpu/CpuInfoReader.java +++ b/services/core/java/com/android/server/cpu/CpuInfoReader.java @@ -21,8 +21,10 @@ import static com.android.server.cpu.CpuMonitorService.TAG; import android.annotation.IntDef; import android.annotation.Nullable; +import android.os.SystemClock; import android.system.Os; import android.system.OsConstants; +import android.util.IndentingPrintWriter; import android.util.IntArray; import android.util.LongSparseLongArray; import android.util.SparseArray; @@ -50,6 +52,9 @@ public final class CpuInfoReader { 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"; + // TODO(b/263154344): Avoid reading from cpuinfo_cur_freq because non-root users don't have + // read permission for this file. The file permissions are set by the Kernel. Instead, read + // the current frequency only from scaling_cur_freq. 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"; @@ -70,16 +75,18 @@ public final class CpuInfoReader { private static final Pattern TIME_IN_STATE_PATTERN = Pattern.compile("(?<freqKHz>[0-9]+)\\s(?<time>[0-9]+)"); private static final long MILLIS_PER_CLOCK_TICK = 1000L / Os.sysconf(OsConstants._SC_CLK_TCK); + private static final long MIN_READ_INTERVAL_MILLISECONDS = 500; @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"FLAG_CPUSET_CATEGORY_"}, flag = true, value = { FLAG_CPUSET_CATEGORY_TOP_APP, FLAG_CPUSET_CATEGORY_BACKGROUND }) - private @interface CpusetCategory{} + /** package **/ @interface CpusetCategory{} // TODO(b/242722241): Protect updatable variables with a local lock. private final File mCpusetDir; + private final long mMinReadIntervalMillis; private final SparseIntArray mCpusetCategoriesByCpus = new SparseIntArray(); private final SparseArray<File> mCpuFreqPolicyDirsById = new SparseArray<>(); private final SparseArray<StaticPolicyInfo> mStaticPolicyInfoById = new SparseArray<>(); @@ -90,16 +97,20 @@ public final class CpuInfoReader { private SparseArray<CpuUsageStats> mCumulativeCpuUsageStats = new SparseArray<>(); private boolean mIsEnabled; private boolean mHasTimeInStateFile; + private long mLastReadUptimeMillis; + private SparseArray<CpuInfo> mLastReadCpuInfos; public CpuInfoReader() { - this(new File(CPUSET_DIR_PATH), new File(CPUFREQ_DIR_PATH), new File(PROC_STAT_FILE_PATH)); + this(new File(CPUSET_DIR_PATH), new File(CPUFREQ_DIR_PATH), new File(PROC_STAT_FILE_PATH), + MIN_READ_INTERVAL_MILLISECONDS); } @VisibleForTesting - CpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile) { + CpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile, long minReadIntervalMillis) { mCpusetDir = cpusetDir; mCpuFreqDir = cpuFreqDir; mProcStatFile = procStatFile; + mMinReadIntervalMillis = minReadIntervalMillis; } /** @@ -167,6 +178,16 @@ public final class CpuInfoReader { if (!mIsEnabled) { return null; } + long uptimeMillis = SystemClock.uptimeMillis(); + if (mLastReadUptimeMillis > 0 + && uptimeMillis - mLastReadUptimeMillis < mMinReadIntervalMillis) { + Slogf.w(TAG, "Skipping reading from device and returning the last read CpuInfos. " + + "Last read was %d ms ago, min read interval is %d ms", + uptimeMillis - mLastReadUptimeMillis, mMinReadIntervalMillis); + return mLastReadCpuInfos; + } + mLastReadUptimeMillis = uptimeMillis; + mLastReadCpuInfos = null; SparseArray<CpuUsageStats> cpuUsageStatsByCpus = readLatestCpuUsageStats(); if (cpuUsageStatsByCpus == null || cpuUsageStatsByCpus.size() == 0) { Slogf.e(TAG, "Failed to read latest CPU usage stats"); @@ -202,6 +223,12 @@ public final class CpuInfoReader { + " policy ID %d", policyId); continue; } + if (curFreqKHz > maxFreqKHz) { + Slogf.w(TAG, "Current CPU frequency (%d) is greater than maximum CPU frequency" + + " (%d) for policy ID (%d). Skipping CPU frequency policy", curFreqKHz, + maxFreqKHz, policyId); + continue; + } for (int coreIdx = 0; coreIdx < staticPolicyInfo.relatedCpuCores.size(); coreIdx++) { int relatedCpuCore = staticPolicyInfo.relatedCpuCores.get(coreIdx); CpuInfo prevCpuInfo = cpuInfoByCpus.get(relatedCpuCore); @@ -241,9 +268,73 @@ public final class CpuInfoReader { } } } + mLastReadCpuInfos = cpuInfoByCpus; return cpuInfoByCpus; } + /** Dumps the current state. */ + public void dump(IndentingPrintWriter writer) { + writer.printf("*%s*\n", getClass().getSimpleName()); + writer.increaseIndent(); // Add intend for the outermost block. + + writer.printf("mCpusetDir = %s\n", mCpusetDir.getAbsolutePath()); + writer.printf("mCpuFreqDir = %s\n", mCpuFreqDir.getAbsolutePath()); + writer.printf("mProcStatFile = %s\n", mProcStatFile.getAbsolutePath()); + writer.printf("mIsEnabled = %s\n", mIsEnabled); + writer.printf("mHasTimeInStateFile = %s\n", mHasTimeInStateFile); + writer.printf("mLastReadUptimeMillis = %d\n", mLastReadUptimeMillis); + writer.printf("mMinReadIntervalMillis = %d\n", mMinReadIntervalMillis); + + 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))); + } + writer.decreaseIndent(); + + 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)); + } + writer.decreaseIndent(); + + 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)); + } + writer.decreaseIndent(); + + 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)); + } + writer.decreaseIndent(); + + writer.println("Last read CPU infos:"); + writer.increaseIndent(); + for (int i = 0; i < mLastReadCpuInfos.size(); i++) { + writer.printf("%s\n", mLastReadCpuInfos.valueAt(i)); + } + writer.decreaseIndent(); + + 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)); + } + writer.decreaseIndent(); + + writer.decreaseIndent(); // Remove intend for the outermost block. + } + /** * Sets the CPU frequency for testing. * @@ -496,6 +587,9 @@ public final class CpuInfoReader { for (int i = 0; i < timeInState.size(); i++) { totalTimeInState += timeInState.valueAt(i); } + if (totalTimeInState == 0) { + return CpuInfo.MISSING_FREQUENCY; + } double avgFreqKHz = 0; for (int i = 0; i < timeInState.size(); i++) { avgFreqKHz += (timeInState.keyAt(i) * timeInState.valueAt(i)) / totalTimeInState; @@ -624,16 +718,29 @@ public final class CpuInfoReader { @CpusetCategory public final int cpusetCategories; public final boolean isOnline; + public final long maxCpuFreqKHz; // Values in the below fields may be missing when a CPU core is offline. public final long curCpuFreqKHz; - public final long maxCpuFreqKHz; public final long avgTimeInStateCpuFreqKHz; @Nullable public final CpuUsageStats latestCpuUsageStats; + private long mNormalizedAvailableCpuFreqKHz; + CpuInfo(int cpuCore, @CpusetCategory int cpusetCategories, boolean isOnline, long curCpuFreqKHz, long maxCpuFreqKHz, long avgTimeInStateCpuFreqKHz, CpuUsageStats latestCpuUsageStats) { + this(cpuCore, cpusetCategories, isOnline, curCpuFreqKHz, maxCpuFreqKHz, + avgTimeInStateCpuFreqKHz, /* normalizedAvailableCpuFreqKHz= */ 0, + latestCpuUsageStats); + this.mNormalizedAvailableCpuFreqKHz = computeNormalizedAvailableCpuFreqKHz(); + } + + // Should be used only for testing. + @VisibleForTesting + CpuInfo(int cpuCore, @CpusetCategory int cpusetCategories, boolean isOnline, + long curCpuFreqKHz, long maxCpuFreqKHz, long avgTimeInStateCpuFreqKHz, + long normalizedAvailableCpuFreqKHz, CpuUsageStats latestCpuUsageStats) { this.cpuCore = cpuCore; this.cpusetCategories = cpusetCategories; this.isOnline = isOnline; @@ -641,6 +748,11 @@ public final class CpuInfoReader { this.maxCpuFreqKHz = maxCpuFreqKHz; this.avgTimeInStateCpuFreqKHz = avgTimeInStateCpuFreqKHz; this.latestCpuUsageStats = latestCpuUsageStats; + this.mNormalizedAvailableCpuFreqKHz = normalizedAvailableCpuFreqKHz; + } + + public long getNormalizedAvailableCpuFreqKHz() { + return mNormalizedAvailableCpuFreqKHz; } @Override @@ -657,6 +769,8 @@ public final class CpuInfoReader { .append(avgTimeInStateCpuFreqKHz == MISSING_FREQUENCY ? "missing" : avgTimeInStateCpuFreqKHz) .append(", latestCpuUsageStats = ").append(latestCpuUsageStats) + .append(", mNormalizedAvailableCpuFreqKHz = ") + .append(mNormalizedAvailableCpuFreqKHz) .append(" }").toString(); } @@ -673,13 +787,32 @@ public final class CpuInfoReader { && isOnline == other.isOnline && curCpuFreqKHz == other.curCpuFreqKHz && maxCpuFreqKHz == other.maxCpuFreqKHz && avgTimeInStateCpuFreqKHz == other.avgTimeInStateCpuFreqKHz - && latestCpuUsageStats.equals(other.latestCpuUsageStats); + && latestCpuUsageStats.equals(other.latestCpuUsageStats) + && mNormalizedAvailableCpuFreqKHz == other.mNormalizedAvailableCpuFreqKHz; } @Override public int hashCode() { return Objects.hash(cpuCore, cpusetCategories, isOnline, curCpuFreqKHz, maxCpuFreqKHz, - avgTimeInStateCpuFreqKHz, latestCpuUsageStats); + avgTimeInStateCpuFreqKHz, latestCpuUsageStats, mNormalizedAvailableCpuFreqKHz); + } + + private long computeNormalizedAvailableCpuFreqKHz() { + if (!isOnline) { + return MISSING_FREQUENCY; + } + long totalTimeMillis = latestCpuUsageStats.getTotalTimeMillis(); + if (totalTimeMillis == 0) { + Slogf.wtf(TAG, "Total CPU time millis is 0. This shouldn't happen unless stats are" + + " polled too frequently"); + return MISSING_FREQUENCY; + } + double nonIdlePercent = 100.0 * (totalTimeMillis + - (double) latestCpuUsageStats.idleTimeMillis) / totalTimeMillis; + long curFreqKHz = avgTimeInStateCpuFreqKHz == MISSING_FREQUENCY + ? curCpuFreqKHz : avgTimeInStateCpuFreqKHz; + double availablePercent = 100.0 - (nonIdlePercent * curFreqKHz / maxCpuFreqKHz); + return (long) ((availablePercent * maxCpuFreqKHz) / 100.0); } } @@ -712,7 +845,7 @@ public final class CpuInfoReader { this.guestNiceTimeMillis = guestNiceTimeMillis; } - public long getTotalTime() { + public long getTotalTimeMillis() { return userTimeMillis + niceTimeMillis + systemTimeMillis + idleTimeMillis + iowaitTimeMillis + irqTimeMillis + softirqTimeMillis + stealTimeMillis + guestTimeMillis + guestNiceTimeMillis; @@ -796,8 +929,8 @@ public final class CpuInfoReader { @Override public String toString() { - return "FrequencyPair{cpuFreqKHz=" + cpuFreqKHz + ", scalingFreqKHz=" + scalingFreqKHz - + '}'; + return "FrequencyPair{cpuFreqKHz = " + cpuFreqKHz + ", scalingFreqKHz = " + + scalingFreqKHz + '}'; } } @@ -812,7 +945,7 @@ public final class CpuInfoReader { @Override public String toString() { - return "StaticPolicyInfo{maxCpuFreqPair=" + maxCpuFreqPair + ", relatedCpuCores=" + return "StaticPolicyInfo{maxCpuFreqPair = " + maxCpuFreqPair + ", relatedCpuCores = " + relatedCpuCores + '}'; } } @@ -831,9 +964,9 @@ public final class CpuInfoReader { @Override public String toString() { - return "DynamicPolicyInfo{curCpuFreqPair=" + curCpuFreqPair - + ", avgTimeInStateCpuFreqKHz=" + avgTimeInStateCpuFreqKHz - + ", affectedCpuCores=" + affectedCpuCores + '}'; + return "DynamicPolicyInfo{curCpuFreqPair = " + curCpuFreqPair + + ", avgTimeInStateCpuFreqKHz = " + avgTimeInStateCpuFreqKHz + + ", affectedCpuCores = " + affectedCpuCores + '}'; } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java index b21478753301..04f6f8b2e9f0 100644 --- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java @@ -92,6 +92,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000, /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095, + /* normalizedAvailableCpuFreqKHz= */ 2_402_267, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610, /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050, /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810, @@ -101,6 +102,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380, + /* normalizedAvailableCpuFreqKHz= */ 2_693_525, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, @@ -111,6 +113,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285, + /* normalizedAvailableCpuFreqKHz= */ 1_901_608, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280, /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020, /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960, @@ -121,6 +124,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285, + /* normalizedAvailableCpuFreqKHz= */ 1_907_125, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610, /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050, /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810, @@ -139,6 +143,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 419_354, + /* normalizedAvailableCpuFreqKHz= */ 2_425_919, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000, /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000, /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000, @@ -148,6 +153,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000, /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 429_032, + /* normalizedAvailableCpuFreqKHz= */ 2_403_009, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000, /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000, /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000, @@ -158,6 +164,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000, /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 403_225, + /* normalizedAvailableCpuFreqKHz= */ 1_688_209, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000, /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0, /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000, @@ -168,6 +175,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, /* isOnline= */ false, /* curCpuFreqKHz= */ MISSING_FREQUENCY, /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, + /* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000, /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000, /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000, @@ -189,6 +197,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000, /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, + /* normalizedAvailableCpuFreqKHz= */ 2_253_713, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610, /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050, /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810, @@ -198,6 +207,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, + /* normalizedAvailableCpuFreqKHz= */ 2_492_687, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, @@ -208,6 +218,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, + /* normalizedAvailableCpuFreqKHz= */ 1_788_079, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280, /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020, /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960, @@ -218,6 +229,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, + /* normalizedAvailableCpuFreqKHz= */ 1_799_962, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610, /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050, /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810, @@ -237,6 +249,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, + /* normalizedAvailableCpuFreqKHz= */ 2323347, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000, /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000, /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000, @@ -246,6 +259,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000, /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, + /* normalizedAvailableCpuFreqKHz= */ 209111, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000, /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000, /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000, @@ -256,6 +270,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000, /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, + /* normalizedAvailableCpuFreqKHz= */ 453514, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000, /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0, /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000, @@ -266,6 +281,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000, /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, + /* normalizedAvailableCpuFreqKHz= */ 37728, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000, /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000, /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000, @@ -323,38 +339,8 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos(); SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>(); - expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, - FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 3_000_000, - /* maxCpuFreqKHz= */ 1_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, - 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))); - expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, - FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, - /* isOnline= */ true, /* curCpuFreqKHz= */ 9, /* maxCpuFreqKHz= */ 2, - /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, - 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))); - expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3, - FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, - /* isOnline= */ true, /* curCpuFreqKHz= */ 9, /* maxCpuFreqKHz= */ 2, - /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, - 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))); - compareCpuInfos("CPU infos with corrupted CPU frequency", expectedCpuInfos, - actualCpuInfos); + compareCpuInfos("CPU infos with corrupted CPU frequency", expectedCpuInfos, actualCpuInfos); } @Test @@ -368,6 +354,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000, /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095, + /* normalizedAvailableCpuFreqKHz= */ 2_402_267, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610, /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050, /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810, @@ -377,6 +364,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380, + /* normalizedAvailableCpuFreqKHz= */ 2_693_525, new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, @@ -393,7 +381,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue(); CpuInfoReader cpuInfoReader = new CpuInfoReader(emptyDir, getCacheFile( VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), - getCacheFile(VALID_PROC_STAT)); + getCacheFile(VALID_PROC_STAT), /* minReadIntervalMillis= */0); assertWithMessage("Init CPU reader info").that(cpuInfoReader.init()).isFalse(); @@ -406,7 +394,7 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { File emptyDir = getCacheFile(EMPTY_DIR); assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue(); CpuInfoReader cpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR), emptyDir, - getCacheFile(VALID_PROC_STAT)); + getCacheFile(VALID_PROC_STAT), /* minReadIntervalMillis= */0); assertWithMessage("Init CPU reader info").that(cpuInfoReader.init()).isFalse(); @@ -420,12 +408,32 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { assertWithMessage("Create empty file %s", emptyFile).that(emptyFile.createNewFile()) .isTrue(); CpuInfoReader cpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR), - getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(EMPTY_FILE)); + getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(EMPTY_FILE), + /* minReadIntervalMillis= */0); assertWithMessage("Cpu infos with empty proc stat").that(cpuInfoReader.readCpuInfos()) .isNull(); } + @Test + public void testReadingTooFrequentlyReturnsLastReadCpuInfos() throws Exception { + CpuInfoReader cpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR), + getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT), + /* minReadIntervalMillis= */ 60_000); + assertWithMessage("Initialize CPU info reader").that(cpuInfoReader.init()).isTrue(); + + SparseArray<CpuInfoReader.CpuInfo> firstCpuInfos = cpuInfoReader.readCpuInfos(); + assertWithMessage("CPU infos first snapshot").that(firstCpuInfos).isNotNull(); + assertWithMessage("CPU infos first snapshot size").that(firstCpuInfos.size()) + .isGreaterThan(0); + + SparseArray<CpuInfoReader.CpuInfo> secondCpuInfos = cpuInfoReader.readCpuInfos(); + compareCpuInfos("CPU infos second snapshot", firstCpuInfos, secondCpuInfos); + + SparseArray<CpuInfoReader.CpuInfo> thirdCpuInfos = cpuInfoReader.readCpuInfos(); + compareCpuInfos("CPU infos third snapshot", firstCpuInfos, thirdCpuInfos); + } + private void compareCpuInfos(String message, SparseArray<CpuInfoReader.CpuInfo> expected, SparseArray<CpuInfoReader.CpuInfo> actual) { @@ -462,7 +470,8 @@ public final class CpuInfoReaderTest extends ExpectableTestCase { private static CpuInfoReader newCpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile) { - CpuInfoReader cpuInfoReader = new CpuInfoReader(cpusetDir, cpuFreqDir, procStatFile); + CpuInfoReader cpuInfoReader = new CpuInfoReader(cpusetDir, cpuFreqDir, procStatFile, + /* minReadIntervalMillis= */ 0); assertWithMessage("Initialize CPU info reader").that(cpuInfoReader.init()).isTrue(); return cpuInfoReader; } |