/*
* System dependent file for SunOS5.x machines, using the kstat library.
*
* John DiMarco, CSLab, University of Toronto <jdd@cs.toronto.edu>
*/
/* LINTLIBRARY */
#include <stdio.h>
#include <sys/types.h>
#include <kstat.h>
#include <fcntl.h>
#include <sys/var.h>
#include <sys/sysinfo.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#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(maxcpunum<ncpu) maxcpunum=ncpu;
return(((cpuflag*ncpu)+(diskflag*ndisk)));
}
/* Called after num_bars to ask for the bar names */
char **
label_bars(nbars)
{
char **names;
int i, base, c;
struct kstat_list *k;
static char hname[MAXHOSTNAMELEN + 1];
char buf[MAXHOSTNAMELEN + 1 + BUFFSIZE];
char *cpname="";
hname[MAXHOSTNAMELEN] = '\0';
if (0 >gethostname(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(0<cpupos[i]) {
cpupos[i]=c;
(void) sprintf(buf, "%s%s%s%d", hname,
hname[0]?" ":"", cpname, i);
names[c] = strcpy(xmalloc(strlen(buf)+1), buf);
c++;
}
}
base+=ncpu;
}
if(diskflag && disk) {
/* do disk names */
for(i=0,k=disk;k;i++,k=k->next){
(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;i<CPU_STATES;i++){
cpu_old[i] = (ulong *)xmalloc(ncpu*sizeof(ulong));
}
}
if(diskflag){
old_update = (kstime_t *)xmalloc(ndisk*sizeof(kstime_t));
old_rtime = (kstime_t *)xmalloc(ndisk*sizeof(kstime_t));
old_wtime = (kstime_t *)xmalloc(ndisk*sizeof(kstime_t));
}
}
/*
* Indicates how many levels each bar has. For most machines, each bar will
* have the same stuff. But one can, for instance, display memory use on one
* bar, processor levels on others, etc.
*/
void
bar_items(nbars, items)
int nbars;
int items[]; /* nbars items in this */
{
int i, n=0;
if(cpuflag){
for(i=0; i<ncpu; i++,n++){
if(sep_wait) {
items[n] = NSTATES;
} else {
items[n] = NSTATES-1;
}
}
}
if(diskflag){
for(i=0; i<ndisk; i++,n++){
items[n] = DISKSTATES;
}
}
}
static void
display_cpu(base)
int base;
{
int i,j,nstates;
int states[CPU_STATES];
cpu_stat_t cpustat;
struct kstat_list *k;
#define delta(cpustate) ((int)(cpustat.cpu_sysinfo.cpu[(cpustate)] - cpu_old[(cpustate)][i]))
for(k=cpu;k;k=k->next){ /* 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;j<CPU_STATES;j++){
cpu_old[j][i]=cpustat.cpu_sysinfo.cpu[j];
}
}
}
static void
display_disk(base)
int base;
{
int i;
kstat_io_t dstat;
struct kstat_list *k;
int states[DISKSTATES], nstates;
for(i=0,k=disk;k;k=k->next,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.
* <sys/types.h> 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;
}
}
syntax highlighted by Code2HTML, v. 0.9.1