Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Neat little Xosview like system monitor for OpenBSD
- See: https://www.volkerschatz.com/unix/homebrew.html
- Compiled nicely on OpenBSD 7.4 - make as line below
- cc -o xobsdview -I/usr/X11R6/include xobsdview.c -L/usr/X11R6/lib -lX11 -lm
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <unistd.h>
- #include <string.h>
- #include <math.h>
- #include <errno.h>
- #include <sys/time.h>
- #include <sys/types.h>
- //#include <sys/ioctl.h>
- #include <sys/sysctl.h>
- #include <sys/select.h> /* for struct timespec needed in sched.h */
- #include <sys/sched.h> /* for CPUSTATES and CP_* state constants */
- #include <net/if.h>
- #include <net/route.h>
- #include <sys/disk.h>
- #include <sys/sensors.h>
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/Xos.h>
- #include <X11/keysym.h>
- #define WINWIDTH 150
- #define WINHEIGHT 300
- #define PADDING 2
- // #define FONTNAME "6x10"
- #define FONTNAME "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
- #define METERMINWIDTH 40
- #define METERMINHEIGHT 4
- #define METERSPLIT 1 /* display lowpass-filtered stats in lower half if != 0 */
- #define METERDECAY2 1.0 /* decay time to half value in seconds */
- #define MAXLOAD 5
- #define MAXDISKBW (300ull << 20) /* disk bandwidth in bytes/s, in+out */
- #define MAXNETBW (25ull << 20) /* network bandwidth in bytes/s, in+out */
- #define LABELCOL 0
- #define VALUECOL 0x808080
- #define IDLECOL 0x7FFFD4
- #define PSUCOL 0x20B2AA
- #ifndef CPUSTATES
- #define CPUSTATES 6
- #endif
- #define MEMSTATES 5
- /* confer SC_* constants in /usr/include/sys/sched.h */
- static const char *cpustabbr[CPUSTATES]= { "US", "NI", "SY", "SP", "IN", "ID" };
- static const uint32_t cpustcol[CPUSTATES]= { 0x2E8B57, 0xD0C000, 0xFFA500, 0xB060D3, 0xFF0000, IDLECOL };
- /* see https://en.wikipedia.org/wiki/X11_color_names for standard colours */
- static const char *memabbr[MEMSTATES]= { "AC", "IN", "WR", "CA", "FR" };
- static const uint32_t memcol[MEMSTATES]= { 0xFF, 0x90B8D0, 0xB060D3, 0xFF0000, IDLECOL };
- static const char *swapabbr[3]= { "ONLY", "USED", "FREE" };
- static const uint32_t swapcol[3]= { 0xFF, 0x90B8D0, IDLECOL };
- static const char *ioabbr[3]= { "IN", "OUT", "IDLE" };
- static const char *diskabbr[3]= { "READ", "WRITE", "IDLE" };
- static const uint32_t iocol[3]= { 0x87CEEB, 0x6A5ACD, IDLECOL };
- #define NWARNCOL 4
- static const uint32_t warncol[NWARNCOL]= { 0x2E8B57, 0xD0C000, 0xFFA500, 0xFF0000 };
- static const uint32_t chargingcol[2]= { 0x57EB90, IDLECOL };
- /* Update interval in seconds */
- #define INTERVAL 0.1
- typedef struct {
- int firstcall, ncpus;
- char *tabbuf;
- size_t tabbufsize;
- double loadavg[3];
- double *cpus;
- struct cpustats *cpustates, *oldcpustates;
- double membytes[MEMSTATES], swapbytes[3];
- double memtotal, swaptotal, pagein, pageout;
- int oldpageins, oldpageouts;
- uint64_t netin, netout, oldtotalnetin, oldtotalnetout;
- uint64_t diskin, diskout, oldtotaldiskin, oldtotaldiskout;
- int sensordev_psu, sensordev_bat, psu_on;
- int64_t bat_curr, bat_max;
- double *filtered;
- }
- obv_stats;
- typedef struct {
- Display *disp;
- Window win;
- GC gc;
- XGCValues gcval;
- char *name;
- int windowx, windowy, havepos;
- unsigned windoww, windowh;
- int labelx, label0y, valuex, meterx, metery, meteroff;
- unsigned meterw, meterh; /* without frame */
- unsigned fontasc, fontdesc, fontw, fontgap;
- }
- obv_view;
- int init(obv_stats *st);
- void dealloc(obv_stats *st);
- void getstat(obv_stats *st);
- void update_filtered(obv_stats *st, int firstcall);
- void init_view(obv_view *view);
- void resize_view(obv_view *view, unsigned ncpus);
- void update_view(obv_view *view, obv_stats *st);
- void exit_view(obv_view *view);
- void draw_meter(obv_view *view, unsigned metind, int split, const double *fractions, const uint32_t *colours, unsigned n);
- void draw_warnmeter(obv_view *view, unsigned metind, int split, double value, int reverse);
- void draw_value(obv_view *view, unsigned metind, int type, double value);
- void draw_key(obv_view *view, unsigned metind, const char **strs, const uint32_t *colours, int n);
- void sprintbytes(char *dest, double bytes);
- int main(int argc, char **argv)
- {
- XEvent event;
- KeySym key;
- Atom protocol[2], message;
- XRectangle cliprect;
- obv_stats st;
- obv_view v= { .windoww= WINWIDTH, .windowh= WINHEIGHT, .windowx= 0, .windowy= 0, .name= "xobsdview", .havepos= 0 };
- int argind, count, quit, updated;
- for( argind= 1; argind < argc; argind += 2 ) {
- if( !strcmp(argv[argind], "-geometry") && argind < argc-1 ) {
- count= sscanf(argv[argind+1], "%ux%u%d%d", &v.windoww, &v.windowh, &v.windowx, &v.windowy);
- v.havepos= count == 4;
- }
- else if( !strcmp(argv[argind], "-name") && argind < argc-1 )
- v.name= argv[argind+1];
- else {
- fprintf(stderr, "usage: xobsdview [ -geometry <geometry> ] [ -name <string> ]\n");
- return 1;
- }
- }
- init(&st);
- getstat(&st);
- if( METERSPLIT )
- update_filtered(&st, 1);
- init_view(&v);
- XSelectInput(v.disp, v.win, KeyPressMask|KeyReleaseMask|ExposureMask|StructureNotifyMask );
- protocol[0]= XInternAtom(v.disp, "WM_PROTOCOLS", False );
- protocol[1]= XInternAtom(v.disp, "WM_DELETE_WINDOW", False );
- XSetWMProtocols( v.disp, v.win, protocol, 2 );
- quit= 0;
- do {
- updated= 0;
- while( XPending(v.disp) > 0 ) {
- XNextEvent( v.disp, &event );
- if( event.type == KeyPress ) {
- key= XLookupKeysym( &event.xkey, 0 );
- if( key == XK_q )
- quit= 1;
- }
- else if( event.type == ClientMessage ) {
- if( event.xclient.message_type == protocol[0] ) {
- if( event.xclient.format == 8 )
- message= event.xclient.data.b[0];
- else if( event.xclient.format == 16 )
- message= event.xclient.data.s[0];
- else if( event.xclient.format == 32 )
- message= event.xclient.data.l[0];
- else message= protocol[1] - 1;
- if( message == protocol[1] )
- quit= 1;
- }
- }
- else if( event.type == ConfigureNotify ) {
- if( v.windoww != event.xconfigure.width || v.windowh != event.xconfigure.height ) {
- v.windoww= event.xconfigure.width;
- v.windowh= event.xconfigure.height;
- resize_view(&v, st.ncpus);
- update_view(&v, &st);
- updated= 1;
- }
- }
- else if( event.type == Expose && event.xexpose.count == 0 ) {
- resize_view(&v, st.ncpus);
- update_view(&v, &st);
- updated= 1;
- }
- }
- if( ! updated )
- update_view(&v, &st);
- usleep(1e6 * INTERVAL);
- getstat(&st);
- if( METERSPLIT )
- update_filtered(&st, 0);
- }
- while( ! quit );
- exit_view(&v);
- dealloc(&st);
- return 0;
- }
- static int sensordev_mib[]= { CTL_HW, HW_SENSORS, /* sensor device index */ 0 };
- int init(obv_stats *st)
- {
- struct sensordev sd;
- size_t size;
- int status, ind, typeind;
- st->sensordev_psu= -1;
- st->sensordev_bat= -1;
- for( ind= 0; st->sensordev_psu < 0 || st->sensordev_bat < 0; ++ind ) {
- sensordev_mib[2]= ind;
- size= sizeof(sd);
- status= sysctl(sensordev_mib, 3, &sd, &size, NULL, 0);
- if( status < 0 || size < sizeof(sd) )
- break;
- if( !strcmp(sd.xname, "acpiac0") )
- st->sensordev_psu= ind;
- else if( !strcmp(sd.xname, "acpibat0") )
- st->sensordev_bat= ind;
- }
- st->ncpus= sysconf(_SC_NPROCESSORS_CONF);
- st->cpustates= malloc(2 * st->ncpus * sizeof(*st->cpustates));
- st->oldcpustates= st->cpustates + st->ncpus;
- st->cpus= malloc(CPUSTATES * st->ncpus * sizeof(double));
- st->memtotal= 1;
- st->swaptotal= 1;
- st->tabbufsize= 2048;
- st->tabbuf= malloc(st->tabbufsize);
- if( METERSPLIT )
- st->filtered= calloc(st->ncpus*CPUSTATES + MEMSTATES + 3 + 3 * 2, sizeof(double));
- else
- st->filtered= NULL;
- st->firstcall= 1;
- return st->cpustates && st->cpus && st->tabbuf && (!METERSPLIT || st->filtered);
- }
- void dealloc(obv_stats *st)
- {
- free(st->cpustates);
- st->cpustates= NULL;
- free(st->cpus);
- st->cpus= NULL;
- free(st->tabbuf);
- st->tabbuf= NULL;
- free(st->filtered);
- st->filtered= NULL;
- }
- static int cpustats_mib[] = { CTL_KERN, KERN_CPUSTATS, /* CPU index */ 0 };
- /* for struct cpustats, see /usr/include/sys/sched.h */
- static const int uvmexp_mib[]= { CTL_VM, VM_UVMEXP };
- /* for struct uvmexp, see /usr/include/uvm/uvmexp.h */
- static const int iflist_mib[]= { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
- /* for structs rt_msghdr and if_msghdr, see /usr/include/net/route.h and if.h */
- static const int diskstats_mib[]= { CTL_HW, HW_DISKSTATS };
- /* for struct diskstats, see /usr/include/sys/disk.h */
- static int sensor_mib[]= { CTL_HW, HW_SENSORS, /* sensor device index */ 0, /* sensor type */ 0, /* sensor index */ 0 };
- void getstat(obv_stats *st)
- {
- struct uvmexp ue;
- struct if_msghdr *ifm;
- struct diskstats *ds;
- struct sensor se;
- char *tryalloc;
- double diff, total;
- size_t size, needsize, off;
- int cpuind, stateind;
- getloadavg(st->loadavg, 3);
- for( cpuind= 0; cpuind < st->ncpus; ++cpuind ) {
- cpustats_mib[2]= cpuind;
- size= sizeof(*st->cpustates);
- memcpy(st->oldcpustates + cpuind, st->cpustates + cpuind, size);
- if( sysctl(cpustats_mib, 3, st->cpustates + cpuind, &size, NULL, 0) < 0 ||
- (st->cpustates[cpuind].cs_flags & CPUSTATS_ONLINE) == 0 || st->firstcall ) {
- memset(st->cpus + cpuind * CPUSTATES, 0, CPUSTATES * sizeof(double));
- st->cpus[cpuind*CPUSTATES+CP_IDLE]= 1.0;
- continue;
- }
- /* Now compute fractions of CPU time spent in each state since the
- previous call, using the total change as a normalisation constant */
- total= 0;
- for( stateind= 0; stateind < CPUSTATES; ++stateind ) {
- diff= st->cpustates[cpuind].cs_time[stateind] - st->oldcpustates[cpuind].cs_time[stateind];
- if( diff < 0.0 ) /* wraparound */
- diff += 0x1p64;
- st->cpus[cpuind*CPUSTATES+stateind]= diff;
- total += diff;
- }
- if( total == 0.0 )
- total= 1.0;
- for( stateind= 0; stateind < CPUSTATES; ++stateind )
- st->cpus[cpuind*CPUSTATES+stateind] /= total;
- }
- size= sizeof(ue);
- if( sysctl(uvmexp_mib, 2, &ue, &size, NULL, 0) < 0 ) {
- st->membytes[0]= st->membytes[1]= st->membytes[2]= st->membytes[3]= 0;
- st->membytes[4]= st->memtotal;
- st->pagein= st->pageout= 0;
- st->swapbytes[0]= st->swapbytes[1]= 0;
- st->swapbytes[2]= st->swaptotal;
- }
- else {
- st->memtotal= ue.npages * (double)ue.pagesize;
- st->membytes[0]= ue.active * (double)ue.pagesize;
- st->membytes[1]= ue.inactive * (double)ue.pagesize;
- st->membytes[2]= ue.wired * (double)ue.pagesize;
- st->membytes[4]= ue.free * (double)ue.pagesize;
- st->membytes[3]= st->memtotal - st->membytes[0] - st->membytes[1] - st->membytes[2] - st->membytes[4];
- /* TODO: check this */
- if( st->firstcall ) {
- st->pagein= 0;
- st->pageout= 0;
- }
- else {
- st->pagein= (ue.pageins - st->oldpageins) * (double)ue.pagesize;
- st->pageout= (ue.pdpageouts - st->oldpageouts) * (double)ue.pagesize;
- }
- st->oldpageins= ue.pageins;
- st->oldpageouts= ue.pdpageouts;
- st->swaptotal= ue.swpages * (double)ue.pagesize;
- st->swapbytes[0]= ue.swpgonly * (double)ue.pagesize;
- st->swapbytes[1]= (ue.swpginuse - ue.swpgonly) * (double)ue.pagesize;
- st->swapbytes[2]= (ue.swpages - ue.swpginuse) * (double)ue.pagesize;
- }
- size= st->tabbufsize;
- while( sysctl(iflist_mib, 6, st->tabbuf, &size, NULL, 0) < 0 && errno == ENOMEM ) {
- needsize= 0;
- if( sysctl(iflist_mib, 6, NULL, &needsize, NULL, 0) < 0 )
- break;
- tryalloc= malloc(needsize);
- if( ! tryalloc )
- break;
- free(st->tabbuf);
- st->tabbuf= tryalloc;
- st->tabbufsize= size= needsize;
- }
- st->netin= 0;
- st->netout= 0;
- for( off= 0; off < size - ((char*)&ifm->ifm_msglen - (char*)ifm) - sizeof(ifm->ifm_msglen); off += ifm->ifm_msglen ) {
- ifm= (struct if_msghdr *)(st->tabbuf + off);
- if( off + ifm->ifm_msglen > size )
- break;
- if( ifm->ifm_version != RTM_VERSION || ifm->ifm_type != RTM_IFINFO )
- continue;
- st->netin += ifm->ifm_data.ifi_ibytes;
- st->netout += ifm->ifm_data.ifi_obytes;
- }
- if( st->firstcall ) {
- st->oldtotalnetin= st->netin;
- st->oldtotalnetout= st->netout;
- st->netin= 0;
- st->netout= 0;
- }
- else {
- st->netin -= st->oldtotalnetin;
- st->netout -= st->oldtotalnetout;
- st->oldtotalnetin += st->netin;
- st->oldtotalnetout += st->netout;
- }
- size= st->tabbufsize;
- while( sysctl(diskstats_mib, 2, st->tabbuf, &size, NULL, 0) < 0 && errno == ENOMEM ) {
- needsize= 0;
- if( sysctl(diskstats_mib, 2, NULL, &needsize, NULL, 0) < 0 )
- break;
- tryalloc= malloc(needsize);
- if( ! tryalloc )
- break;
- free(st->tabbuf);
- st->tabbuf= tryalloc;
- st->tabbufsize= size= needsize;
- }
- st->diskin= 0;
- st->diskout= 0;
- for( off= 0; (off+1) * sizeof(struct diskstats) <= size; ++off ) {
- ds= (struct diskstats*)st->tabbuf + off;
- st->diskin += ds->ds_rbytes;
- st->diskout += ds->ds_wbytes;
- }
- if( st->firstcall ) {
- st->oldtotaldiskin= st->diskin;
- st->oldtotaldiskout= st->diskout;
- st->diskin= 0;
- st->diskout= 0;
- }
- else {
- st->diskin -= st->oldtotaldiskin;
- st->diskout -= st->oldtotaldiskout;
- st->oldtotaldiskin += st->diskin;
- st->oldtotaldiskout += st->diskout;
- }
- if( st->sensordev_psu >= 0 ) {
- sensor_mib[2]= st->sensordev_psu;
- sensor_mib[3]= SENSOR_INDICATOR;
- sensor_mib[4]= 0;
- size= sizeof(se);
- if( sysctl(sensor_mib, 5, &se, &size, NULL, 0) >= 0 && size == sizeof(se) )
- st->psu_on= se.value;
- else
- st->psu_on= 0;
- }
- if( st->sensordev_bat >= 0 ) {
- sensor_mib[2]= st->sensordev_bat;
- sensor_mib[3]= SENSOR_AMPHOUR;
- sensor_mib[4]= 0;
- size= sizeof(se);
- if( sysctl(sensor_mib, 5, &se, &size, NULL, 0) >= 0 &&
- size == sizeof(se) && se.flags == 0 )
- st->bat_max= se.value;
- else
- st->bat_max= 0;
- sensor_mib[4]= 3;
- size= sizeof(se);
- if( sysctl(sensor_mib, 5, &se, &size, NULL, 0) >= 0 &&
- size == sizeof(se) && se.flags == 0 )
- st->bat_curr= se.value;
- else
- st->bat_curr= 0;
- }
- st->firstcall= 0;
- }
- void update_filtered(obv_stats *st, int firstcall)
- {
- double ffcoeff, fbcoeff;
- int ind;
- if( firstcall ) {
- fbcoeff= 0.0;
- ffcoeff= 1.0;
- }
- else {
- fbcoeff= exp2(-INTERVAL / METERDECAY2);
- ffcoeff= 1.0 - fbcoeff;
- }
- for( ind= 0; ind< st->ncpus*CPUSTATES; ++ind )
- st->filtered[ind]= fbcoeff * st->filtered[ind] + ffcoeff * st->cpus[ind];
- for( ind= 0; ind< MEMSTATES; ++ind )
- st->filtered[st->ncpus*CPUSTATES+ind]=
- fbcoeff * st->filtered[st->ncpus*CPUSTATES+ind] + ffcoeff * st->membytes[ind];
- for( ind= 0; ind< 3; ++ind )
- st->filtered[st->ncpus*CPUSTATES+MEMSTATES+ind]=
- fbcoeff * st->filtered[st->ncpus*CPUSTATES+MEMSTATES+ind] + ffcoeff * st->swapbytes[ind];
- st->filtered[st->ncpus*CPUSTATES+MEMSTATES+3]=
- fbcoeff * st->filtered[st->ncpus*CPUSTATES+MEMSTATES+3] + ffcoeff * st->pagein;
- st->filtered[st->ncpus*CPUSTATES+MEMSTATES+4]=
- fbcoeff * st->filtered[st->ncpus*CPUSTATES+MEMSTATES+4] + ffcoeff * st->pageout;
- st->filtered[st->ncpus*CPUSTATES+MEMSTATES+5]=
- fbcoeff * st->filtered[st->ncpus*CPUSTATES+MEMSTATES+5] + ffcoeff * st->diskin;
- st->filtered[st->ncpus*CPUSTATES+MEMSTATES+6]=
- fbcoeff * st->filtered[st->ncpus*CPUSTATES+MEMSTATES+6] + ffcoeff * st->diskout;
- st->filtered[st->ncpus*CPUSTATES+MEMSTATES+7]=
- fbcoeff * st->filtered[st->ncpus*CPUSTATES+MEMSTATES+7] + ffcoeff * st->netin;
- st->filtered[st->ncpus*CPUSTATES+MEMSTATES+8]=
- fbcoeff * st->filtered[st->ncpus*CPUSTATES+MEMSTATES+8] + ffcoeff * st->netout;
- }
- void init_view(obv_view *view)
- {
- XTextProperty name;
- XSizeHints *size_hints;
- XWMHints *wm_hints;
- XClassHint *class_hints;
- XCharStruct fontextents;
- char *namestr;
- int screen, dummy;
- view->disp= XOpenDisplay(NULL);
- if( !view->disp ) {
- fprintf(stderr, "xdrawtest: Error: could not connect to X server!\n");
- exit(1);
- }
- screen= DefaultScreen( view->disp );
- view->win= XCreateSimpleWindow( view->disp, RootWindow(view->disp, screen),
- view->windowx, view->windowy, view->windoww, view->windowh,
- 0, BlackPixel(view->disp, screen), WhitePixel(view->disp, screen) );
- size_hints= XAllocSizeHints();
- size_hints->flags = 0;
- if( view->havepos ) {
- size_hints->flags |= PPosition;
- size_hints->x= view->windowx; /* ignored in favour of create window arg */
- size_hints->y= view->windowy;
- }
- wm_hints= XAllocWMHints();
- wm_hints->flags = StateHint | InputHint;
- wm_hints->initial_state= NormalState;
- wm_hints->input= True;
- class_hints= XAllocClassHint();
- class_hints->res_name= "xobsdview";
- class_hints->res_class= "xobsdview";
- namestr= view->name;
- XStringListToTextProperty( &namestr, 1, &name );
- XSetWMProperties(view->disp, view->win, &name, &name, NULL, 0, size_hints, wm_hints, class_hints );
- view->gc= XCreateGC(view->disp, view->win, 0, NULL);
- view->gcval.font= XLoadFont(view->disp, FONTNAME);
- if( view->gcval.font == BadName ) {
- fprintf(stderr, "Could not load font %s\n", FONTNAME);
- exit_view(view);
- XFree(size_hints);
- XFree(wm_hints);
- XFree(class_hints);
- exit(1);
- }
- else
- XChangeGC(view->disp, view->gc, GCFont, &view->gcval);
- XMapWindow(view->disp, view->win);
- XSetBackground(view->disp, view->gc, WhitePixel(view->disp, screen));
- XQueryTextExtents(view->disp, XGContextFromGC(view->gc), "N", 1, &dummy, &dummy, &dummy, &fontextents);
- view->fontasc= fontextents.ascent;
- view->fontdesc= fontextents.descent;
- view->fontw= fontextents.width;
- view->fontgap= view->fontw / 2;
- XFree(size_hints);
- XFree(wm_hints);
- XFree(class_hints);
- }
- void resize_view(obv_view *view, unsigned ncpus)
- {
- char cpustr[6];
- const char *label;
- int nmeters, ind, y;
- nmeters= ncpus + 7;
- view->meteroff= (view->windowh - PADDING) / nmeters;
- if( view->meteroff < METERMINHEIGHT + 2 + view->fontasc + view->fontdesc + 1 + 4 ) {
- view->meteroff= METERMINHEIGHT + 2 + view->fontasc + view->fontdesc + 1 + 4;
- view->meterh= METERMINHEIGHT;
- }
- else
- view->meterh= view->meteroff - (2 + view->fontasc + view->fontdesc + 1 + 4);
- view->labelx= PADDING;
- view->valuex= view->labelx + 5*view->fontw;
- view->meterx= view->valuex + 4*view->fontw + view->fontgap;
- view->meterw= view->windoww - PADDING - 1 - view->meterx;
- if( view->meterw < METERMINWIDTH )
- view->meterw= METERMINWIDTH;
- view->metery= PADDING + view->fontasc + view->fontdesc + 3;
- view->label0y= view->metery + (view->meterh - view->fontasc - view->fontdesc) / 2 + view->fontasc;
- XSetForeground(view->disp, view->gc, 0xFFFFFF);
- XFillRectangle(view->disp, view->win, view->gc, 0, 0, view->windoww, view->windowh);
- XSetForeground(view->disp, view->gc, 0);
- y= view->metery - 1;
- for( ind= 0; ind< ncpus+7; ++ind, y += view->meteroff )
- XDrawRectangle(view->disp, view->win, view->gc, view->meterx-1, y, view->meterw+1, view->meterh+1);
- y= view->label0y;
- XDrawString(view->disp, view->win, view->gc, view->labelx, y, "LOAD", 4);
- y += view->meteroff;
- for( ind= 0; ind< ncpus; ++ind ) {
- snprintf(cpustr, 6, "CPU%d", ind);
- XDrawString(view->disp, view->win, view->gc, view->labelx, y, cpustr, 4 + (ind > 9));
- y += view->meteroff;
- }
- XDrawString(view->disp, view->win, view->gc, view->labelx, y, "MEM", 3);
- y += view->meteroff;
- XDrawString(view->disp, view->win, view->gc, view->labelx, y, "SWAP", 4);
- y += view->meteroff;
- XDrawString(view->disp, view->win, view->gc, view->labelx, y, "PAGE", 4);
- y += view->meteroff;
- XDrawString(view->disp, view->win, view->gc, view->labelx, y, "DISK", 4);
- y += view->meteroff;
- XDrawString(view->disp, view->win, view->gc, view->labelx, y, "NET", 3);
- y += view->meteroff;
- XDrawString(view->disp, view->win, view->gc, view->labelx, y, "BAT", 3);
- label= "PROCS";
- draw_key(view, 0, &label, warncol, 1);
- for( ind= 0; ind< ncpus; ++ind )
- draw_key(view, ind+1, cpustabbr, cpustcol, CPUSTATES);
- draw_key(view, ncpus+1, memabbr, memcol, MEMSTATES);
- draw_key(view, ncpus+2, swapabbr, swapcol, 3);
- draw_key(view, ncpus+3, ioabbr, iocol, 3);
- draw_key(view, ncpus+4, diskabbr, iocol, 3);
- draw_key(view, ncpus+5, ioabbr, iocol, 3);
- label= "CHARGE";
- draw_key(view, ncpus+6, &label, warncol, 1);
- }
- void update_view(obv_view *view, obv_stats *st)
- {
- double values[MEMSTATES+3];
- int ind;
- draw_warnmeter(view, 0, !!METERSPLIT, st->loadavg[0]/MAXLOAD, 0);
- draw_value(view, 0, 0, st->loadavg[0]);
- if( METERSPLIT )
- draw_warnmeter(view, 0, 2, st->loadavg[1]/MAXLOAD, 0);
- for( ind= 0; ind< st->ncpus; ++ind ) {
- draw_meter(view, ind+1, !!METERSPLIT, st->cpus + ind*CPUSTATES, cpustcol, CPUSTATES);
- draw_value(view, ind+1, 1, 1.0 - st->cpus[(ind+1)*CPUSTATES-1]);
- if( METERSPLIT )
- draw_meter(view, ind+1, 2, st->filtered + ind*CPUSTATES, cpustcol, CPUSTATES);
- }
- for( ind= 0; ind< MEMSTATES; ++ind )
- values[ind]= st->membytes[ind] / st->memtotal;
- draw_meter(view, st->ncpus+1, !!METERSPLIT, values, memcol, MEMSTATES);
- draw_value(view, st->ncpus+1, 2, st->memtotal - st->membytes[MEMSTATES-2] - st->membytes[MEMSTATES-1]);
- if( METERSPLIT ) {
- for( ind= 0; ind< MEMSTATES; ++ind )
- values[ind]= st->filtered[st->ncpus*CPUSTATES+ind] / st->memtotal;
- draw_meter(view, st->ncpus+1, 2, values, memcol, MEMSTATES);
- }
- for( ind= 0; ind< 3; ++ind )
- values[ind]= st->swapbytes[ind] / st->swaptotal;
- draw_meter(view, st->ncpus+2, !!METERSPLIT, values, swapcol, 3);
- draw_value(view, st->ncpus+2, 2, st->swapbytes[0] + st->swapbytes[1]);
- if( METERSPLIT ) {
- for( ind= 0; ind< 3; ++ind )
- values[ind]= st->filtered[st->ncpus*CPUSTATES+MEMSTATES+ind] / st->swaptotal;
- draw_meter(view, st->ncpus+2, 2, values, swapcol, 3);
- }
- values[0]= st->pagein / INTERVAL / MAXDISKBW;
- values[1]= st->pageout / INTERVAL / MAXDISKBW;
- draw_meter(view, st->ncpus+3, !!METERSPLIT, values, iocol, 3);
- draw_value(view, st->ncpus+3, 2, (st->pagein + st->pageout) / INTERVAL);
- if( METERSPLIT ) {
- values[0]= st->filtered[st->ncpus*CPUSTATES+MEMSTATES+3] / INTERVAL / MAXDISKBW;
- values[1]= st->filtered[st->ncpus*CPUSTATES+MEMSTATES+4] / INTERVAL / MAXDISKBW;
- draw_meter(view, st->ncpus+3, 2, values, iocol, 3);
- }
- values[0]= (double)st->diskin / INTERVAL / MAXDISKBW;
- values[1]= (double)st->diskout / INTERVAL / MAXDISKBW;
- draw_meter(view, st->ncpus+4, !!METERSPLIT, values, iocol, 3);
- draw_value(view, st->ncpus+4, 2, (double)(st->diskin + st->diskout) / INTERVAL);
- if( METERSPLIT ) {
- values[0]= st->filtered[st->ncpus*CPUSTATES+MEMSTATES+5] / INTERVAL / MAXDISKBW;
- values[1]= st->filtered[st->ncpus*CPUSTATES+MEMSTATES+6] / INTERVAL / MAXDISKBW;
- draw_meter(view, st->ncpus+4, 2, values, iocol, 3);
- }
- values[0]= (double)st->netin / INTERVAL / MAXNETBW;
- values[1]= (double)st->netout / INTERVAL / MAXNETBW;
- draw_meter(view, st->ncpus+5, !!METERSPLIT, values, iocol, 3);
- draw_value(view, st->ncpus+5, 2, (double)(st->netin + st->netout) / INTERVAL);
- if( METERSPLIT ) {
- values[0]= st->filtered[st->ncpus*CPUSTATES+MEMSTATES+7] / INTERVAL / MAXNETBW;
- values[1]= st->filtered[st->ncpus*CPUSTATES+MEMSTATES+8] / INTERVAL / MAXNETBW;
- draw_meter(view, st->ncpus+5, 2, values, iocol, 3);
- }
- if( st->bat_max > 0 ) {
- values[0]= (double)st->bat_curr / st->bat_max;
- if( st->psu_on )
- draw_meter(view, st->ncpus+6, 0, values, chargingcol, 2);
- else
- draw_warnmeter(view, st->ncpus+6, 0, values[0], 1);
- draw_value(view, st->ncpus+6, 1, values[0]);
- }
- }
- void exit_view(obv_view *view)
- {
- XUnmapWindow(view->disp, view->win);
- XUnloadFont(view->disp, view->gcval.font);
- XFreeGC(view->disp, view->gc);
- XCloseDisplay(view->disp);
- }
- /* Draw horizontally stacked coloured bars of a meter of multiple values that
- add up to 1.0. The meter index determines the y position. If split is 1,
- only the upper half of the bar is painted; if it is 2, only the lower half.
- The last 3 arguments give the values and colours. The last value is
- ignored; its bar is filled in to the right end of the meter. */
- void draw_meter(obv_view *view, unsigned metind, int split, const double *fractions, const uint32_t *colours, unsigned n)
- {
- double sum;
- unsigned y, h, xoff, xtop, ind;
- y= view->metery + metind * view->meteroff;
- if( split ) {
- h= (view->meterh + 1) / 2;
- if( split == 2 ) {
- y += h;
- if( view->meterh & 1 )
- --h;
- }
- }
- else
- h= view->meterh;
- xoff= 0;
- sum= 0.0;
- for( ind= 0; ind < n-1; ++ind ) {
- if( fractions[ind] <= 0.0 )
- continue;
- sum += fractions[ind];
- if( sum > 1.0 )
- sum= 1.0;
- xtop= (unsigned)(view->meterw * sum + 0.5);
- if( xtop <= xoff )
- continue;
- XSetForeground(view->disp, view->gc, colours[ind]);
- XFillRectangle(view->disp, view->win, view->gc, view->meterx+xoff, y, xtop-xoff, h);
- xoff= xtop;
- if( xoff >= view->meterw )
- return;
- }
- XSetForeground(view->disp, view->gc, colours[n-1]);
- XFillRectangle(view->disp, view->win, view->gc, view->meterx+xoff, y, view->meterw-xoff, h);
- }
- /* Draw a horizontal bar indicating a single value, in a colour also indicating
- the value. The meter index determines the y position. If split is 1, only
- the upper half of the bar is painted; if it is 2, only the lower half. The
- colour is interpolated from warncol[] for values between 0.1 and 0.9. */
- void draw_warnmeter(obv_view *view, unsigned metind, int split, double value, int reverse)
- {
- double colfrac;
- uint32_t colour;
- unsigned y, h;
- int w, ind, colind;
- y= view->metery + metind * view->meteroff;
- if( split ) {
- h= (view->meterh + 1) / 2;
- if( split == 2 ) {
- y += h;
- if( view->meterh & 1 )
- --h;
- }
- }
- else
- h= view->meterh;
- w= value * view->meterw + 0.5;
- if( w < 0 )
- w= 0;
- else if( w > view->meterw )
- w= view->meterw;
- if( reverse )
- value= 1.0 - value;
- colfrac= (value - 0.1) / 0.8 * (NWARNCOL - 1);
- if( colfrac <= 0.0 )
- colour= warncol[0];
- else if( colfrac >= NWARNCOL-1 )
- colour= warncol[NWARNCOL-1];
- else {
- colind= (int)colfrac;
- colfrac -= colind;
- for( ind= 0; ind< 4; ++ind )
- ((uint8_t*)&colour)[ind]= colfrac * ((uint8_t*)(warncol+colind+1))[ind] + (1.0 - colfrac) * ((uint8_t*)(warncol+colind))[ind];
- }
- XSetForeground(view->disp, view->gc, colour);
- XFillRectangle(view->disp, view->win, view->gc, view->meterx, y, w, h);
- if( w < view->meterw ) {
- XSetForeground(view->disp, view->gc, IDLECOL);
- XFillRectangle(view->disp, view->win, view->gc, view->meterx + w, y, view->meterw - w, h);
- }
- }
- /* Draw value as text to the left of meter. type is 0 for numeric, 1 for
- percentage, 2 for data volume. */
- void draw_value(obv_view *view, unsigned metind, int type, double value)
- {
- char valstr[5];
- if( type == 0 )
- snprintf(valstr, 5, "%4g", value);
- else if( type == 1 )
- snprintf(valstr, 5, "%3d%%", (int)(100*value+0.5));
- else
- sprintbytes(valstr, value);
- XSetForeground(view->disp, view->gc, VALUECOL);
- XDrawImageString(view->disp, view->win, view->gc, view->valuex, view->label0y + metind*view->meteroff, valstr, 4);
- }
- /* Draw a concatenated string in multiple colours above the meter with the
- given index. */
- void draw_key(obv_view *view, unsigned metind, const char **strs, const uint32_t *colours, int n)
- {
- int x, y, w, ind, xoff, nchars, dummy;
- w= 0;
- for( ind= 0; ind < n; ++ind )
- w += strlen(strs[ind]);
- w= w * view->fontw + (n - 1) * view->fontgap;
- x= view->meterx;
- if( w > view->meterw )
- x -= w - view->meterw;
- y= view->metery + metind * view->meteroff - 3 - view->fontdesc;
- for( ind= 0; ind < n; ++ind ) {
- nchars= strlen(strs[ind]);
- XSetForeground(view->disp, view->gc, colours[ind]);
- XDrawString(view->disp, view->win, view->gc, x, y, strs[ind], nchars);
- x += view->fontw * nchars;
- x += view->fontgap;
- }
- }
- /* Print abbreviated byte count in 5 chars including terminating 0. */
- static const char suffix[]= "kMGTPE";
- void sprintbytes(char *dest, double bytes)
- {
- int tenbits;
- tenbits= bytes > 0.0 ? (int)floor(log2(bytes)/10) : 0;
- bytes /= exp2(10.0 * tenbits);
- if( bytes < 10 )
- snprintf(dest, 4, "%.1f", bytes);
- else if( bytes < 100 )
- snprintf(dest, 4, " %d", (int)floor(bytes));
- else
- snprintf(dest, 4, "%d", (int)floor(bytes));
- if( tenbits == 0 )
- dest[3]= ' ';
- else if( tenbits < 7 )
- dest[3]= suffix[tenbits-1];
- else
- dest[3]= '!';
- dest[4]= 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement