Old s-sunos5.c
  1 /* 
  2  * System dependent file for SunOS5.x machines, using the kstat library.
  3  * 
  4  * John DiMarco, CSLab, University of Toronto <jdd@cs.toronto.edu> 
  5  */
  6 
  7 /* LINTLIBRARY */
  8 
  9 #include <stdio.h>
 10 #include <kstat.h>
 11 #include <fcntl.h>
 12 #include <sys/var.h>
 13 #include <sys/sysinfo.h>
 14 #include <sys/ioctl.h>
 15 #include <stdlib.h>
 16 #include <unistd.h>
 17 #include <string.h>
 18 
 19 #ifndef MAXHOSTNAMELEN
 20   /* Some U*x deviants managed to not have this in sys/param.h */
 21 # define MAXHOSTNAMELEN 64
 22 #endif
 23 
 24 static kstat_ctl_t *kctl;
 25 
 26 static struct kstat_list {
 27         kstat_t *k;
 28         struct kstat_list *next;
 29 } *disk=NULL, *cpu=NULL;
 30 
 31 #ifndef kstime_t
 32 #define kstime_t hrtime_t
 33 #endif 
 34 
 35 static ulong *cpu_old[CPU_STATES];
 36 static kstime_t *old_update, *old_rtime, *old_wtime;
 37 
 38 #define DISKSTATES 3 /* idle, wait, run */
 39 #define NSTATES 4 /* idle, wait, user, kernel */
 40 
 41 extern char *xmalloc(/* int nbytes */);
 42 extern void shorten(/* char *hname */);
 43 
 44 extern int read();
 45 extern long lseek();
 46 
 47 extern int diskflag;
 48 extern int cpuflag;
 49 extern int sep_wait;
 50 
 51 int ncpu;       /* number of CPUs */
 52 int ndisk;      /* number of disks */
 53 
 54 int maxcpunum=0;        /* highest-numbered CPU */
 55 
 56 int *cpupos;
 57 
 58 #define BUFFSIZE 64
 59 
 60 extern void draw_bar(/*int bar_num, int *states, int num_states*/);
 61 
 62 /* Called at the beginning to inquire how many bars are needed. */
 63 int
 64 num_bars()
 65 {
 66         kstat_t *k;
 67         struct kstat_list *diskcur,*cpucur;
 68 
 69         /* Open the kstat interface */
 70         if(NULL==(kctl=kstat_open())){
 71                 perror("kstat");
 72                 exit(1);
 73         }
 74 
 75         /* 
 76          * Follow the kstat chain, making note of each useful module we
 77          * come across. Usefulness = disk if diskflag, cpu if cpuflag.
 78          */
 79         for(k=kctl->kc_chain;k;k=k->ks_next){
 80                 if(cpuflag){
 81                         if(0==(strncmp(k->ks_name, "cpu_stat", 8))){
 82                                 struct kstat_list *new;
 83                                 int cpunum;
 84 
 85                                 (void)sscanf(k->ks_name, "cpu_stat%d", &cpunum);
 86                                 if(cpunum>maxcpunum) maxcpunum = cpunum;
 87                                 new = (struct kstat_list *)xmalloc(
 88                                         sizeof(struct kstat_list));
 89                                 new->k=k;
 90                                 new->next=NULL;
 91                                 if(NULL==cpu){
 92                                         cpu=new;
 93                                         cpucur=new;
 94                                 } else {
 95                                         cpucur->next=new;
 96                                         cpucur=new;
 97                                 }
 98                                 ncpu++;
 99                         }
100                 }
101                 if(diskflag){
102                         if(0==(strcmp(k->ks_class, "disk"))
103                            && KSTAT_TYPE_IO==k->ks_type){
104                                 struct kstat_list *new;
105 
106                                 new = (struct kstat_list *)xmalloc(
107                                                 sizeof(struct kstat_list));
108                                 new->k=k;
109                                 new->next=NULL;
110                                 if(NULL==disk){
111                                         disk=new;
112                                         diskcur=new;
113                                 } else {
114                                         diskcur->next=new;
115                                         diskcur=new;
116                                 }
117 
118                                 ndisk++;
119                         }
120                 }
121         }
122         if(maxcpunum<ncpu) maxcpunum=ncpu;
123         return(((cpuflag*ncpu)+(diskflag*ndisk)));
124 }
125 
126 /* Called after num_bars to ask for the bar names */
127 char **
128 label_bars(nbars)
129 {
130         char **names;
131         int i, base, c;
132         struct kstat_list *k;
133         static char hname[MAXHOSTNAMELEN + 1];
134         char buf[MAXHOSTNAMELEN + 1 + BUFFSIZE];
135         char *cpname="";
136 
137         hname[MAXHOSTNAMELEN] = '\0';
138         if (0 >gethostname(hname, MAXHOSTNAMELEN)) {
139                 perror("gethostname");
140                 *hname = '\0';
141         }
142         shorten(hname);
143         names = (char **) xmalloc(nbars * sizeof(char *));
144 
145         base=0; 
146         if(cpuflag && cpu) {
147                 /* do cpu names */
148 
149                 /* set up cpupos to map cpu numbers to cpu index */
150                 cpupos=(int *)xmalloc((maxcpunum+1) * sizeof(int));
151                 for(i=0;i<=maxcpunum;i++) cpupos[i]=-1;
152                 for(k=cpu;k;k=k->next){
153                         (void)sscanf(k->k->ks_name, "cpu_stat%d", &i);
154                         cpupos[i]=1;
155                 }
156                 c=0;
157                 for(i=0;i<=maxcpunum;i++) {
158                         if(0<cpupos[i]) {
159                                 cpupos[i]=c;
160                                 (void) sprintf(buf, "%s%s%s%d", hname, 
161                                         hname[0]?" ":"", cpname, i);
162                                 names[c] = strcpy(xmalloc(strlen(buf)+1), buf);
163                                 c++;
164                         }
165                 }
166 
167                 base+=ncpu;
168         }
169         if(diskflag && disk) {
170                 /* do disk names */
171                 for(i=0,k=disk;k;i++,k=k->next){
172                         (void) sprintf(buf, "%s%s%s", hname, hname[0]?" ":"", 
173                                         k->k->ks_name);
174                         names[base+i] = strcpy(xmalloc(strlen(buf) + 1), buf);
175                 }
176                 base+=ndisk;
177         }
178 
179         return names;
180 }
181 
182 /* 
183  *  Called after the bars are created to perform any machine dependent
184  *  initializations.
185  */
186 /* ARGSUSED */
187 void
188 init_bars(nbars)
189 int nbars;
190 {
191         if(cpuflag) {
192                 int i;
193                 for(i=0;i<CPU_STATES;i++){
194                         cpu_old[i] = (ulong *)xmalloc(ncpu*sizeof(ulong));
195                 }
196         }
197         if(diskflag){
198                 old_update = (kstime_t *)xmalloc(ndisk*sizeof(kstime_t));
199                 old_rtime = (kstime_t *)xmalloc(ndisk*sizeof(kstime_t));
200                 old_wtime = (kstime_t *)xmalloc(ndisk*sizeof(kstime_t));
201         }
202 }
203 
204 /*
205  * Indicates how many levels each bar has.  For most machines, each bar will
206  * have the same stuff.  But one can, for instance, display memory use on one
207  * bar, processor levels on others, etc.
208  */
209 void
210 bar_items(nbars, items)
211 int nbars;
212 int items[];    /* nbars items in this */
213 {
214     int i, n=0;
215 
216     if(cpuflag){
217         for(i=0; i<ncpu; i++,n++){
218                 if(sep_wait) {
219                         items[n] = NSTATES;
220                 } else {
221                         items[n] = NSTATES-1;
222                 }
223         }
224     }
225     if(diskflag){
226         for(i=0; i<ndisk; i++,n++){
227                 items[n] = DISKSTATES;
228         }
229     }
230 }
231 
232 static void
233 display_cpu(base)
234 int base;
235 {
236         int i,j,nstates;
237         int states[CPU_STATES];
238         cpu_stat_t cpustat;
239         struct kstat_list *k;
240 #define delta(cpustate) ((int)(cpustat.cpu_sysinfo.cpu[(cpustate)] - cpu_old[(cpustate)][i]))
241 
242 
243         for(k=cpu;k;k=k->next){      /* for each cpu... */
244                 int cpunum;
245 
246                 (void)sscanf(k->k->ks_name, "cpu_stat%d", &cpunum);
247                 i=cpupos[cpunum];
248 
249                 /* grab info */
250                 if(-1==kstat_read(kctl, k->k, (void *)&cpustat)){
251                         perror("kstat: cpustat");
252                         exit(1);
253                 }
254                 
255                 nstates=0;
256                 if(sep_wait) {
257                         states[nstates++] = delta(CPU_IDLE);
258                         states[nstates++] = delta(CPU_WAIT);
259                 } else {
260                         states[nstates++] = delta(CPU_IDLE) + delta(CPU_WAIT);
261                 }
262                 states[nstates++] = delta(CPU_USER);
263                 states[nstates++] = delta(CPU_KERNEL);
264 
265                 draw_bar(i+base, states, nstates);
266 
267                 /* save old values */
268                 for(j=0;j<CPU_STATES;j++){
269                         cpu_old[j][i]=cpustat.cpu_sysinfo.cpu[j];
270                 }
271         }
272 }
273 
274 static void
275 display_disk(base)
276 int base;
277 {
278         int i;
279         kstat_io_t dstat;
280         struct kstat_list *k;
281         int states[DISKSTATES], nstates;
282         
283         for(i=0,k=disk;k;k=k->next,i++){ /* for each disk... */
284                 double elapsed, run, wait, idle;
285                 /* grab info */
286                 if(-1==kstat_read(kctl, k->k, (void *)&dstat)){
287                         perror( "kstat: diskstat");
288                         exit(1);
289                 }
290 
291                 /* 
292                  * The goofy *(double *)& stuff is to support both compilers
293                  * that know about long long and those that don't. 
294                  * <sys/types.h> defines long long as a union of long[2]
295                  * and double if it thinks the compiler doesn't know 
296                  * about long long. 
297                  */
298                 elapsed = *(double *)&dstat.wlastupdate - 
299                           *(double *)&old_update[i];
300                 if(elapsed <= 0.0) elapsed = (double) NANOSEC;
301 
302                 run = 100 * (*(double *)&dstat.rtime - 
303                                 *(double *)&old_rtime[i]) /elapsed; 
304                 wait = 100 * (*(double *)&dstat.wtime - 
305                                 *(double *)&old_wtime[i]) /elapsed;
306                 idle = 100 - (run + wait);
307                 if(idle<0.0) idle=0.0;
308 
309                 nstates=0;
310                 states[nstates++] = (int)idle;
311                 states[nstates++] = (int)wait;
312                 states[nstates++] = (int)run;
313 
314                 draw_bar(i+base, states, 3);
315 
316                 /* save old values */
317 
318                 *(double *)&old_update[i] = *(double *)&dstat.wlastupdate;
319                 *(double *)&old_rtime[i] = *(double *)&dstat.rtime;
320                 *(double *)&old_wtime[i] = *(double *)&dstat.wtime;
321 
322         }
323 }
324 
325 /* 
326  *  This procedure gets called every interval to compute and display the
327  *  bars. It should call draw_bar() with the bar number, the array of
328  *  integer values to display in the bar, and the number of values in
329  *  the array.
330  */
331 /* ARGSUSED */
332 void
333 display_bars(nbars)
334 int nbars;
335 {
336         int n=0;
337         
338         if(cpuflag) {
339                 display_cpu(n);
340                 n+=ncpu;
341         }
342         if(diskflag) {
343                 display_disk(n);
344                 n+=ndisk;
345         }
346 }