summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2012-03-14 16:28:38 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-03-14 16:28:38 -0700
commit81fe4fbd6ba87a0be556c57c14de0b23cf51f179 (patch)
treef1d31ac922a50504102dedb848a1791c4788f543 /libs
parent1f1bc8b12a85026788495567f83ffd1baf2630d8 (diff)
parentf57e2bceb9f09b0a06ebfe89cd5fd46efcfd6fc8 (diff)
downloadframeworks_base-81fe4fbd6ba87a0be556c57c14de0b23cf51f179.zip
frameworks_base-81fe4fbd6ba87a0be556c57c14de0b23cf51f179.tar.gz
frameworks_base-81fe4fbd6ba87a0be556c57c14de0b23cf51f179.tar.bz2
Merge "AudioFlinger playback thread CPU measurement in Hz"
Diffstat (limited to 'libs')
-rw-r--r--libs/cpustats/ThreadCpuUsage.cpp127
1 files changed, 120 insertions, 7 deletions
diff --git a/libs/cpustats/ThreadCpuUsage.cpp b/libs/cpustats/ThreadCpuUsage.cpp
index ffee039..99b4c83 100644
--- a/libs/cpustats/ThreadCpuUsage.cpp
+++ b/libs/cpustats/ThreadCpuUsage.cpp
@@ -14,18 +14,26 @@
* limitations under the License.
*/
+#define LOG_TAG "ThreadCpuUsage"
+//#define LOG_NDEBUG 0
+
#include <errno.h>
+#include <stdlib.h>
#include <time.h>
+#include <utils/Debug.h>
#include <utils/Log.h>
#include <cpustats/ThreadCpuUsage.h>
+namespace android {
+
bool ThreadCpuUsage::setEnabled(bool isEnabled)
{
bool wasEnabled = mIsEnabled;
// only do something if there is a change
if (isEnabled != wasEnabled) {
+ ALOGV("setEnabled(%d)", isEnabled);
int rc;
// enabling
if (isEnabled) {
@@ -65,20 +73,28 @@ bool ThreadCpuUsage::setEnabled(bool isEnabled)
return wasEnabled;
}
-void ThreadCpuUsage::sampleAndEnable()
+bool ThreadCpuUsage::sampleAndEnable(double& ns)
{
+ bool ret;
bool wasEverEnabled = mWasEverEnabled;
if (enable()) {
// already enabled, so add a new sample relative to previous
- sample();
+ return sample(ns);
} else if (wasEverEnabled) {
// was disabled, but add sample for accumulated time while enabled
- mStatistics.sample((double) mAccumulator);
+ ns = (double) mAccumulator;
mAccumulator = 0;
+ ALOGV("sampleAndEnable %.0f", ns);
+ return true;
+ } else {
+ // first time called
+ ns = 0.0;
+ ALOGV("sampleAndEnable false");
+ return false;
}
}
-void ThreadCpuUsage::sample()
+bool ThreadCpuUsage::sample(double &ns)
{
if (mWasEverEnabled) {
if (mIsEnabled) {
@@ -87,6 +103,8 @@ void ThreadCpuUsage::sample()
rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
if (rc) {
ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+ ns = 0.0;
+ return false;
} else {
long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
(ts.tv_nsec - mPreviousTs.tv_nsec);
@@ -96,10 +114,14 @@ void ThreadCpuUsage::sample()
} else {
mWasEverEnabled = false;
}
- mStatistics.sample((double) mAccumulator);
+ ns = (double) mAccumulator;
+ ALOGV("sample %.0f", ns);
mAccumulator = 0;
+ return true;
} else {
ALOGW("Can't add sample because measurements have never been enabled");
+ ns = 0.0;
+ return false;
}
}
@@ -122,12 +144,13 @@ long long ThreadCpuUsage::elapsed() const
ALOGW("Can't compute elapsed time because measurements have never been enabled");
elapsed = 0;
}
+ ALOGV("elapsed %lld", elapsed);
return elapsed;
}
-void ThreadCpuUsage::resetStatistics()
+void ThreadCpuUsage::resetElapsed()
{
- mStatistics.reset();
+ ALOGV("resetElapsed");
if (mMonotonicKnown) {
int rc;
rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
@@ -137,3 +160,93 @@ void ThreadCpuUsage::resetStatistics()
}
}
}
+
+/*static*/
+int ThreadCpuUsage::sScalingFds[ThreadCpuUsage::MAX_CPU];
+pthread_once_t ThreadCpuUsage::sOnceControl = PTHREAD_ONCE_INIT;
+int ThreadCpuUsage::sKernelMax;
+
+/*static*/
+void ThreadCpuUsage::init()
+{
+ // read the number of CPUs
+ sKernelMax = 1;
+ int fd = open("/sys/devices/system/cpu/kernel_max", O_RDONLY);
+ if (fd >= 0) {
+#define KERNEL_MAX_SIZE 12
+ char kernelMax[KERNEL_MAX_SIZE];
+ ssize_t actual = read(fd, kernelMax, sizeof(kernelMax));
+ if (actual >= 2 && kernelMax[actual-1] == '\n') {
+ sKernelMax = atoi(kernelMax);
+ if (sKernelMax >= MAX_CPU - 1) {
+ ALOGW("kernel_max %d but MAX_CPU %d", sKernelMax, MAX_CPU);
+ sKernelMax = MAX_CPU;
+ } else if (sKernelMax < 0) {
+ ALOGW("kernel_max invalid %d", sKernelMax);
+ sKernelMax = 1;
+ } else {
+ ++sKernelMax;
+ ALOGV("number of CPUs %d", sKernelMax);
+ }
+ } else {
+ ALOGW("Can't read number of CPUs");
+ }
+ (void) close(fd);
+ } else {
+ ALOGW("Can't open number of CPUs");
+ }
+
+ // open fd to each frequency per CPU
+#define FREQ_SIZE 64
+ char freq_path[FREQ_SIZE];
+#define FREQ_DIGIT 27
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(MAX_CPU <= 10);
+ strlcpy(freq_path, "/sys/devices/system/cpu/cpu?/cpufreq/scaling_cur_freq", sizeof(freq_path));
+ int i;
+ for (i = 0; i < MAX_CPU; ++i) {
+ sScalingFds[i] = -1;
+ }
+ for (i = 0; i < sKernelMax; ++i) {
+ freq_path[FREQ_DIGIT] = i + '0';
+ fd = open(freq_path, O_RDONLY);
+ if (fd >= 0) {
+ // keep this fd until process exit
+ sScalingFds[i] = fd;
+ } else {
+ ALOGW("Can't open CPU %d", i);
+ }
+ }
+}
+
+uint32_t ThreadCpuUsage::getCpukHz(int cpuNum)
+{
+ if (cpuNum < 0 || cpuNum >= MAX_CPU) {
+ ALOGW("getCpukHz called with invalid CPU %d", cpuNum);
+ return 0;
+ }
+ int fd = sScalingFds[cpuNum];
+ if (fd < 0) {
+ ALOGW("getCpukHz called for unopened CPU %d", cpuNum);
+ return 0;
+ }
+#define KHZ_SIZE 12
+ char kHz[KHZ_SIZE]; // kHz base 10
+ ssize_t actual = pread(fd, kHz, sizeof(kHz), (off_t) 0);
+ uint32_t ret;
+ if (actual >= 2 && kHz[actual-1] == '\n') {
+ ret = atoi(kHz);
+ } else {
+ ret = 0;
+ }
+ if (ret != mCurrentkHz[cpuNum]) {
+ if (ret > 0) {
+ ALOGV("CPU %d frequency %u kHz", cpuNum, ret);
+ } else {
+ ALOGW("Can't read CPU %d frequency", cpuNum);
+ }
+ mCurrentkHz[cpuNum] = ret;
+ }
+ return ret;
+}
+
+} // namespace android