nrelease - fix/improve livecd
[dragonfly.git] / usr.sbin / iostat / iostat.c
1 /*
2  * Copyright (c) 1997, 1998  Kenneth D. Merry.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/usr.sbin/iostat/iostat.c,v 1.17.2.2 2001/07/19 04:15:42 kris Exp $
29  */
30 /*
31  * Parts of this program are derived from the original FreeBSD iostat
32  * program:
33  */
34 /*-
35  * Copyright (c) 1986, 1991, 1993
36  *      The Regents of the University of California.  All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. Neither the name of the University nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  */
62 /*
63  * Ideas for the new iostat statistics output modes taken from the NetBSD
64  * version of iostat:
65  */
66 /*
67  * Copyright (c) 1996 John M. Vinopal
68  * All rights reserved.
69  *
70  * Redistribution and use in source and binary forms, with or without
71  * modification, are permitted provided that the following conditions
72  * are met:
73  * 1. Redistributions of source code must retain the above copyright
74  *    notice, this list of conditions and the following disclaimer.
75  * 2. Redistributions in binary form must reproduce the above copyright
76  *    notice, this list of conditions and the following disclaimer in the
77  *    documentation and/or other materials provided with the distribution.
78  * 3. All advertising materials mentioning features or use of this software
79  *    must display the following acknowledgement:
80  *      This product includes software developed for the NetBSD Project
81  *      by John M. Vinopal.
82  * 4. The name of the author may not be used to endorse or promote products
83  *    derived from this software without specific prior written permission.
84  *
85  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
86  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
87  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
88  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
89  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
90  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
91  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
92  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
93  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95  * SUCH DAMAGE.
96  */
97
98 #include <sys/param.h>
99 #include <sys/errno.h>
100 #include <sys/ttycom.h>
101
102 #include <err.h>
103 #include <ctype.h>
104 #include <fcntl.h>
105 #include <kinfo.h>
106 #include <stdio.h>
107 #include <stdlib.h>
108 #include <string.h>
109 #include <unistd.h>
110 #include <limits.h>
111 #include <devstat.h>
112
113 struct statinfo cur, last;
114 uint64_t tk_nin, old_tk_nin, diff_tk_nin;
115 uint64_t tk_nout, old_tk_nout, diff_tk_nout;
116 struct kinfo_cputime cp_time, old_cp_time, diff_cp_time;
117 double cp_time_total;
118 int num_devices;
119 struct device_selection *dev_select;
120 int maxshowdevs;
121 int dflag = 0, Dflag=0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0;
122
123 /* local function declarations */
124 static void usage(void);
125 static void phdr(int signo);
126 static void devstats(int perf_select);
127 static void cpustats(void);
128 static void adddeletion(const char *prefix,
129             int num_selected, char ***deletions, int *num_deletions);
130
131 static void
132 usage(void)
133 {
134         /*
135          * We also support the following 'traditional' syntax:
136          * iostat [drives] [wait [count]]
137          * This isn't mentioned in the man page, or the usage statement,
138          * but it is supported.
139          */
140         fprintf(stderr, "usage: iostat [-CdhIKoT] [-c count]"
141                 " [-n devs]\n"
142                 "\t      [-t type,if,pass] [-w wait] [drives]\n");
143 }
144
145 int
146 main(int argc, char **argv)
147 {
148         int c;
149         int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0;
150         int count = 0, waittime = 0;
151         struct devstat_match *matches;
152         int num_matches = 0;
153         int num_deletions = 0;
154         int hz;
155         int headercount;
156         long generation;
157         int num_devices_specified;
158         int num_selected, num_selections;
159         long select_generation;
160         char **deletions;
161         char **specified_devices;
162         devstat_select_mode select_mode;
163
164         matches = NULL;
165         deletions = NULL;
166         maxshowdevs = 3;
167
168         while ((c = getopt(argc, argv, "c:CdDhIKM:n:N:ot:Tw:")) != -1) {
169                 switch(c) {
170                         case 'c':
171                                 cflag++;
172                                 count = atoi(optarg);
173                                 if (count < 1)
174                                         errx(1, "count %d is < 1", count);
175                                 break;
176                         case 'C':
177                                 Cflag++;
178                                 break;
179                         case 'd':
180                                 dflag++;
181                                 break;
182                         case 'D':
183                                 Dflag++;
184                                 break;
185                         case 'h':
186                                 hflag++;
187                                 break;
188                         case 'I':
189                                 Iflag++;
190                                 break;
191                         case 'K':
192                                 Kflag++;
193                                 break;
194                         case 'n':
195                                 nflag++;
196                                 maxshowdevs = atoi(optarg);
197                                 if (maxshowdevs < 0)
198                                         errx(1, "number of devices %d is < 0",
199                                              maxshowdevs);
200                                 break;
201                         case 'o':
202                                 oflag++;
203                                 break;
204                         case 't':
205                                 tflag++;
206                                 if (buildmatch(optarg, &matches, 
207                                                &num_matches) != 0)
208                                         errx(1, "%s", devstat_errbuf);
209                                 break;
210                         case 'T':
211                                 Tflag++;
212                                 break;
213                         case 'w':
214                                 wflag++;
215                                 waittime = atoi(optarg);
216                                 if (waittime < 1)
217                                         errx(1, "wait time is < 1");
218                                 break;
219                         default:
220                                 usage();
221                                 exit(1);
222                                 break;
223                 }
224         }
225
226         argc -= optind;
227         argv += optind;
228
229         /*
230          * Make sure that the userland devstat version matches the kernel
231          * devstat version.  If not, exit and print a message informing 
232          * the user of his mistake.
233          */
234         if (checkversion() < 0)
235                 errx(1, "%s", devstat_errbuf);
236
237         /*
238          * Figure out how many devices we should display.
239          */
240         if (nflag == 0) {
241                 struct winsize ws;
242
243                 if (oflag > 0) {
244                         if ((dflag > 0) && (Cflag == 0) && (Tflag == 0))
245                                 maxshowdevs = 5;
246                         else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0))
247                                 maxshowdevs = 5;
248                         else
249                                 maxshowdevs = 4;
250                 } else {
251                         if ((dflag > 0) && (Cflag == 0))
252                                 maxshowdevs = 4;                
253                         else
254                                 maxshowdevs = 3;
255                 }
256                 if (ioctl(1, TIOCGWINSZ, &ws) >= 0 && ws.ws_col > 80)
257                         maxshowdevs += (ws.ws_col - 80) / 17;
258         }
259
260         /* find out how many devices we have */
261         if ((num_devices = getnumdevs()) < 0)
262                 err(1, "can't get number of devices");
263
264         if ((cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo))) ==
265              NULL)
266                 err(1, "devinfo malloc failed");
267         if ((last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo))) ==
268              NULL)
269                 err(1, "devinfo malloc failed");
270         bzero(cur.dinfo, sizeof(struct devinfo));
271         bzero(last.dinfo, sizeof(struct devinfo));
272
273         /*
274          * Grab all the devices.  We don't look to see if the list has
275          * changed here, since it almost certainly has.  We only look for
276          * errors.
277          */
278         if (getdevs(&cur) == -1)
279                 errx(1, "%s", devstat_errbuf);
280
281         num_devices = cur.dinfo->numdevs;
282         generation = cur.dinfo->generation;
283
284         /*
285          * If the user specified any devices on the command line, see if
286          * they are in the list of devices we have now.
287          */
288         if ((specified_devices = (char **)malloc(sizeof(char *))) == NULL)
289                 err(1, "specified_devices malloc failed");
290         for (num_devices_specified = 0; *argv; ++argv) {
291                 if (isdigit(**argv))
292                         break;
293                 num_devices_specified++;
294                 specified_devices = (char **)realloc(specified_devices,
295                                                      sizeof(char *) *
296                                                      num_devices_specified);
297                 specified_devices[num_devices_specified - 1] = *argv;
298
299         }
300         if (nflag == 0 && maxshowdevs < num_devices_specified)
301                 maxshowdevs = num_devices_specified;
302
303         dev_select = NULL;
304
305         if ((num_devices_specified == 0) && (num_matches == 0))
306                 select_mode = DS_SELECT_ADD;
307         else
308                 select_mode = DS_SELECT_ONLY;
309
310         /*
311          * At this point, selectdevs will almost surely indicate that the
312          * device list has changed, so we don't look for return values of 0
313          * or 1.  If we get back -1, though, there is an error.
314          */
315         if (selectdevs(&dev_select, &num_selected,
316                        &num_selections, &select_generation,
317                        generation, cur.dinfo->devices, num_devices,
318                        matches, num_matches,
319                        specified_devices, num_devices_specified,
320                        select_mode, maxshowdevs, hflag) == -1) {
321                 errx(1, "%s", devstat_errbuf);
322         }
323
324         /*
325          * These devices are not usually desired
326          */
327         if (select_mode == DS_SELECT_ADD) {
328                 adddeletion("md", num_selected, &deletions, &num_deletions);
329                 adddeletion("pass", num_selected, &deletions, &num_deletions);
330                 adddeletion("sg", num_selected, &deletions, &num_deletions);
331                 if (selectdevs(&dev_select, &num_selected,
332                                &num_selections, &select_generation,
333                                generation, cur.dinfo->devices, num_devices,
334                                matches, num_matches,
335                                deletions, num_deletions,
336                                DS_SELECT_REMOVE, maxshowdevs, hflag) == -1) {
337                         errx(1, "%s", devstat_errbuf);
338                 }
339                 select_mode = DS_SELECT_ADDONLY;
340         }
341
342         /*
343          * Look for the traditional wait time and count arguments.
344          */
345         if (*argv) {
346                 waittime = atoi(*argv);
347
348                 /* Let the user know he goofed, but keep going anyway */
349                 if (wflag != 0) 
350                         warnx("discarding previous wait interval, using"
351                               " %d instead", waittime);
352                 wflag++;
353
354                 if (*++argv) {
355                         count = atoi(*argv);
356                         if (cflag != 0)
357                                 warnx("discarding previous count, using %d"
358                                       " instead", count);
359                         cflag++;
360                 } else
361                         count = -1;
362         }
363
364         /*
365          * If the user specified a count, but not an interval, we default
366          * to an interval of 1 second.
367          */
368         if ((wflag == 0) && (cflag > 0))
369                 waittime = 1;
370
371         /*
372          * If the user specified a wait time, but not a count, we want to
373          * go on ad infinitum.  This can be redundant if the user uses the
374          * traditional method of specifying the wait, since in that case we
375          * already set count = -1 above.  Oh well.
376          */
377         if ((wflag > 0) && (cflag == 0))
378                 count = -1;
379
380         if (kinfo_get_sched_hz(&hz))
381                 err(1, "kinfo_get_sched_hz");
382         if (kinfo_get_sched_stathz(&hz))
383                 err(1, "kinfo_get_sched_stathz");
384
385         /*
386          * If the user stops the program (control-Z) and then resumes it,
387          * print out the header again.
388          */
389         signal(SIGCONT, phdr);
390
391         for (headercount = 1;;) {
392                 struct devinfo *tmp_dinfo;
393
394                 if (!--headercount) {
395                         phdr(0);
396                         headercount = 20;
397                 }
398                 if (kinfo_get_tty_tk_nin(&tk_nin))
399                         err(1, "kinfo_get_tty_tk_nin");
400                 if (kinfo_get_tty_tk_nout(&tk_nout))
401                         err(1, "kinfo_get_tty_tk_nout");
402                 if (kinfo_get_sched_cputime(&cp_time))
403                         err(1, "kinfo_get_sched_cputime");
404
405                 tmp_dinfo = last.dinfo;
406                 last.dinfo = cur.dinfo;
407                 cur.dinfo = tmp_dinfo;
408
409                 last.busy_time = cur.busy_time;
410
411                 /*
412                  * Here what we want to do is refresh our device stats.
413                  * getdevs() returns 1 when the device list has changed.
414                  * If the device list has changed, we want to go through
415                  * the selection process again, in case a device that we
416                  * were previously displaying has gone away.
417                  */
418                 switch (getdevs(&cur)) {
419                 case -1:
420                         errx(1, "%s", devstat_errbuf);
421                         break;
422                 case 1: {
423                         int retval;
424
425                         num_devices = cur.dinfo->numdevs;
426                         generation = cur.dinfo->generation;
427                         retval = selectdevs(&dev_select, &num_selected,
428                                             &num_selections, &select_generation,
429                                             generation, cur.dinfo->devices,
430                                             num_devices, matches, num_matches,
431                                             specified_devices,
432                                             num_devices_specified,
433                                             select_mode, maxshowdevs, hflag);
434                         switch(retval) {
435                         case -1:
436                                 errx(1, "%s", devstat_errbuf);
437                                 break;
438                         case 1:
439                                 phdr(0);
440                                 headercount = 20;
441                                 break;
442                         default:
443                                 break;
444                         }
445                         break;
446                 }
447                 default:
448                         break;
449                 }
450
451                 /*
452                  * We only want to re-select devices if we're in 'top'
453                  * mode.  This is the only mode where the devices selected
454                  * could actually change.
455                  */
456                 if (hflag > 0) {
457                         int retval;
458                         retval = selectdevs(&dev_select, &num_selected,
459                                             &num_selections, &select_generation,
460                                             generation, cur.dinfo->devices,
461                                             num_devices, matches, num_matches,
462                                             specified_devices,
463                                             num_devices_specified,
464                                             select_mode, maxshowdevs, hflag);
465                         switch(retval) {
466                         case -1:
467                                 errx(1,"%s", devstat_errbuf);
468                                 break;
469                         case 1:
470                                 phdr(0);
471                                 headercount = 20;
472                                 break;
473                         default:
474                                 break;
475                         }
476                 }
477
478                 diff_tk_nin = tk_nin - old_tk_nin;
479                 old_tk_nin = tk_nin;
480                 diff_tk_nout = tk_nout - old_tk_nout;
481                 old_tk_nout = tk_nout;
482
483                 diff_cp_time.cp_user = cp_time.cp_user - old_cp_time.cp_user;
484                 diff_cp_time.cp_nice = cp_time.cp_nice - old_cp_time.cp_nice;
485                 diff_cp_time.cp_sys = cp_time.cp_sys - old_cp_time.cp_sys;
486                 diff_cp_time.cp_intr = cp_time.cp_intr - old_cp_time.cp_intr;
487                 diff_cp_time.cp_idle = cp_time.cp_idle - old_cp_time.cp_idle;
488                 cp_time_total = diff_cp_time.cp_user + diff_cp_time.cp_nice +
489                     diff_cp_time.cp_sys + diff_cp_time.cp_intr +
490                     diff_cp_time.cp_idle;
491                 old_cp_time = cp_time;
492
493                 if (cp_time_total == 0.0)
494                         cp_time_total = 1.0;
495
496                 if ((dflag == 0) || (Tflag > 0))
497                         printf("%4.0f%5.0f", diff_tk_nin / cp_time_total * 1e6, 
498                                 diff_tk_nout / cp_time_total * 1e6);
499                 devstats(hflag);
500                 if ((dflag == 0) || (Cflag > 0))
501                         cpustats();
502                 printf("\n");
503                 fflush(stdout);
504
505                 if (count >= 0 && --count <= 0)
506                         break;
507
508                 sleep(waittime);
509         }
510
511         exit(0);
512 }
513
514 static void
515 adddeletion(const char *prefix, int num_selected,
516             char ***deletions, int *num_deletions)
517 {
518         int i;
519
520         for (i = 0; i < num_selected; i++) {
521                 char tmpstr[80];
522
523                 if (strcmp(prefix, dev_select[i].device_name) != 0)
524                         continue;
525                 snprintf(tmpstr, sizeof(tmpstr), "%s%d",
526                         dev_select[i].device_name, dev_select[i].unit_number);
527                 ++*num_deletions;
528                 *deletions = realloc(*deletions,
529                                      *num_deletions * sizeof(char *));
530                 (*deletions)[*num_deletions - 1] = strdup(tmpstr);
531         }
532 }
533
534
535 static void
536 phdr(__unused int signo)
537 {
538         int i;
539         int printed;
540
541         if ((dflag == 0) || (Tflag > 0))
542                 printf("      tty");
543         for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){
544                 int di;
545                 if (dev_select[i].selected != 0) {
546                         di = dev_select[i].position;
547                         if (oflag > 0)
548                                 printf("%12.6s%d ", 
549                                             cur.dinfo->devices[di].device_name,
550                                             cur.dinfo->devices[di].unit_number);
551                         else
552                                 if (Dflag > 0)
553                                         printf("%19.6s%d            ",
554                                                     cur.dinfo->devices[di].device_name,
555                                                     cur.dinfo->devices[di].unit_number);
556                                 else
557                                         printf("%15.6s%d ",
558                                                     cur.dinfo->devices[di].device_name,
559                                                     cur.dinfo->devices[di].unit_number);
560                         printed++;
561                 }
562         }
563         if ((dflag == 0) || (Cflag > 0))
564                 printf("            cpu\n");
565         else
566                 printf("\n");
567
568         if ((dflag == 0) || (Tflag > 0))
569                 printf(" tin tout");
570
571         for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){
572                 if (dev_select[i].selected != 0) {
573                         if (oflag > 0) {
574                                 if (Iflag == 0)
575                                         printf(" sps tps  msps ");
576                                 else
577                                         printf(" blk xfr msps ");
578                         } else {
579                                 if (Iflag == 0) {
580                                         if (Dflag > 0)
581                                                 printf("   KB/t rtps  MBr/s wtps  MBw/s ");
582                                         else
583                                                 printf("  KB/t tps   MB/s ");
584                                 }
585                                 else
586                                         printf("  KB/t xfrs   MB ");
587                         }
588                         printed++;
589                 }
590         }
591         if ((dflag == 0) || (Cflag > 0))
592                 printf(" us ni sy in id\n");
593         else
594                 printf("\n");
595
596 }
597
598 static void
599 devstats(int perf_select)
600 {
601         int dn;
602         long double kb_per_transfer;
603         long double transfers_per_second;
604         long double transfers_per_secondr, transfers_per_secondw;
605         long double mb_per_second;
606         long double mb_per_secondr, mb_per_secondw;
607         u_int64_t total_bytes, total_transfers, total_blocks;
608         long double busy_seconds;
609         long double total_mb;
610         long double blocks_per_second, ms_per_transaction;
611         
612         /*
613          * Calculate elapsed time up front, since it's the same for all
614          * devices.
615          */
616         busy_seconds = compute_etime(cur.busy_time, last.busy_time);
617
618         for (dn = 0; dn < num_devices; dn++) {
619                 int di;
620
621                 if (perf_select == 0 && dev_select[dn].selected == 0)
622                         continue;
623
624                 di = dev_select[dn].position;
625
626                 if (compute_stats(&cur.dinfo->devices[di],
627                                   &last.dinfo->devices[di], busy_seconds,
628                                   &total_bytes, &total_transfers,
629                                   &total_blocks, &kb_per_transfer,
630                                   &transfers_per_second, &mb_per_second,
631                                   &blocks_per_second, &ms_per_transaction)!= 0)
632                         errx(1, "%s", devstat_errbuf);
633                 if (compute_stats_read(&cur.dinfo->devices[di],
634                                 &last.dinfo->devices[di], busy_seconds,
635                                 NULL, NULL,
636                                 NULL, NULL,
637                                 &transfers_per_secondr, &mb_per_secondr,
638                                 NULL, NULL)!= 0)
639                         errx(1, "%s", devstat_errbuf);
640                 if (compute_stats_write(&cur.dinfo->devices[di],
641                                 &last.dinfo->devices[di], busy_seconds,
642                                 NULL, NULL,
643                                 NULL, NULL,
644                                 &transfers_per_secondw, &mb_per_secondw,
645                                 NULL, NULL)!= 0)
646                         errx(1, "%s", devstat_errbuf);
647
648                 if (perf_select != 0) {
649                         dev_select[dn].bytes = total_bytes;
650                         if (dev_select[dn].selected == 0)
651                                 continue;
652                 }
653
654                 if (Kflag) {
655                         int block_size = cur.dinfo->devices[di].block_size;
656                         total_blocks = total_blocks * (block_size ?
657                                                        block_size : 512) / 1024;
658                 }
659
660                 if (oflag > 0) {
661                         int msdig = (ms_per_transaction < 100.0) ? 1 : 0;
662
663                         if (Iflag == 0)
664                                 printf("%4.0Lf%4.0Lf%5.*Lf ",
665                                        blocks_per_second,
666                                        transfers_per_second,
667                                        msdig,
668                                        ms_per_transaction);
669                         else 
670                                 printf("%4.1ju%4.1ju%5.*Lf ",
671                                        (uintmax_t)total_blocks,
672                                        (uintmax_t)total_transfers,
673                                        msdig,
674                                        ms_per_transaction);
675                 } else {
676                         if (Iflag == 0) 
677                                 if (Dflag > 0) {
678                                         printf(" %5.2Lf %4.0Lf %6.2Lf %4.0Lf %6.2Lf  ",
679                                                kb_per_transfer,
680                                                transfers_per_secondr,
681                                                mb_per_secondr,
682                                                transfers_per_secondw,
683                                                mb_per_secondw);
684                                 } else {
685                                         printf(" %5.2Lf %4.0Lf %5.2Lf ",
686                                                kb_per_transfer,
687                                                transfers_per_second,
688                                                mb_per_second);
689                                 }
690                         else {
691                                 total_mb = total_bytes;
692                                 total_mb /= 1024 * 1024;
693
694                                 printf(" %5.2Lf %3.1ju %5.2Lf ",
695                                        kb_per_transfer,
696                                        (uintmax_t)total_transfers,
697                                        total_mb);
698                         }
699                 }
700         }
701 }
702
703 static void
704 cpustats(void)
705 {
706         if (cp_time_total == 0.0)
707                 cp_time_total = 1.0;
708
709         printf(" %2.0f", 100. * diff_cp_time.cp_user / cp_time_total);
710         printf(" %2.0f", 100. * diff_cp_time.cp_nice / cp_time_total);
711         printf(" %2.0f", 100. * diff_cp_time.cp_sys / cp_time_total);
712         printf(" %2.0f", 100. * diff_cp_time.cp_intr / cp_time_total);
713         printf(" %2.0f", 100. * diff_cp_time.cp_idle / cp_time_total);
714 }