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 }