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