/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/ccs/lib/libperfstat/simpleperfstatthread.c 1.1      */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2013                   */
/* 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                                                     */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libperfstat.h>
#include <errno.h>
#include <procinfo.h>
#include <sys/types.h>

/* define default interval and count values */
#define INTERVAL_DEFAULT 1 
#define COUNT_DEFAULT    1

/* Check value returned by malloc for NULL */

#define CHECK_FOR_MALLOC_NULL(X) {  if ((X) == NULL) {\
                                       perror ("malloc");\
                                       exit(2);\
                                     }\
                  }

static int returncode=0, count = COUNT_DEFAULT, interval = INTERVAL_DEFAULT;
perfstat_thread_t *p,*q,*agg_proc;;
perfstat_rawdata_t buf;
int thrds_count=0,i,max_sorted;

/*
 * NAME: showusage
 *       to display the usage
 *
 */

void showusage()
{
	fprintf(stderr,"usage: [-i <interval in seconds> ] [-c <number of iterations> ]\n");
	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.
 */

int do_initialization(void)
{
	thrds_count= perfstat_thread(NULL,NULL,sizeof(perfstat_thread_t),0);
	p=(perfstat_thread_t*)malloc(sizeof(perfstat_thread_t)*thrds_count);
	CHECK_FOR_MALLOC_NULL(p);
	
	q=(perfstat_thread_t*)malloc(sizeof(perfstat_thread_t)*thrds_count);
	CHECK_FOR_MALLOC_NULL(q);
	
	agg_proc = (perfstat_thread_t *)malloc(thrds_count* sizeof(perfstat_thread_t));
	CHECK_FOR_MALLOC_NULL(agg_proc);
	
}

static void do_cleanup()
{
   free(p);
   free(q);
   free(agg_proc);
}

void display_metrics(void)
{
	while(count){
				
		/* Obtain the thread's count value by calling perfstat_thread API with name, userbuff as  NULL and desired number as 0*/ 
		max_sorted = perfstat_thread(NULL,NULL,sizeof(perfstat_thread_t),0);
		if(max_sorted <=0){
			fprintf(stdout, "perfstat_thread_util call failed with error %d\n");
			return(-1);
		}
		
		/* Fill the userbuff(q) with deatials PID,TID,CPU time,Bound cpu id details */
		max_sorted=perfstat_thread(NULL,q,sizeof(perfstat_thread_t),thrds_count);
		if(max_sorted <=0){
			fprintf(stdout, "perfstat_thread_util call failed with error %d\n");
			return(-1);
		}
		
		/* Fileds of q will be used as previous satistics in perfstat_thread_util
		 * to calculate cpu utilization*/
		bzero(&buf, sizeof(perfstat_rawdata_t));
        buf.prevstat = q;
        buf.sizeof_data = sizeof(perfstat_thread_t);
        buf.prev_elems = max_sorted;
 
		sleep(interval);
				
		/* Fill the userbuff(q) with deatials PID,TID,CPU time,Bound cpu id details */
		max_sorted = perfstat_thread(NULL,p,sizeof(perfstat_thread_t),thrds_count);
		if(max_sorted <=0){
			fprintf(stdout, "perfstat_thread_util call failed with error %d\n");
			return(-1);
		}
		
		/* Fileds of p will be used as current satistics in perfstat_thread_util
		 * to calculate cpu utilization*/
		buf.curstat = p;
		buf.cur_elems = max_sorted;

		/* perfstat_thread_util API uses current and previous statistics to and give cpu utilizqation% */
        max_sorted=perfstat_thread_util(&buf,agg_proc,sizeof(perfstat_thread_t),thrds_count);
        if(max_sorted <=0){
            fprintf(stdout, "perfstat_thread_util call failed with error %d\n");
			return(-1);
        }

		for(i=0;i<max_sorted;i++){
			fprintf(stdout,"Process=%u	Thread=%u      Bound=%d\n",agg_proc[i].pid,agg_proc[i].tid,agg_proc[i].cpuid);
			fprintf(stdout,"cpu utilization=%f\n",(agg_proc[i].ucpu_time+agg_proc[i].scpu_time)*100);
		}
		count--;
	}
}

/*  This program gives the usage of perfstat_thread and perfstat_thread_util API's 
 *  to obtain the kernel threads details and the CPU utilization for each thread
 */
int main(int argc,char* argv[])
{

    int c=0;

    while((c = getopt(argc, argv, "i:c:"))!= EOF){
       switch(c)
       {
           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;
	   default:
			fprintf(stdout,"error\n");
      }
    }

	do_initialization();
    display_metrics();
	do_cleanup();
	
	return(0);

}

