1921832327619f7852b16f73a19504702c5a28a31Glenn Kasten/*
2921832327619f7852b16f73a19504702c5a28a31Glenn Kasten * Copyright (C) 2011 The Android Open Source Project
3921832327619f7852b16f73a19504702c5a28a31Glenn Kasten *
4921832327619f7852b16f73a19504702c5a28a31Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5921832327619f7852b16f73a19504702c5a28a31Glenn Kasten * you may not use this file except in compliance with the License.
6921832327619f7852b16f73a19504702c5a28a31Glenn Kasten * You may obtain a copy of the License at
7921832327619f7852b16f73a19504702c5a28a31Glenn Kasten *
8921832327619f7852b16f73a19504702c5a28a31Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9921832327619f7852b16f73a19504702c5a28a31Glenn Kasten *
10921832327619f7852b16f73a19504702c5a28a31Glenn Kasten * Unless required by applicable law or agreed to in writing, software
11921832327619f7852b16f73a19504702c5a28a31Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12921832327619f7852b16f73a19504702c5a28a31Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13921832327619f7852b16f73a19504702c5a28a31Glenn Kasten * See the License for the specific language governing permissions and
14921832327619f7852b16f73a19504702c5a28a31Glenn Kasten * limitations under the License.
15921832327619f7852b16f73a19504702c5a28a31Glenn Kasten */
16921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
17921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#define LOG_TAG "ThreadCpuUsage"
18921832327619f7852b16f73a19504702c5a28a31Glenn Kasten//#define LOG_NDEBUG 0
19921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
20921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#include <errno.h>
21921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#include <stdlib.h>
229d014d04bd1e26b68ea979885ccbc6f131a7eda3Elliott Hughes#include <string.h>
23921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#include <time.h>
24921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
25921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#include <utils/Log.h>
26921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
27921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#include <cpustats/ThreadCpuUsage.h>
28921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
29921832327619f7852b16f73a19504702c5a28a31Glenn Kastennamespace android {
30921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
31921832327619f7852b16f73a19504702c5a28a31Glenn Kastenbool ThreadCpuUsage::setEnabled(bool isEnabled)
32921832327619f7852b16f73a19504702c5a28a31Glenn Kasten{
33921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    bool wasEnabled = mIsEnabled;
34921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    // only do something if there is a change
35921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (isEnabled != wasEnabled) {
36921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ALOGV("setEnabled(%d)", isEnabled);
37921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        int rc;
38921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        // enabling
39921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        if (isEnabled) {
40921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mPreviousTs);
41921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            if (rc) {
42921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
43921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                isEnabled = false;
44921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            } else {
45921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                mWasEverEnabled = true;
46921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                // record wall clock time at first enable
47921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                if (!mMonotonicKnown) {
48921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                    rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
49921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                    if (rc) {
50921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                        ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
51921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                    } else {
52921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                        mMonotonicKnown = true;
53921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                    }
54921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                }
55921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            }
56921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        // disabling
57921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        } else {
58921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            struct timespec ts;
59921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
60921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            if (rc) {
61921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
62921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            } else {
63921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
64921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                        (ts.tv_nsec - mPreviousTs.tv_nsec);
65921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                mAccumulator += delta;
66921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#if 0
67921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                mPreviousTs = ts;
68921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#endif
69921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            }
70921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        }
71921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        mIsEnabled = isEnabled;
72921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
73921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    return wasEnabled;
74921832327619f7852b16f73a19504702c5a28a31Glenn Kasten}
75921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
76921832327619f7852b16f73a19504702c5a28a31Glenn Kastenbool ThreadCpuUsage::sampleAndEnable(double& ns)
77921832327619f7852b16f73a19504702c5a28a31Glenn Kasten{
78921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    bool wasEverEnabled = mWasEverEnabled;
79921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (enable()) {
80921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        // already enabled, so add a new sample relative to previous
81921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        return sample(ns);
82921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    } else if (wasEverEnabled) {
83921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        // was disabled, but add sample for accumulated time while enabled
84921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ns = (double) mAccumulator;
85921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        mAccumulator = 0;
86921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ALOGV("sampleAndEnable %.0f", ns);
87921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        return true;
88921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    } else {
89921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        // first time called
90921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ns = 0.0;
91921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ALOGV("sampleAndEnable false");
92921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        return false;
93921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
94921832327619f7852b16f73a19504702c5a28a31Glenn Kasten}
95921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
96921832327619f7852b16f73a19504702c5a28a31Glenn Kastenbool ThreadCpuUsage::sample(double &ns)
97921832327619f7852b16f73a19504702c5a28a31Glenn Kasten{
98921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (mWasEverEnabled) {
99921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        if (mIsEnabled) {
100921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            struct timespec ts;
101921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            int rc;
102921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
103921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            if (rc) {
104921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
105921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                ns = 0.0;
106921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                return false;
107921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            } else {
108921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
109921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                        (ts.tv_nsec - mPreviousTs.tv_nsec);
110921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                mAccumulator += delta;
111921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                mPreviousTs = ts;
112921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            }
113921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        } else {
114921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            mWasEverEnabled = false;
115921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        }
116921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ns = (double) mAccumulator;
117921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ALOGV("sample %.0f", ns);
118921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        mAccumulator = 0;
119921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        return true;
120921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    } else {
121921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ALOGW("Can't add sample because measurements have never been enabled");
122921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ns = 0.0;
123921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        return false;
124921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
125921832327619f7852b16f73a19504702c5a28a31Glenn Kasten}
126921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
127921832327619f7852b16f73a19504702c5a28a31Glenn Kastenlong long ThreadCpuUsage::elapsed() const
128921832327619f7852b16f73a19504702c5a28a31Glenn Kasten{
129921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    long long elapsed;
130921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (mMonotonicKnown) {
131921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        struct timespec ts;
132921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        int rc;
133921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        rc = clock_gettime(CLOCK_MONOTONIC, &ts);
134921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        if (rc) {
135921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
136921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            elapsed = 0;
137921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        } else {
138921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            // mMonotonicTs is updated only at first enable and resetStatistics
139921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            elapsed = (ts.tv_sec - mMonotonicTs.tv_sec) * 1000000000LL +
140921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                    (ts.tv_nsec - mMonotonicTs.tv_nsec);
141921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        }
142921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    } else {
143921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ALOGW("Can't compute elapsed time because measurements have never been enabled");
144921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        elapsed = 0;
145921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
146921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    ALOGV("elapsed %lld", elapsed);
147921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    return elapsed;
148921832327619f7852b16f73a19504702c5a28a31Glenn Kasten}
149921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
150921832327619f7852b16f73a19504702c5a28a31Glenn Kastenvoid ThreadCpuUsage::resetElapsed()
151921832327619f7852b16f73a19504702c5a28a31Glenn Kasten{
152921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    ALOGV("resetElapsed");
153921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (mMonotonicKnown) {
154921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        int rc;
155921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
156921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        if (rc) {
157921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
158921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            mMonotonicKnown = false;
159921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        }
160921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
161921832327619f7852b16f73a19504702c5a28a31Glenn Kasten}
162921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
163921832327619f7852b16f73a19504702c5a28a31Glenn Kasten/*static*/
164921832327619f7852b16f73a19504702c5a28a31Glenn Kastenint ThreadCpuUsage::sScalingFds[ThreadCpuUsage::MAX_CPU];
165921832327619f7852b16f73a19504702c5a28a31Glenn Kastenpthread_once_t ThreadCpuUsage::sOnceControl = PTHREAD_ONCE_INIT;
166921832327619f7852b16f73a19504702c5a28a31Glenn Kastenint ThreadCpuUsage::sKernelMax;
167921832327619f7852b16f73a19504702c5a28a31Glenn Kastenpthread_mutex_t ThreadCpuUsage::sMutex = PTHREAD_MUTEX_INITIALIZER;
168921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
169921832327619f7852b16f73a19504702c5a28a31Glenn Kasten/*static*/
170921832327619f7852b16f73a19504702c5a28a31Glenn Kastenvoid ThreadCpuUsage::init()
171921832327619f7852b16f73a19504702c5a28a31Glenn Kasten{
172921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    // read the number of CPUs
173921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    sKernelMax = 1;
174921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    int fd = open("/sys/devices/system/cpu/kernel_max", O_RDONLY);
175921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (fd >= 0) {
176921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#define KERNEL_MAX_SIZE 12
177921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        char kernelMax[KERNEL_MAX_SIZE];
178921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ssize_t actual = read(fd, kernelMax, sizeof(kernelMax));
179921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        if (actual >= 2 && kernelMax[actual-1] == '\n') {
180921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            sKernelMax = atoi(kernelMax);
181921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            if (sKernelMax >= MAX_CPU - 1) {
182921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                ALOGW("kernel_max %d but MAX_CPU %d", sKernelMax, MAX_CPU);
183921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                sKernelMax = MAX_CPU;
184921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            } else if (sKernelMax < 0) {
185921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                ALOGW("kernel_max invalid %d", sKernelMax);
186921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                sKernelMax = 1;
187921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            } else {
188921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                ++sKernelMax;
189921832327619f7852b16f73a19504702c5a28a31Glenn Kasten                ALOGV("number of CPUs %d", sKernelMax);
190921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            }
191921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        } else {
192921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            ALOGW("Can't read number of CPUs");
193921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        }
194921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        (void) close(fd);
195921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    } else {
196921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ALOGW("Can't open number of CPUs");
197921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
198921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    int i;
199921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    for (i = 0; i < MAX_CPU; ++i) {
200921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        sScalingFds[i] = -1;
201921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
202921832327619f7852b16f73a19504702c5a28a31Glenn Kasten}
203921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
204921832327619f7852b16f73a19504702c5a28a31Glenn Kastenuint32_t ThreadCpuUsage::getCpukHz(int cpuNum)
205921832327619f7852b16f73a19504702c5a28a31Glenn Kasten{
206921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (cpuNum < 0 || cpuNum >= MAX_CPU) {
207921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ALOGW("getCpukHz called with invalid CPU %d", cpuNum);
208921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        return 0;
209921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
210921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    // double-checked locking idiom is not broken for atomic values such as fd
211921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    int fd = sScalingFds[cpuNum];
212921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (fd < 0) {
213921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        // some kernels can't open a scaling file until hot plug complete
214921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        pthread_mutex_lock(&sMutex);
215921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        fd = sScalingFds[cpuNum];
216921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        if (fd < 0) {
217921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#define FREQ_SIZE 64
218921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            char freq_path[FREQ_SIZE];
219921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#define FREQ_DIGIT 27
220fc3afda925f4b493ef68a745fdd753d9330316adMark Salyzyn            static_assert(MAX_CPU <= 10, "MAX_CPU too large");
221921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#define FREQ_PATH "/sys/devices/system/cpu/cpu?/cpufreq/scaling_cur_freq"
222921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            strlcpy(freq_path, FREQ_PATH, sizeof(freq_path));
223921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            freq_path[FREQ_DIGIT] = cpuNum + '0';
224921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            fd = open(freq_path, O_RDONLY | O_CLOEXEC);
225921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            // keep this fd until process exit or exec
226921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            sScalingFds[cpuNum] = fd;
227921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        }
228921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        pthread_mutex_unlock(&sMutex);
229921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        if (fd < 0) {
230921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            ALOGW("getCpukHz can't open CPU %d", cpuNum);
231921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            return 0;
232921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        }
233921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
234921832327619f7852b16f73a19504702c5a28a31Glenn Kasten#define KHZ_SIZE 12
235921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    char kHz[KHZ_SIZE];   // kHz base 10
236921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    ssize_t actual = pread(fd, kHz, sizeof(kHz), (off_t) 0);
237921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    uint32_t ret;
238921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (actual >= 2 && kHz[actual-1] == '\n') {
239921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ret = atoi(kHz);
240921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    } else {
241921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        ret = 0;
242921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
243921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    if (ret != mCurrentkHz[cpuNum]) {
244921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        if (ret > 0) {
245921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            ALOGV("CPU %d frequency %u kHz", cpuNum, ret);
246921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        } else {
247921832327619f7852b16f73a19504702c5a28a31Glenn Kasten            ALOGW("Can't read CPU %d frequency", cpuNum);
248921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        }
249921832327619f7852b16f73a19504702c5a28a31Glenn Kasten        mCurrentkHz[cpuNum] = ret;
250921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    }
251921832327619f7852b16f73a19504702c5a28a31Glenn Kasten    return ret;
252921832327619f7852b16f73a19504702c5a28a31Glenn Kasten}
253921832327619f7852b16f73a19504702c5a28a31Glenn Kasten
254921832327619f7852b16f73a19504702c5a28a31Glenn Kasten}   // namespace android
255