Re: cpu usage display conky vs. top

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Suvayu Ali <fatkasuvayu+linux@xxxxxxxxx> writes:

> On Mon, Jul 22, 2013 at 12:33:53PM +0200, lee wrote:
>> 
>> I've done that yesterday.  It's working already, showing an
>> automatically scaling graph of the used network bandwidth over 360
>> samples, with the update interval given on the command line.  Let it
>> update every 10 seconds, and you see the last hour.  Xosview can't do
>> that, and conky probably can't, either.
>> 
>> It also has almost zero CPU usage, and memory usage is only 40064/2272
>> virt/res.  Now I could add showing processes or whatever I like to see
>> :)
>
> If you do not mind, it be educational for me to see your source.
>
> :)

Sure --- you'll need libsx to compile it, though.  Since the Fedora
package providing libsx unfortunately is orphaned, I took the Debian
source package, applied their patches as much as possible and managed to
compile libsx.  I can tar up what I have and send it to you if you want,
just let me know.

I added load average monitoring today.  The code is somewhat ugly
because it's a derivative of a monitor I wrote to use with i3, and that
one doesn't have any graphics.

Ah, two keys are currently defined:

q: quit
t: set update interval


If you know a faster way to shift arrays, please let me know.  I tried
memmove() and it segfaulted, and I haven't looked into it further yet.

The text display can be messed up for you, depending on what fonts it
will use.  With libsx, you can only get the width of a text to be
printed with a particular font but not the height, so for now I simply
hardcoded the positions so that it fits the font it's using here.


// bwstats
// This software is licensed under the GPL.
// Author: lee@xxxxxxxxxxxxxxx, 2013-07-21
//
// compile with something like:
// gcc -lsx -lXpm -lXaw -lXt -lX11 -O2 -Wall -fomit-frame-pointer
//     -fexpensive-optimizations -march=native bwstat.c -o bwstat
//
// That should compile without warnings.  Now run:
//
// bwstat /sys/class/net/em1/statistics/rx_bytes
//          /sys/class/net/em1/statistics/tx_bytes
//
// Replace these files with whatever files have the statistics
// of the network interface you want to monitor.
//


#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/sysinfo.h>

#include <libsx.h>


#define BUFFSIZE 128
#define KIB (1024)

#define SAMPLES 360
#define TEXT 64


typedef struct {
  unsigned long rx;
  unsigned long tx;
  struct timeval tv;
} rxtx;


typedef struct {
  FILE *rx;
  FILE *tx;
  char buffer[BUFFSIZE];
} filestuff;


typedef struct {
  double rxbw;
  double txbw;
  time_t timestamp;
} bandwidth;


typedef struct {
  Widget w;
  int width;
  int height;
  float valuesTX[SAMPLES];
  float valuesRX[SAMPLES];
  float loadavgs[SAMPLES];
  int index;
} DrawAreaData;


typedef struct {
  Widget w;
  int width;
  int height;
} DrawAreaText;


typedef struct {
  int txbar;
  int rxbar;
  int sepline;
  int loadavg;
  int bg;
} colours;


typedef struct {
  filestuff *t;
  rxtx *new;
  rxtx *old;
  bandwidth *bw;
  int notimeout;
  unsigned long tick;
  DrawAreaData Data;
  DrawAreaText Text;
  colours col;
} mydata;


typedef struct {
  float maxTX;
  float maxRX;
  float maxAV;
} maxtxrx;


typedef struct {
  int days;
  int hours;
  int minutes;
  int seconds;
} updays;


void sec2days(long seconds, updays *ud) {
  ud->days = seconds / 86400;
  seconds -= 86400 * ud->days;
  ud->hours = seconds / 3600;
  seconds -= 3600 * ud->hours;
  ud->minutes = seconds / 60;
  ud->seconds = seconds - 60 * ud->minutes;
}


int getstat(filestuff *f, rxtx *s) {
  int ret = 0;

  if(gettimeofday( &(s->tv), NULL) ) {
    perror("gettimeofday");
    ret = 3;
  }
  else {
    bzero(f->buffer, BUFFSIZE);
    int c;
    unsigned long offset = 0;
    while( (  (   c = fgetc(f->rx) ) != EOF) && offset < BUFFSIZE) {
      *(f->buffer + offset) = c;
      offset++;
    }
    if(offset < BUFFSIZE) {
      s->rx = atol(f->buffer);

      bzero(f->buffer, BUFFSIZE);
      offset = 0;
      while( (  (   c = fgetc(f->tx) ) != EOF) && offset < BUFFSIZE) {
	*(f->buffer + offset) = c;
	offset++;
      }
      if(offset < BUFFSIZE) {
	s->tx = atol(f->buffer);
      }
      else {
	ret = 2;
      }
    }
    else {
      ret = 1;
    }
  }

  return ret;
}


void delta(rxtx *old, rxtx *new, bandwidth *bw) {
  unsigned long drx = new->rx - old->rx;
  unsigned long dtx = new->tx - old->tx;

  double dtime = (double)(new->tv.tv_sec - old->tv.tv_sec)
    + (double)( (double)(new->tv.tv_usec - old->tv.tv_usec)
		     / (double)1000000.0);

  bw->rxbw = (double)drx / dtime;
  bw->txbw = (double)dtx / dtime;
  bw->timestamp = new->tv.tv_sec;
}


void array_shift_left(float arrayRX[], float arrayTX[], float arrayAV[], int idx)
{
  int n = 1;
  while(n <= idx) {
    arrayRX[n] = arrayRX[n + 1];
    arrayTX[n] = arrayTX[n + 1];
    arrayAV[n] = arrayAV[n + 1];
    n++;
  }
}


void get_data(mydata *d) {
  rewind(d->t->rx);
  rewind(d->t->tx);

  if( !getstat(d->t, d->new) ) {
    delta(d->old, d->new, d->bw);
    memcpy(d->old, d->new, sizeof(rxtx) );

    double loads[1];
    if(getloadavg(loads, 1) != 1) {
      loads[0] = 0.0;
      puts("error: getloadavg() failed");
    }

    if(d->Data.index < SAMPLES - 1) {
      d->Data.valuesRX[d->Data.index] = (float)(d->bw->rxbw / (double)KIB);
      d->Data.valuesTX[d->Data.index] = (float)(d->bw->txbw / (double)KIB);
      d->Data.loadavgs[d->Data.index] = (float)loads[0];
      (d->Data.index)++;
    }
    else {
      array_shift_left(d->Data.valuesRX, d->Data.valuesTX, d->Data.loadavgs,
		       d->Data.index);
      d->Data.valuesRX[d->Data.index] = (float)(d->bw->rxbw / (double)KIB);
      d->Data.valuesTX[d->Data.index] = (float)(d->bw->txbw / (double)KIB);
      d->Data.loadavgs[d->Data.index] = (float)loads[0];
    }
  }
  else {
    puts("error: getstat() failed");
  }
}


void get_maxval(float vTX[], float vRX[], float vAV[], maxtxrx *m, int idx) {
  m->maxTX = m->maxRX = m->maxAV = 0.0;
  int n = 0;
  while(n <= idx) {
    if(m->maxTX < vTX[n] ) {
      m->maxTX = vTX[n];
    }
    if(m->maxRX < vRX[n] ) {
      m->maxRX = vRX[n];
    }
    if(m->maxAV < vAV[n] ) {
      m->maxAV = vAV[n];
    }
    n++;
  }
}


float comp_percentage(float ref, float this) {
  return ( (ref == 0.0) ? 0 : (int)(this * 100.0 / ref + 0.5) );
}


int comp_percent(float from, float percentage) {
  return (int)(percentage * from / 100.0 + 0.5);
}


void draw_bar(void *data) {
  mydata *d = data;

  SetDrawArea(d->Data.w);
  SetColor(d->col.sepline);
  SetLineWidth(2);
  ClearDrawArea();
  int height = d->Data.height;
  --height;
  int halfheight = height / 2;
  DrawLine(0, halfheight, d->Data.width, halfheight);
  SetLineWidth(d->Data.width / SAMPLES);

  int idx = d->Data.index;
  maxtxrx m;
  get_maxval(d->Data.valuesTX, d->Data.valuesRX, d->Data.loadavgs, &m, idx);

  XPoint pline[SAMPLES];
  int n = 0;
  while(n <= idx) {
    float percentage = comp_percentage(m.maxTX, d->Data.valuesTX[n] );
    int h = comp_percent( (float)halfheight, percentage);
    SetColor(d->col.txbar);
    DrawLine(n, halfheight - 1, n, halfheight - h);

    percentage = comp_percentage(m.maxRX, d->Data.valuesRX[n] );
    h = comp_percent( (float)halfheight, percentage);
    SetColor(d->col.rxbar);
    DrawLine(n, halfheight + 1, n, halfheight + h);

    percentage = comp_percentage(m.maxAV, d->Data.loadavgs[n] );
    h = comp_percent( (float)height, percentage);
    pline[n].x = n;
    pline[n].y = height - h;

    n++;
  }
  SetColor(d->col.loadavg);
  DrawPolyline(pline, idx);

  //  SyncDisplay();
  SetDrawArea(d->Text.w);
  ClearDrawArea();
  idx -= idx < SAMPLES - 1;

  double loads[3];
  if(getloadavg(loads, 3) == 3) {
    char txt[TEXT * 2];
    snprintf(txt, TEXT * 2 - 1,
	     "rx: %8.2f (%8.2f) tx: %8.2f (%8.2f)",
	     d->Data.valuesRX[idx], m.maxRX,
	     d->Data.valuesTX[idx], m.maxTX);
    SetColor(d->col.txbar);
    DrawText(txt, 8, 14);

    struct sysinfo syi;
    updays up;
    if( !sysinfo( &syi) ) {
      sec2days(syi.uptime, &up);
    }
    else {
      memset( &up, 0, sizeof(updays) );
    }

    snprintf(txt, TEXT * 2 - 1,
	     "%5.2f %5.2f %5.2f (%5.2f), up: %d:%02d:%02d:%02d",
	     d->Data.loadavgs[idx], loads[1], loads[2], m.maxAV,
	     up.days, up.hours, up.minutes, up.seconds);
    SetColor(d->col.loadavg);
    DrawText(txt, 12, 28);
  }
  else {
    char txt[TEXT * 2];
    snprintf(txt, TEXT * 2 - 1,
	     "rx: %8.2f (%8.2f) tx: %8.2f (%8.2f), %5.2f (%5.2f)",
	     d->Data.valuesRX[idx], m.maxRX,
	     d->Data.valuesTX[idx], m.maxTX, d->Data.loadavgs[idx], m.maxAV);
    DrawText(txt, 10, d->Text.height - 10);
    puts("error: getloadavg() failed");
  }
  //  SyncDisplay();
}


void update_display(void *data) {
  mydata *d = data;

  if( !(d->notimeout) ) {
    get_data(d);
  }

  draw_bar(d);

  if( !(d->notimeout) ) {
    AddTimeOut(d->tick, update_display, data);
  }
  else {
    d->notimeout = 0;
  }
}


void cleanup(void *data) {
  mydata *d = data;
  if(d->t->rx != NULL) {
    fclose(d->t->rx);
  }
  if(d->t->tx != NULL) {
    fclose(d->t->tx);
  }
}


void  keypress(Widget w, char *input, int up_or_down, void *data) {
  if( *input == 'q') {
    mydata *d = data;
    cleanup(d);
    exit(0);
  }

  if(  ( *input == 't') && up_or_down) {
    char txt[TEXT];
    mydata *d = data;
    snprintf(txt, TEXT - 1, "%f", (float)(d->tick / 1000.0) );
    char *enter = GetText("Update Interval", txt, 128, 50);
    if(enter) {
      d->tick = (unsigned long)(atof(enter) * 1000.0);
      if(d->tick <= 0) {
	d->tick = 1000;
      }
    }
  }
}


void cb_drawarea(Widget w, int width, int height, void *data) {
  mydata *d = data;
  if(w == d->Data.w) {
    d->Data.width = width;
    d->Data.height = height;
  }
  if(w == d->Text.w) {
    d->Text.width = width;
    d->Text.height = height;
  }

  d->notimeout = 1;
  update_display(data);
}


int main(int argc, char *argv[] ) {

  if( !OpenDisplay(argc, argv) ) {
    puts("cannot open display");
    exit(1);
  }

  if(argc != 3) {
    puts("usage: bwstat interval /path/to/statsfile-rx /path/to/statsfile-tx");
    exit(1);
  }

  filestuff t;
  t.rx = fopen(argv[1], "r");
  if(t.rx == NULL) {
    perror(argv[1] );
    exit(2);
  }
  t.tx = fopen(argv[2], "r");
  if(t.tx == NULL) {
    perror(argv[2] );
    fclose(t.rx);
    exit(3);
  }

  bandwidth bw;
  memset( &bw, 0, sizeof(bandwidth) );
  rxtx new;
  memset( &new, 0, sizeof(rxtx) );
  rxtx old;
  memset( &old, 0, sizeof(rxtx) );

  mydata display;
  memset( &display, 0, sizeof(mydata) );
  display.t = &t;
  display.new = &new;
  display.old = &old;
  display.bw = &bw;
  display.Data.width = 360;
  display.Data.height = 201;
  display.Text.width = display.Data.width;
  display.Text.height = 32;
  display.notimeout = 0;
  display.tick = 5000;
  display.Data.w = MakeDrawArea(display.Data.width,
				display.Data.height,
				cb_drawarea, &display);
  display.Text.w = MakeDrawArea(display.Text.width,
				display.Text.height,
				cb_drawarea, &display);

  SetWidgetPos(display.Text.w, PLACE_UNDER, display.Data.w,
	       NO_CARE, NULL);
  SetKeypressCB(display.Data.w, keypress);
  SetKeypressCB(display.Text.w, keypress);

  ShowDisplay();

  display.col.rxbar = GetNamedColor("green");
  display.col.txbar = GetNamedColor("darkgreen");
  display.col.sepline = GetNamedColor("darkgoldenrod");
  display.col.loadavg = GetNamedColor("lightslategray");
  display.col.bg = GetNamedColor("gray6");

  SetBgColor(display.Data.w, display.col.bg);
  SetBgColor(display.Text.w, display.col.bg);

  update_display( (void *)( &display) );
  MainLoop();

  exit(0);
}




-- 
Fedora release 19 (Schrödinger’s Cat)
-- 
users mailing list
users@xxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe or change subscription options:
https://admin.fedoraproject.org/mailman/listinfo/users
Guidelines: http://fedoraproject.org/wiki/Mailing_list_guidelines
Have a question? Ask away: http://ask.fedoraproject.org




[Index of Archives]     [Older Fedora Users]     [Fedora Announce]     [Fedora Package Announce]     [EPEL Announce]     [EPEL Devel]     [Fedora Magazine]     [Fedora Summer Coding]     [Fedora Laptop]     [Fedora Cloud]     [Fedora Advisory Board]     [Fedora Education]     [Fedora Security]     [Fedora Scitech]     [Fedora Robotics]     [Fedora Infrastructure]     [Fedora Websites]     [Anaconda Devel]     [Fedora Devel Java]     [Fedora Desktop]     [Fedora Fonts]     [Fedora Marketing]     [Fedora Management Tools]     [Fedora Mentors]     [Fedora Package Review]     [Fedora R Devel]     [Fedora PHP Devel]     [Kickstart]     [Fedora Music]     [Fedora Packaging]     [Fedora SELinux]     [Fedora Legal]     [Fedora Kernel]     [Fedora OCaml]     [Coolkey]     [Virtualization Tools]     [ET Management Tools]     [Yum Users]     [Yosemite News]     [Gnome Users]     [KDE Users]     [Fedora Art]     [Fedora Docs]     [Fedora Sparc]     [Libvirt Users]     [Fedora ARM]

  Powered by Linux