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
This commit is contained in:
Lakshman Annadorai
2023-02-01 13:00:05 -08:00
committed by Cherrypicker Worker
parent ceab3a6e8a
commit 17a7c61a43

View File

@@ -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
@@ -272,6 +276,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++) {
@@ -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);
}
}
}