2 * iostat: report CPU and I/O statistics
3 * (C) 1998-2016 by Sebastien GODARD (sysstat <at> orange.fr)
5 ***************************************************************************
6 * This program is free software; you can redistribute it and/or modify it *
7 * under the terms of the GNU General Public License as published by the *
8 * Free Software Foundation; either version 2 of the License, or (at your *
9 * option) any later version. *
11 * This program is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
16 * You should have received a copy of the GNU General Public License along *
17 * with this program; if not, write to the Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *
19 ***************************************************************************
32 #include <sys/types.h>
34 #include <sys/utsname.h>
46 #define _(string) gettext(string)
48 #define _(string) (string)
51 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
52 char *sccsid(void) { return (SCCSID); }
54 struct stats_cpu *st_cpu[2];
55 unsigned long long uptime[2] = {0, 0};
56 unsigned long long uptime0[2] = {0, 0};
57 struct io_stats *st_iodev[2];
58 struct io_hdr_stats *st_hdr_iodev;
59 struct io_dlist *st_dev_list;
61 /* Last group name entered on the command line */
62 char group_name[MAX_NAME_LEN];
64 int iodev_nr = 0; /* Nb of devices and partitions found. Includes nb of device groups */
65 int group_nr = 0; /* Nb of device groups */
66 int cpu_nr = 0; /* Nb of processors on the machine */
67 int dlist_idx = 0; /* Nb of devices entered on the command line */
68 int flags = 0; /* Flag for common options and system state */
69 unsigned int dm_major; /* Device-mapper major number */
74 struct sigaction alrm_act;
77 ***************************************************************************
78 * Print usage and exit.
81 * @progname Name of sysstat command.
82 ***************************************************************************
84 void usage(char *progname)
86 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
89 fprintf(stderr, _("Options are:\n"
90 "[ -c ] [ -d ] [ -h ] [ -k | -m ] [ -N ] [ -t ] [ -V ] [ -x ] [ -y ] [ -z ]\n"
91 "[ -j { ID | LABEL | PATH | UUID | ... } ] [ -o JSON ]\n"
92 "[ [ -H ] -g <group_name> ] [ -p [ <device> [,...] | ALL ] ]\n"
93 "[ <device> [...] | ALL ] [ --debuginfo ]\n"));
95 fprintf(stderr, _("Options are:\n"
96 "[ -c ] [ -d ] [ -h ] [ -k | -m ] [ -N ] [ -t ] [ -V ] [ -x ] [ -y ] [ -z ]\n"
97 "[ -j { ID | LABEL | PATH | UUID | ... } ] [ -o JSON ]\n"
98 "[ [ -H ] -g <group_name> ] [ -p [ <device> [,...] | ALL ] ]\n"
99 "[ <device> [...] | ALL ]\n"));
105 ***************************************************************************
106 * Set disk output unit. Unit will be kB/s unless POSIXLY_CORRECT
107 * environment variable has been set, in which case the output will be
108 * expressed in blocks/s.
109 ***************************************************************************
111 void set_disk_output_unit(void)
113 if (DISPLAY_KILOBYTES(flags) || DISPLAY_MEGABYTES(flags))
116 /* Check POSIXLY_CORRECT environment variable */
117 if (getenv(ENV_POSIXLY_CORRECT) == NULL) {
118 /* Variable not set: Unit is kB/s and not blocks/s */
119 flags |= I_D_KILOBYTES;
124 ***************************************************************************
125 * SIGALRM signal handler. No need to reset the handler here.
128 * @sig Signal number.
129 ***************************************************************************
131 void alarm_handler(int sig)
137 ***************************************************************************
138 * Initialize stats common structures.
139 ***************************************************************************
141 void init_stats(void)
145 /* Allocate structures for CPUs "all" and 0 */
146 for (i = 0; i < 2; i++) {
147 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * 2)) == NULL) {
151 memset(st_cpu[i], 0, STATS_CPU_SIZE * 2);
156 ***************************************************************************
157 * Set every device entry to unregistered status. But don't change status
158 * for group entries (whose status is DISK_GROUP).
161 * @iodev_nr Number of devices and partitions.
162 * @st_hdr_iodev Pointer on first structure describing a device/partition.
163 ***************************************************************************
165 void set_entries_unregistered(int iodev_nr, struct io_hdr_stats *st_hdr_iodev)
168 struct io_hdr_stats *shi = st_hdr_iodev;
170 for (i = 0; i < iodev_nr; i++, shi++) {
171 if (shi->status == DISK_REGISTERED) {
172 shi->status = DISK_UNREGISTERED;
178 ***************************************************************************
179 * Free unregistered entries (mark them as unused).
182 * @iodev_nr Number of devices and partitions.
183 * @st_hdr_iodev Pointer on first structure describing a device/partition.
184 ***************************************************************************
186 void free_unregistered_entries(int iodev_nr, struct io_hdr_stats *st_hdr_iodev)
189 struct io_hdr_stats *shi = st_hdr_iodev;
191 for (i = 0; i < iodev_nr; i++, shi++) {
192 if (shi->status == DISK_UNREGISTERED) {
199 ***************************************************************************
200 * Allocate and init I/O device structures.
203 * @dev_nr Number of devices and partitions (also including groups
204 * if option -g has been used).
205 ***************************************************************************
207 void salloc_device(int dev_nr)
211 for (i = 0; i < 2; i++) {
213 (struct io_stats *) malloc(IO_STATS_SIZE * dev_nr)) == NULL) {
217 memset(st_iodev[i], 0, IO_STATS_SIZE * dev_nr);
221 (struct io_hdr_stats *) malloc(IO_HDR_STATS_SIZE * dev_nr)) == NULL) {
225 memset(st_hdr_iodev, 0, IO_HDR_STATS_SIZE * dev_nr);
229 ***************************************************************************
230 * Allocate structures for devices entered on the command line.
233 * @list_len Number of arguments on the command line.
234 ***************************************************************************
236 void salloc_dev_list(int list_len)
238 if ((st_dev_list = (struct io_dlist *) malloc(IO_DLIST_SIZE * list_len)) == NULL) {
242 memset(st_dev_list, 0, IO_DLIST_SIZE * list_len);
246 ***************************************************************************
247 * Free structures used for devices entered on the command line.
248 ***************************************************************************
250 void sfree_dev_list(void)
256 ***************************************************************************
257 * Look for the device in the device list and store it if not found.
260 * @dlist_idx Length of the device list.
261 * @device_name Name of the device.
264 * @dlist_idx Length of the device list.
267 * Position of the device in the list.
268 ***************************************************************************
270 int update_dev_list(int *dlist_idx, char *device_name)
273 struct io_dlist *sdli = st_dev_list;
275 for (i = 0; i < *dlist_idx; i++, sdli++) {
276 if (!strcmp(sdli->dev_name, device_name))
280 if (i == *dlist_idx) {
282 * Device not found: Store it.
283 * Group names will be distinguished from real device names
284 * thanks to their names which begin with a space.
287 strncpy(sdli->dev_name, device_name, MAX_NAME_LEN - 1);
294 ***************************************************************************
295 * Allocate and init structures, according to system state.
296 ***************************************************************************
298 void io_sys_init(void)
300 /* Allocate and init stat common counters */
303 /* How many processors on this machine? */
304 cpu_nr = get_cpu_nr(~0, FALSE);
306 /* Get number of block devices and partitions in /proc/diskstats */
307 if ((iodev_nr = get_diskstats_dev_nr(CNT_PART, CNT_ALL_DEV)) > 0) {
308 flags |= I_F_HAS_DISKSTATS;
309 iodev_nr += NR_DEV_PREALLOC;
312 if (!HAS_DISKSTATS(flags) ||
313 (DISPLAY_PARTITIONS(flags) && !DISPLAY_PART_ALL(flags))) {
315 * If /proc/diskstats exists but we also want stats for the partitions
316 * of a particular device, stats will have to be found in /sys. So we
317 * need to know if /sys is mounted or not, and set flags accordingly.
320 /* Get number of block devices (and partitions) in sysfs */
321 if ((iodev_nr = get_sysfs_dev_nr(DISPLAY_PARTITIONS(flags))) > 0) {
322 flags |= I_F_HAS_SYSFS;
323 iodev_nr += NR_DEV_PREALLOC;
326 fprintf(stderr, _("Cannot find disk data\n"));
331 /* Also allocate stat structures for "group" devices */
332 iodev_nr += group_nr;
335 * Allocate structures for number of disks found, but also
336 * for groups of devices if option -g has been entered on the command line.
337 * iodev_nr must be <> 0.
339 salloc_device(iodev_nr);
343 ***************************************************************************
344 * When group stats are to be displayed (option -g entered on the command
345 * line), save devices and group names in the io_hdr_stats structures. This
346 * is normally done later when stats are actually read from /proc or /sys
347 * files (via a call to save_stats() function), but here we want to make
348 * sure that the structures are ordered and that each device belongs to its
350 * Note that we can still have an unexpected device that gets attached to a
351 * group as devices can be registered or unregistered dynamically.
352 ***************************************************************************
354 void presave_device_list(void)
357 struct io_hdr_stats *shi = st_hdr_iodev;
358 struct io_dlist *sdli = st_dev_list;
361 /* First, save the last group name entered on the command line in the list */
362 update_dev_list(&dlist_idx, group_name);
364 /* Now save devices and group names in the io_hdr_stats structures */
365 for (i = 0; (i < dlist_idx) && (i < iodev_nr); i++, shi++, sdli++) {
366 strncpy(shi->name, sdli->dev_name, MAX_NAME_LEN);
367 shi->name[MAX_NAME_LEN - 1] = '\0';
369 if (shi->name[0] == ' ') {
370 /* Current device name is in fact the name of a group */
371 shi->status = DISK_GROUP;
374 shi->status = DISK_REGISTERED;
380 * No device names have been entered on the command line but
381 * the name of a group. Save that name at the end of the
382 * data table so that all devices that will be read will be
383 * included in that group.
386 strncpy(shi->name, group_name, MAX_NAME_LEN);
387 shi->name[MAX_NAME_LEN - 1] = '\0';
389 shi->status = DISK_GROUP;
394 ***************************************************************************
395 * Free various structures.
396 ***************************************************************************
398 void io_sys_free(void)
402 for (i = 0; i < 2; i++) {
403 /* Free CPU structures */
406 /* Free I/O device structures */
414 ***************************************************************************
415 * Save stats for current device or partition.
418 * @name Name of the device/partition.
419 * @curr Index in array for current sample statistics.
420 * @st_io Structure with device or partition to save.
421 * @iodev_nr Number of devices and partitions.
422 * @st_hdr_iodev Pointer on structures describing a device/partition.
425 * @st_hdr_iodev Pointer on structures describing a device/partition.
426 ***************************************************************************
428 void save_stats(char *name, int curr, void *st_io, int iodev_nr,
429 struct io_hdr_stats *st_hdr_iodev)
432 struct io_hdr_stats *st_hdr_iodev_i;
433 struct io_stats *st_iodev_i;
435 /* Look for device in data table */
436 for (i = 0; i < iodev_nr; i++) {
437 st_hdr_iodev_i = st_hdr_iodev + i;
438 if (!strcmp(st_hdr_iodev_i->name, name)) {
445 * This is a new device: Look for an unused entry to store it.
446 * Thus we are able to handle dynamically registered devices.
448 for (i = 0; i < iodev_nr; i++) {
449 st_hdr_iodev_i = st_hdr_iodev + i;
450 if (!st_hdr_iodev_i->used) {
451 /* Unused entry found... */
452 st_hdr_iodev_i->used = TRUE; /* Indicate it is now used */
453 strncpy(st_hdr_iodev_i->name, name, MAX_NAME_LEN - 1);
454 st_hdr_iodev_i->name[MAX_NAME_LEN - 1] = '\0';
455 st_iodev_i = st_iodev[!curr] + i;
456 memset(st_iodev_i, 0, IO_STATS_SIZE);
462 st_hdr_iodev_i = st_hdr_iodev + i;
463 if (st_hdr_iodev_i->status == DISK_UNREGISTERED) {
464 st_hdr_iodev_i->status = DISK_REGISTERED;
466 st_iodev_i = st_iodev[curr] + i;
467 *st_iodev_i = *((struct io_stats *) st_io);
470 * else it was a new device
471 * but there was no free structure to store it.
476 ***************************************************************************
477 * Read sysfs stat for current block device or partition.
480 * @curr Index in array for current sample statistics.
481 * @filename File name where stats will be read.
482 * @dev_name Device or partition name.
485 * 0 if file couldn't be opened, 1 otherwise.
486 ***************************************************************************
488 int read_sysfs_file_stat(int curr, char *filename, char *dev_name)
491 struct io_stats sdev;
493 unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks;
494 unsigned long rd_ios, rd_merges_or_rd_sec, wr_ios, wr_merges;
495 unsigned long rd_sec_or_wr_ios, wr_sec, rd_ticks_or_wr_sec;
497 /* Try to read given stat file */
498 if ((fp = fopen(filename, "r")) == NULL)
501 i = fscanf(fp, "%lu %lu %lu %lu %lu %lu %lu %u %u %u %u",
502 &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
503 &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks);
506 /* Device or partition */
507 sdev.rd_ios = rd_ios;
508 sdev.rd_merges = rd_merges_or_rd_sec;
509 sdev.rd_sectors = rd_sec_or_wr_ios;
510 sdev.rd_ticks = (unsigned int) rd_ticks_or_wr_sec;
511 sdev.wr_ios = wr_ios;
512 sdev.wr_merges = wr_merges;
513 sdev.wr_sectors = wr_sec;
514 sdev.wr_ticks = wr_ticks;
515 sdev.ios_pgr = ios_pgr;
516 sdev.tot_ticks = tot_ticks;
517 sdev.rq_ticks = rq_ticks;
520 /* Partition without extended statistics */
521 sdev.rd_ios = rd_ios;
522 sdev.rd_sectors = rd_merges_or_rd_sec;
523 sdev.wr_ios = rd_sec_or_wr_ios;
524 sdev.wr_sectors = rd_ticks_or_wr_sec;
527 if ((i == 11) || !DISPLAY_EXTENDED(flags)) {
529 * In fact, we _don't_ save stats if it's a partition without
530 * extended stats and yet we want to display ext stats.
532 save_stats(dev_name, curr, &sdev, iodev_nr, st_hdr_iodev);
541 ***************************************************************************
542 * Read sysfs stats for all the partitions of a device.
545 * @curr Index in array for current sample statistics.
546 * @dev_name Device name.
547 ***************************************************************************
549 void read_sysfs_dlist_part_stat(int curr, char *dev_name)
553 char dfile[MAX_PF_NAME], filename[MAX_PF_NAME];
555 snprintf(dfile, MAX_PF_NAME, "%s/%s", SYSFS_BLOCK, dev_name);
556 dfile[MAX_PF_NAME - 1] = '\0';
558 /* Open current device directory in /sys/block */
559 if ((dir = opendir(dfile)) == NULL)
562 /* Get current entry */
563 while ((drd = readdir(dir)) != NULL) {
564 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
566 snprintf(filename, MAX_PF_NAME, "%s/%s/%s", dfile, drd->d_name, S_STAT);
567 filename[MAX_PF_NAME - 1] = '\0';
569 /* Read current partition stats */
570 read_sysfs_file_stat(curr, filename, drd->d_name);
573 /* Close device directory */
578 ***************************************************************************
579 * Read stats from the sysfs filesystem for the devices entered on the
583 * @curr Index in array for current sample statistics.
584 ***************************************************************************
586 void read_sysfs_dlist_stat(int curr)
589 char filename[MAX_PF_NAME];
591 struct io_dlist *st_dev_list_i;
593 /* Every I/O device (or partition) is potentially unregistered */
594 set_entries_unregistered(iodev_nr, st_hdr_iodev);
596 for (dev = 0; dev < dlist_idx; dev++) {
597 st_dev_list_i = st_dev_list + dev;
599 /* Some devices may have a slash in their name (eg. cciss/c0d0...) */
600 while ((slash = strchr(st_dev_list_i->dev_name, '/'))) {
604 snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
605 SYSFS_BLOCK, st_dev_list_i->dev_name, S_STAT);
606 filename[MAX_PF_NAME - 1] = '\0';
608 /* Read device stats */
609 ok = read_sysfs_file_stat(curr, filename, st_dev_list_i->dev_name);
611 if (ok && st_dev_list_i->disp_part) {
612 /* Also read stats for its partitions */
613 read_sysfs_dlist_part_stat(curr, st_dev_list_i->dev_name);
617 /* Free structures corresponding to unregistered devices */
618 free_unregistered_entries(iodev_nr, st_hdr_iodev);
622 ***************************************************************************
623 * Read stats from the sysfs filesystem for every block devices found.
626 * @curr Index in array for current sample statistics.
627 ***************************************************************************
629 void read_sysfs_stat(int curr)
633 char filename[MAX_PF_NAME];
636 /* Every I/O device entry is potentially unregistered */
637 set_entries_unregistered(iodev_nr, st_hdr_iodev);
639 /* Open /sys/block directory */
640 if ((dir = opendir(SYSFS_BLOCK)) != NULL) {
642 /* Get current entry */
643 while ((drd = readdir(dir)) != NULL) {
644 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
646 snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
647 SYSFS_BLOCK, drd->d_name, S_STAT);
648 filename[MAX_PF_NAME - 1] = '\0';
650 /* If current entry is a directory, try to read its stat file */
651 ok = read_sysfs_file_stat(curr, filename, drd->d_name);
654 * If '-p ALL' was entered on the command line,
655 * also try to read stats for its partitions
657 if (ok && DISPLAY_PART_ALL(flags)) {
658 read_sysfs_dlist_part_stat(curr, drd->d_name);
662 /* Close /sys/block directory */
666 /* Free structures corresponding to unregistered devices */
667 free_unregistered_entries(iodev_nr, st_hdr_iodev);
671 ***************************************************************************
672 * Read stats from /proc/diskstats.
675 * @curr Index in array for current sample statistics.
676 ***************************************************************************
678 void read_diskstats_stat(int curr)
681 char line[256], dev_name[MAX_NAME_LEN];
683 struct io_stats sdev;
685 unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks;
686 unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
687 unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
689 unsigned int major, minor;
691 /* Every I/O device entry is potentially unregistered */
692 set_entries_unregistered(iodev_nr, st_hdr_iodev);
694 if ((fp = fopen(DISKSTATS, "r")) == NULL)
697 while (fgets(line, sizeof(line), fp) != NULL) {
699 /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq */
700 i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u %u",
701 &major, &minor, dev_name,
702 &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
703 &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks);
706 /* Device or partition */
707 if (!dlist_idx && !DISPLAY_PARTITIONS(flags) &&
708 !is_device(dev_name, ACCEPT_VIRTUAL_DEVICES))
710 sdev.rd_ios = rd_ios;
711 sdev.rd_merges = rd_merges_or_rd_sec;
712 sdev.rd_sectors = rd_sec_or_wr_ios;
713 sdev.rd_ticks = (unsigned int) rd_ticks_or_wr_sec;
714 sdev.wr_ios = wr_ios;
715 sdev.wr_merges = wr_merges;
716 sdev.wr_sectors = wr_sec;
717 sdev.wr_ticks = wr_ticks;
718 sdev.ios_pgr = ios_pgr;
719 sdev.tot_ticks = tot_ticks;
720 sdev.rq_ticks = rq_ticks;
723 /* Partition without extended statistics */
724 if (DISPLAY_EXTENDED(flags) ||
725 (!dlist_idx && !DISPLAY_PARTITIONS(flags)))
728 sdev.rd_ios = rd_ios;
729 sdev.rd_sectors = rd_merges_or_rd_sec;
730 sdev.wr_ios = rd_sec_or_wr_ios;
731 sdev.wr_sectors = rd_ticks_or_wr_sec;
734 /* Unknown entry: Ignore it */
737 if ((ioc_dname = ioc_name(major, minor)) != NULL) {
738 if (strcmp(dev_name, ioc_dname) && strcmp(ioc_dname, K_NODEV)) {
740 * No match: Use name generated from sysstat.ioconf data
741 * (if different from "nodev") works around known issues
742 * with EMC PowerPath.
744 strncpy(dev_name, ioc_dname, MAX_NAME_LEN - 1);
745 dev_name[MAX_NAME_LEN - 1] = '\0';
749 if ((DISPLAY_DEVMAP_NAME(flags)) && (major == dm_major)) {
751 * If the device is a device mapper device, try to get its
752 * assigned name of its logical device.
754 dm_name = transform_devmapname(major, minor);
756 strncpy(dev_name, dm_name, MAX_NAME_LEN - 1);
757 dev_name[MAX_NAME_LEN - 1] = '\0';
761 save_stats(dev_name, curr, &sdev, iodev_nr, st_hdr_iodev);
765 /* Free structures corresponding to unregistered devices */
766 free_unregistered_entries(iodev_nr, st_hdr_iodev);
770 ***************************************************************************
771 * Compute stats for device groups using stats of every device belonging
772 * to each of these groups.
775 * @curr Index in array for current sample statistics.
776 ***************************************************************************
778 void compute_device_groups_stats(int curr)
780 struct io_stats gdev, *ioi;
781 struct io_hdr_stats *shi = st_hdr_iodev;
784 memset(&gdev, 0, IO_STATS_SIZE);
787 for (i = 0; i < iodev_nr; i++, shi++) {
788 if (shi->used && (shi->status == DISK_REGISTERED)) {
789 ioi = st_iodev[curr] + i;
791 if (!DISPLAY_UNFILTERED(flags)) {
792 if (!ioi->rd_ios && !ioi->wr_ios)
796 gdev.rd_ios += ioi->rd_ios;
797 gdev.rd_merges += ioi->rd_merges;
798 gdev.rd_sectors += ioi->rd_sectors;
799 gdev.rd_ticks += ioi->rd_ticks;
800 gdev.wr_ios += ioi->wr_ios;
801 gdev.wr_merges += ioi->wr_merges;
802 gdev.wr_sectors += ioi->wr_sectors;
803 gdev.wr_ticks += ioi->wr_ticks;
804 gdev.ios_pgr += ioi->ios_pgr;
805 gdev.tot_ticks += ioi->tot_ticks;
806 gdev.rq_ticks += ioi->rq_ticks;
809 else if (shi->status == DISK_GROUP) {
810 save_stats(shi->name, curr, &gdev, iodev_nr, st_hdr_iodev);
811 shi->used = nr_disks;
813 memset(&gdev, 0, IO_STATS_SIZE);
819 ***************************************************************************
820 * Write current sample's timestamp, either in plain or JSON format.
823 * @tab Number of tabs to print.
824 * @rectime Current date and time.
825 ***************************************************************************
827 void write_sample_timestamp(int tab, struct tm *rectime)
829 if (DISPLAY_ISO(flags)) {
830 strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime);
833 strftime(timestamp, sizeof(timestamp), "%x %X", rectime);
835 if (DISPLAY_JSON_OUTPUT(flags)) {
836 xprintf(tab, "\"timestamp\": \"%s\",", timestamp);
839 printf("%s\n", timestamp);
844 ***************************************************************************
845 * Display CPU utilization in plain format.
848 * @curr Index in array for current sample statistics.
849 * @itv Interval of time.
850 ***************************************************************************
852 void write_plain_cpu_stat(int curr, unsigned long long itv)
854 printf("avg-cpu: %%user %%nice %%system %%iowait %%steal %%idle\n");
858 ll_sp_value(st_cpu[!curr]->cpu_user, st_cpu[curr]->cpu_user, itv),
859 ll_sp_value(st_cpu[!curr]->cpu_nice, st_cpu[curr]->cpu_nice, itv),
861 * Time spent in system mode also includes time spent servicing
862 * hard and soft interrupts.
864 ll_sp_value(st_cpu[!curr]->cpu_sys + st_cpu[!curr]->cpu_softirq +
865 st_cpu[!curr]->cpu_hardirq,
866 st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_softirq +
867 st_cpu[curr]->cpu_hardirq, itv),
868 ll_sp_value(st_cpu[!curr]->cpu_iowait, st_cpu[curr]->cpu_iowait, itv),
869 ll_sp_value(st_cpu[!curr]->cpu_steal, st_cpu[curr]->cpu_steal, itv),
870 (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ?
872 ll_sp_value(st_cpu[!curr]->cpu_idle, st_cpu[curr]->cpu_idle, itv));
878 ***************************************************************************
879 * Display CPU utilization in JSON format.
882 * @tab Number of tabs to print.
883 * @curr Index in array for current sample statistics.
884 * @itv Interval of time.
885 ***************************************************************************
887 void write_json_cpu_stat(int tab, int curr, unsigned long long itv)
889 xprintf0(tab, "\"avg-cpu\": {\"user\": %.2f, \"nice\": %.2f, \"system\": %.2f,"
890 " \"iowait\": %.2f, \"steal\": %.2f, \"idle\": %.2f}",
891 ll_sp_value(st_cpu[!curr]->cpu_user, st_cpu[curr]->cpu_user, itv),
892 ll_sp_value(st_cpu[!curr]->cpu_nice, st_cpu[curr]->cpu_nice, itv),
894 * Time spent in system mode also includes time spent servicing
895 * hard and soft interrupts.
897 ll_sp_value(st_cpu[!curr]->cpu_sys + st_cpu[!curr]->cpu_softirq +
898 st_cpu[!curr]->cpu_hardirq,
899 st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_softirq +
900 st_cpu[curr]->cpu_hardirq, itv),
901 ll_sp_value(st_cpu[!curr]->cpu_iowait, st_cpu[curr]->cpu_iowait, itv),
902 ll_sp_value(st_cpu[!curr]->cpu_steal, st_cpu[curr]->cpu_steal, itv),
903 (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ?
905 ll_sp_value(st_cpu[!curr]->cpu_idle, st_cpu[curr]->cpu_idle, itv));
909 ***************************************************************************
910 * Display CPU utilization in plain or JSON format.
913 * @curr Index in array for current sample statistics.
914 * @itv Interval of time.
915 * @tab Number of tabs to print (JSON format only).
916 ***************************************************************************
918 void write_cpu_stat(int curr, unsigned long long itv, int tab)
920 if (DISPLAY_JSON_OUTPUT(flags)) {
921 write_json_cpu_stat(tab, curr, itv);
924 write_plain_cpu_stat(curr, itv);
929 ***************************************************************************
930 * Display disk stats header in plain or JSON format.
933 * @fctr Conversion factor.
934 * @tab Number of tabs to print (JSON format only).
935 ***************************************************************************
937 void write_disk_stat_header(int *fctr, int *tab)
939 if (DISPLAY_KILOBYTES(flags)) {
942 else if (DISPLAY_MEGABYTES(flags)) {
946 if (DISPLAY_JSON_OUTPUT(flags)) {
947 xprintf((*tab)++, "\"disk\": [");
951 if (DISPLAY_EXTENDED(flags)) {
953 printf("Device: rrqm/s wrqm/s r/s w/s");
954 if (DISPLAY_MEGABYTES(flags)) {
955 printf(" rMB/s wMB/s");
957 else if (DISPLAY_KILOBYTES(flags)) {
958 printf(" rkB/s wkB/s");
961 printf(" rsec/s wsec/s");
963 printf(" avgrq-sz avgqu-sz await r_await w_await svctm %%util\n");
967 printf("Device: tps");
968 if (DISPLAY_KILOBYTES(flags)) {
969 printf(" kB_read/s kB_wrtn/s kB_read kB_wrtn\n");
971 else if (DISPLAY_MEGABYTES(flags)) {
972 printf(" MB_read/s MB_wrtn/s MB_read MB_wrtn\n");
975 printf(" Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn\n");
981 ***************************************************************************
982 * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
986 * @itv Interval of time.
987 * @fctr Conversion factor.
988 * @shi Structures describing the devices and partitions.
989 * @ioi Current sample statistics.
990 * @ioj Previous sample statistics.
991 * @devname Current device name.
992 * @xds Extended stats for current device.
993 * @r_await r_await metric value.
994 * @w_await w_await metric value.
995 ***************************************************************************
997 void write_plain_ext_stat(unsigned long long itv, int fctr,
998 struct io_hdr_stats *shi, struct io_stats *ioi,
999 struct io_stats *ioj, char *devname, struct ext_disk_stats *xds,
1000 double r_await, double w_await)
1002 if (DISPLAY_HUMAN_READ(flags)) {
1003 cprintf_in(IS_STR, "%s\n", devname, 0);
1007 cprintf_in(IS_STR, "%-13s", devname, 0);
1010 /* rrq/s wrq/s r/s w/s rsec wsec rqsz qusz await r_await w_await svctm %util */
1012 S_VALUE(ioj->rd_merges, ioi->rd_merges, itv),
1013 S_VALUE(ioj->wr_merges, ioi->wr_merges, itv));
1015 S_VALUE(ioj->rd_ios, ioi->rd_ios, itv),
1016 S_VALUE(ioj->wr_ios, ioi->wr_ios, itv));
1018 S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1019 S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr,
1021 S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1022 cprintf_f(3, 7, 2, xds->await, r_await, w_await);
1023 /* The ticks output is biased to output 1000 ticks per second */
1024 cprintf_f(1, 6, 2, xds->svctm);
1026 * Again: Ticks in milliseconds.
1027 * In the case of a device group (option -g), shi->used is the number of
1028 * devices in the group. Else shi->used equals 1.
1031 shi->used ? xds->util / 10.0 / (double) shi->used
1032 : xds->util / 10.0); /* shi->used should never be zero here */
1037 ***************************************************************************
1038 * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1042 * @tab Number of tabs to print.
1043 * @itv Interval of time.
1044 * @fctr Conversion factor.
1045 * @shi Structures describing the devices and partitions.
1046 * @ioi Current sample statistics.
1047 * @ioj Previous sample statistics.
1048 * @devname Current device name.
1049 * @xds Extended stats for current device.
1050 * @r_await r_await metric value.
1051 * @w_await w_await metric value.
1052 ***************************************************************************
1054 void write_json_ext_stat(int tab, unsigned long long itv, int fctr,
1055 struct io_hdr_stats *shi, struct io_stats *ioi,
1056 struct io_stats *ioj, char *devname, struct ext_disk_stats *xds,
1057 double r_await, double w_await)
1060 "{\"disk_device\": \"%s\", \"rrqm\": %.2f, \"wrqm\": %.2f, "
1061 "\"r\": %.2f, \"w\": %.2f, \"rkB\": %.2f, \"wkB\": %.2f, "
1062 "\"avgrq-sz\": %.2f, \"avgqu-sz\": %.2f, "
1063 "\"await\": %.2f, \"r_await\": %.2f, \"w_await\": %.2f, "
1064 "\"svctm\": %.2f, \"util\": %.2f}",
1066 S_VALUE(ioj->rd_merges, ioi->rd_merges, itv),
1067 S_VALUE(ioj->wr_merges, ioi->wr_merges, itv),
1068 S_VALUE(ioj->rd_ios, ioi->rd_ios, itv),
1069 S_VALUE(ioj->wr_ios, ioi->wr_ios, itv),
1070 S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1071 S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr,
1073 S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0,
1078 shi->used ? xds->util / 10.0 / (double) shi->used
1079 : xds->util / 10.0); /* shi->used should never be zero here */
1083 ***************************************************************************
1084 * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1085 * in plain or JSON format.
1088 * @itv Interval of time.
1089 * @fctr Conversion factor.
1090 * @shi Structures describing the devices and partitions.
1091 * @ioi Current sample statistics.
1092 * @ioj Previous sample statistics.
1093 * @tab Number of tabs to print (JSON output only).
1094 ***************************************************************************
1096 void write_ext_stat(unsigned long long itv, int fctr,
1097 struct io_hdr_stats *shi, struct io_stats *ioi,
1098 struct io_stats *ioj, int tab)
1100 char *devname = NULL;
1101 struct stats_disk sdc, sdp;
1102 struct ext_disk_stats xds;
1103 double r_await, w_await;
1106 * Counters overflows are possible, but don't need to be handled in
1107 * a special way: The difference is still properly calculated if the
1108 * result is of the same type as the two values.
1109 * Exception is field rq_ticks which is incremented by the number of
1110 * I/O in progress times the number of milliseconds spent doing I/O.
1111 * But the number of I/O in progress (field ios_pgr) happens to be
1112 * sometimes negative...
1114 sdc.nr_ios = ioi->rd_ios + ioi->wr_ios;
1115 sdp.nr_ios = ioj->rd_ios + ioj->wr_ios;
1117 sdc.tot_ticks = ioi->tot_ticks;
1118 sdp.tot_ticks = ioj->tot_ticks;
1120 sdc.rd_ticks = ioi->rd_ticks;
1121 sdp.rd_ticks = ioj->rd_ticks;
1122 sdc.wr_ticks = ioi->wr_ticks;
1123 sdp.wr_ticks = ioj->wr_ticks;
1125 sdc.rd_sect = ioi->rd_sectors;
1126 sdp.rd_sect = ioj->rd_sectors;
1127 sdc.wr_sect = ioi->wr_sectors;
1128 sdp.wr_sect = ioj->wr_sectors;
1130 compute_ext_disk_stats(&sdc, &sdp, itv, &xds);
1132 r_await = (ioi->rd_ios - ioj->rd_ios) ?
1133 (ioi->rd_ticks - ioj->rd_ticks) /
1134 ((double) (ioi->rd_ios - ioj->rd_ios)) : 0.0;
1135 w_await = (ioi->wr_ios - ioj->wr_ios) ?
1136 (ioi->wr_ticks - ioj->wr_ticks) /
1137 ((double) (ioi->wr_ios - ioj->wr_ios)) : 0.0;
1139 /* Get device name */
1140 if (DISPLAY_PERSIST_NAME_I(flags)) {
1141 devname = get_persistent_name_from_pretty(shi->name);
1144 devname = shi->name;
1147 if (DISPLAY_JSON_OUTPUT(flags)) {
1148 write_json_ext_stat(tab, itv, fctr, shi, ioi, ioj, devname, &xds,
1152 write_plain_ext_stat(itv, fctr, shi, ioi, ioj, devname, &xds,
1158 ***************************************************************************
1159 * Write basic stats, read from /proc/diskstats or from sysfs, in plain
1163 * @itv Interval of time.
1164 * @fctr Conversion factor.
1165 * @ioi Current sample statistics.
1166 * @ioj Previous sample statistics.
1167 * @devname Current device name.
1168 * @rd_sec Number of sectors read.
1169 * @wr_sec Number of sectors written.
1170 ***************************************************************************
1172 void write_plain_basic_stat(unsigned long long itv, int fctr,
1173 struct io_stats *ioi, struct io_stats *ioj,
1174 char *devname, unsigned long long rd_sec,
1175 unsigned long long wr_sec)
1177 if (DISPLAY_HUMAN_READ(flags)) {
1178 cprintf_in(IS_STR, "%s\n", devname, 0);
1182 cprintf_in(IS_STR, "%-13s", devname, 0);
1185 S_VALUE(ioj->rd_ios + ioj->wr_ios, ioi->rd_ios + ioi->wr_ios, itv));
1187 S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1188 S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr);
1190 (unsigned long long) rd_sec / fctr,
1191 (unsigned long long) wr_sec / fctr);
1196 ***************************************************************************
1197 * Write basic stats, read from /proc/diskstats or from sysfs, in JSON
1201 * @tab Number of tabs to print.
1202 * @itv Interval of time.
1203 * @fctr Conversion factor.
1204 * @ioi Current sample statistics.
1205 * @ioj Previous sample statistics.
1206 * @devname Current device name.
1207 * @rd_sec Number of sectors read.
1208 * @wr_sec Number of sectors written.
1209 ***************************************************************************
1211 void write_json_basic_stat(int tab, unsigned long long itv, int fctr,
1212 struct io_stats *ioi, struct io_stats *ioj,
1213 char *devname, unsigned long long rd_sec,
1214 unsigned long long wr_sec)
1217 "{\"disk_device\": \"%s\", \"tps\": %.2f, "
1218 "\"kB_read_per_sec\": %.2f, \"kB_wrtn_per_sec\": %.2f, "
1219 "\"kB_read\": %llu, \"kB_wrtn\": %llu}",
1221 S_VALUE(ioj->rd_ios + ioj->wr_ios, ioi->rd_ios + ioi->wr_ios, itv),
1222 S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1223 S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr,
1224 (unsigned long long) rd_sec / fctr,
1225 (unsigned long long) wr_sec / fctr);
1229 ***************************************************************************
1230 * Write basic stats, read from /proc/diskstats or from sysfs, in plain or
1234 * @itv Interval of time.
1235 * @fctr Conversion factor.
1236 * @shi Structures describing the devices and partitions.
1237 * @ioi Current sample statistics.
1238 * @ioj Previous sample statistics.
1239 * @tab Number of tabs to print (JSON format only).
1240 ***************************************************************************
1242 void write_basic_stat(unsigned long long itv, int fctr,
1243 struct io_hdr_stats *shi, struct io_stats *ioi,
1244 struct io_stats *ioj, int tab)
1246 char *devname = NULL;
1247 unsigned long long rd_sec, wr_sec;
1249 /* Print device name */
1250 if (DISPLAY_PERSIST_NAME_I(flags)) {
1251 devname = get_persistent_name_from_pretty(shi->name);
1254 devname = shi->name;
1257 /* Print stats coming from /sys or /proc/diskstats */
1258 rd_sec = ioi->rd_sectors - ioj->rd_sectors;
1259 if ((ioi->rd_sectors < ioj->rd_sectors) && (ioj->rd_sectors <= 0xffffffff)) {
1260 rd_sec &= 0xffffffff;
1262 wr_sec = ioi->wr_sectors - ioj->wr_sectors;
1263 if ((ioi->wr_sectors < ioj->wr_sectors) && (ioj->wr_sectors <= 0xffffffff)) {
1264 wr_sec &= 0xffffffff;
1267 if (DISPLAY_JSON_OUTPUT(flags)) {
1268 write_json_basic_stat(tab, itv, fctr, ioi, ioj, devname,
1272 write_plain_basic_stat(itv, fctr, ioi, ioj, devname,
1278 ***************************************************************************
1279 * Print everything now (stats and uptime).
1282 * @curr Index in array for current sample statistics.
1283 * @rectime Current date and time.
1284 ***************************************************************************
1286 void write_stats(int curr, struct tm *rectime)
1288 int dev, i, fctr = 1, tab = 4, next = FALSE;
1289 unsigned long long itv;
1290 struct io_hdr_stats *shi;
1291 struct io_dlist *st_dev_list_i;
1294 TEST_STDOUT(STDOUT_FILENO);
1296 if (DISPLAY_JSON_OUTPUT(flags)) {
1297 xprintf(tab++, "{");
1300 /* Print time stamp */
1301 if (DISPLAY_TIMESTAMP(flags)) {
1302 write_sample_timestamp(tab, rectime);
1304 if (DISPLAY_DEBUG(flags)) {
1305 fprintf(stderr, "%s\n", timestamp);
1310 /* Interval is multiplied by the number of processors */
1311 itv = get_interval(uptime[!curr], uptime[curr]);
1313 if (DISPLAY_CPU(flags)) {
1315 if (DISPLAY_DEBUG(flags)) {
1317 fprintf(stderr, "itv=%llu st_cpu[curr]{ cpu_user=%llu cpu_nice=%llu "
1318 "cpu_sys=%llu cpu_idle=%llu cpu_iowait=%llu cpu_steal=%llu "
1319 "cpu_hardirq=%llu cpu_softirq=%llu cpu_guest=%llu "
1320 "cpu_guest_nice=%llu }\n",
1322 st_cpu[curr]->cpu_user,
1323 st_cpu[curr]->cpu_nice,
1324 st_cpu[curr]->cpu_sys,
1325 st_cpu[curr]->cpu_idle,
1326 st_cpu[curr]->cpu_iowait,
1327 st_cpu[curr]->cpu_steal,
1328 st_cpu[curr]->cpu_hardirq,
1329 st_cpu[curr]->cpu_softirq,
1330 st_cpu[curr]->cpu_guest,
1331 st_cpu[curr]->cpu_guest_nice);
1335 /* Display CPU utilization */
1336 write_cpu_stat(curr, itv, tab);
1338 if (DISPLAY_JSON_OUTPUT(flags)) {
1339 if (DISPLAY_DISK(flags)) {
1347 /* On SMP machines, reduce itv to one processor (see note above) */
1348 itv = get_interval(uptime0[!curr], uptime0[curr]);
1351 if (DISPLAY_DISK(flags)) {
1352 struct io_stats *ioi, *ioj;
1356 /* Display disk stats header */
1357 write_disk_stat_header(&fctr, &tab);
1359 for (i = 0; i < iodev_nr; i++, shi++) {
1362 if (dlist_idx && !HAS_SYSFS(flags)) {
1364 * With /proc/diskstats, stats for every device
1365 * are read even if we have entered a list on devices
1366 * on the command line. Thus we need to check
1367 * if stats for current device are to be displayed.
1369 for (dev = 0; dev < dlist_idx; dev++) {
1370 st_dev_list_i = st_dev_list + dev;
1371 if (!strcmp(shi->name, st_dev_list_i->dev_name))
1374 if (dev == dlist_idx)
1375 /* Device not found in list: Don't display it */
1379 ioi = st_iodev[curr] + i;
1380 ioj = st_iodev[!curr] + i;
1382 if (!DISPLAY_UNFILTERED(flags)) {
1383 if (!ioi->rd_ios && !ioi->wr_ios)
1387 if (DISPLAY_ZERO_OMIT(flags)) {
1388 if ((ioi->rd_ios == ioj->rd_ios) &&
1389 (ioi->wr_ios == ioj->wr_ios))
1390 /* No activity: Ignore it */
1394 if (DISPLAY_GROUP_TOTAL_ONLY(flags)) {
1395 if (shi->status != DISK_GROUP)
1399 if (DISPLAY_DEBUG(flags)) {
1401 fprintf(stderr, "name=%s itv=%llu fctr=%d ioi{ rd_sectors=%lu "
1402 "wr_sectors=%lu rd_ios=%lu rd_merges=%lu rd_ticks=%u "
1403 "wr_ios=%lu wr_merges=%lu wr_ticks=%u ios_pgr=%u tot_ticks=%u "
1423 if (DISPLAY_JSON_OUTPUT(flags) && next) {
1428 if (DISPLAY_EXTENDED(flags)) {
1429 write_ext_stat(itv, fctr, shi, ioi, ioj, tab);
1432 write_basic_stat(itv, fctr, shi, ioi, ioj, tab);
1436 if (DISPLAY_JSON_OUTPUT(flags)) {
1438 xprintf(--tab, "]");
1442 if (DISPLAY_JSON_OUTPUT(flags)) {
1443 xprintf0(--tab, "}");
1451 ***************************************************************************
1452 * Main loop: Read I/O stats from the relevant sources and display them.
1455 * @count Number of reports to print.
1456 * @rectime Current date and time.
1457 ***************************************************************************
1459 void rw_io_stat_loop(long int count, struct tm *rectime)
1464 /* Should we skip first report? */
1465 if (DISPLAY_OMIT_SINCE_BOOT(flags) && interval > 0) {
1469 /* Don't buffer data if redirected to a pipe */
1470 setbuf(stdout, NULL);
1475 * Read system uptime (only for SMP machines).
1476 * Init uptime0. So if /proc/uptime cannot fill it,
1477 * this will be done by /proc/stat.
1480 read_uptime(&(uptime0[curr]));
1484 * Read stats for CPU "all" and 0.
1485 * Note that stats for CPU 0 are not used per se. It only makes
1486 * read_stat_cpu() fill uptime0.
1488 read_stat_cpu(st_cpu[curr], 2, &(uptime[curr]), &(uptime0[curr]));
1492 * A device or partition name was explicitly entered
1493 * on the command line, with or without -p option
1496 if (HAS_DISKSTATS(flags) && !DISPLAY_PARTITIONS(flags)) {
1497 read_diskstats_stat(curr);
1499 else if (HAS_SYSFS(flags)) {
1500 read_sysfs_dlist_stat(curr);
1505 * No devices nor partitions entered on the command line
1506 * (for example if -p ALL was used).
1508 if (HAS_DISKSTATS(flags)) {
1509 read_diskstats_stat(curr);
1511 else if (HAS_SYSFS(flags)) {
1512 read_sysfs_stat(curr);
1516 /* Compute device groups stats */
1518 compute_device_groups_stats(curr);
1522 get_localtime(rectime, 0);
1524 /* Check whether we should skip first report */
1527 write_stats(curr, rectime);
1537 if (DISPLAY_JSON_OUTPUT(flags)) {
1550 if (DISPLAY_JSON_OUTPUT(flags)) {
1551 printf("\t\t\t]\n\t\t}\n\t]\n}}\n");
1556 ***************************************************************************
1557 * Main entry to the iostat program.
1558 ***************************************************************************
1560 int main(int argc, char **argv)
1564 int i, report_set = FALSE;
1566 struct utsname header;
1567 struct io_dlist *st_dev_list_i;
1569 char *t, *persist_devname, *devname;
1572 /* Init National Language Support */
1576 /* Init color strings */
1582 /* Allocate structures for device list */
1584 salloc_dev_list(argc - 1 + count_csvalues(argc, argv));
1587 /* Process args... */
1588 while (opt < argc) {
1590 /* -p option used individually. See below for grouped use */
1591 if (!strcmp(argv[opt], "-p")) {
1592 flags |= I_D_PARTITIONS;
1594 (strspn(argv[opt], DIGITS) != strlen(argv[opt])) &&
1595 (strncmp(argv[opt], "-", 1))) {
1596 flags |= I_D_UNFILTERED;
1598 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
1599 if (!strcmp(t, K_ALL)) {
1600 flags |= I_D_PART_ALL;
1603 devname = device_name(t);
1604 if (DISPLAY_PERSIST_NAME_I(flags)) {
1605 /* Get device persistent name */
1606 persist_devname = get_pretty_name_from_persistent(devname);
1607 if (persist_devname != NULL) {
1608 devname = persist_devname;
1611 /* Store device name */
1612 i = update_dev_list(&dlist_idx, devname);
1613 st_dev_list_i = st_dev_list + i;
1614 st_dev_list_i->disp_part = TRUE;
1620 flags |= I_D_PART_ALL;
1624 else if (!strcmp(argv[opt], "-g")) {
1626 * Option -g: Stats for a group of devices.
1627 * group_name contains the last group name entered on
1628 * the command line. If we define an additional one, save
1629 * the previous one in the list. We do that this way because we
1630 * want the group name to appear in the list _after_ all
1631 * the devices included in that group. The last group name
1632 * will be saved in the list later, in presave_device_list() function.
1635 update_dev_list(&dlist_idx, group_name);
1639 * MAX_NAME_LEN - 2: one char for the heading space,
1640 * and one for the trailing '\0'.
1642 snprintf(group_name, MAX_NAME_LEN, " %-.*s", MAX_NAME_LEN - 2, argv[opt++]);
1650 else if (!strcmp(argv[opt], "-j")) {
1652 if (strnlen(argv[opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1) {
1655 strncpy(persistent_name_type, argv[opt], MAX_FILE_LEN - 1);
1656 persistent_name_type[MAX_FILE_LEN - 1] = '\0';
1657 strtolower(persistent_name_type);
1658 /* Check that this is a valid type of persistent device name */
1659 if (!get_persistent_type_dir(persistent_name_type)) {
1660 fprintf(stderr, _("Invalid type of persistent device name\n"));
1664 * Persistent names are usually long: Display
1665 * them as human readable by default.
1667 flags |= I_D_PERSIST_NAME + I_D_HUMAN_READ;
1675 else if (!strcmp(argv[opt], "-o")) {
1676 /* Select output format */
1677 if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
1678 flags |= I_D_JSON_OUTPUT;
1687 else if (!strcmp(argv[opt], "--debuginfo")) {
1693 else if (!strncmp(argv[opt], "-", 1)) {
1694 for (i = 1; *(argv[opt] + i); i++) {
1696 switch (*(argv[opt] + i)) {
1699 /* Display cpu usage */
1705 /* Display disk utilization */
1711 /* Display stats only for the groups */
1712 flags |= I_D_GROUP_TOTAL_ONLY;
1717 * Display device utilization report
1718 * in a human readable format.
1720 flags |= I_D_HUMAN_READ;
1724 if (DISPLAY_MEGABYTES(flags)) {
1727 /* Display stats in kB/s */
1728 flags |= I_D_KILOBYTES;
1732 if (DISPLAY_KILOBYTES(flags)) {
1735 /* Display stats in MB/s */
1736 flags |= I_D_MEGABYTES;
1740 /* Display device mapper logical name */
1741 flags |= I_D_DEVMAP_NAME;
1745 /* If option -p is grouped then it cannot take an arg */
1746 flags |= I_D_PARTITIONS + I_D_PART_ALL;
1750 /* Display timestamp */
1751 flags |= I_D_TIMESTAMP;
1755 /* Display extended stats */
1756 flags |= I_D_EXTENDED;
1760 /* Don't display stats since system restart */
1761 flags |= I_D_OMIT_SINCE_BOOT;
1765 /* Omit output for devices with no activity */
1766 flags |= I_D_ZERO_OMIT;
1770 /* Print version number and exit */
1781 else if (!isdigit(argv[opt][0])) {
1783 * By default iostat doesn't display unused devices.
1784 * If some devices are explicitly entered on the command line
1785 * then don't apply this rule any more.
1787 flags |= I_D_UNFILTERED;
1789 if (strcmp(argv[opt], K_ALL)) {
1790 /* Store device name entered on the command line */
1791 devname = device_name(argv[opt++]);
1792 if (DISPLAY_PERSIST_NAME_I(flags)) {
1793 persist_devname = get_pretty_name_from_persistent(devname);
1794 if (persist_devname != NULL) {
1795 devname = persist_devname;
1798 update_dev_list(&dlist_idx, devname);
1806 interval = atol(argv[opt++]);
1815 count = atol(argv[opt++]);
1816 if ((count < 1) || !interval) {
1830 /* Default: Display CPU and DISK reports */
1832 flags |= I_D_CPU + I_D_DISK;
1835 * Also display DISK reports if options -p, -x or a device has been entered
1836 * on the command line.
1838 if (DISPLAY_PARTITIONS(flags) || DISPLAY_EXTENDED(flags) ||
1839 DISPLAY_UNFILTERED(flags)) {
1843 /* Option -T can only be used with option -g */
1844 if (DISPLAY_GROUP_TOTAL_ONLY(flags) && !group_nr) {
1848 /* Select disk output unit (kB/s or blocks/s) */
1849 set_disk_output_unit();
1851 /* Ignore device list if '-p ALL' entered on the command line */
1852 if (DISPLAY_PART_ALL(flags)) {
1856 if (DISPLAY_DEVMAP_NAME(flags)) {
1857 dm_major = get_devmap_major();
1860 /* Init structures according to machine architecture */
1864 * If groups of devices have been defined
1865 * then save devices and groups in the list.
1867 presave_device_list();
1870 get_localtime(&rectime, 0);
1872 /* Get system name, release number and hostname */
1874 if (print_gal_header(&rectime, header.sysname, header.release,
1875 header.nodename, header.machine, cpu_nr,
1876 DISPLAY_JSON_OUTPUT(flags))) {
1879 if (!DISPLAY_JSON_OUTPUT(flags)) {
1883 /* Set a handler for SIGALRM */
1884 memset(&alrm_act, 0, sizeof(alrm_act));
1885 alrm_act.sa_handler = alarm_handler;
1886 sigaction(SIGALRM, &alrm_act, NULL);
1890 rw_io_stat_loop(count, &rectime);
1892 /* Free structures */