/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* bos720 src/bos/usr/ccs/lib/libperfstat/simplelparstat.c 1.3.2.1 */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* Restricted Materials of IBM */ /* */ /* COPYRIGHT International Business Machines Corp. 2007,2012 */ /* 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[] = "@(#)42 1.3.2.1 src/bos/usr/ccs/lib/libperfstat/simplelparstat.c, libperfstat, bos720 2/9/12 02:28:16"; #include #include #include #include #include #define XINTFRAC ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) /* convert physical processor tics to seconds */ #define HTIC2SEC(x) ((double)x * XINTFRAC)/(double)1000000000.0 #define INTERVAL_DEFAULT 2 #define COUNT_DEFAULT 10 /*simplelparstat.c file can be used in two modes:- 1) Auto Mode:It makes use of perfstat_cpu_util API to calculate utilization values,enable 'UTIL_AUTO' macro for execution in auto mode. 2) Manual Mode: Calculations are done in the current code. */ /*#define UTIL_AUTO 1*/ #ifdef UTIL_AUTO #define UTIL_MS 1 #define UTIL_PCT 0 #define UTIL_CORE 2 #define UTIL_PURR 0 #define UTIL_SPURR 1 void display_lpar_util_auto(int mode,int cpumode,int count,int interval); #endif static int disp_util_header = 1; static u_longlong_t last_time_base; static u_longlong_t last_pcpu_user, last_pcpu_sys, last_pcpu_idle, last_pcpu_wait; static u_longlong_t last_lcpu_user, last_lcpu_sys, last_lcpu_idle, last_lcpu_wait; static u_longlong_t last_busy_donated, last_idle_donated; static u_longlong_t last_busy_stolen, last_idle_stolen; static u_longlong_t last_phint = 0, last_vcsw = 0, last_pit = 0; /* 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; void display_lpar_util(void); int main(int argc, char* argv[]) { int interval = INTERVAL_DEFAULT; int count = COUNT_DEFAULT; int i, rc; char *optlist = "i:c:n:"; int mode=0,cpumode=0; /* Process the arguments */ while ((i = getopt(argc, argv, optlist)) != 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 */ fprintf (stderr, "usage: %s [-i ] [-c ] [-n ]\n", argv[0]); return(-1); } } 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); } } #ifdef UTIL_AUTO printf("Enter CPU mode.\n"); printf(" 0 PURR \n 1 SPURR \n"); scanf("%d",&cpumode); printf("Enter print mode.\n"); printf(" 0 PERCENTAGE\n 1 MILLISECONDS\n 2 CORES \n"); scanf("%d",&mode); if((mode>2)&& (cpumode>1)) { printf("Error: Invalid Input\n"); exit(0); } display_lpar_util_auto(mode,cpumode,count,interval); #else /* Iterate "count" times */ while (count > 0) { display_lpar_util(); sleep(interval); count--; } #endif if(collect_remote_node_stats) { /* Now disable cluster statistics by calling perfstat_config */ perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL); } return(0); } /* Save the current values for the next iteration */ void save_last_values(perfstat_cpu_total_t *cpustats, perfstat_partition_total_t *lparstats) { last_vcsw = lparstats->vol_virt_cswitch + lparstats->invol_virt_cswitch; last_time_base = lparstats->timebase_last; last_phint = lparstats->phantintrs; last_pit = lparstats->pool_idle_time; last_pcpu_user = lparstats->puser; last_pcpu_sys = lparstats->psys; last_pcpu_idle = lparstats->pidle; last_pcpu_wait = lparstats->pwait; last_lcpu_user = cpustats->user; last_lcpu_sys = cpustats->sys; last_lcpu_idle = cpustats->idle; last_lcpu_wait = cpustats->wait; last_busy_donated = lparstats->busy_donated_purr; last_idle_donated = lparstats->idle_donated_purr; last_busy_stolen = lparstats->busy_stolen_purr; last_idle_stolen = lparstats->idle_stolen_purr; } /* retrieve metrics using perfstat API */ void collect_metrics (perfstat_cpu_total_t *cpustats, perfstat_partition_total_t *lparstats) { if (collect_remote_node_stats) { strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN); nodeid.spec = NODENAME; if (perfstat_partition_total_node(&nodeid, lparstats, sizeof(perfstat_partition_total_t), 1) <= 0) { perror("perfstat_partition_total_node"); exit(-1); } if (perfstat_cpu_total_node(&nodeid, cpustats, sizeof(perfstat_cpu_total_t), 1) <= 0) { perror("perfstat_cpu_total_node"); exit(-1); } } else { if (perfstat_partition_total(NULL, lparstats, sizeof(perfstat_partition_total_t), 1) <= 0) { perror("perfstat_partition_total"); exit(-1); } if (perfstat_cpu_total(NULL, cpustats, sizeof(perfstat_cpu_total_t), 1) <= 0) { perror("perfstat_cpu_total"); exit(-1); } } } /* print header informations */ void print_header(perfstat_partition_total_t *lparstats) { if (lparstats->type.b.shared_enabled) { /* partition is a SPLPAR */ if (lparstats->type.b.pool_util_authority) { /* partition has PUA access */ printf("\n%5s %5s %6s %6s %5s %5s %5s %5s %4s %5s", "%user", "%sys", "%wait", "%idle", "physc", "%entc", "lbusy", "app", "vcsw", "phint"); printf("\n%5s %5s %6s %6s %5s %5s %5s %5s %4s %5s", "-----", "----", "-----", "-----", "-----", "-----", "-----", "---", "----", "-----"); } else { printf("\n%5s %5s %6s %6s %5s %5s %5s %4s %5s", "%user", "%sys", "%wait", "%idle", "physc", "%entc", "lbusy", "vcsw", "phint"); printf("\n%5s %5s %6s %6s %5s %5s %5s %4s %5s", "-----", "----", "-----", "-----", "-----", "-----", "-----", "----", "-----"); } } else { /* partition is a DLPAR */ printf("\n%5s %5s %6s %6s", "%user", "%sys", "%wait", "%idle"); printf("\n%5s %5s %6s %6s", "-----", "----", "-----", "-----"); if (lparstats->type.b.donate_enabled) { /* if donation is enabled for this DLPAR */ printf(" %6s %6s", "%phsyc", "%vcsw"); printf(" %6s %6s", "------", "-----"); } } fprintf(stdout,"\n"); } /* Gather and display lpar utilization metrics */ void display_lpar_util(void) { u_longlong_t delta_pcpu_user, delta_pcpu_sys, delta_pcpu_idle, delta_pcpu_wait; u_longlong_t delta_lcpu_user, delta_lcpu_sys, delta_lcpu_idle, delta_lcpu_wait; u_longlong_t delta_busy_stolen, delta_busy_donated, delta_idle_stolen, delta_idle_donated; u_longlong_t vcsw, lcputime, pcputime; u_longlong_t entitled_purr, unused_purr; u_longlong_t delta_purr, delta_time_base; double phys_proc_consumed, entitlement, percent_ent, delta_sec; perfstat_partition_total_t lparstats; perfstat_cpu_total_t cpustats; /* retrieve the metrics */ collect_metrics (&cpustats, &lparstats); /* Print the header for utilization metrics (only once) */ if (disp_util_header) { print_header (&lparstats); disp_util_header = 0; /* first iteration, we only read the data, print the header and save the data */ save_last_values(&cpustats, &lparstats); return; } /* calculate physcial processor tics during the last interval in user, system, idle and wait mode */ delta_pcpu_user = lparstats.puser - last_pcpu_user; delta_pcpu_sys = lparstats.psys - last_pcpu_sys; delta_pcpu_idle = lparstats.pidle - last_pcpu_idle; delta_pcpu_wait = lparstats.pwait - last_pcpu_wait; /* calculate total physcial processor tics during the last interval */ delta_purr = pcputime = delta_pcpu_user + delta_pcpu_sys + delta_pcpu_idle + delta_pcpu_wait; /* calculate clock tics during the last interval in user, system, idle and wait mode */ delta_lcpu_user = cpustats.user - last_lcpu_user; delta_lcpu_sys = cpustats.sys - last_lcpu_sys; delta_lcpu_idle = cpustats.idle - last_lcpu_idle; delta_lcpu_wait = cpustats.wait - last_lcpu_wait; /* calculate total clock tics during the last interval */ lcputime = delta_lcpu_user + delta_lcpu_sys + delta_lcpu_idle + delta_lcpu_wait; /* calculate entitlement for this partition - entitled physical processors for this partition */ entitlement = (double)lparstats.entitled_proc_capacity / 100.0 ; /* calculate delta time in terms of physical processor tics */ delta_time_base = lparstats.timebase_last - last_time_base; if (lparstats.type.b.shared_enabled) { /* partition is a SPLPAR */ /* calculate entitled physical processor tics for this partitions */ entitled_purr = delta_time_base * entitlement; if (entitled_purr < delta_purr) { /* for uncapped SPLPAR */ /* in case of uncapped SPLPAR, consider entitled physical processor tics or * consumed physical processor tics, which ever is greater */ entitled_purr = delta_purr; } /* calculate unused physical processor tics out of the entitled physical processor tics */ unused_purr = entitled_purr - delta_purr; /* distributed unused physical processor tics amoung wait and idle proportionally to wait and idle in clock tics */ delta_pcpu_wait += unused_purr * ((double)delta_lcpu_wait / (double)(delta_lcpu_wait + delta_lcpu_idle)); delta_pcpu_idle += unused_purr * ((double)delta_lcpu_idle / (double)(delta_lcpu_wait + delta_lcpu_idle)); /* far SPLPAR, consider the entitled physical processor tics as the actual delta physical processor tics */ pcputime = entitled_purr; } else if (lparstats.type.b.donate_enabled) { /* if donation is enabled for this DLPAR */ /* calculate busy stolen and idle stolen physical processor tics during the last interval */ /* these physical processor tics are stolen from this partition by the hypervsior * which will be used by wanting partitions */ delta_busy_stolen = lparstats.busy_stolen_purr - last_busy_stolen; delta_idle_stolen = lparstats.idle_stolen_purr - last_idle_stolen; /* calculate busy donated and idle donated physical processor tics during the last interval */ /* these physical processor tics are voluntarily donated by this partition to the hypervsior * which will be used by wanting partitions */ delta_busy_donated = lparstats.busy_donated_purr - last_busy_donated; delta_idle_donated = lparstats.idle_donated_purr - last_idle_donated; /* add busy donated and busy stolen to the kernel bucket, as cpu * cycles were donated / stolen when this partition is busy */ delta_pcpu_sys += delta_busy_donated; delta_pcpu_sys += delta_busy_stolen; /* distribute idle stolen to wait and idle proportionally to the logical wait and idle in clock tics, as * cpu cycles were stolen when this partition is idle or in wait */ delta_pcpu_wait += delta_idle_stolen * ((double)delta_lcpu_wait / (double)(delta_lcpu_wait + delta_lcpu_idle)); delta_pcpu_idle += delta_idle_stolen * ((double)delta_lcpu_idle / (double)(delta_lcpu_wait + delta_lcpu_idle)); /* distribute idle donated to wait and idle proportionally to the logical wait and idle in clock tics, as * cpu cycles were donated when this partition is idle or in wait */ delta_pcpu_wait += delta_idle_donated * ((double)delta_lcpu_wait / (double)(delta_lcpu_wait + delta_lcpu_idle)); delta_pcpu_idle += delta_idle_donated * ((double)delta_lcpu_idle / (double)(delta_lcpu_wait + delta_lcpu_idle)); /* add donated to the total physical processor tics for CPU usage calculation, as they were * distributed to respective buckets accordingly */ pcputime += (delta_idle_donated + delta_busy_donated); /* add stolen to the total physical processor tics for CPU usage calculation, as they were * distributed to respective buckets accordingly */ pcputime += (delta_idle_stolen + delta_busy_stolen); } /* Processor Utilization - Applies for both SPLPAR and DLPAR*/ printf("%5.1f ", (double)delta_pcpu_user * 100.0 / (double)pcputime); printf("%5.1f ", (double)delta_pcpu_sys * 100.0 / (double)pcputime); printf("%6.1f ", (double)delta_pcpu_wait * 100.0 / (double)pcputime); printf("%6.1f ", (double)delta_pcpu_idle * 100.0 / (double)pcputime); if (lparstats.type.b.shared_enabled) { /* print SPLPAR specific stats */ /* Physical Processor Consumed by this partition */ phys_proc_consumed = (double)delta_purr / (double)delta_time_base; printf("%5.2f ", (double)phys_proc_consumed); /* Percentage of Entitlement Consumed - percentage of entitled physical processor tics consumed */ percent_ent = (double)((phys_proc_consumed / entitlement) * 100); printf("%5.1f ", percent_ent); /* Logical Processor Utilization of this partition */ printf("%5.1f ", (double)(delta_lcpu_user+delta_lcpu_sys) * 100.0 / (double)lcputime); if (lparstats.type.b.pool_util_authority) { /* Available physical Processor units available in the shared pool (app) */ printf("%5.2f ", (double)(lparstats.pool_idle_time - last_pit) / XINTFRAC*(double)delta_time_base); } /* Virtual CPU Context Switches per second */ vcsw = lparstats.vol_virt_cswitch + lparstats.invol_virt_cswitch; delta_sec = HTIC2SEC(delta_time_base); printf("%4.0f ", (double)(vcsw - last_vcsw) / delta_sec); /* Phantom Interrupts per second */ printf("%5.0f",(double)(lparstats.phantintrs - last_phint) / delta_sec); } else if (lparstats.type.b.donate_enabled) { /* print donation-enabled DLPAR specific stats */ /* Physical Processor Consumed by this partition * (excluding donated and stolen physical processor tics). */ phys_proc_consumed = (double)delta_purr / (double)delta_time_base; printf("%5.2f ", (double)phys_proc_consumed); /* Virtual CPU Context Switches per second */ vcsw = lparstats.vol_virt_cswitch + lparstats.invol_virt_cswitch; delta_sec = HTIC2SEC(delta_time_base); printf("%5.0f ", (double)(vcsw - last_vcsw) / delta_sec); } printf("\n"); save_last_values(&cpustats, &lparstats); } #ifdef UTIL_AUTO void display_lpar_util_auto(int mode,int cpumode,int count,int interval) { float user_core_purr,kern_core_purr,wait_core_purr,idle_core_purr; float user_core_spurr,kern_core_spurr,wait_core_spurr,idle_core_spurr,sum_core_spurr; u_longlong_t user_ms_purr,kern_ms_purr,wait_ms_purr,idle_ms_purr,sum_ms; u_longlong_t user_ms_spurr,kern_ms_spurr,wait_ms_spurr,idle_ms_spurr; perfstat_rawdata_t data; u_longlong_t delta_purr, delta_time_base; double phys_proc_consumed, entitlement, percent_ent, delta_sec; perfstat_partition_total_t lparstats; static perfstat_cpu_total_t oldt,newt; perfstat_cpu_util_t util; int rc; /* retrieve the metrics */ /* Print the header for utilization metrics (only once) */ if (disp_util_header) { if(mode==UTIL_PCT) printf("\n%5s %5s %6s %6s %5s \n", "%user", "%sys", "%wait", "%idle", "physc"); else if(mode==UTIL_MS) printf("\n%5s %5s %6s %6s %5s \n", "user(ms)", "sys(ms)", "wait(ms)", "idle(ms)", "physc"); else if(mode==UTIL_CORE) printf("\n%5s %5s %6s %6s %5s \n", "user", "sys", "wait", "idle", "physc"); disp_util_header = 0; /* first iteration, we only read the data, print the header and save the data */ } while(count) { collect_metrics (&oldt, &lparstats); sleep(interval); collect_metrics (&newt, &lparstats); data.type = UTIL_CPU_TOTAL; data.curstat = &newt; data.prevstat= &oldt; data.sizeof_data = sizeof(perfstat_cpu_total_t); data.cur_elems = 1; data.prev_elems = 1; rc = perfstat_cpu_util(&data, &util,sizeof(perfstat_cpu_util_t), 1); if(rc <= 0) { perror("Error in perfstat_cpu_util"); exit(-1); } delta_time_base = util.delta_time; switch(mode) { case UTIL_PCT: printf(" %5.1f %5.1f %5.1f %5.1f %5.4f \n",util.user_pct,util.kern_pct,util.wait_pct,util.idle_pct,util.physical_consumed); break; case UTIL_MS: user_ms_purr=((util.user_pct*delta_time_base)/100.0); kern_ms_purr=((util.kern_pct*delta_time_base)/100.0); wait_ms_purr=((util.wait_pct*delta_time_base)/100.0); idle_ms_purr=((util.idle_pct*delta_time_base)/100.0); if(cpumode==UTIL_PURR) { printf(" %llu %llu %llu %llu %5.4f\n",user_ms_purr,kern_ms_purr,wait_ms_purr,idle_ms_purr,util.physical_consumed); } else if(cpumode==UTIL_SPURR) { user_ms_spurr=(user_ms_purr*util.freq_pct)/100.0; kern_ms_spurr=(kern_ms_purr*util.freq_pct)/100.0; wait_ms_spurr=(wait_ms_purr*util.freq_pct)/100.0; sum_ms=user_ms_spurr+kern_ms_spurr+wait_ms_spurr; idle_ms_spurr=delta_time_base-sum_ms; printf(" %llu %llu %llu %llu %5.4f \n",user_ms_spurr,kern_ms_spurr,wait_ms_spurr,idle_ms_spurr,util.physical_consumed); } break; case UTIL_CORE: user_core_purr=((util.user_pct*util.physical_consumed)/100.0); kern_core_purr=((util.kern_pct*util.physical_consumed)/100.0); wait_core_purr=((util.wait_pct*util.physical_consumed)/100.0); idle_core_purr=((util.idle_pct*util.physical_consumed)/100.0); user_core_spurr=((user_core_purr*util.freq_pct)/100.0); kern_core_spurr=((kern_core_purr*util.freq_pct)/100.0); wait_core_spurr=((wait_core_purr*util.freq_pct)/100.0); if(cpumode==UTIL_PURR) { printf("%5.4f %5.4f %5.4f %5.4f %5.4f\n",user_core_purr,kern_core_purr,wait_core_purr,idle_core_purr,util.physical_consumed); } else if(cpumode==UTIL_SPURR) { sum_core_spurr=user_core_spurr+kern_core_spurr+wait_core_spurr; idle_core_spurr=util.physical_consumed-sum_core_spurr; printf("%5.4f %5.4f %5.4f %5.4f %5.4f \n",user_core_spurr,kern_core_spurr,wait_core_spurr,idle_core_spurr,util.physical_consumed); } break; default: printf("In correct usage\n"); return; } count--; } } #endif