Logo Search packages:      
Sourcecode: pcp version File versions  Download package

pmtop.c

/*
 * Copyright (c) 1999 Silicon Graphics, Inc.  All Rights Reserved.
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 * 
 * Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
 * Mountain View, CA 94043, USA, or: http://www.sgi.com
 */

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <libgen.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include "pmapi.h"
#include "impl.h"

/*
 * Outputs psinfo.psargs and top value.
 *
 * Want to periodically write to stdout
 * with the top processes for the following categories:
 *
 * cpuburn - rate converted proc.psusage.utime + stime
 * syscalls - rate converted proc.psusage.pu_sysc
 * reads - rate converted proc.psusage.bread + gbread 
 * writes - rate converted proc.psusage.bwrit + gbwrit
 * ctxswitch - rate converted proc.psusage.pu_vctx + proc.psusage.pu_ictx
 * residentsize - proc.psusage.rss
 * 
 */


#define MAX_PMID  15 /* must give enough space for all possible metrics in fetch */
char    *namelist[MAX_PMID];
pmID  pmidlist[MAX_PMID];
int   type_tab[MAX_PMID]; /* the types of the metrics */
int   valfmt_tab[MAX_PMID]; /* the types of the metrics */
int   num_pmid;
int   num_proc_pmid;

/* indexes into [MAX_PMID] arrays */
int   kernel_utime;
int   kernel_stime;
int   kernel_sysc;
int   kernel_ctx;
int   pu_utime;
int   pu_stime;
int   pu_sysc;
int   pu_bread;
int   pu_gbread;
int   pu_bwrit;
int   pu_gbwrit;
int   pu_rss;
int   pu_vctx;
int   pu_ictx;

char  local[MAXHOSTNAMELEN];
char  *hostname;
struct timeval    delta = { 2, 0 }; /* default interval */
int   top = 5;
long  num_samples = -1; /* forever */
int   num_inst = 0;
int   *instances = NULL;
char  **instance_names = NULL;
char  *runtime = NULL;
int     zflag = 0;                  /* for -z */
char    *tz = NULL;         /* for -Z timezone */
char  pid_label_fmt[8];
char  pid_fmt[8];
char  *line_fmt = "%.79s";
int   pid_len = 0;
pmInDom proc_indom;

/* values of interest */
#define CPU_VAL   0
#define SYSCALLS_VAL    1
#define CTX_VAL         2
#define WRITES_VAL      3
#define READS_VAL 4
#define RSS_VAL         5
#define USR_VAL         6
#define SYS_VAL         7
#define NUM_VALUES      8

/* which values to calculate and print */
#define SHOW_CPU  (1<<CPU_VAL)
#define SHOW_SYSCALLS   (1<<SYSCALLS_VAL)
#define SHOW_CTX  (1<<CTX_VAL)
#define SHOW_WRITES     (1<<WRITES_VAL)
#define SHOW_READS      (1<<READS_VAL)
#define SHOW_RSS  (1<<RSS_VAL)
#define SHOW_USR  (1<<USR_VAL)
#define SHOW_SYS  (1<<SYS_VAL)

int   show_spec = SHOW_CPU|SHOW_SYSCALLS|SHOW_CTX|SHOW_WRITES|SHOW_READS|SHOW_RSS; /* default to show all */

/* copied from pmdbg.h */
typedef struct {
    char        *name;
    int         bit;
} show_map_t;
static show_map_t show_map[] = {
    { "CPU",   SHOW_CPU },
    { "SYSC",  SHOW_SYSCALLS },
    { "CTX",   SHOW_CTX },
    { "WRITE", SHOW_WRITES },
    { "READ",  SHOW_READS },
    { "RSS",   SHOW_RSS },
    { "USR",   SHOW_USR },
    { "SYS",   SHOW_SYS },
};
static int num_show = sizeof(show_map) / sizeof(show_map[0]);

typedef struct {
   int inst; /* index into instances and names */
   double values[NUM_VALUES];
} rate_entry_t;
rate_entry_t *rate_tab = NULL;

double global_rates[NUM_VALUES] = {0};
double sum_rates[NUM_VALUES] = {0};

typedef struct {
   char *val_fmt;
   char *label_fmt;
   char *label;
   char *units;
   char *fullname;
} format_entry_t;

/*
 * Warning - must match order of *_VAL macros
 */
format_entry_t format_tab[] =
{ 
    {"%7.2f", "%7s", "CPU%", "", "CPU Utilization"},
    {"%9.0f", "%9s", "SYSCALLS", "sys/sec", "System Calls"},
    {"%9.0f", "%9s", "CTX", "ctx/sec", "Context Switches"},
    {"%8.0f", "%8s", "WRITES", "Kb/sec", "Writes"},
    {"%8.0f", "%8s", "READS", "Kb/sec", "Reads"},
    {"%9.0f", "%9s", "RSS", "Kb", "Resident Size"},
    {"%7.2f", "%7s", "USR%", "", "User CPU Utilization"},
    {"%7.2f", "%7s", "SYS%", "", "System CPU Utilization"},
};

/* value table */
typedef struct val_entry_t {
    int num;
    pmValue values[MAX_PMID][2];
} val_entry_t;
val_entry_t *val_tab = NULL;

/* index will use high end for globals */
/* parallels index with other MAX_PMID arrays */
pmValue global_val[MAX_PMID][2]; 


#define min(x,y) (((x)<(y))?(x):(y))

void get_indom(void);

/* copied and modified from __pmParseDebug() from util.c */
int
parse_show_spec(const char *spec)
{
    int           val = 0;
    int           tmp;
    const char    *p;
    char    *pend;
    int           i;

    for (p = spec; *p; ) {
      tmp = (int)strtol(p, &pend, 10);
      if (tmp == -1)
          /* special case ... -1 really means set all the bits! */
          tmp = INT_MAX;
      if (*pend == '\0') {
          val |= tmp;
          break;
      }
      else if (*pend == ',') {
          val |= tmp;
          p = pend + 1;
      }
      else {
          pend = strchr(p, ',');
          if (pend != NULL)
            *pend = '\0';

          for (i = 0; i < num_show; i++) {
            if (strcasecmp(p, show_map[i].name) == 0) {
                val |= show_map[i].bit;
                if (pend != NULL) {
                  *pend = ',';
                  p = pend + 1;
                }
                else
                  p = "";           /* force termination of outer loop */
                break;
            }
          }

          if (i == num_show) {
            if (pend != NULL)
                *pend = ',';
            return PM_ERR_CONV;
          }
      }
    }

    return val;
}

static char *
get_time(void)
{
    static char str[80];
    time_t now = time(NULL);
    struct tm *tm = localtime(&now);
    strftime(str, sizeof(str), "%c %Z", tm);
    return str;
}

__uint64_t
get_value(int metric, pmValue *value)
{
    int sts;
    pmAtomValue val;

    if ((sts = pmExtractValue(valfmt_tab[metric], value,
              type_tab[metric], &val, PM_TYPE_U64)) < 0) {
      fprintf(stderr, "%s: Failed to extract metric value: %s\n", 
            pmProgname, pmErrStr(sts));
      exit(1);

    }
    return val.ull;
}

int 
cpuburn_cmp(const void* x, const void* y)
{
   rate_entry_t *c1 = (rate_entry_t *)x;
   rate_entry_t *c2 = (rate_entry_t *)y;

   if (c1->values[CPU_VAL] == c2->values[CPU_VAL])
      return 0;
   else if (c2->values[CPU_VAL] > c1->values[CPU_VAL])
      return 1;
   else
      return -1;
}

int 
sys_cmp(const void* x, const void* y)
{
   rate_entry_t *c1 = (rate_entry_t *)x;
   rate_entry_t *c2 = (rate_entry_t *)y;

   if (c1->values[SYS_VAL] == c2->values[SYS_VAL])
      return 0;
   else if (c2->values[SYS_VAL] > c1->values[SYS_VAL])
      return 1;
   else
      return -1;
}

int 
usr_cmp(const void* x, const void* y)
{
   rate_entry_t *c1 = (rate_entry_t *)x;
   rate_entry_t *c2 = (rate_entry_t *)y;

   if (c1->values[USR_VAL] == c2->values[USR_VAL])
      return 0;
   else if (c2->values[USR_VAL] > c1->values[USR_VAL])
      return 1;
   else
      return -1;
}

int 
syscall_cmp(const void* x, const void* y)
{
   rate_entry_t *c1 = (rate_entry_t *)x;
   rate_entry_t *c2 = (rate_entry_t *)y;

   if (c1->values[SYSCALLS_VAL] == c2->values[SYSCALLS_VAL])
      return 0;
   else if (c2->values[SYSCALLS_VAL] > c1->values[SYSCALLS_VAL])
      return 1;
   else
      return -1;
}

int 
ctx_cmp(const void* x, const void* y)
{
   rate_entry_t *c1 = (rate_entry_t *)x;
   rate_entry_t *c2 = (rate_entry_t *)y;

   if (c1->values[CTX_VAL] == c2->values[CTX_VAL])
      return 0;
   else if (c2->values[CTX_VAL] > c1->values[CTX_VAL])
      return 1;
   else
      return -1;
}

int 
write_cmp(const void* x, const void* y)
{
   rate_entry_t *c1 = (rate_entry_t *)x;
   rate_entry_t *c2 = (rate_entry_t *)y;

   if (c1->values[WRITES_VAL] == c2->values[WRITES_VAL])
      return 0;
   else if (c2->values[WRITES_VAL] > c1->values[WRITES_VAL])
      return 1;
   else
      return -1;
}

int 
read_cmp(const void* x, const void* y)
{
   rate_entry_t *c1 = (rate_entry_t *)x;
   rate_entry_t *c2 = (rate_entry_t *)y;

   if (c1->values[READS_VAL] == c2->values[READS_VAL])
      return 0;
   else if (c2->values[READS_VAL] > c1->values[READS_VAL])
      return 1;
   else
      return -1;
}

int 
rss_cmp(const void* x, const void* y)
{
   rate_entry_t *c1 = (rate_entry_t *)x;
   rate_entry_t *c2 = (rate_entry_t *)y;

   if (c1->values[RSS_VAL] == c2->values[RSS_VAL])
      return 0;
   else if (c2->values[RSS_VAL] > c1->values[RSS_VAL])
      return 1;
   else
      return -1;
}

/*
 * sum the rate values for the top entries
 */
void
calc_sum_rates(int num_entries, int val_type)
{
    int i;
    double sum = 0;

    for(i=0; i < min(top, num_entries); i++) {
      rate_entry_t *entry = &rate_tab[i];
      sum += entry->values[val_type];
    }

    sum_rates[val_type] = sum;
}

void
print_top(rate_entry_t *rate_tab, int num_entries, int val_type)
{
    static char line[2048];
    char *ptr;
    int i,j;
    double x;

    /* --- section heading --- */
    if (global_rates[val_type] <= 0) {
      printf("%s\n", format_tab[val_type].label);
    }
    else {
      x= 100*sum_rates[val_type]/global_rates[val_type];
      printf("%s - top %d processes account for %.0f%% of %s\n",
             format_tab[val_type].label,
             top, x>100?100:x,
             format_tab[val_type].fullname);
    }

    /* --- fields heading --- */
    printf(pid_label_fmt, "PID");
    for(j=0; j < NUM_VALUES; j++) {
      if (show_spec & (1<<j)) {
          format_entry_t *fmt = &format_tab[j];
          printf(fmt->label_fmt, fmt->label);
      }
    } 
    printf(" CMD\n");

    /* units */
    printf(pid_label_fmt, " ");
    for(j=0; j < NUM_VALUES; j++) {
      if (show_spec & (1<<j)) {
          format_entry_t *fmt = &format_tab[j];
          printf(fmt->label_fmt, fmt->units);
      }
    } 
    printf("\n");


    /* --- values --- */
    for(i=0; i < min(top, num_entries); i++) {
      rate_entry_t *entry = &rate_tab[i];

      *line = '\0';
      ptr = line;

      /* pid */
      sprintf(ptr, pid_fmt, instances[entry->inst]);
      ptr += strlen(ptr);

      /* other values */
      for(j=0; j < NUM_VALUES; j++) {
          if (show_spec & (1<<j)) {
            format_entry_t *fmt = &format_tab[j];
            sprintf(ptr, fmt->val_fmt, entry->values[j]);
            ptr += strlen(ptr);
          }
      }

      /* cmd */
        /* skip over leading pid-name in instance name */
      sprintf(ptr, " %s", &instance_names[entry->inst][pid_len+1]);

      /* ensure line fits in certain width */
      printf(line_fmt, line);
      printf("\n");
    }

    printf("\n");
}

void 
doit(void)
{
    int i, r, m, v, sts;
    static double now = 0, then = 0;
    double delta_d;
    static unsigned long num_times = 0;
    static pmResult *result[2];
    int num_entries;

    num_times++;

    if (num_times > 2) {
      pmFreeResult(result[0]);      

        /* if forever, ensure no wrapping */
        if (num_samples < 0)
          num_times = 3;
    }

    if (num_times > 1) {
      result[0] = result[1];
    }

    get_indom();
    if ((sts = pmFetch(num_pmid, pmidlist, &result[1])) < 0) {
      for (i = 0; i < num_pmid; i++)
          fprintf(stderr, "%s: pmFetch: %s\n", namelist[i], pmErrStr(sts));
      exit(1);
    }


    if (num_times > 1) {
        then = result[0]->timestamp.tv_sec + result[0]->timestamp.tv_usec/1000000;
        now = result[1]->timestamp.tv_sec + result[1]->timestamp.tv_usec/1000000;
      delta_d = now - then;

        if (result[1]->numpmid != num_pmid) {
          fprintf(stderr, "%s: Failed to fetch all metrics (%d out of %d)\n", 
                pmProgname, result[1]->numpmid, num_pmid);
          exit(1);
      }
      
      /* --- build value table --- */

      for(i=0; i<num_inst; i++) {
          val_tab[i].num = 0;
      }

      /* go thru each result */
      for(r=0; r<2; r++) {
          /* go thru each metric */
          for(m=0; m<num_pmid; m++) {
            pmValueSet *vset = result[r]->vset[m];
            if (vset->numval < 0) {
                fprintf(stderr, "%s: Error when fetching metric %s: %s\n", 
                  pmProgname, namelist[m], pmErrStr(vset->numval));
                continue;
            }
            if (vset->numval == 0)
                continue;
            valfmt_tab[m] = vset->valfmt;

            /* handle global metrics */
            if (((show_spec & (SHOW_CPU | SHOW_SYS)) && m == kernel_stime) || 
                ((show_spec & (SHOW_CPU | SHOW_USR)) && m == kernel_utime) || 
                ((show_spec & SHOW_SYSCALLS) && m == kernel_sysc) || 
                ((show_spec & SHOW_CTX) && m == kernel_ctx)) {
                if (vset->numval != 1) {
                  fprintf(stderr, "%s: Wrong num of values for kernel metric: %d\n", 
                      pmProgname, vset->numval);
                  exit(1);
                }
                global_val[m][r] = vset->vlist[0];    
                continue;
            }

            /* handle proc-instance metrics */

            /* Find result inst
             * Would be faster to start from where left off
             * last time. Need to remember this for a metric/result.
             */
            for(v=0; v<vset->numval; v++) {
                pmValue val = vset->vlist[v];
                /* go thru each possible inst */
                for(i=0; i<num_inst; i++) {
                  if (instances[i] == val.inst) {
                      val_tab[i].num++; /* needs to be zeroed at start */
                      val_tab[i].values[m][r] = val;
                      break;
                  }
                }
            }
          }
      }
      
      /* --- calculate rates --- */

      /* handle global metrics */
      if (show_spec & SHOW_CPU) {
          __uint64_t utime[2], stime[2];
          double cpuburn_val;

          utime[0] = get_value(kernel_utime, &global_val[kernel_utime][0]);
          utime[1] = get_value(kernel_utime, &global_val[kernel_utime][1]);
          stime[0] = get_value(kernel_stime, &global_val[kernel_stime][0]);
          stime[1] = get_value(kernel_stime, &global_val[kernel_stime][1]);
          
          cpuburn_val = (utime[1] - utime[0] + stime[1] - stime[0]) / delta_d;
          cpuburn_val /= 10; 
          cpuburn_val = cpuburn_val > 100 ? 100 : cpuburn_val;
          global_rates[CPU_VAL] = cpuburn_val;
      }


      if (show_spec & SHOW_SYSCALLS) {
          __uint64_t sysc[2];

          sysc[0] = get_value(kernel_sysc, &global_val[kernel_sysc][0]);
          sysc[1] = get_value(kernel_sysc, &global_val[kernel_sysc][1]);
          
          global_rates[SYSCALLS_VAL] = (sysc[1] - sysc[0]) / delta_d;
      }

      if (show_spec & SHOW_CTX) {
          __uint64_t ctx[2];

          ctx[0] = get_value(kernel_ctx, &global_val[kernel_ctx][0]);
          ctx[1] = get_value(kernel_ctx, &global_val[kernel_ctx][1]);
          
          global_rates[CTX_VAL] = (ctx[1] - ctx[0]) / delta_d;
      }

      if (show_spec & SHOW_SYS) {
          __uint64_t stime[2];

          stime[0] = get_value(kernel_stime, &global_val[kernel_stime][0]);
          stime[1] = get_value(kernel_stime, &global_val[kernel_stime][1]);
          
          global_rates[SYS_VAL] = ((stime[1] - stime[0]) / delta_d) / 10;
      }

      if (show_spec & SHOW_USR) {
          __uint64_t utime[2];

          utime[0] = get_value(kernel_utime, &global_val[kernel_utime][0]);
          utime[1] = get_value(kernel_utime, &global_val[kernel_utime][1]);
          
          global_rates[USR_VAL] = ((utime[1] - utime[0]) / delta_d) / 10;
      }


      /* handle proc-instance metrics */
      num_entries = 0;
      for(i=0; i<num_inst; i++) {
          val_entry_t *vt = &val_tab[i];
          rate_entry_t *rt;
          if (vt->num < (num_proc_pmid*2)) {
            /* couldn't get instances for all proc metrics for both(*2) results */
            continue;
          }
          
          rt = &rate_tab[num_entries];
          rt->inst = i;

          /* create cpuburn values */
          if (show_spec & SHOW_CPU) {
            __uint64_t utime[2], stime[2];
            double cpuburn_val;

            utime[0] = get_value(pu_utime, &vt->values[pu_utime][0]);
            utime[1] = get_value(pu_utime, &vt->values[pu_utime][1]);
            stime[0] = get_value(pu_stime, &vt->values[pu_stime][0]);
            stime[1] = get_value(pu_stime, &vt->values[pu_stime][1]);
            
            cpuburn_val = (utime[1] - utime[0] + stime[1] - stime[0]) / delta_d;
            cpuburn_val /= 10; 
            cpuburn_val = cpuburn_val > 100 ? 100 : cpuburn_val;
            rt->values[CPU_VAL] = cpuburn_val;
          }

          /* create syscalls values */
          if (show_spec & SHOW_SYSCALLS) {
            __uint64_t sysc[2];

            sysc[0] = get_value(pu_sysc, &vt->values[pu_sysc][0]);
            sysc[1] = get_value(pu_sysc, &vt->values[pu_sysc][1]);
            
            rt->values[SYSCALLS_VAL] = (sysc[1] - sysc[0]) / delta_d;
          }

          /* create ctx values */
          if (show_spec & SHOW_CTX) {
            double ictx, vctx;

            vctx = get_value(pu_vctx, &vt->values[pu_vctx][1]) - 
                   get_value(pu_vctx, &vt->values[pu_vctx][0]);
            ictx = get_value(pu_ictx, &vt->values[pu_ictx][1]) - 
                   get_value(pu_ictx, &vt->values[pu_ictx][0]);
            
            rt->values[CTX_VAL] = (vctx + ictx) / delta_d;
          }

          /* create reads values */
          if (show_spec & SHOW_READS) {
            double br, gbr;

            br = get_value(pu_bread, &vt->values[pu_bread][1]) - 
                 get_value(pu_bread, &vt->values[pu_bread][0]);
            gbr = get_value(pu_gbread, &vt->values[pu_gbread][1]) -
                  get_value(pu_gbread, &vt->values[pu_gbread][0]);
            
            rt->values[READS_VAL] = (gbr * 1024 * 1024 + br / 1024) / delta_d;
          }

          /* create writes values */
          if (show_spec & SHOW_WRITES) {
            double bw, gbw;

            bw = get_value(pu_bwrit, &vt->values[pu_bwrit][1]) -
                 get_value(pu_bwrit, &vt->values[pu_bwrit][0]);
            gbw = get_value(pu_gbwrit, &vt->values[pu_gbwrit][1]) -
                  get_value(pu_gbwrit, &vt->values[pu_gbwrit][0]);
            
            rt->values[WRITES_VAL] = (gbw * 1024 * 1024 + bw / 1024) / delta_d;
          }

          /* create rss values */
          if (show_spec & SHOW_RSS) {
            rt->values[RSS_VAL] = get_value(pu_rss, &vt->values[pu_rss][1]);
          }

          /* create sys cpu time values */
          if (show_spec & SHOW_SYS) {
            __uint64_t stime[2];

            stime[0] = get_value(pu_stime, &vt->values[pu_stime][0]);
            stime[1] = get_value(pu_stime, &vt->values[pu_stime][1]);
            
            rt->values[SYS_VAL] = ((stime[1] - stime[0]) / delta_d) / 10;
            rt->values[SYS_VAL] = rt->values[SYS_VAL] > 100 ? 100 : rt->values[SYS_VAL];
          }

          /* create user cpu time values */
          if (show_spec & SHOW_USR) {
            __uint64_t utime[2];

            utime[0] = get_value(pu_utime, &vt->values[pu_utime][0]);
            utime[1] = get_value(pu_utime, &vt->values[pu_utime][1]);
            
            rt->values[USR_VAL] = ((utime[1] - utime[0]) / delta_d) / 10;
            rt->values[USR_VAL] = rt->values[USR_VAL] > 100 ? 100 : rt->values[USR_VAL];
          }


          num_entries++;
      }

      /* --- report values --- */
      printf("HOST: %s\n", hostname);
      printf("DATE: %s\n\n", get_time());

      if (show_spec & SHOW_CPU) {
          qsort(rate_tab, num_entries, sizeof(rate_entry_t), cpuburn_cmp);
          calc_sum_rates(num_entries, CPU_VAL);
          print_top(rate_tab, num_entries, CPU_VAL);
      }

      if (show_spec & SHOW_SYSCALLS) {
          qsort(rate_tab, num_entries, sizeof(rate_entry_t), syscall_cmp);
          calc_sum_rates(num_entries, SYSCALLS_VAL);
          print_top(rate_tab, num_entries, SYSCALLS_VAL);
      }

      if (show_spec & SHOW_CTX) {
          qsort(rate_tab, num_entries, sizeof(rate_entry_t), ctx_cmp);
          calc_sum_rates(num_entries, CTX_VAL);
          print_top(rate_tab, num_entries, CTX_VAL);
      }

      if (show_spec & SHOW_WRITES) {
          qsort(rate_tab, num_entries, sizeof(rate_entry_t), write_cmp);
          print_top(rate_tab, num_entries, WRITES_VAL);
      }

      if (show_spec & SHOW_READS) {
          qsort(rate_tab, num_entries, sizeof(rate_entry_t), read_cmp);
          print_top(rate_tab, num_entries, READS_VAL);
      }

      if (show_spec & SHOW_RSS) {
          qsort(rate_tab, num_entries, sizeof(rate_entry_t), rss_cmp);
          print_top(rate_tab, num_entries, RSS_VAL);
      }

      if (show_spec & SHOW_SYS) {
          qsort(rate_tab, num_entries, sizeof(rate_entry_t), sys_cmp);
          calc_sum_rates(num_entries, SYS_VAL);
          print_top(rate_tab, num_entries, SYS_VAL);
      }

      if (show_spec & SHOW_USR) {
          qsort(rate_tab, num_entries, sizeof(rate_entry_t), usr_cmp);
          calc_sum_rates(num_entries, USR_VAL);
          print_top(rate_tab, num_entries, USR_VAL);
      }
    }

    if (num_times-1 == num_samples) {
      exit(0);
    }
}


static void
print_usage(void)
{
    fprintf(stderr,
"Usage: %s [options]\n\
\n\
Options:\n\
  -h host   metrics source is PMCD on host\n\
  -m top    look at top m values\n\
  -p spec,...     print certain values e.g. cpu,sysc,rss\n\
  -s num    number of samples to output\n\
  -t interval   default reporting interval [default 2 seconds]\n\
  -w        wide output for command name\n\
  -Z timezone   set reporting timezone\n\
  -z            set reporting timezone to local time of metrics source\n\
where spec = cpu|sysc|ctx|read|write|rss|sys|usr\n",
      pmProgname);
}

void
parse_options(int argc, char *argv[])
{
    int           c;
    int           sts;
    int           errflag = 0;
    char    *opts = "D:h:m:p:s:t:wzZ:?";
    extern char   *optarg;
    extern int    pmDebug;
    char    *p;
    char    *endnum;
    int           one_trip = 1;

    while ((c = getopt(argc, argv, opts)) != EOF) {
      switch (c) {
          case 'w':   /* wide flag */
            line_fmt = "%.1024s";
            break;
          case 'p':     /* show flag */
            if (one_trip) {
                show_spec = 0; one_trip = 0;
            }
            sts = parse_show_spec(optarg);
            if (sts < 0) {
                fprintf(stderr, "%s: unrecognized print flag specification (%s)\n",
                  pmProgname, optarg);
                errflag++;
            }
            else
                show_spec |= sts;
            break;

          case 'D':     /* debug flag */
            sts = __pmParseDebug(optarg);
            if (sts < 0) {
                fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n",
                  pmProgname, optarg);
                errflag++;
            }
            else
                pmDebug |= sts;
            break;


          case 'h':     /* contact PMCD on this hostname */
            hostname = optarg;
            break;
      
          case 'm':   /* top m */
            top = (int)strtol(optarg, &endnum, 10);
            if (top <= 0) {
                fprintf(stderr, "%s: -m requires a positive integer\n", pmProgname);
                errflag++;    
            }
            break;

          case 's':   /* number of samples to output */
            num_samples = (int)strtol(optarg, &endnum, 10);
            if (top <= 0) {
                fprintf(stderr, "%s: -s requires a positive integer\n", pmProgname);
                errflag++;    
            }
            break;

          case 't':           /* change default logging interval */
            if (pmParseInterval(optarg, &delta, &p) < 0) {
                fprintf(stderr, "%s: illegal -t argument\n", pmProgname);
                fputs(p, stderr);
                free(p);
                errflag++;
            }
            break;

          case 'z':       /* timezone from host */
            if (tz != NULL) {
                fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname);
                errflag++;
            }
            zflag++;
            break;

          case 'Z':       /* $TZ timezone */
            if (zflag) {
                fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname);
                errflag++;
            }
            tz = optarg;
            break;


          case '?':
            if (errflag == 0) {
                print_usage();
                exit(0);
            }
      }
    }

    while (optind < argc) {
        fprintf(stderr, "%s: Invalid argument: %s\n", pmProgname, argv[optind]);
        errflag++;
      optind++;
    }

    if (errflag) {
      print_usage();
      exit(1);
    }

}

/*
 * go thru show_spec and build up the namelist and
 * index variables into the array
 */
void
create_namelist(void)
{
    int i = 0; /* for each pmid */
    int j = 0; /* for global pmids */

    if (show_spec & SHOW_CPU || show_spec & SHOW_USR) {
      namelist[i] = "proc.psusage.utime";
      pu_utime = i;
      i++;
      namelist[i] = "kernel.all.cpu.user";
      kernel_utime = i;
      i++; j++;
    }
    if (show_spec & SHOW_CPU || show_spec & SHOW_SYS) {
      namelist[i] = "proc.psusage.stime";
      pu_stime = i;
      i++;
      namelist[i] = "kernel.all.cpu.sys";
      kernel_stime = i;
      i++; j++;
    }
    if (show_spec & SHOW_SYSCALLS) {
      namelist[i] = "proc.psusage.sysc";
      pu_sysc = i;
      i++;
      namelist[i] = "kernel.all.syscall";
      kernel_sysc = i;
      i++; j++;
    }
    if (show_spec & SHOW_CTX) {
      namelist[i] = "proc.psusage.ictx";
      pu_ictx = i;
      i++;
      namelist[i] = "proc.psusage.vctx";
      pu_vctx = i;
      i++;
      namelist[i] = "kernel.all.pswitch";
      kernel_ctx = i;
      i++; j++;
    }
    if (show_spec & SHOW_READS) {
      namelist[i] = "proc.psusage.bread";
      pu_bread = i;
      i++;
      namelist[i] = "proc.psusage.gbread";
      pu_gbread = i;
      i++;
    }
    if (show_spec & SHOW_WRITES) {
      namelist[i] = "proc.psusage.bwrit";
      pu_bwrit = i;
      i++;
      namelist[i] = "proc.psusage.gbwrit";
      pu_gbwrit = i;
      i++;
    }
    if (show_spec & SHOW_RSS) {
      namelist[i] = "proc.psusage.rss";
      pu_rss = i;
      i++;
    }

    num_pmid = i;
    num_proc_pmid = i - j;
}

void
get_indom(void)
{
    static int onetrip = 1;

    if (instances != NULL) 
      free(instances);
    if (instance_names != NULL)
      free(instance_names);

    if ((num_inst = pmGetInDom(proc_indom, &instances, &instance_names)) <= 0) {
      fprintf(stderr, "%s: Failed to find any proc instances : %s\n",
            pmProgname, pmErrStr(num_inst));
      exit(1);
    }

    
    /* process the instance names
     * - find how long a pid is 
     * - create pid label fmt based on pid length
     */
    if (onetrip) {
      char *str = instance_names[0];

      onetrip=0;

      /* get pid str up to first space */
      pid_len = 0;
      while (*str != '\0' && *str != ' ') {
          pid_len++;
          str++;
      }
      if (*str == '\0') {
          /* shouldn't happen */
          fprintf(stderr, "%s: Bad proc instance : %s\n",
                pmProgname, instance_names[0]);
          exit(1);
      }

      sprintf(pid_label_fmt, "%%%ds", pid_len);
      sprintf(pid_fmt, "%%%dd", pid_len);
    }


    rate_tab = realloc(rate_tab, sizeof(rate_entry_t)*num_inst);
    if (rate_tab == NULL) {
      fprintf(stderr, "%s: Failed to allocate rate table\n",
            pmProgname);
      exit(1);
    }

    val_tab = realloc(val_tab, sizeof(val_entry_t)*num_inst);
    if (val_tab == NULL) {
      fprintf(stderr, "%s: Failed to allocate value table\n",
            pmProgname);
      exit(1);
    }

    pmDelProfile(proc_indom, 0, NULL);
    pmAddProfile(proc_indom, num_inst, instances);
}

int
main(int argc, char *argv[])
{
    pmDesc desc;
    int sts, i;

    pmProgname = basename(argv[0]);

    parse_options(argc, argv);

    create_namelist();

    if (hostname == NULL) {
      (void)gethostname(local, MAXHOSTNAMELEN);
      local[MAXHOSTNAMELEN-1] = '\0';
      hostname = local;
    }

    if ((sts = pmNewContext(PM_CONTEXT_HOST, hostname)) < 0) {
      fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n",
            pmProgname, hostname, pmErrStr(sts));
      exit(1);
    }

    if (zflag) {
        if ((sts = pmNewContextZone()) < 0) {
            fprintf(stderr, "%s: Cannot set context timezone: %s\n",
                pmProgname, pmErrStr(sts));
            exit(1);
        }
    }
    else if (tz != NULL) {
        if ((sts = pmNewZone(tz)) < 0) {
            fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n",
                pmProgname, tz, pmErrStr(sts));
            exit(1);
        }
    }

    {
      char *tz;
      char buf[80];
      if (pmWhichZone(&tz) >= 0) {
          sprintf(buf, "TZ=%s", tz);
          putenv(buf);
      }
    }

    if ((sts = pmLookupName(num_pmid, namelist, pmidlist)) < 0) {
      fprintf(stderr, "%s: Failed to lookup metrics : %s\n",
            pmProgname, pmErrStr(sts));
      exit(1);
    }

    for(i=0; i<num_pmid; i++) {
      if ((sts = pmLookupDesc(pmidlist[i], &desc)) < 0) {
          fprintf(stderr, "%s: Failed to lookup descriptor for metric \"%s\": %s\n",
                pmProgname, namelist[i], pmErrStr(sts));
          exit(1);
      }
      type_tab[i] = desc.type;      
      /* ASSUMES that the first metric will always be a proc metric */
      if (i == 0) {
         proc_indom = desc.indom;
      } 
    }

    for(;;) {
      doit();
        sleep(delta.tv_sec);
    }

    return 0;
}

Generated by  Doxygen 1.6.0   Back to index