/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/ccs/lib/libperfstat/simpleadapterstat.c 1.3.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[] = "@(#)63        1.3.1.1  src/bos/usr/ccs/lib/libperfstat/simpleadapterstat.c, libperfstat, bos720 4/21/10 08:16:37";

/* simpleadapterstat.c                                                    */ 
/* Sample  program  used to  display  the statistics of diskadapter.      */ 
/* This  program does not give any data when run inside a workload        */ 
/* partition.								  */   

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

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


/* To Check whether malloc is successful or not */

#define CHECK_FOR_MALLOC_NULL(X) {  if ((X) == NULL) {\
                                       perror ("malloc");\
                                       exit(2);\
                                     }\
                                 }
/* Default values for interval and count  */
#define INTERVAL_DEFAULT 1
#define COUNT_DEFAULT 1

/* 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 *);

/* variables and data structures declaration */

static perfstat_diskadapter_t *statp, *statq;
static int num_adapt;
static int interval = INTERVAL_DEFAULT;
static int count = COUNT_DEFAULT;
static int rc;

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

cid_t cid;               /* store the WPAR cid */



/*
 * 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
 *    - exit with code 1.
 */

static int do_initialization(void)
{
   if (collect_remote_node_stats){
       strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
       nodeid.spec = NODENAME;
       /* Get the total number of disk adapters available  in the current system */
       num_adapt = perfstat_diskadapter_node(&nodeid, NULL, sizeof(perfstat_diskadapter_t), 0);
   }
   else{
       /* Get the total number of disk adapters available  in the current system */
       num_adapt = perfstat_diskadapter(NULL, NULL, sizeof(perfstat_diskadapter_t), 0);
   } 

   if (num_adapt == 0) {
       printf("There are no disk adapters.\n");
       exit(0);
   }

   if (num_adapt < 0) {
       perror("perfstat_diskadapter: ");
       exit(1);
   }
		   
   /* Allocate sufficient memory for perfstat structures */
			
   statp = (perfstat_diskadapter_t *)malloc(sizeof(perfstat_diskadapter_t) * num_adapt);
   CHECK_FOR_MALLOC_NULL(statp);
  
   statq = (perfstat_diskadapter_t *)malloc(sizeof(perfstat_diskadapter_t) * num_adapt);
   CHECK_FOR_MALLOC_NULL(statq);
   
   /* Make the structures as 0 */  
   memset(statq, 0, (sizeof(perfstat_diskadapter_t) * num_adapt));

   memset(statp, 0, (sizeof(perfstat_diskadapter_t) * num_adapt));

   return (0);
}

/*
 *NAME:  Showusage
 *        This function displays the usage
 */


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_cleanup
 *       This function frees the memory allocated for the perfstat structures.
 * 
 */

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

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


/*
 * NAME: collect_diskadapter_metrics
 *       This function collects the raw values in to
 *       the specified structures and derive the metrics from the
 *       raw values
 *
 */ 

void collect_diskadapter_metrics(void)
{
   perfstat_id_t first;
   unsigned long long delta_read, delta_write,delta_xfers, delta_xrate;

   if(collect_remote_node_stats) {
       strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
       nodeid.spec = NODENAME;
       strcpy(nodeid.name, FIRST_DISKADAPTER);
       rc = perfstat_diskadapter_node(&nodeid ,statq, sizeof(perfstat_diskadapter_t),num_adapt);			
   }
   else {
       strcpy(first.name, FIRST_DISKADAPTER);
       rc = perfstat_diskadapter(&first ,statq, sizeof(perfstat_diskadapter_t),num_adapt);			
   }

   if (rc < num_adapt){
       perror("perfstat_diskadapter: ");
       exit(1);
   }

   /* Name - name of the diskadapter
    * Disks- number of disks connected
    * Size - total size of all the disks
    * Free - free space on disk
    * ARS  - average read per second
    * AWS  - average write per second
    */

   printf("\n%-8s %7s %8s %8s %8s %8s\n", " Name ", " Disks ", " Size ", " Free ", " ARS ", " AWS ");
   printf("%-8s %7s %8s %8s %8s %8s\n", "======", "======", "======", "======", "=====", "=====");
	
   while (count > 0) {
       sleep(interval);
        
       if(collect_remote_node_stats) {
           rc = perfstat_diskadapter_node(&nodeid, statp, sizeof(perfstat_diskadapter_t), num_adapt);
       }
       else {
           rc = perfstat_diskadapter(&first ,statp, sizeof(perfstat_diskadapter_t),num_adapt);
       }

       if (rc < num_adapt ) {
	   perror("perfstat_diskadapter:");
           exit(-1);
       }

       /* print statistics for each of the diskadapter */
       for (int i = 0; i < rc; i++) {
            delta_write = statp[i].wblks - statq[i].wblks;
	    delta_read  = statp[i].rblks - statq[i].rblks;
            delta_xfers = statp[i].xfers - statq[i].xfers;
            delta_xrate = statp[i].xrate - statq[i].xrate;

	    printf("%-8s %7d %8llu %8llu %8llu %8llu\n", statp[i].name, statp[i].number,
	                 statp[i].size, statp[i].free, (u_longlong_t)(delta_read / (statp[i].xrate - statq[i].xrate)),
	                 (u_longlong_t)(delta_write / (delta_xfers - delta_xrate)));
       }

       /* copy to the old data structures */
       memcpy(statq, statp, sizeof(perfstat_diskadapter_t) * num_adapt);
       count--;
       printf("\n");
   }
   /* Free all the memory allocated for all the data structures */
   do_cleanup();
}


/*
 *NAME: main 
 *
 */

int main(int argc, char* argv[]) 
{
   int i;
   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);
       }
   }
   do_initialization();
   /* call the functions to collect the metrics and display them */
   collect_diskadapter_metrics();
   
   if(collect_remote_node_stats)
   {   /* Now disable cluster statistics by calling perfstat_config */
       perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL);
   }
   return (0);
}



