| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "CPUGauge" |
| |
| #include <stdint.h> |
| #include <limits.h> |
| #include <sys/types.h> |
| #include <math.h> |
| |
| #include <utils/threads.h> |
| #include <utils/Errors.h> |
| #include <utils/Log.h> |
| |
| #include <ui/PixelFormat.h> |
| #include <ui/Rect.h> |
| #include <ui/Region.h> |
| #include <ui/DisplayInfo.h> |
| #include <ui/ISurfaceComposer.h> |
| #include <ui/ISurfaceFlingerClient.h> |
| |
| #include <pixelflinger/pixelflinger.h> |
| |
| #include "CPUGauge.h" |
| |
| namespace android { |
| |
| CPUGauge::CPUGauge( const sp<ISurfaceComposer>& composer, |
| nsecs_t interval, |
| int clock, |
| int refclock) |
| : Thread(false), |
| mInterval(interval), mClock(clock), mRefClock(refclock), |
| mReferenceTime(0), |
| mReferenceWorkingTime(0), mCpuUsage(0), |
| mRefIdleTime(0), mIdleTime(0) |
| { |
| mFd = fopen("/proc/stat", "r"); |
| setvbuf(mFd, NULL, _IONBF, 0); |
| |
| mSession = SurfaceComposerClient::clientForConnection( |
| composer->createConnection()->asBinder()); |
| } |
| |
| CPUGauge::~CPUGauge() |
| { |
| fclose(mFd); |
| } |
| |
| const sp<SurfaceComposerClient>& CPUGauge::session() const |
| { |
| return mSession; |
| } |
| |
| void CPUGauge::onFirstRef() |
| { |
| run("CPU Gauge"); |
| } |
| |
| status_t CPUGauge::readyToRun() |
| { |
| LOGI("Starting CPU gauge..."); |
| return NO_ERROR; |
| } |
| |
| bool CPUGauge::threadLoop() |
| { |
| DisplayInfo dinfo; |
| session()->getDisplayInfo(0, &dinfo); |
| sp<Surface> s(session()->createSurface(getpid(), 0, dinfo.w, 4, PIXEL_FORMAT_OPAQUE)); |
| session()->openTransaction(); |
| s->setLayer(INT_MAX); |
| session()->closeTransaction(); |
| |
| static const GGLfixed colors[4][4] = { |
| { 0x00000, 0x10000, 0x00000, 0x10000 }, |
| { 0x10000, 0x10000, 0x00000, 0x10000 }, |
| { 0x10000, 0x00000, 0x00000, 0x10000 }, |
| { 0x00000, 0x00000, 0x00000, 0x10000 }, |
| }; |
| |
| GGLContext* gl; |
| gglInit(&gl); |
| gl->activeTexture(gl, 0); |
| gl->disable(gl, GGL_TEXTURE_2D); |
| gl->disable(gl, GGL_BLEND); |
| |
| const int w = dinfo.w; |
| |
| while(!exitPending()) |
| { |
| mLock.lock(); |
| const float cpuUsage = this->cpuUsage(); |
| const float totalCpuUsage = 1.0f - idle(); |
| mLock.unlock(); |
| |
| Surface::SurfaceInfo info; |
| s->lock(&info); |
| GGLSurface fb; |
| fb.version = sizeof(GGLSurface); |
| fb.width = info.w; |
| fb.height = info.h; |
| fb.stride = info.w; |
| fb.format = info.format; |
| fb.data = (GGLubyte*)info.bits; |
| |
| gl->colorBuffer(gl, &fb); |
| gl->color4xv(gl, colors[3]); |
| gl->recti(gl, 0, 0, w, 4); |
| gl->color4xv(gl, colors[2]); // red |
| gl->recti(gl, 0, 0, int(totalCpuUsage*w), 2); |
| gl->color4xv(gl, colors[0]); // green |
| gl->recti(gl, 0, 2, int(cpuUsage*w), 4); |
| |
| s->unlockAndPost(); |
| |
| usleep(ns2us(mInterval)); |
| } |
| |
| gglUninit(gl); |
| return false; |
| } |
| |
| void CPUGauge::sample() |
| { |
| if (mLock.tryLock() == NO_ERROR) { |
| const nsecs_t now = systemTime(mRefClock); |
| const nsecs_t referenceTime = now-mReferenceTime; |
| if (referenceTime >= mInterval) { |
| const float reftime = 1.0f / referenceTime; |
| const nsecs_t nowWorkingTime = systemTime(mClock); |
| |
| char buf[256]; |
| fgets(buf, 256, mFd); |
| rewind(mFd); |
| char *str = buf+5; |
| char const * const usermode = strsep(&str, " "); (void)usermode; |
| char const * const usernice = strsep(&str, " "); (void)usernice; |
| char const * const systemmode = strsep(&str, " ");(void)systemmode; |
| char const * const idle = strsep(&str, " "); |
| const nsecs_t nowIdleTime = atoi(idle) * 10000000LL; |
| mIdleTime = float(nowIdleTime - mRefIdleTime) * reftime; |
| mRefIdleTime = nowIdleTime; |
| |
| const nsecs_t workingTime = nowWorkingTime - mReferenceWorkingTime; |
| const float newCpuUsage = float(workingTime) * reftime; |
| if (mCpuUsage != newCpuUsage) { |
| mCpuUsage = newCpuUsage; |
| mReferenceWorkingTime = nowWorkingTime; |
| mReferenceTime = now; |
| } |
| } |
| mLock.unlock(); |
| } |
| } |
| |
| |
| }; // namespace android |