aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tradefed/targetprep
diff options
context:
space:
mode:
authorGuang Zhu <guangzhu@google.com>2015-06-28 19:15:22 -0700
committerGuang Zhu <guangzhu@google.com>2015-06-30 10:52:28 -0700
commitd6af5695dcaf2508a6df84029348f876d5169435 (patch)
treedef55631aa985de9bd6f2ab149d60c1478413c06 /src/com/android/tradefed/targetprep
parentfa45981f10d805eb551bd3cbd430473d9d8a3a29 (diff)
downloadtradefederation-d6af5695dcaf2508a6df84029348f876d5169435.tar.gz
Add preparer to poll core status until no long throttled
This preparer will poll device until max frequency on each core has reached the highest ladder as defined in available scaling frequencies. Bug: 21907055 Change-Id: I4a6b36249f88ab000bad01340436e3f38636a989
Diffstat (limited to 'src/com/android/tradefed/targetprep')
-rw-r--r--src/com/android/tradefed/targetprep/CpuThrottlingWaiter.java142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/com/android/tradefed/targetprep/CpuThrottlingWaiter.java b/src/com/android/tradefed/targetprep/CpuThrottlingWaiter.java
new file mode 100644
index 000000000..06ba6c3cd
--- /dev/null
+++ b/src/com/android/tradefed/targetprep/CpuThrottlingWaiter.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 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.tradefed.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.util.RunUtil;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * An {@link ITargetPreparer} that waits until max frequency on all cores are restored to highest
+ * level available
+ *
+ */
+@OptionClass(alias = "cpu-throttle-waiter")
+public class CpuThrottlingWaiter implements ITargetPreparer {
+
+ @Option(name = "poll-interval",
+ description = "Interval in seconds, to poll for core frequencies; defaults to 5s")
+ private long mPollIntervalSecs = 5;
+
+ @Option(name = "max-wait", description = "Max wait time in seconds, for all cores to be"
+ + " free of throttling; defaults to 240s")
+ private long mMaxWaitSecs = 240;
+
+ @Option(name = "post-idle-wait", description = "Additional time to wait in seconds, after cores"
+ + " are no longer subject to throttling; defaults to 120s")
+ private long mPostIdleWaitSecs = 120;
+
+ @Option(name = "abort-on-timeout", description = "If test should be aborted if cores are still"
+ + " subject to throttling after timeout has reached; defaults to false")
+ private boolean mAbortOnTimeout = false;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+ BuildError, DeviceNotAvailableException {
+ // first figure out number of CPU cores available and their corresponding max frequencies
+ // map: path/to/core : max frequency
+ Map<String, String> cpuMaxFreqs = getCpuMaxFreqs(device);
+ if (cpuMaxFreqs.isEmpty()) {
+ CLog.i("Unable to determine cores available, falling back to max wait time");
+ RunUtil.getDefault().sleep(mMaxWaitSecs * 1000);
+ return;
+ }
+ // poll CPU frequencies
+ long start = System.currentTimeMillis();
+ long maxWaitMs = mMaxWaitSecs * 1000;
+ long intervalMs = mPollIntervalSecs * 1000;
+ while (true) {
+ boolean ready = true;
+ for (Entry<String, String> e : cpuMaxFreqs.entrySet()) {
+ // check current frequency of each CPU
+ String freq = device.executeShellCommand(
+ String.format("cat %s/cpuinfo_max_freq", e.getKey())).trim();
+ if (!e.getValue().equals(freq)) {
+ // not ready
+ CLog.d("CPU %s not ready: %s/%s", e.getKey(), freq, e.getValue());
+ ready = false;
+ break; // for loop
+ }
+ }
+ if (ready) {
+ break; // while loop
+ }
+ if ((System.currentTimeMillis() - start) > maxWaitMs) {
+ CLog.w("cores still throttled after %ds", maxWaitMs);
+ String result = device.executeShellCommand(
+ "cat /sys/devices/system/cpu/*/cpufreq/cpuinfo_max_freq");
+ CLog.w("Current CPU frequencies:\n%s", result);
+ if (mAbortOnTimeout) {
+ throw new TargetSetupError("cores are still throttled after wait timeout");
+ }
+ break; // while loop
+ }
+ RunUtil.getDefault().sleep(intervalMs);
+ }
+ // extra idle time so that in case of thermal related throttling, allow heat to dissipate
+ RunUtil.getDefault().sleep(mPostIdleWaitSecs * 1000);
+ CLog.i("Done waiting, total time elapsed: %ds",
+ (System.currentTimeMillis() - start) / 1000);
+ }
+
+ /**
+ * Reads info under /sys/devices/system/cpu to determine cores available, and max frequencies
+ * possible for each core
+ * @param device device under test
+ * @return a {@link Map} with paths to sysfs cpuinfo as key, and corresponding max frequency as
+ * value
+ * @throws DeviceNotAvailableException
+ */
+ protected Map<String, String> getCpuMaxFreqs(ITestDevice device)
+ throws DeviceNotAvailableException {
+ Map<String, String> ret = new HashMap<>();
+ String result = device.executeShellCommand("ls -d /sys/devices/system/cpu/cpu*/cpufreq");
+ String[] lines = result.split("\r?\n");
+ List<String> cpuPaths = new ArrayList<>();
+ for (String line : lines) {
+ cpuPaths.add(line.trim());
+ }
+ for (String cpu : cpuPaths) {
+ result = device.executeShellCommand(
+ String.format("cat %s/scaling_available_frequencies", cpu)).trim();
+ // return should be something like:
+ // 300000 422400 652800 729600 883200 960000 1036800 1190400 1267200 1497600 1574400
+ String[] freqs = result.split("\\s+");
+ String maxFreq = freqs[freqs.length - 1]; // highest available frequency is last
+ // check if the string is a number
+ if (!maxFreq.matches("^\\d+$")) {
+ CLog.w("Unable to determine max frequency available for CPU: %s", cpu);
+ } else {
+ CLog.d("CPU: %s MaxFreq: %s", cpu, maxFreq);
+ ret.put(cpu, maxFreq);
+ }
+ }
+ return ret;
+ }
+}