ThreadCpuUsage.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * Copyright (C) 2011 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #define LOG_TAG "ThreadCpuUsage"
  17. //#define LOG_NDEBUG 0
  18. #include <errno.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <time.h>
  22. #include <utils/Log.h>
  23. #include <cpustats/ThreadCpuUsage.h>
  24. // implemented by host, but not declared in <string.h> as FreeBSD does
  25. extern "C" {
  26. extern size_t strlcpy(char *dst, const char *src, size_t dstsize);
  27. }
  28. namespace android {
  29. bool ThreadCpuUsage::setEnabled(bool isEnabled)
  30. {
  31. bool wasEnabled = mIsEnabled;
  32. // only do something if there is a change
  33. if (isEnabled != wasEnabled) {
  34. ALOGV("setEnabled(%d)", isEnabled);
  35. int rc;
  36. // enabling
  37. if (isEnabled) {
  38. rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mPreviousTs);
  39. if (rc) {
  40. ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
  41. isEnabled = false;
  42. } else {
  43. mWasEverEnabled = true;
  44. // record wall clock time at first enable
  45. if (!mMonotonicKnown) {
  46. rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
  47. if (rc) {
  48. ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
  49. } else {
  50. mMonotonicKnown = true;
  51. }
  52. }
  53. }
  54. // disabling
  55. } else {
  56. struct timespec ts;
  57. rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
  58. if (rc) {
  59. ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
  60. } else {
  61. long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
  62. (ts.tv_nsec - mPreviousTs.tv_nsec);
  63. mAccumulator += delta;
  64. #if 0
  65. mPreviousTs = ts;
  66. #endif
  67. }
  68. }
  69. mIsEnabled = isEnabled;
  70. }
  71. return wasEnabled;
  72. }
  73. bool ThreadCpuUsage::sampleAndEnable(double& ns)
  74. {
  75. bool wasEverEnabled = mWasEverEnabled;
  76. if (enable()) {
  77. // already enabled, so add a new sample relative to previous
  78. return sample(ns);
  79. } else if (wasEverEnabled) {
  80. // was disabled, but add sample for accumulated time while enabled
  81. ns = (double) mAccumulator;
  82. mAccumulator = 0;
  83. ALOGV("sampleAndEnable %.0f", ns);
  84. return true;
  85. } else {
  86. // first time called
  87. ns = 0.0;
  88. ALOGV("sampleAndEnable false");
  89. return false;
  90. }
  91. }
  92. bool ThreadCpuUsage::sample(double &ns)
  93. {
  94. if (mWasEverEnabled) {
  95. if (mIsEnabled) {
  96. struct timespec ts;
  97. int rc;
  98. rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
  99. if (rc) {
  100. ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
  101. ns = 0.0;
  102. return false;
  103. } else {
  104. long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
  105. (ts.tv_nsec - mPreviousTs.tv_nsec);
  106. mAccumulator += delta;
  107. mPreviousTs = ts;
  108. }
  109. } else {
  110. mWasEverEnabled = false;
  111. }
  112. ns = (double) mAccumulator;
  113. ALOGV("sample %.0f", ns);
  114. mAccumulator = 0;
  115. return true;
  116. } else {
  117. ALOGW("Can't add sample because measurements have never been enabled");
  118. ns = 0.0;
  119. return false;
  120. }
  121. }
  122. long long ThreadCpuUsage::elapsed() const
  123. {
  124. long long elapsed;
  125. if (mMonotonicKnown) {
  126. struct timespec ts;
  127. int rc;
  128. rc = clock_gettime(CLOCK_MONOTONIC, &ts);
  129. if (rc) {
  130. ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
  131. elapsed = 0;
  132. } else {
  133. // mMonotonicTs is updated only at first enable and resetStatistics
  134. elapsed = (ts.tv_sec - mMonotonicTs.tv_sec) * 1000000000LL +
  135. (ts.tv_nsec - mMonotonicTs.tv_nsec);
  136. }
  137. } else {
  138. ALOGW("Can't compute elapsed time because measurements have never been enabled");
  139. elapsed = 0;
  140. }
  141. ALOGV("elapsed %lld", elapsed);
  142. return elapsed;
  143. }
  144. void ThreadCpuUsage::resetElapsed()
  145. {
  146. ALOGV("resetElapsed");
  147. if (mMonotonicKnown) {
  148. int rc;
  149. rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
  150. if (rc) {
  151. ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
  152. mMonotonicKnown = false;
  153. }
  154. }
  155. }
  156. /*static*/
  157. int ThreadCpuUsage::sScalingFds[ThreadCpuUsage::MAX_CPU];
  158. pthread_once_t ThreadCpuUsage::sOnceControl = PTHREAD_ONCE_INIT;
  159. int ThreadCpuUsage::sKernelMax;
  160. pthread_mutex_t ThreadCpuUsage::sMutex = PTHREAD_MUTEX_INITIALIZER;
  161. /*static*/
  162. void ThreadCpuUsage::init()
  163. {
  164. // read the number of CPUs
  165. sKernelMax = 1;
  166. int fd = open("/sys/devices/system/cpu/kernel_max", O_RDONLY);
  167. if (fd >= 0) {
  168. #define KERNEL_MAX_SIZE 12
  169. char kernelMax[KERNEL_MAX_SIZE];
  170. ssize_t actual = read(fd, kernelMax, sizeof(kernelMax));
  171. if (actual >= 2 && kernelMax[actual-1] == '\n') {
  172. sKernelMax = atoi(kernelMax);
  173. if (sKernelMax >= MAX_CPU - 1) {
  174. ALOGW("kernel_max %d but MAX_CPU %d", sKernelMax, MAX_CPU);
  175. sKernelMax = MAX_CPU;
  176. } else if (sKernelMax < 0) {
  177. ALOGW("kernel_max invalid %d", sKernelMax);
  178. sKernelMax = 1;
  179. } else {
  180. ++sKernelMax;
  181. ALOGV("number of CPUs %d", sKernelMax);
  182. }
  183. } else {
  184. ALOGW("Can't read number of CPUs");
  185. }
  186. (void) close(fd);
  187. } else {
  188. ALOGW("Can't open number of CPUs");
  189. }
  190. int i;
  191. for (i = 0; i < MAX_CPU; ++i) {
  192. sScalingFds[i] = -1;
  193. }
  194. }
  195. uint32_t ThreadCpuUsage::getCpukHz(int cpuNum)
  196. {
  197. if (cpuNum < 0 || cpuNum >= MAX_CPU) {
  198. ALOGW("getCpukHz called with invalid CPU %d", cpuNum);
  199. return 0;
  200. }
  201. // double-checked locking idiom is not broken for atomic values such as fd
  202. int fd = sScalingFds[cpuNum];
  203. if (fd < 0) {
  204. // some kernels can't open a scaling file until hot plug complete
  205. pthread_mutex_lock(&sMutex);
  206. fd = sScalingFds[cpuNum];
  207. if (fd < 0) {
  208. #define FREQ_SIZE 64
  209. char freq_path[FREQ_SIZE];
  210. #define FREQ_DIGIT 27
  211. static_assert(MAX_CPU <= 10, "MAX_CPU too large");
  212. #define FREQ_PATH "/sys/devices/system/cpu/cpu?/cpufreq/scaling_cur_freq"
  213. strlcpy(freq_path, FREQ_PATH, sizeof(freq_path));
  214. freq_path[FREQ_DIGIT] = cpuNum + '0';
  215. fd = open(freq_path, O_RDONLY | O_CLOEXEC);
  216. // keep this fd until process exit or exec
  217. sScalingFds[cpuNum] = fd;
  218. }
  219. pthread_mutex_unlock(&sMutex);
  220. if (fd < 0) {
  221. ALOGW("getCpukHz can't open CPU %d", cpuNum);
  222. return 0;
  223. }
  224. }
  225. #define KHZ_SIZE 12
  226. char kHz[KHZ_SIZE]; // kHz base 10
  227. ssize_t actual = pread(fd, kHz, sizeof(kHz), (off_t) 0);
  228. uint32_t ret;
  229. if (actual >= 2 && kHz[actual-1] == '\n') {
  230. ret = atoi(kHz);
  231. } else {
  232. ret = 0;
  233. }
  234. if (ret != mCurrentkHz[cpuNum]) {
  235. if (ret > 0) {
  236. ALOGV("CPU %d frequency %u kHz", cpuNum, ret);
  237. } else {
  238. ALOGW("Can't read CPU %d frequency", cpuNum);
  239. }
  240. mCurrentkHz[cpuNum] = ret;
  241. }
  242. return ret;
  243. }
  244. } // namespace android