Created
June 11, 2022 23:52
-
-
Save stolk/3356e4e350bae7921e55693ba65d6f4a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/fb.h> | |
#include <sys/ioctl.h> | |
#include <sys/mman.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <inttypes.h> | |
#include <stdlib.h> | |
#include <assert.h> | |
#include <unistd.h> | |
static uint32_t* fbi=0; | |
static int fbw=0; | |
static int fbh=0; | |
static uint32_t* im; | |
#define STENCILX 136 | |
#define STENCILY 362 | |
#define STENCILW 208 | |
#define STENCILH 35 | |
static uint32_t graph[STENCILH][STENCILW]; | |
static int writer=0; | |
uint8_t* readpgm(const char* nm, int* w, int* h) | |
{ | |
FILE* f = fopen(nm, "rb"); | |
assert(f); | |
int maxv=0; | |
char eol=0; | |
int scanned = fscanf(f, "P5 %d %d %d%c", w, h, &maxv, &eol); | |
assert(scanned==4); | |
uint8_t* img = (uint8_t*)malloc(*w * *h); | |
assert(img); | |
const int numr = fread(img, *w, *h, f); | |
assert(numr==*h); | |
fclose(f); | |
return img; | |
} | |
static void cut_stencil(void) | |
{ | |
uint32_t* dst = fbi + STENCILX + STENCILY*fbw; | |
const size_t sz = STENCILW * sizeof(int32_t); | |
for (int i=0; i<STENCILH; ++i) | |
{ | |
memcpy(dst, graph[i], sz); | |
//memset(dst, 0, sz); | |
dst += fbw; | |
} | |
} | |
static void write_sample(float s) | |
{ | |
static int tprv = 0; | |
const int t = (int) ( STENCILH - 1.5f - s * (STENCILH-3) ); | |
uint32_t* dst = fbi + STENCILX + 1 + writer + STENCILY*fbw; | |
for (int y=0; y<STENCILH; ++y) | |
{ | |
*dst = ((y>=t && y<=tprv) || (y>=tprv && y<=t)) ? 0x0080ff80 : 0x00000000; | |
dst += fbw; | |
} | |
writer = writer+1; | |
writer = writer >= STENCILW-2 ? 0 : writer; | |
tprv = t; | |
} | |
static uint32_t *prev=0; | |
static uint32_t *curr=0; | |
// Reads for each cpu: how many jiffies were spent in each state: | |
// user, nice, system, idle, iowait, irq, softirq | |
// NOTE: nice is a sub category of user. iowait is a sub category of idle. (soft)irq are sub categories too. | |
void get_usages( int num_cpus, float* usages ) | |
{ | |
if ( !prev || !curr ) | |
{ | |
const size_t sz = sizeof(uint32_t) * 7 * num_cpus; | |
prev = (uint32_t*) malloc( sz ); | |
curr = (uint32_t*) malloc( sz ); | |
memset( prev, 0, sz ); | |
memset( curr, 0, sz ); | |
} | |
static FILE* f = 0; | |
if ( !f ) | |
{ | |
f = fopen( "/proc/stat", "rb" ); | |
assert( f ); | |
} | |
char info[16384]; | |
const int numr = fread( info, 1, sizeof(info), f ); | |
assert( numr > 0 ); | |
rewind(f); | |
if ( numr < sizeof(info) ) | |
{ | |
info[numr] = 0; | |
for ( int cpu=0; cpu<num_cpus; ++cpu ) | |
{ | |
char tag[16]; | |
snprintf( tag, sizeof(tag), "cpu%d", cpu ); | |
const char* s = strstr( info, tag ); | |
assert( s ); | |
int cpunr; | |
uint32_t* prv = prev + cpu * 7; | |
uint32_t* cur = curr + cpu * 7; | |
const int numscanned = sscanf( s, "cpu%d %u %u %u %u %u %u %u", &cpunr, cur+0, cur+1, cur+2, cur+3, cur+4, cur+5, cur+6 ); | |
assert( numscanned == 8 ); | |
assert( cpunr == cpu ); | |
uint32_t deltas[7]; | |
for ( int i=0; i<7; ++i ) | |
{ | |
deltas[i] = cur[i] - prv[i]; | |
prv[i] = cur[i]; | |
} | |
const uint32_t user = deltas[0]; | |
const uint32_t syst = deltas[2]; | |
const uint32_t idle = deltas[3]; | |
const uint32_t work = user + syst; | |
float denom = (idle+work); | |
denom = denom <= 0 ? 1 : denom; | |
usages[ cpu ] = work / denom; | |
} | |
} | |
} | |
int setup(void) | |
{ | |
// How many cores in this system? | |
const int num_cpus = sysconf( _SC_NPROCESSORS_ONLN ); | |
fprintf( stderr, "Found %d cpus.\n", num_cpus ); | |
return num_cpus; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
int fb = open("/dev/fb0", O_RDWR); | |
assert(fb > 0); | |
struct fb_fix_screeninfo info_fix; | |
struct fb_var_screeninfo info_var; | |
int r; | |
r=ioctl(fb, FBIOGET_FSCREENINFO, &info_fix); | |
if (r<0) perror("FBIOGET_FSCREENINFO"); | |
assert(r>=0); | |
r=ioctl(fb, FBIOGET_VSCREENINFO, &info_var); | |
if (r<0) perror("FBIOGET_VSCREENINFO"); | |
assert(r>=0); | |
fbw = info_fix.line_length/4; | |
fbh = info_var.yres; | |
fprintf(stderr,"RES: %dx%d\n", fbw, fbh); | |
const size_t len = 4 * fbw * fbh; | |
fbi = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0); | |
assert(fbi != MAP_FAILED); | |
const int num_cpus = setup(); | |
float* usages = (float*)malloc(sizeof(float) * num_cpus); | |
get_usages(num_cpus, usages); | |
if (argc==2) | |
{ | |
const char* fname = argv[1]; | |
FILE* f = fopen(fname,"rb"); | |
assert(f); | |
const int numpix = fbw*fbh; | |
const size_t imsz = numpix*sizeof(uint32_t); | |
im = (uint32_t*)malloc(imsz); | |
const size_t numr = fread(im, sizeof(uint32_t), numpix, f); | |
assert(numr==numpix); | |
fclose(f); | |
memcpy(fbi, im, imsz); | |
cut_stencil(); | |
} | |
//for (int i=0; i<100000; ++i) | |
while(1) | |
{ | |
static float smooth_val=0.0f; | |
get_usages(num_cpus, usages); | |
smooth_val = 0.9f * smooth_val + 0.1f * usages[0]; | |
assert(usages[0]>=0); | |
assert(usages[0]<=1); | |
write_sample(smooth_val); | |
usleep(10000); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment