summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lakshman Annadorai <lakshmana@google.com> 2023-02-01 13:00:05 -0800
committer Cherrypicker Worker <android-build-cherrypicker-worker@google.com> 2023-03-16 23:35:36 +0000
commit17a7c61a4353901e07523efa46c327f5e3d00e4e (patch)
tree49f8b0e5bd9e09f10ae89e7b67709b33d141aaf9
parentceab3a6e8aa8e9d0fb622692bcb35b8b67b1c20f (diff)
Verify CPU availability against client thresholds and notify the clients.
Test: atest CpuMonitorServiceTest Bug: 242722241 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:741709bf4a7d6087b34efd4bda82df5dba717f13) Merged-In: I6c189b6880bf9fb5cd73e7cd31419d915bbaff61 Change-Id: I6c189b6880bf9fb5cd73e7cd31419d915bbaff61
-rw-r--r--services/core/java/com/android/server/cpu/CpuMonitorService.java97
1 files changed, 92 insertions, 5 deletions
diff --git a/services/core/java/com/android/server/cpu/CpuMonitorService.java b/services/core/java/com/android/server/cpu/CpuMonitorService.java
index fac8a2f7b168..7e930b4a1ef5 100644
--- a/services/core/java/com/android/server/cpu/CpuMonitorService.java
+++ b/services/core/java/com/android/server/cpu/CpuMonitorService.java
@@ -32,6 +32,7 @@ import android.os.HandlerThread;
import android.os.Process;
import android.os.SystemClock;
import android.util.IndentingPrintWriter;
+import android.util.IntArray;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
@@ -51,6 +52,7 @@ import java.io.PrintWriter;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
/** Service to monitor CPU availability and usage. */
public final class CpuMonitorService extends SystemService {
@@ -92,6 +94,8 @@ public final class CpuMonitorService extends SystemService {
@GuardedBy("mLock")
private final SparseArray<CpusetInfo> mCpusetInfosByCpuset;
private final Runnable mMonitorCpuStats = this::monitorCpuStats;
+ private final NotifyCpuAvailabilityFunctor mNotifyCpuAvailabilityFunctor =
+ new NotifyCpuAvailabilityFunctor();
@GuardedBy("mLock")
private long mCurrentMonitoringIntervalMillis = DEFAULT_MONITORING_INTERVAL_MILLISECONDS;
@@ -115,7 +119,7 @@ public final class CpuMonitorService extends SystemService {
}
}
CpuAvailabilityCallbackInfo callbackInfo = new CpuAvailabilityCallbackInfo(config,
- executor);
+ callback, executor);
mAvailabilityCallbackInfosByCallbacksByCpuset.add(config.cpuset, callback,
callbackInfo);
if (DEBUG) {
@@ -254,7 +258,7 @@ public final class CpuMonitorService extends SystemService {
CpusetInfo cpusetInfo = mCpusetInfosByCpuset.valueAt(i);
cpusetInfo.populateLatestCpuAvailabilityInfo(uptimeMillis,
mLatestAvailabilityDurationMillis);
- // TODO(b/242722241): Check CPU availability against thresholds and notify clients.
+ checkClientThresholdsAndNotifyLocked(cpusetInfo);
}
// TODO(b/267500110): Detect heavy CPU load. On detecting heavy CPU load, increase
@@ -273,6 +277,41 @@ public final class CpuMonitorService extends SystemService {
}
@GuardedBy("mLock")
+ private void checkClientThresholdsAndNotifyLocked(CpusetInfo cpusetInfo) {
+ int prevAvailabilityPercent = cpusetInfo.getPrevCpuAvailabilityPercent();
+ CpuAvailabilityInfo latestAvailabilityInfo = cpusetInfo.getLatestCpuAvailabilityInfo();
+ ArrayMap<CpuMonitorInternal.CpuAvailabilityCallback,
+ CpuAvailabilityCallbackInfo> callbackMap =
+ mAvailabilityCallbackInfosByCallbacksByCpuset.get(cpusetInfo.cpuset);
+ if (latestAvailabilityInfo == null || prevAvailabilityPercent < 0
+ || callbackMap.isEmpty()) {
+ // When either the current or the previous CPU availability percents are
+ // missing, skip the current cpuset as there is not enough data to verify
+ // whether the CPU availability has crossed any monitoring threshold.
+ return;
+ }
+ for (int i = 0; i < callbackMap.size(); i++) {
+ CpuAvailabilityCallbackInfo callbackInfo = callbackMap.valueAt(i);
+ if (didCrossAnyThreshold(prevAvailabilityPercent,
+ latestAvailabilityInfo.latestAvgAvailabilityPercent,
+ callbackInfo.config.getThresholds())) {
+ asyncNotifyCpuAvailabilityToClient(latestAvailabilityInfo, callbackInfo);
+ }
+ }
+ }
+
+ private void asyncNotifyCpuAvailabilityToClient(CpuAvailabilityInfo availabilityInfo,
+ CpuAvailabilityCallbackInfo callbackInfo) {
+ if (callbackInfo.executor == null) {
+ mHandler.post(() -> mNotifyCpuAvailabilityFunctor.accept(callbackInfo.callback,
+ availabilityInfo));
+ } else {
+ callbackInfo.executor.execute(() -> mNotifyCpuAvailabilityFunctor.accept(
+ callbackInfo.callback, availabilityInfo));
+ }
+ }
+
+ @GuardedBy("mLock")
private boolean hasClientCallbacksLocked() {
for (int i = 0; i < mAvailabilityCallbackInfosByCallbacksByCpuset.numMaps(); i++) {
if (mAvailabilityCallbackInfosByCallbacksByCpuset.numElementsForKeyAt(i) > 0) {
@@ -306,21 +345,47 @@ public final class CpuMonitorService extends SystemService {
return false;
}
+ private static boolean didCrossAnyThreshold(int prevAvailabilityPercent,
+ int curAvailabilityPercent, IntArray thresholds) {
+ if (prevAvailabilityPercent == curAvailabilityPercent) {
+ return false;
+ }
+ for (int i = 0; i < thresholds.size(); i++) {
+ int threshold = thresholds.get(i);
+ // TODO(b/267500110): Identify whether or not the clients need to be notified when
+ // the CPU availability jumps too frequently around the provided thresholds.
+ // A. Should the client be notified twice - once when the availability reaches
+ // the threshold and once when it moves away (increase/decrease) from the threshold
+ // immediately?
+ // B. Should there be some sort of rate-limiting to avoid notifying the client too
+ // frequently? Should the client be able to config the rate-limit?
+ if (prevAvailabilityPercent < threshold && curAvailabilityPercent >= threshold) {
+ return true;
+ }
+ if (prevAvailabilityPercent >= threshold && curAvailabilityPercent < threshold) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static final class CpuAvailabilityCallbackInfo {
public final CpuAvailabilityMonitoringConfig config;
+ public final CpuMonitorInternal.CpuAvailabilityCallback callback;
@Nullable
public final Executor executor;
CpuAvailabilityCallbackInfo(CpuAvailabilityMonitoringConfig config,
- @Nullable Executor executor) {
+ CpuMonitorInternal.CpuAvailabilityCallback callback, @Nullable Executor executor) {
this.config = config;
+ this.callback = callback;
this.executor = executor;
}
@Override
public String toString() {
- return "CpuAvailabilityCallbackInfo{" + "config=" + config + ", mExecutor=" + executor
- + '}';
+ return "CpuAvailabilityCallbackInfo{config = " + config + ", callback = " + callback
+ + ", mExecutor = " + executor + '}';
}
}
@@ -375,6 +440,11 @@ public final class CpuMonitorService extends SystemService {
currentSnapshot.appendCpuInfo(cpuInfo);
}
+ @Nullable
+ public CpuAvailabilityInfo getLatestCpuAvailabilityInfo() {
+ return mLatestCpuAvailabilityInfo;
+ }
+
public void populateLatestCpuAvailabilityInfo(long currentUptimeMillis,
long latestAvailabilityDurationMillis) {
int numSnapshots = mSnapshotsByUptime.size();
@@ -407,6 +477,14 @@ public final class CpuMonitorService extends SystemService {
latestAvailabilityDurationMillis);
}
+ public int getPrevCpuAvailabilityPercent() {
+ int numSnapshots = mSnapshotsByUptime.size();
+ if (numSnapshots < 2) {
+ return -1;
+ }
+ return mSnapshotsByUptime.valueAt(numSnapshots - 2).getAverageAvailableCpuFreqPercent();
+ }
+
private int getCumulativeAvgAvailabilityPercent(long earliestUptimeMillis) {
long totalAvailableCpuFreqKHz = 0;
long totalOnlineMaxCpuFreqKHz = 0;
@@ -485,4 +563,13 @@ public final class CpuMonitorService extends SystemService {
}
}
}
+
+ private static final class NotifyCpuAvailabilityFunctor implements
+ BiConsumer<CpuMonitorInternal.CpuAvailabilityCallback, CpuAvailabilityInfo> {
+ @Override
+ public void accept(CpuMonitorInternal.CpuAvailabilityCallback callback,
+ CpuAvailabilityInfo availabilityInfo) {
+ callback.onAvailabilityChanged(availabilityInfo);
+ }
+ }
}