home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / A / PS / PROCPS-0.000 / PROCPS-0 / procps-0.97 / vmstat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-25  |  8.1 KB  |  282 lines

  1. #define VERSION Version: 0.06, last modified 2 August 94: ALPHA 
  2. #define PROGNAME "vmstat"
  3. /* Copyright 1994 by Henry Ware <al172@yfn.ysu.edu>. Copyleft same year. */
  4. /* This attempts to display virtual memory statistics.
  5.  
  6.    vmstat should not run as root.
  7. */
  8. /* TODO etc.
  9.  * Count the system calls.  How?  I don't even know where to start.
  10.  * add more items- aim at Posix 1003.2 (1003.7?) compliance, if relevant (I.  
  11.    don't think it is, but let me know.)
  12.  * sometimes d(inter)<d(ticks)!!  This is not possible: inter is a sum of 
  13.    positive numbers including ticks.  But it happens.  This doesn't seem to
  14.    affect things much, however.
  15.  * It would be interesting to see when the buffers avert a block io:
  16.    Like SysV4's "sar -b"... it might fit better here, with Linux's variable 
  17.    buffer size.
  18.  * Ideally, blocks in & out would be counted in 1k increments, rather than
  19.    by block: this only makes a difference for CDs and is a problematic fix.
  20. */
  21. /* PROCPS
  22.    The procps suite is maintained as a suite by Charles Blake
  23.    <cblake@sdcc3.UCSD.EDU>.
  24. */
  25.    
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <ctype.h>
  29. #include <fcntl.h>
  30. #include <assert.h>
  31. #include <sys/types.h>
  32. #include <sys/dir.h>
  33. #include <linux/dirent.h>
  34. #include <limits.h>
  35. #include <unistd.h>
  36. #include <sys/ioctl.h>
  37.  
  38. #define NDEBUG !DEBUG
  39.  
  40. #define BUFFSIZE 1024
  41. #define FALSE 0
  42. #define TRUE 1
  43.  
  44. int main(int, char **);
  45. void usage(void);
  46. void crash(char *);
  47. int winhi(void);
  48. void showheader(void);
  49. void getstat(unsigned *, unsigned *, unsigned *, unsigned long *,
  50.          unsigned *, unsigned *, unsigned *, unsigned *,
  51.          unsigned *, unsigned *, unsigned *);
  52. void getmeminfo(unsigned *, unsigned *, unsigned *);
  53. void getrunners(unsigned *, unsigned *, unsigned *);
  54. static char buff[BUFFSIZE]; /* used in the procedures */
  55.  
  56. /***************************************************************
  57.                              Main 
  58. ***************************************************************/
  59.  
  60. int main(int argc, char *argv[]) {
  61.  
  62.   const char format[]="%2u %1u %1u %5u %5u %5u %3u %3u %4u %4u %4u %4u %3u %3u %3u\n";
  63.   unsigned int height=22; /* window height, reset later if needed. */
  64.   unsigned long int args[2]={0,0};
  65.   unsigned int moreheaders=TRUE;
  66.   unsigned int tog=0; /* toggle switch for cleaner code */
  67.   unsigned int i,hz;
  68.   unsigned int running,blocked,swapped;
  69.   unsigned int cpu_use[2], cpu_nic[2], cpu_sys[2];
  70.   unsigned int duse,dsys,didl,div,divo2;
  71.   unsigned int memfree,membuff,swapused;
  72.   unsigned long cpu_idl[2];
  73.   unsigned int pgpgin[2], pgpgout[2], pswpin[2], pswpout[2];
  74.   unsigned int inter[2],ticks[2],ctxt[2];
  75.   unsigned int per=0, pero2; 
  76.   unsigned long num=0;
  77.   
  78.   argc=0; /* redefined as number of integer arguments */
  79.   for (argv++;*argv;argv++) {
  80.     if ('-' ==(**argv)) {
  81.       if (*(++(*argv))=='n') {
  82.     /* print only one header */
  83.     moreheaders=FALSE;
  84.       }
  85.       else {
  86.     /* no other aguments defined yet. */
  87.     usage();
  88.       }
  89.     }
  90.     else {
  91.       if (!sscanf(*argv,"%lu",args+argc++)) usage();
  92.     }
  93.   }
  94.   switch (argc) {
  95.   case 0:  /* no numeric args */
  96.     per=1; 
  97.     num=0;
  98.     break;
  99.   case 1:
  100.     per=(unsigned) args[0];
  101.     num=ULONG_MAX;
  102.     break;
  103.   case 2:
  104.     per=(unsigned) args[0];
  105.     num=args[1];
  106.     break;
  107.   default : 
  108.     usage();
  109.     break;
  110.   }
  111.  
  112.   if (moreheaders) {
  113.       int tmp=winhi()-3;
  114.       height=((tmp>0)?tmp:22);
  115.   }    
  116.  
  117.   pero2=(per/2);
  118.   showheader();
  119.   getrunners(&running,&blocked,&swapped);
  120.   getmeminfo(&memfree,&membuff,&swapused);
  121.   getstat(cpu_use,cpu_nic,cpu_sys,cpu_idl,
  122.       pgpgin,pgpgout,pswpin,pswpout,
  123.       inter,ticks,ctxt);
  124.   duse= *(cpu_use)+ *(cpu_nic); 
  125.   dsys= *(cpu_sys);
  126.   didl= (*(cpu_idl))%UINT_MAX;
  127.   div= (duse+dsys+didl);
  128.   hz=sysconf(_SC_CLK_TCK); /* get ticks/s from system */
  129.   divo2= div/2;
  130.   printf(format,
  131.      running,blocked,swapped,
  132.      swapused,memfree,membuff,
  133.      (*(pswpin)*4*hz+divo2)/div,
  134.      (*(pswpout)*4*hz+divo2)/div,
  135.      (*(pgpgin)*hz+divo2)/div,
  136.      (*(pgpgout)*hz+divo2)/div,
  137.      (*(inter)*hz+divo2)/div,
  138.      (*(ctxt)*hz+divo2)/div,
  139.      (100*duse+divo2)/div,(100*dsys+divo2)/div,(100*didl+divo2)/div);
  140.  
  141.   for(i=1;i<num;i++) { /* \\\\\\\\\\\\\\\\\\\\ main loop ////////////////// */
  142.     sleep(per);
  143.     if (moreheaders && ((i%height)==0)) showheader();
  144.     tog= !tog;
  145.     getrunners(&running,&blocked,&swapped);
  146.     getmeminfo(&memfree,&membuff,&swapused);
  147.     getstat(cpu_use+tog,cpu_nic+tog,cpu_sys+tog,cpu_idl+tog,
  148.       pgpgin+tog,pgpgout+tog,pswpin+tog,pswpout+tog,
  149.       inter+tog,ticks+tog,ctxt+tog);
  150.     duse= *(cpu_use+tog)-*(cpu_use+!tog)+*(cpu_nic+tog)-*(cpu_nic+!tog);
  151.     dsys= *(cpu_sys+tog)-*(cpu_sys+!tog);
  152.     didl= (*(cpu_idl+tog)-*(cpu_idl+!tog))%UINT_MAX;
  153.     div= (duse+dsys+didl);
  154.     divo2= div/2;
  155.     printf(format,
  156.        running,blocked,swapped,
  157.        swapused,memfree,membuff,
  158.        (((*(pswpin+tog)-*(pswpin+(!tog)))*4+pero2)/per),
  159.        ((*(pswpout+tog)-*(pswpout+(!tog)))*4+pero2)/per,
  160.        (*(pgpgin+tog)-*(pgpgin+(!tog))+pero2)/per,
  161.        (*(pgpgout+tog)-*(pgpgout+(!tog))+pero2)/per,
  162.        (*(inter+tog)-*(inter+(!tog))+pero2)/per,
  163.        (*(ctxt+tog)-*(ctxt+(!tog))+pero2)/per,
  164.        (100*duse+divo2)/div,(100*dsys+divo2)/div,(100*didl+divo2)/div);
  165.   }
  166.   exit(EXIT_SUCCESS);
  167. }
  168.  
  169. /**************************** others ***********************************/
  170.  
  171. void usage(void) {
  172.   fprintf(stderr,"usage: %s [-n] [delay [count]]\n",PROGNAME);
  173.   fprintf(stderr,"              -n causes the headers not to be reprinted regularly.\n");
  174.   fprintf(stderr,"              delay is the delay between updates in seconds. \n");
  175.   fprintf(stderr,"              count is the number of updates.\n");
  176.   exit(EXIT_FAILURE);
  177. }
  178.  
  179. void crash(char *filename) {
  180.     perror(filename);
  181.     exit(EXIT_FAILURE);
  182. }
  183.  
  184. int winhi(void) {
  185.     struct winsize win;
  186.     int rows = 24;
  187.  
  188.     if (ioctl(1, TIOCGWINSZ, &win) != -1 && win.ws_row > 0)
  189.       rows = win.ws_row;
  190.  
  191.     return rows;
  192. }
  193.  
  194.  
  195. void showheader(void){
  196.   printf("%6s%18s%8s%10s%10s%12s\n",
  197.      "procs","memory","swap","io","system","cpu");
  198.   printf(" %1s %1s %1s %5s %5s %5s %3s %3s %4s %4s %4s %4s %3s %3s %3s\n",
  199.      "r","b","w","swpd","free","buff","si","so","bi","bo",
  200.      "in","cs","us","sy","id");
  201. }
  202.  
  203. void getstat(unsigned *cuse, unsigned *cice, unsigned *csys, unsigned long *cide,
  204.          unsigned *pin, unsigned *pout, unsigned *sin, unsigned *sout,
  205.          unsigned *itot, unsigned *i1, unsigned *ct) {
  206.   static int stat;
  207.  
  208.   if ((stat=open("/proc/stat", O_RDONLY, 0)) != -1) {
  209.     read(stat,buff,BUFFSIZE-1);
  210.     close(stat);
  211.     sscanf(buff,
  212. "cpu  %u %u %u %lu disk %*u %*u %*u %*u page %u %u swap %u %u intr %u %u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u ctxt %u",
  213.        cuse, cice, csys, cide,
  214.        pin, pout, sin, sout, itot, i1, ct);
  215.     assert(*itot>*i1);
  216.   }
  217.   else {
  218.     crash("/proc/stat");
  219.   }
  220. }
  221.  
  222. void getmeminfo(unsigned *memfree, unsigned *membuff, 
  223.             unsigned *swapused) {
  224.   static int mem;
  225.  
  226.   if ((mem = open("/proc/meminfo", O_RDONLY, 0)) != -1) {
  227.     read(mem,buff,BUFFSIZE-1);
  228.     close(mem);
  229.     sscanf(buff, "%*s %*s %*s %*s %*s %*s %*u %*u %u %*u %u %*s %*u %u %*u",
  230.        memfree,membuff,swapused);
  231.     *memfree /= 1024; /* bytes to k of course. */
  232.     *membuff /= 1024;
  233.     *swapused /= 1024;
  234.   }
  235.   else {
  236.     crash("/proc/meminfo");
  237.   }
  238. }
  239.  
  240. void getrunners(unsigned int *running, unsigned int *blocked, 
  241.         unsigned int *swapped) {
  242.   static struct direct *ent;
  243.   static char filename[80];
  244.   static int fd;
  245.   static unsigned size;
  246.   static char c;
  247.   DIR *proc;
  248.  
  249.   *running=0;
  250.   *blocked=0;
  251.   *swapped=0;
  252.  
  253.   if ((proc=opendir("/proc"))==NULL) crash("/proc");
  254.  
  255.   while((ent=readdir(proc))) {
  256.     if (isdigit(ent->d_name[0])) {  /*just to weed out the obvious junk*/
  257.       sprintf(filename, "/proc/%s/stat", ent->d_name);
  258.       if ((fd = open(filename, O_RDONLY, 0)) != -1) { /*this weeds the rest*/
  259.     read(fd,buff,BUFFSIZE-1);
  260.     sscanf(buff, "%*d %*s %c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %*u %*u %*d %*u %u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u\n",&c,&size);
  261.     close(fd);
  262.  
  263.     if (c=='R') {
  264.       if (size>0) (*running)++;
  265.       else (*swapped)++;
  266.         }
  267.     else if (c=='D') {
  268.       if (size>0) (*blocked)++;
  269.       else (*swapped)++;
  270.         }
  271.       }
  272.     }
  273.   }
  274.   closedir(proc);
  275.  
  276. #if 1
  277.   /* is this next line a good idea?  It removes this thing which
  278.      uses (hopefully) little time, from the count of running processes */
  279.   (*running)--;
  280. #endif
  281. }
  282.