/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/ccs/lib/libperfstat/simplesysinfo.c 1.3             */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2008                   */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
static char sccsid[] = "@(#)68        1.3  src/bos/usr/ccs/lib/libperfstat/simplesysinfo.c, libperfstat, bos720 8/8/08 07:16:39";

/* The sample program used to display the sysinfo metrics                 * 
 * The first iteration values indicate the values from system startup     *
 * From next iteration it gives the metrics of that interval              */

#include <stdio.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <sys/proc.h>
#include <wpars/wparcfg.h>
#include <libperfstat.h>
#include <stdlib.h>

/* default values for interval and count */

#define INTERVAL_DEFAULT  1
#define COUNT_DEFAULT     1

/* values for wpar status */

#define ACTIVE 		  0 
#define NOTACTIVE	  1 

/* Check value returned by malloc for NULL */
#define CHECK_FOR_MALLOC_NULL(X) {  if ((X) == NULL) {\
                                       perror ("malloc");\
                                       exit(2);\
                                        }\
                                  }

/* Non zero WPAR ID indicates WPAR */

#define IS_WPAR(X) ((X))

 /* stores wpar id for perfstat library */

perfstat_id_wpar_t     wparid;
perfstat_wpar_total_t  wparinfo;
perfstat_wpar_total_t *wparlist;

 /*Corral id for WPAR */

cid_t cid;


int interval = INTERVAL_DEFAULT, count = COUNT_DEFAULT;
int totalwpar, activewpar;   /* to store and number of wpars available and active wpars */

/*
 *Name: do_cleanup
 *      free all allocated data structures
 */

void do_cleanup(void)
{
   if (wparlist)
       free(wparlist);	
 
}

/*
 *Name: display_global_sysinfo_stat
 *      Function used when called from global. 
 *      Gets all the system metrics using perfstat APIs and displays them 
 *
 */

void display_global_sysinfo_stat(void)
{
   perfstat_cpu_total_t *cpustat,*cpustat_last;
   perfstat_id_t first;

   /* allocate memory for data structures and check for any error */
 
   cpustat = (perfstat_cpu_total_t *)malloc(sizeof(perfstat_cpu_total_t));
   CHECK_FOR_MALLOC_NULL(cpustat);

   cpustat_last = (perfstat_cpu_total_t *)malloc(sizeof(perfstat_cpu_total_t));
   CHECK_FOR_MALLOC_NULL(cpustat_last);

   /* get the system wide statistics */

   if (perfstat_cpu_total(NULL , cpustat_last, sizeof(perfstat_cpu_total_t), 1) <= 0){
       perror("perfstat_cpu_total ");
       exit(1);
   }

   printf ("%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n", "cswch", "scalls", "sread", "swrite", "fork", "exec", 
							"rchar", "wchar", "deviceint", "bwrite", "bread", "phread");
   printf ("%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n", "=====", "======", "=====", "======", "====", "====", 
							"=====", "=====", "=========", "======", "=====", "======"); 
   while (count > 0){
       sleep(interval);
       if (perfstat_cpu_total(NULL ,cpustat, sizeof(perfstat_cpu_total_t), 1) <= 0){
           perror("perfstat_cpu_total ");
           exit(1);
       }
       /* print the difference between the old structure and new structure */ 
       printf("%10llu %10llu %10llu %10llu %10llu %10llu %10llu %10llu %10llu %10llu %10llu %10llu\n",(cpustat->pswitch - cpustat_last->pswitch),
                                                         (cpustat->syscall - cpustat_last->syscall), (cpustat->sysread - cpustat_last->sysread ),
                                                         (cpustat->syswrite - cpustat_last->syswrite),(cpustat->sysfork - cpustat_last->sysfork),
							 (cpustat->sysexec - cpustat_last->sysexec ), (cpustat->readch - cpustat_last->readch),
							 (cpustat->writech - cpustat_last->writech ),(cpustat->devintrs - cpustat_last->devintrs),
                                                         (cpustat->bwrite - cpustat_last->bwrite), (cpustat->bread - cpustat_last->bread ),
                                                         (cpustat->phread - cpustat_last->phread ));
       count--;

       /*copy the present structure to the old structure */
       memcpy(cpustat_last , cpustat , sizeof(perfstat_cpu_total_t));
   }
   /* free the memory allocated for the data structures */
   free(cpustat);
   free(cpustat_last);

}
 
/*
 *Name: display_wpar_sysinfo_stat
 *      Displays both wpar and global metrics 
 *
 */

void display_wpar_sysinfo_stat(void)
{
   perfstat_wpar_total_t wparinfo;
   perfstat_cpu_total_wpar_t cinfo_wpar, cinfo_wpar_last;
   perfstat_cpu_total_t sysinfo, sysinfo_last;

   /* ste the spec and pass the wparname */ 
   wparid.spec = WPARNAME;
   strcpy(wparid.u.wparname, NULL);
   
   /* save the number of wpars which are active */
   activewpar = perfstat_wpar_total( NULL , &wparinfo ,sizeof(perfstat_wpar_total_t), 1);

   /* if the activewpar is less than zero exit with a perror */
   if (activewpar < 0){
       perror("perfstat_wpar_total :");
       exit(1); 
   }

   /* if the wpar is not active exit with a message */
   if (activewpar == 0){
       printf("wpar not active \n");
       exit(1);
   } 
   
   /* get the wpar wide cpu information */ 
   if (perfstat_cpu_total_wpar(NULL, &cinfo_wpar_last, sizeof(perfstat_cpu_total_wpar_t), 1) <=0){
       perror("perfstat_cpu_total_wpar :");
       exit(1);
   }
   if (perfstat_cpu_total(NULL , &sysinfo_last, sizeof(perfstat_cpu_total_t), 1) <=0){
       perror("perfstat_cpu_total_wpar :");
       exit(1);
   }
   printf("%10s %10s %10s %10s %10s %10s %10s %10s\n","wparname ", "cswch" , "syscalls", "fork","runque", "swpque", "runocc", "swpocc" );
   printf("%10s %10s %10s %10s %10s %10s %10s %10s\n","======== ", "=====" , "========", "====","======", "======", "======", "======" );

   while (count > 0){
       sleep(interval);
       if (perfstat_cpu_total_wpar( NULL,&cinfo_wpar,  sizeof(perfstat_cpu_total_wpar_t), 1) <=0){
           perror("perfstat_cpu_total_wpar :");
           exit(1);
       }
       if (perfstat_cpu_total(NULL, &sysinfo, sizeof(perfstat_cpu_total_t), 1) <=0){
           perror("perfstat_cpu_total :");
           exit(1);
       }
      
       /* display the difference between the current and old structure for the current wpar and system wide values*/ 
       printf("%10s %10llu %10llu %10llu %10llu %10llu %10llu %10llu\n",wparinfo.name, (cinfo_wpar.pswitch - cinfo_wpar_last.pswitch),
				(cinfo_wpar.syscall - cinfo_wpar_last.syscall), (cinfo_wpar.sysfork - cinfo_wpar_last.sysfork), 
				(cinfo_wpar.runque - cinfo_wpar_last.runque), (cinfo_wpar.swpque - cinfo_wpar_last.swpque), 
				(cinfo_wpar.runocc - cinfo_wpar_last.runocc), (cinfo_wpar.swpocc - cinfo_wpar_last.swpocc));

       printf("%10s %10llu %10llu %10llu %10llu %10llu %10llu %10llu\n\n", "Global", (sysinfo.pswitch - sysinfo_last.pswitch),
				(sysinfo.syscall - sysinfo_last.syscall), (sysinfo.sysfork - sysinfo_last.sysfork), 
				(sysinfo.runque - sysinfo_last.runque), (sysinfo.swpque - sysinfo_last.swpque), 
				(sysinfo.runocc - sysinfo_last.runocc), (sysinfo.swpocc - sysinfo_last.swpocc));
       count--;

       /* copy the data to the old structure */
       memcpy(&cinfo_wpar_last, &cinfo_wpar, sizeof(perfstat_wpar_total_t));
       memcpy(&sysinfo_last , &sysinfo , sizeof(perfstat_cpu_total_t));
   }
}
  
/* Name: display_wpar_total_sysinfo_stat
 *       displays statistics of individual wpar 
 *
 */
 
int display_wpar_total_sysinfo_stat(void)
{
   int i, *status;
   perfstat_wpar_total_t *wparinfo;
   perfstat_cpu_total_wpar_t *cinfo_wpar, *cinfo_wpar_last;
 
   /* allocate memory for the datastructures and check for any error */ 
   status = (int *) calloc(totalwpar ,sizeof(int));
   CHECK_FOR_MALLOC_NULL(status);

   cinfo_wpar = (perfstat_cpu_total_wpar_t *) malloc(sizeof (perfstat_cpu_total_wpar_t) * totalwpar);
   CHECK_FOR_MALLOC_NULL(cinfo_wpar);

   cinfo_wpar_last = (perfstat_cpu_total_wpar_t *) malloc(sizeof (perfstat_cpu_total_wpar_t) * totalwpar); 
   CHECK_FOR_MALLOC_NULL(cinfo_wpar_last);

   wparlist = (perfstat_wpar_total_t *) malloc(sizeof(perfstat_wpar_total_t) * totalwpar);
   CHECK_FOR_MALLOC_NULL(wparlist);

   activewpar = perfstat_wpar_total(&wparid, wparlist, sizeof(perfstat_wpar_total_t), totalwpar);
   
   if (activewpar < 0){
       perror("perfstat_wpar_total :");
       exit(1);
   }

   /* If no active wpars exit with a message */
   if (activewpar == 0){
       printf("no active wpars found \n");
       exit(1);
   }
   for (i = 0; i < activewpar; i++){
        /* copy the wparname into wparid and collect the data for all active wpars */
        strcpy(wparid.u.wparname, wparlist[i].name);
        if (perfstat_cpu_total_wpar(&wparid, &cinfo_wpar_last[i], sizeof(perfstat_cpu_total_wpar_t), 1) <= 0){
            status[i] = NOTACTIVE;
            continue;
        }
   }
   /*print the headers */ 
   printf("%20s %12s %12s %12s %12s %12s %12s %12s\n","wparname", "cswitch", "fork", "runque", "swpque", "runocc", "swpocc", "syscalls");
   printf("%20s %12s %12s %12s %12s %12s %12s %12s\n","========", "=======", "====", "======", "======", "======", "======", "========");
 
   while (count > 0){
         sleep(interval);
         for (i = 0; i < activewpar; i++){
              strcpy(wparid.u.wparname, wparlist[i].name);
              if (perfstat_cpu_total_wpar(&wparid, &cinfo_wpar[i], sizeof(perfstat_cpu_total_wpar_t), 1) <= 0){
                  status[i] = NOTACTIVE;
                  continue;
              }
         }
	 /* print the data for all active wpars */
         for (i = 0; i < activewpar; i++){
              if(status[i] == ACTIVE)
              printf("%20s %12llu %12llu %12llu %12llu %12llu %12llu %12llu\n", wparlist[i].name,
			(cinfo_wpar[i].pswitch - cinfo_wpar_last[i].pswitch), (cinfo_wpar[i].sysfork - cinfo_wpar_last[i].sysfork),
			(cinfo_wpar[i].runque - cinfo_wpar_last[i].runque), (cinfo_wpar[i].swpque - cinfo_wpar_last[i].swpque),
			(cinfo_wpar[i].runocc - cinfo_wpar_last[i].runocc), (cinfo_wpar[i].swpocc - cinfo_wpar_last[i].swpocc),
			(cinfo_wpar[i].syscall- cinfo_wpar_last[i].syscall));
         }
         printf("\n");
         count--;
         memcpy(cinfo_wpar_last,cinfo_wpar,(totalwpar * sizeof(perfstat_cpu_total_wpar_t)));
   }
   /* free all the memory structures */
   free(cinfo_wpar);
   free(cinfo_wpar_last);
   free(status); 
}

/*
 *Name: showusage
 *      displays the usage message
 *
 */

void showusage()
{
   if (!cid)
       printf("Usage:simplesysinfo [-@ { ALL | WPARNAME }] [interval] [count]\n ");
   else
       printf("Usage:simplesysinfo [interval] [count]\n");

   exit(1);
}
 
/* NAME: main
 *       This function determines the interval, iteration count.
 *       Then it calls the corresponding functions to display
 *       the corresponding metrics
 */

int main(int argc, char* argv[])
{  
   int rc ,atflag = 0, c;
   char wpar[MAXCORRALNAMELEN+1];
   strcpy(wpar, NULL);
   cid = corral_getcid();
    
   while((c = getopt(argc, argv, "@:"))!= EOF){
        if (c == '@'){
            if (IS_WPAR(cid))
                showusage();
            atflag = 1;
            strcpy(wpar, optarg);
        }
   }
   argc -= optind;
   argv += optind;
   
   if (argc > 2)
       showusage();

   if (argc){
       if ((interval = atoi(argv[0])) <= 0)
           showusage();
       argc--;
   }

   if (argc){
       if ((count = atoi(argv[1])) <= 0)
           showusage();
   }      

       
 /* If no -@ flag call display_global_sysinfo_stat function */ 
   if (!atflag ){
       if (!cid)
           /*display global values */
           display_global_sysinfo_stat();
       else
           /* display wpar values */
           display_wpar_sysinfo_stat();
   } 
   else{
       /* if the argument to -@ is not ALL set the totalwpars to 1 */
       if (strcmp(wpar, "ALL")) {
           strcpy(wparid.u.wparname, wpar);
           wparid.spec = WPARNAME;
           totalwpar = 1;
       }
       else{
	   totalwpar = perfstat_wpar_total(NULL, NULL, sizeof(perfstat_wpar_total_t), 0);
 
           if (totalwpar < 0){
               perror("perfstat_wpar_total : ");
               exit(1);
           }
           if (totalwpar == 0){
               printf("No wpars found");
               exit(1);
           }
           wparid.spec = WPARNAME;
           strcpy(wparid.u.wparname, NULL);
      }
      display_wpar_total_sysinfo_stat();
     
   }
   do_cleanup();
   return(0);
}
