/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/ccs/lib/libperfstat/simplediskstat.c 1.5.1.1        */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2008,2010              */
/* 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[] = "@(#)64        1.5.1.1  src/bos/usr/ccs/lib/libperfstat/simplediskstat.c, libperfstat, bos720 4/21/10 08:25:18";

/* The sample program retrieves the metrics                               */
/* related to each and every individual disk in the LPAR                  */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <libperfstat.h>
#include <errno.h>
#include <wpars/wparcfg.h>

/* Non zero WPAR ID indicates WPAR */
#define IS_WPAR(X) ((X))

/* Default values for interval and count */
#define INTERVAL_DEFAULT  1	
#define COUNT_DEFAULT  	  1	

/* To Check whether malloc is successful or not */
#define CHECK_FOR_MALLOC_NULL(X) {  if ((X) == NULL) {\
                                       perror ("malloc");\
                                       exit(2);\
                                     }\
                                 }

/* Stores the information related to Individual disks*/
static perfstat_disk_t *statp, *statq;

/* Used to store the current corral id */
cid_t cid;

static int ndisks;    /*  number of disks */
static int interval = INTERVAL_DEFAULT;
static int count = COUNT_DEFAULT ;
static int rc;

/* support for remote node statistics collection in a cluster environment */
perfstat_id_node_t nodeid;
static char nodename[MAXHOSTNAMELEN];
static int collect_remote_node_stats = 0;

/* Function prototypes */
static int do_initialization(void);
static void do_cleanup(void);
static void collect_disk_metrics(void);
static void print_disk_header(void);
static void showusage(char *);


/*
 *NAME: showusage
 *      This function displays the usage syntax
 *
 */

static void showusage(char *cmd)
{
   fprintf (stderr, "usage: %s [-i <interval in seconds> ] [-c <number of iterations> ] [-n <node name in the cluster> ]\n", cmd);
   exit(1);
}


/*
 * NAME: do_initialization
 *       This function initializes the data structues.
 *       It also collects initial set of values.
 * 
 * RETURNS:
 * On successful completion:
 *   - returns 0.
 * In case of error
 *   - exits with code 1.
 */

static int do_initialization(void)
{
   int rc;

   /* Get the total number of disks available */
   if(collect_remote_node_stats) {
       strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
       nodeid.spec = NODENAME;
       ndisks = perfstat_disk_node(&nodeid, NULL,sizeof(perfstat_disk_t), 0);
   }
   else {
       ndisks = perfstat_disk(NULL, NULL,sizeof(perfstat_disk_t), 0);
   }

   if (ndisks == 0) {
	   printf("no disk found\n");
	   exit(0);
   }
   if (ndisks < 0) {
   	   perror("perfstat_disk: ");
	   exit(1);
   }
		   
   /* Allocate sufficient memory */
			
   statp = (perfstat_disk_t *)malloc(sizeof(perfstat_disk_t) * ndisks);
   CHECK_FOR_MALLOC_NULL(statp);
			
   statq = (perfstat_disk_t *)malloc(sizeof(perfstat_disk_t) * ndisks);
   CHECK_FOR_MALLOC_NULL(statq);
   
   /* Initialize the structures to zero */
   memset(statq, 0, (sizeof(perfstat_disk_t) * ndisks));
   memset(statp, 0, (sizeof(perfstat_disk_t) * ndisks));
   
   return(0);
}

/*
 * NAME: do_cleanup
 *       This function cleans up the data structues allocated.
 * 
 */

static void do_cleanup(void)
{
   if (statp) {
       free(statp);
   }

   if (statq) {
       free(statq);
   }
}

/*
 *NAME: collect_disk_metrics
 *      This function collects the metrics for all available disks.
 *
 */

void collect_disk_metrics(void)
{
   unsigned long long delta_read, delta_write,delta_xrate, delta_xfers;

   perfstat_id_t first;
 
   /*call do_initialisation and allocate memory for the data structures */
   do_initialization();
 
		
   /* ask to get all the structures available in one call */
   /* return code is number of structures returned */
		
   if(collect_remote_node_stats) {
       strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
       nodeid.spec = NODENAME;
       strcpy(nodeid.name, FIRST_DISK);
       rc = perfstat_disk_node(&nodeid, statq, sizeof(perfstat_disk_t), ndisks);
   }
   else {
       strcpy(first.name, FIRST_DISK);
       rc = perfstat_disk(&first, statq, sizeof(perfstat_disk_t), ndisks);
   }

   if (rc < ndisks) {
       perror("perfstat_disk:");
       exit(-1);
   }	
   while (count > 0) {

       sleep (interval);
       if(collect_remote_node_stats) {
           rc = perfstat_disk_node(&nodeid, statp, sizeof(perfstat_disk_t), ndisks);
       }
       else {
           rc = perfstat_disk(&first, statp, sizeof(perfstat_disk_t), ndisks);
       }
         
       if (rc < ndisks ) {
           perror("perfstat_disk:");
           exit(-1);
 	   }
 
       /* print statistics for each of the disks */
	   for (int i = 0; i < rc; i++) {
	    	delta_write = statp[i].wserv - statq[i].wserv;
 	        delta_read  = statp[i].rserv - statq[i].rserv;
                delta_xfers = statp[i].xfers - statq[i].xfers;
                delta_xrate = statp[i].xrate - statq[i].xrate;
		printf("%-10s %10llu %10llu %10llu %13llu %8llu %10llu %13llu %8llu \n", 
                          	statp[i].name, statp[i].size,
                            	statp[i].free, statp[i].min_rserv,
                	    	statp[i].max_rserv,
                            	delta_read / delta_xrate,
                            	statp[i].min_wserv, statp[i].max_wserv,
                            	delta_write / (delta_xfers - delta_xrate));
       }
       memcpy(statq, statp, sizeof(perfstat_disk_t)*ndisks);
       count--;
       printf("\n");
   }

   /* remove all data structures */
   do_cleanup();
}

/*
 *NAME: print_disk_header
 *      This function gets the lpar info and prints the header
 *
 */
 
void print_disk_header()
{
   /* To Store the LPAR level disk information */

   perfstat_disk_total_t dinfo;

   /* gather LPAR level disk data */
   perfstat_disk_total(NULL, &dinfo, sizeof(perfstat_disk_total_t), 1);

   /* Check how many perfstat_disk_t structures are available*/
   ndisks = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0);
		   
   if (ndisks <= 0){
       perror("perfstat_disk:");
       exit(1);
   }
		   
   /* Print the count of DISKS in the LPAR */
   printf("\nDisks             = %d \n",dinfo.number); 
		   
   /* Print the total size of all disks */
   printf("Size (in MB)      = %llu \n",dinfo.size); 

   /* Print the amount time disks are active */
   printf("Active time       = %llu\n",dinfo.time);

   /* Print the free portion of all disks */
   printf("Free space(in MB) = %llu\n\n",dinfo.free);

   /* Name   - name of the disk
    * Size   - size of the disk
    * Free   - free space on the disk
    * MinRST - minimum read service time
    * MaxRST - maximum read service time
    * AvgRST - average read service time
    * MinWST - minimum write service time
    * MaxWST - maximum write service time
    * AvgWST - average write service time
    */

   printf("%-10s %10s %10s %10s %13s %8s %10s %13s %8s\n", "Name", "Size(MB)", "Free(MB)", "MinRST", "MaxRST",
							   "AvgRST", "MinWST", "MaxWST", "AvgWST");
   printf("%-10s %10s %10s %10s %13s %8s %10s %13s %8s\n", "----", "--------", "--------", "------", "------",
							   "------","------","------","------");
}


/*
 *NAME:  main
 *
 */

int main(int argc, char* argv[]) 
{
   int i;
   /* get the current corral's cid */		   
   cid = corral_getcid();
   /* Check Whether running Inside WPAR or on Global*/
   if(IS_WPAR(cid)) {
	  printf("The metrics requested for WPAR cannot be retrieved.\n");
	  exit(1);
   }

   /* Process the arguments */
   while ((i = getopt(argc, argv, "i:c:n:")) != EOF)
   {
       switch(i)
       {
           case 'i':               /* Interval */
                    interval = atoi(optarg);
                    if( interval <= 0 )
                        interval = INTERVAL_DEFAULT;
                    break;
           case 'c':               /* Number of interations */
                    count = atoi(optarg);
                    if( count <= 0 )
                        count = COUNT_DEFAULT;
                    break;
           case 'n':               /* Node name in a cluster environment */
                    strncpy(nodename, optarg, MAXHOSTNAMELEN);
                    nodename[MAXHOSTNAMELEN-1] = '\0';
                    collect_remote_node_stats = 1;
                    break;
           default:
                   /* Invalid arguments. Print the usage and terminate */
                   showusage(argv[0]);
       }
   }

   if(collect_remote_node_stats)
   {   /* perfstat_config needs to be called to enable cluster statistics collection */
       rc = perfstat_config(PERFSTAT_ENABLE|PERFSTAT_CLUSTER_STATS, NULL);
       if (rc == -1)
       {
           perror("cluster statistics collection is not available");
           exit(-1);
       }
   }

   print_disk_header();
   collect_disk_metrics();

   if(collect_remote_node_stats)
   {   /* Now disable cluster statistics by calling perfstat_config */
       perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL);
   }

   return(0);
}
