/* * System dependent file for SunOS5.x machines, using the kstat library. * * John DiMarco, CSLab, University of Toronto */ /* LINTLIBRARY */ #include #include #include #include #include #include #include #include #include #include #ifndef MAXHOSTNAMELEN /* Some U*x deviants managed to not have this in sys/param.h */ # define MAXHOSTNAMELEN 64 #endif static kstat_ctl_t *kctl; static struct kstat_list { kstat_t *k; struct kstat_list *next; } *disk=NULL, *cpu=NULL; #ifndef kstime_t #define kstime_t hrtime_t #endif static ulong *cpu_old[CPU_STATES]; static kstime_t *old_update, *old_rtime, *old_wtime; #define DISKSTATES 3 /* idle, wait, run */ #define NSTATES 4 /* idle, wait, user, kernel */ extern char *xmalloc(/* int nbytes */); extern void shorten(/* char *hname */); extern int read(); extern long lseek(); extern int diskflag; extern int cpuflag; extern int sep_wait; int ncpu; /* number of CPUs */ int ndisk; /* number of disks */ int maxcpunum=0; /* highest-numbered CPU */ int *cpupos; #define BUFFSIZE 64 extern void draw_bar(/*int bar_num, int *states, int num_states*/); /* Called by -version */ void version() { printf("SunOS 5.x\n"); } /* Called at the beginning to inquire how many bars are needed. */ int num_bars() { kstat_t *k; struct kstat_list *diskcur,*cpucur; /* Open the kstat interface */ if(NULL==(kctl=kstat_open())){ perror("kstat"); exit(1); } /* * Follow the kstat chain, making note of each useful module we * come across. Usefulness = disk if diskflag, cpu if cpuflag. */ for(k=kctl->kc_chain;k;k=k->ks_next){ if(cpuflag){ if(0==(strncmp(k->ks_name, "cpu_stat", 8))){ struct kstat_list *new; int cpunum; (void)sscanf(k->ks_name, "cpu_stat%d", &cpunum); if(cpunum>maxcpunum) maxcpunum = cpunum; new = (struct kstat_list *)xmalloc( sizeof(struct kstat_list)); new->k=k; new->next=NULL; if(NULL==cpu){ cpu=new; cpucur=new; } else { cpucur->next=new; cpucur=new; } ncpu++; } } if(diskflag){ if(0==(strcmp(k->ks_class, "disk")) && KSTAT_TYPE_IO==k->ks_type){ struct kstat_list *new; new = (struct kstat_list *)xmalloc( sizeof(struct kstat_list)); new->k=k; new->next=NULL; if(NULL==disk){ disk=new; diskcur=new; } else { diskcur->next=new; diskcur=new; } ndisk++; } } } if(maxcpunumgethostname(hname, MAXHOSTNAMELEN)) { perror("gethostname"); *hname = '\0'; } shorten(hname); names = (char **) xmalloc(nbars * sizeof(char *)); base=0; if(cpuflag && cpu) { /* do cpu names */ /* set up cpupos to map cpu numbers to cpu index */ cpupos=(int *)xmalloc((maxcpunum+1) * sizeof(int)); for(i=0;i<=maxcpunum;i++) cpupos[i]=-1; for(k=cpu;k;k=k->next){ (void)sscanf(k->k->ks_name, "cpu_stat%d", &i); cpupos[i]=1; } c=0; for(i=0;i<=maxcpunum;i++) { if(0next){ (void) sprintf(buf, "%s%s%s", hname, hname[0]?" ":"", k->k->ks_name); names[base+i] = strcpy(xmalloc(strlen(buf) + 1), buf); } base+=ndisk; } return names; } /* * Called after the bars are created to perform any machine dependent * initializations. */ /* ARGSUSED */ void init_bars(nbars) int nbars; { if(cpuflag) { int i; for(i=0;inext){ /* for each cpu... */ int cpunum; (void)sscanf(k->k->ks_name, "cpu_stat%d", &cpunum); i=cpupos[cpunum]; /* grab info */ if(-1==kstat_read(kctl, k->k, (void *)&cpustat)){ perror("kstat: cpustat"); exit(1); } nstates=0; if(sep_wait) { states[nstates++] = delta(CPU_IDLE); states[nstates++] = delta(CPU_WAIT); } else { states[nstates++] = delta(CPU_IDLE) + delta(CPU_WAIT); } states[nstates++] = delta(CPU_USER); states[nstates++] = delta(CPU_KERNEL); draw_bar(i+base, states, nstates); /* save old values */ for(j=0;jnext,i++){ /* for each disk... */ double elapsed, run, wait, idle; /* grab info */ if(-1==kstat_read(kctl, k->k, (void *)&dstat)){ perror( "kstat: diskstat"); exit(1); } /* * The goofy *(double *)& stuff is to support both compilers * that know about long long and those that don't. * defines long long as a union of long[2] * and double if it thinks the compiler doesn't know * about long long. */ elapsed = *(double *)&dstat.wlastupdate - *(double *)&old_update[i]; if(elapsed <= 0.0) elapsed = (double) NANOSEC; run = 100 * (*(double *)&dstat.rtime - *(double *)&old_rtime[i]) /elapsed; wait = 100 * (*(double *)&dstat.wtime - *(double *)&old_wtime[i]) /elapsed; idle = 100 - (run + wait); if(idle<0.0) idle=0.0; nstates=0; states[nstates++] = (int)idle; states[nstates++] = (int)wait; states[nstates++] = (int)run; draw_bar(i+base, states, 3); /* save old values */ *(double *)&old_update[i] = *(double *)&dstat.wlastupdate; *(double *)&old_rtime[i] = *(double *)&dstat.rtime; *(double *)&old_wtime[i] = *(double *)&dstat.wtime; } } /* * This procedure gets called every interval to compute and display the * bars. It should call draw_bar() with the bar number, the array of * integer values to display in the bar, and the number of values in * the array. */ /* ARGSUSED */ void display_bars(nbars) int nbars; { int n=0; if(cpuflag) { display_cpu(n); n+=ncpu; } if(diskflag) { display_disk(n); n+=ndisk; } }