/* * 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