diff options
| author | 2012-03-06 11:27:10 -0800 | |
|---|---|---|
| committer | 2012-03-14 16:03:01 -0700 | |
| commit | f57e2bceb9f09b0a06ebfe89cd5fd46efcfd6fc8 (patch) | |
| tree | 14f817b15ff2ee61648f15c54a7d8f6db465ae37 /libs/cpustats/ThreadCpuUsage.cpp | |
| parent | a2d68c93941d71194995efdfedc440110d7c5532 (diff) | |
AudioFlinger playback thread CPU measurement in Hz
Log statistics on CPU usage in Hz in addition to wall clock time
Use CPU statistics for all playback threads, not just MIXER
(but they are disabled by default by a compile-time debug macro).
ThreadCpuUsage library:
- Move statistics out of the library and leave that up to the caller
- Add API to determine a CPU's frequency
Change-Id: Ia1011123146e641fcf210ef26e78ae2b4d3b64ad
Diffstat (limited to 'libs/cpustats/ThreadCpuUsage.cpp')
| -rw-r--r-- | libs/cpustats/ThreadCpuUsage.cpp | 127 |
1 files changed, 120 insertions, 7 deletions
diff --git a/libs/cpustats/ThreadCpuUsage.cpp b/libs/cpustats/ThreadCpuUsage.cpp index ffee039e1ee1..99b4c836394c 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 |