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 17 #include <errno.h> 18 #include <time.h> 19 20 #include <utils/Log.h> 21 22 #include <cpustats/ThreadCpuUsage.h> 23 24 bool ThreadCpuUsage::setEnabled(bool isEnabled) 25 { 26 bool wasEnabled = mIsEnabled; 27 // only do something if there is a change 28 if (isEnabled != wasEnabled) { 29 int rc; 30 // enabling 31 if (isEnabled) { 32 rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mPreviousTs); 33 if (rc) { 34 LOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno); 35 isEnabled = false; 36 } else { 37 mWasEverEnabled = true; 38 // record wall clock time at first enable 39 if (!mMonotonicKnown) { 40 rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs); 41 if (rc) { 42 LOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno); 43 } else { 44 mMonotonicKnown = true; 45 } 46 } 47 } 48 // disabling 49 } else { 50 struct timespec ts; 51 rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); 52 if (rc) { 53 LOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno); 54 } else { 55 long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL + 56 (ts.tv_nsec - mPreviousTs.tv_nsec); 57 mAccumulator += delta; 58 #if 0 59 mPreviousTs = ts; 60 #endif 61 } 62 } 63 mIsEnabled = isEnabled; 64 } 65 return wasEnabled; 66 } 67 68 void ThreadCpuUsage::sampleAndEnable() 69 { 70 bool wasEverEnabled = mWasEverEnabled; 71 if (enable()) { 72 // already enabled, so add a new sample relative to previous 73 sample(); 74 } else if (wasEverEnabled) { 75 // was disabled, but add sample for accumulated time while enabled 76 mStatistics.sample((double) mAccumulator); 77 mAccumulator = 0; 78 } 79 } 80 81 void ThreadCpuUsage::sample() 82 { 83 if (mWasEverEnabled) { 84 if (mIsEnabled) { 85 struct timespec ts; 86 int rc; 87 rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); 88 if (rc) { 89 LOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno); 90 } else { 91 long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL + 92 (ts.tv_nsec - mPreviousTs.tv_nsec); 93 mAccumulator += delta; 94 mPreviousTs = ts; 95 } 96 } else { 97 mWasEverEnabled = false; 98 } 99 mStatistics.sample((double) mAccumulator); 100 mAccumulator = 0; 101 } else { 102 LOGW("Can't add sample because measurements have never been enabled"); 103 } 104 } 105 106 long long ThreadCpuUsage::elapsed() const 107 { 108 long long elapsed; 109 if (mMonotonicKnown) { 110 struct timespec ts; 111 int rc; 112 rc = clock_gettime(CLOCK_MONOTONIC, &ts); 113 if (rc) { 114 LOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno); 115 elapsed = 0; 116 } else { 117 // mMonotonicTs is updated only at first enable and resetStatistics 118 elapsed = (ts.tv_sec - mMonotonicTs.tv_sec) * 1000000000LL + 119 (ts.tv_nsec - mMonotonicTs.tv_nsec); 120 } 121 } else { 122 LOGW("Can't compute elapsed time because measurements have never been enabled"); 123 elapsed = 0; 124 } 125 return elapsed; 126 } 127 128 void ThreadCpuUsage::resetStatistics() 129 { 130 mStatistics.reset(); 131 if (mMonotonicKnown) { 132 int rc; 133 rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs); 134 if (rc) { 135 LOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno); 136 mMonotonicKnown = false; 137 } 138 } 139 } 140