2 * iostat: report CPU and I/O statistics
3 * (C) 1998-2020 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>
42 #include <locale.h> /* For setlocale() */
45 #define _(string) gettext(string)
47 #define _(string) (string)
51 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
52 char *sccsid(void) { return (SCCSID); }
59 struct stats_cpu *st_cpu[2];
60 unsigned long long uptime_cs[2] = {0, 0};
61 unsigned long long tot_jiffies[2] = {0, 0};
62 struct io_device *dev_list = NULL;
64 /* Number of decimal places */
67 int group_nr = 0; /* Nb of device groups */
68 int cpu_nr = 0; /* Nb of processors on the machine */
69 int flags = 0; /* Flag for common options and system state */
72 char timestamp[TIMESTAMP_LEN];
73 char alt_dir[MAX_FILE_LEN];
75 struct sigaction alrm_act, int_act;
76 int sigint_caught = 0;
79 ***************************************************************************
80 * Print usage and exit.
83 * @progname Name of sysstat command.
84 ***************************************************************************
86 void usage(char *progname)
88 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
91 fprintf(stderr, _("Options are:\n"
92 "[ -c ] [ -d ] [ -h ] [ -k | -m ] [ -N ] [ -s ] [ -t ] [ -V ] [ -x ] [ -y ] [ -z ]\n"
93 "[ { -f | +f } <directory> ] [ -j { ID | LABEL | PATH | UUID | ... } ]\n"
94 "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ] [ -o JSON ]\n"
95 "[ [ -H ] -g <group_name> ] [ -p [ <device> [,...] | ALL ] ]\n"
96 "[ <device> [...] | ALL ] [ --debuginfo ]\n"));
98 fprintf(stderr, _("Options are:\n"
99 "[ -c ] [ -d ] [ -h ] [ -k | -m ] [ -N ] [ -s ] [ -t ] [ -V ] [ -x ] [ -y ] [ -z ]\n"
100 "[ { -f | +f } <directory> ] [ -j { ID | LABEL | PATH | UUID | ... } ]\n"
101 "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ] [ -o JSON ]\n"
102 "[ [ -H ] -g <group_name> ] [ -p [ <device> [,...] | ALL ] ]\n"
103 "[ <device> [...] | ALL ]\n"));
109 ***************************************************************************
110 * Set disk output unit. Unit will be kB/s unless POSIXLY_CORRECT
111 * environment variable has been set, in which case the output will be
112 * expressed in blocks/s.
113 ***************************************************************************
115 void set_disk_output_unit(void)
117 if (DISPLAY_KILOBYTES(flags) || DISPLAY_MEGABYTES(flags))
120 /* Check POSIXLY_CORRECT environment variable */
121 if (__getenv(ENV_POSIXLY_CORRECT) == NULL) {
122 /* Variable not set: Unit is kB/s and not blocks/s */
123 flags |= I_D_KILOBYTES;
128 ***************************************************************************
129 * SIGALRM signal handler. No need to reset the handler here.
132 * @sig Signal number.
133 ***************************************************************************
135 void alarm_handler(int sig)
141 ***************************************************************************
142 * SIGINT signal handler.
145 * @sig Signal number.
146 **************************************************************************
148 void int_handler(int sig)
154 ***************************************************************************
155 * Initialize stats common structures.
156 ***************************************************************************
158 void init_stats(void)
162 /* Allocate structures for CPUs "all" and 0 */
163 for (i = 0; i < 2; i++) {
164 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * 2)) == NULL) {
168 memset(st_cpu[i], 0, STATS_CPU_SIZE * 2);
173 ***************************************************************************
174 * Set every device entry to nonexistent status.
177 * @dlist Pointer on the start of the linked list.
178 ***************************************************************************
180 void set_devices_nonexistent(struct io_device *dlist)
182 while (dlist != NULL) {
183 dlist->exist = FALSE;
189 ***************************************************************************
190 * Check if a device is present in the list, and add it if requested.
191 * Also look for its type (device or partition) and save it.
194 * @dlist Address of pointer on the start of the linked list.
196 * @dtype T_PART_DEV (=2) if the device and all its partitions should
197 * also be read (option -p used), T_GROUP (=3) if it's a group
198 * name, and 0 otherwise.
201 * Pointer on the io_device structure in the list where the device is located
202 * (whether it was already in the list or if it has been added).
203 * NULL if the device name is too long or if the device doesn't exist and we
204 * don't want to add it.
205 ***************************************************************************
207 struct io_device *add_list_device(struct io_device **dlist, char *name, int dtype)
209 struct io_device *d, *ds;
212 if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN)
213 /* Device name is too long */
216 while (*dlist != NULL) {
218 if ((i = strcmp(d->name, name)) == 0) {
219 /* Device found in list */
220 if ((dtype == T_PART_DEV) && (d->dev_tp == T_DEV)) {
226 if (!GROUP_DEFINED(flags) && !DISPLAY_EVERYTHING(flags) && (i > 0))
228 * If no group defined and we don't use /proc/diskstats,
229 * insert current device in alphabetical order.
230 * NB: Using /proc/diskstats ("iostat -p ALL") is a bit better than
231 * using alphabetical order because sda10 comes after sda9...
238 /* Device not found */
241 /* Add device to the list */
242 if ((*dlist = (struct io_device *) malloc(sizeof(struct io_device))) == NULL) {
246 memset(*dlist, 0, sizeof(struct io_device));
249 for (i = 0; i < 2; i++) {
250 if ((d->dev_stats[i] = (struct io_stats *) malloc(sizeof(struct io_stats))) == NULL) {
254 memset(d->dev_stats[i], 0, sizeof(struct io_stats));
256 strncpy(d->name, name, MAX_NAME_LEN);
257 d->name[MAX_NAME_LEN - 1] = '\0';
261 if (dtype == T_GROUP) {
265 if (!alt_dir[0] || USE_ALL_DIR(flags)) {
266 rc = is_device(SLASH_SYS, name, ACCEPT_VIRTUAL_DEVICES);
269 if (alt_dir[0] && (!USE_ALL_DIR(flags) || (USE_ALL_DIR(flags) && !rc))) {
270 rc = is_device(alt_dir, name, ACCEPT_VIRTUAL_DEVICES);
274 d->dev_tp = (dtype == T_PART_DEV ? T_PART_DEV : T_DEV);
277 /* This is a partition (T_PART) */
286 ***************************************************************************
287 * Get device major and minor numbers.
290 * @filename Name of the device ("sda", "/dev/sdb1"...)
293 * @major Major number of the device.
294 * @minor Minor number of the device.
297 * 0 on success, and -1 otherwise.
298 ***************************************************************************
300 int get_major_minor_nr(char filename[], int *major, int *minor)
304 char dfile[MAX_PF_NAME];
306 snprintf(dfile, sizeof(dfile), "%s%s", filename[0] == '/' ? "" : SLASH_DEV, filename);
307 dfile[sizeof(dfile) - 1] = '\0';
309 while ((bang = strchr(dfile, '!'))) {
311 * Some devices may have had a slash replaced with a bang character (eg. cciss!c0d0...)
312 * Restore their original names so that they can be found in /dev directory.
317 if (__stat(dfile, &statbuf) < 0)
320 *major = __major(statbuf.st_rdev);
321 *minor = __minor(statbuf.st_rdev);
327 ***************************************************************************
328 * Read sysfs stat for current block device or partition.
331 * @filename File name where stats will be read.
332 * @ios Structure where stats will be saved.
335 * @ios Structure where stats have been saved.
338 * 0 on success, -1 otherwise.
339 ***************************************************************************
341 int read_sysfs_file_stat_work(char *filename, struct io_stats *ios)
344 struct io_stats sdev;
346 unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks;
347 unsigned long rd_ios, rd_merges_or_rd_sec, wr_ios, wr_merges;
348 unsigned long rd_sec_or_wr_ios, wr_sec, rd_ticks_or_wr_sec;
349 unsigned long dc_ios, dc_merges, dc_sec, fl_ios;
351 /* Try to read given stat file */
352 if ((fp = fopen(filename, "r")) == NULL)
355 i = fscanf(fp, "%lu %lu %lu %lu %lu %lu %lu %u %u %u %u %lu %lu %lu %u %lu %u",
356 &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
357 &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
358 &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
361 memset(&sdev, 0, sizeof(struct io_stats));
364 /* Device or partition */
365 sdev.rd_ios = rd_ios;
366 sdev.rd_merges = rd_merges_or_rd_sec;
367 sdev.rd_sectors = rd_sec_or_wr_ios;
368 sdev.rd_ticks = (unsigned int) rd_ticks_or_wr_sec;
369 sdev.wr_ios = wr_ios;
370 sdev.wr_merges = wr_merges;
371 sdev.wr_sectors = wr_sec;
372 sdev.wr_ticks = wr_ticks;
373 sdev.ios_pgr = ios_pgr;
374 sdev.tot_ticks = tot_ticks;
375 sdev.rq_ticks = rq_ticks;
379 sdev.dc_ios = dc_ios;
380 sdev.dc_merges = dc_merges;
381 sdev.dc_sectors = dc_sec;
382 sdev.dc_ticks = dc_ticks;
387 sdev.fl_ios = fl_ios;
388 sdev.fl_ticks = fl_ticks;
392 /* Partition without extended statistics */
393 sdev.rd_ios = rd_ios;
394 sdev.rd_sectors = rd_merges_or_rd_sec;
395 sdev.wr_ios = rd_sec_or_wr_ios;
396 sdev.wr_sectors = rd_ticks_or_wr_sec;
407 ***************************************************************************
408 * Read sysfs stat for current whole device using /sys or an alternate
412 * @devname Device name for which stats have to be read.
413 * @ios Structure where stats will be saved.
416 * @ios Structure where stats have been saved.
419 * 0 on success, -1 otherwise.
420 ***************************************************************************
422 int read_sysfs_file_stat(char *devname, struct io_stats *ios)
425 char dfile[MAX_PF_NAME];
427 if (!alt_dir[0] || USE_ALL_DIR(flags)) {
428 /* Read stats for current whole device using /sys/block/ directory */
429 snprintf(dfile, sizeof(dfile), "%s/%s/%s/%s",
430 SLASH_SYS, __BLOCK, devname, S_STAT);
431 dfile[sizeof(dfile) - 1] = '\0';
433 rc = read_sysfs_file_stat_work(dfile, ios);
436 if (alt_dir[0] && (!USE_ALL_DIR(flags) || (USE_ALL_DIR(flags) && (rc < 0)))) {
437 /* Read stats for current whole device using an alternate /sys directory */
438 snprintf(dfile, sizeof(dfile), "%s/%s/%s/%s",
439 alt_dir, __BLOCK, devname, S_STAT);
440 dfile[sizeof(dfile) - 1] = '\0';
442 rc = read_sysfs_file_stat_work(dfile, ios);
449 ***************************************************************************
450 * Read sysfs stats for all the partitions of a whole device. Devices are
451 * saved in the linked list.
454 * @curr Index in array for current sample statistics.
455 * @dname Whole device name.
456 * @sysdev sysfs location.
459 * 0 on success, -1 otherwise.
460 ***************************************************************************
462 int read_sysfs_device_part_stat_work(int curr, char *dname, char *sysdev)
466 struct io_stats sdev;
468 char dfile[MAX_PF_NAME], filename[MAX_PF_NAME + 512];
471 snprintf(dfile, sizeof(dfile), "%s/%s/%s", sysdev, __BLOCK, dname);
472 dfile[sizeof(dfile) - 1] = '\0';
474 /* Open current device directory in /sys/block */
475 if ((dir = __opendir(dfile)) == NULL)
478 /* Get current entry */
479 while ((drd = __readdir(dir)) != NULL) {
481 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
483 snprintf(filename, sizeof(filename), "%s/%s/%s", dfile, drd->d_name, S_STAT);
484 filename[sizeof(filename) - 1] = '\0';
486 /* Read current partition stats */
487 if (read_sysfs_file_stat_work(filename, &sdev) < 0)
490 d = add_list_device(&dev_list, drd->d_name, 0);
492 *(d->dev_stats[curr]) = sdev;
495 /* Get major and minor numbers for given device */
496 if (get_major_minor_nr(d->name, &major, &minor) == 0) {
504 /* Close device directory */
511 ***************************************************************************
512 * Read sysfs stats for all the partitions of a whole device.
513 * Stats are from /sys or an alternate directory.
516 * @curr Index in array for current sample statistics.
517 * @dname Whole device name.
520 * 0 on success, -1 otherwise.
521 ***************************************************************************
523 int read_sysfs_device_part_stat(int curr, char *dname)
527 if (!alt_dir[0] || USE_ALL_DIR(flags)) {
528 /* Read partition stats from /sys */
529 rc = read_sysfs_device_part_stat_work(curr, dname, SLASH_SYS);
532 if (alt_dir[0] && (!USE_ALL_DIR(flags) || (USE_ALL_DIR(flags) && (rc < 0)))) {
533 /* Read partition stats from an alternate /sys directory */
534 rc = read_sysfs_device_part_stat_work(curr, dname, alt_dir);
541 ***************************************************************************
542 * Read sysfs stats for every whole device. Devices are saved in the linked
546 * @curr Index in array for current sample statistics.
547 * @sysblock __sys/block directory location.
550 * 0 on success, -1 otherwise.
551 ***************************************************************************
553 int read_sysfs_all_devices_stat_work(int curr, char *sysblock)
557 struct io_stats sdev;
559 char dfile[MAX_PF_NAME];
562 /* Open __sys/block directory */
563 if ((dir = __opendir(sysblock)) == NULL)
566 /* Get current entry */
567 while ((drd = __readdir(dir)) != NULL) {
569 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
571 snprintf(dfile, sizeof(dfile), "%s/%s/%s", sysblock, drd->d_name, S_STAT);
572 dfile[sizeof(dfile) - 1] = '\0';
574 /* Read current whole device stats */
575 if (read_sysfs_file_stat_work(dfile, &sdev) < 0)
578 d = add_list_device(&dev_list, drd->d_name, 0);
580 *(d->dev_stats[curr]) = sdev;
583 /* Get major and minor numbers for given device */
584 if (get_major_minor_nr(d->name, &major, &minor) == 0) {
592 /* Close device directory */
599 ***************************************************************************
600 * Read sysfs stats for every whole device from /sys or an alternate
604 * @curr Index in array for current sample statistics.
607 * 0 on success, -1 otherwise.
608 ***************************************************************************
610 int read_sysfs_all_devices_stat(int curr)
613 char sysblock[MAX_PF_NAME];
615 if (!alt_dir[0] || USE_ALL_DIR(flags)) {
616 /* Read all whole devices from /sys */
617 rc = read_sysfs_all_devices_stat_work(curr, SYSFS_BLOCK);
621 snprintf(sysblock, sizeof(sysblock), "%s/%s", alt_dir, __BLOCK);
622 sysblock[sizeof(sysblock) - 1] = '\0';
623 /* Read stats from an alternate sys location */
624 rc = read_sysfs_all_devices_stat_work(curr, sysblock);
631 ***************************************************************************
632 * Read sysfs stats for a partition using __sys/dev/block/M:m/ directory.
635 * @curr Index in array for current sample statistics.
636 * @d Device structure.
637 * @sysdev sysfs directory.
640 * 0 on success, and -1 otherwise.
641 ***************************************************************************
643 int read_sysfs_part_stat_work(int curr, struct io_device *d, char *sysdev)
645 char dfile[MAX_PF_NAME];
649 /* Get major and minor numbers for given device */
650 if (get_major_minor_nr(d->name, &major, &minor) < 0)
656 /* Read stats for device */
657 snprintf(dfile, sizeof(dfile), "%s/%s/%d:%d/%s",
658 sysdev, __DEV_BLOCK, d->major, d->minor, S_STAT);
659 dfile[sizeof(dfile) - 1] = '\0';
661 return read_sysfs_file_stat_work(dfile, d->dev_stats[curr]);
665 ***************************************************************************
666 * Read sysfs stats for a partition using /sys/dev/block/M:m/ directory or
667 * an alternate directory.
670 * @curr Index in array for current sample statistics.
671 * @d Device structure.
674 * 0 on success, and -1 otherwise.
675 ***************************************************************************
677 int read_sysfs_part_stat(int curr, struct io_device *d)
681 if (!alt_dir[0] || USE_ALL_DIR(flags)) {
682 /* Read partition stats from /sys */
683 rc = read_sysfs_part_stat_work(curr, d, SLASH_SYS);
686 if (alt_dir[0] && (!USE_ALL_DIR(flags) || (USE_ALL_DIR(flags) && (rc < 0)))) {
687 /* Read partition stats from an alternate /sys directory */
688 rc = read_sysfs_part_stat_work(curr, d, alt_dir);
695 ***************************************************************************
696 * Read stats from the sysfs filesystem for the devices entered on the
700 * @curr Index in array for current sample statistics.
701 ***************************************************************************
703 void read_sysfs_dlist_stat(int curr)
705 struct io_device *dlist;
707 for (dlist = dev_list; dlist != NULL; dlist = dlist->next) {
709 /* Device stats already read */
712 else if (dlist->dev_tp == T_PART) {
714 * This is a partition.
715 * Read its stats using /sys/dev/block/M:n/ directory.
717 if (read_sysfs_part_stat(curr, dlist) == 0) {
722 else if ((dlist->dev_tp == T_PART_DEV) || (dlist->dev_tp == T_DEV)) {
723 /* Read stats for current whole device using /sys/block/ directory */
724 if (read_sysfs_file_stat(dlist->name, dlist->dev_stats[curr]) == 0) {
728 if (dlist->dev_tp == T_PART_DEV) {
729 /* Also read all its partitions now */
730 read_sysfs_device_part_stat(curr, dlist->name);
735 /* Read all whole devices stats if requested ("iostat ALL ...") */
736 if (DISPLAY_ALL_DEVICES(flags)) {
737 read_sysfs_all_devices_stat(curr);
742 ***************************************************************************
743 * Read stats from the diskstats file. Only used when "-p ALL" has been
744 * entered on the command line.
747 * @curr Index in array for current sample statistics.
748 * @diskstats Path to diskstats file (e.g. "/proc/diskstats").
749 ***************************************************************************
751 void read_diskstats_stat_work(int curr, char *diskstats)
754 char line[256], dev_name[MAX_NAME_LEN];
756 struct io_stats sdev;
758 unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks;
759 unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
760 unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
761 unsigned long dc_ios, dc_merges, dc_sec, fl_ios;
762 unsigned int major, minor;
764 if ((fp = fopen(diskstats, "r")) == NULL)
767 while (fgets(line, sizeof(line), fp) != NULL) {
769 memset(&sdev, 0, sizeof(struct io_stats));
771 /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq dcio dcmerge dcsect dcuse flio fltm */
772 i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u %u %lu %lu %lu %u %lu %u",
773 &major, &minor, dev_name,
774 &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
775 &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
776 &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
780 sdev.rd_ios = rd_ios;
781 sdev.rd_merges = rd_merges_or_rd_sec;
782 sdev.rd_sectors = rd_sec_or_wr_ios;
783 sdev.rd_ticks = (unsigned int) rd_ticks_or_wr_sec;
784 sdev.wr_ios = wr_ios;
785 sdev.wr_merges = wr_merges;
786 sdev.wr_sectors = wr_sec;
787 sdev.wr_ticks = wr_ticks;
788 sdev.ios_pgr = ios_pgr;
789 sdev.tot_ticks = tot_ticks;
790 sdev.rq_ticks = rq_ticks;
794 sdev.dc_ios = dc_ios;
795 sdev.dc_merges = dc_merges;
796 sdev.dc_sectors = dc_sec;
797 sdev.dc_ticks = dc_ticks;
802 sdev.fl_ios = fl_ios;
803 sdev.fl_ticks = fl_ticks;
807 /* Partition without extended statistics */
808 if (DISPLAY_EXTENDED(flags))
811 sdev.rd_ios = rd_ios;
812 sdev.rd_sectors = rd_merges_or_rd_sec;
813 sdev.wr_ios = rd_sec_or_wr_ios;
814 sdev.wr_sectors = rd_ticks_or_wr_sec;
817 /* Unknown entry: Ignore it */
820 d = add_list_device(&dev_list, dev_name, 0);
822 *d->dev_stats[curr] = sdev;
831 ***************************************************************************
832 * Read stats from /proc/diskstats or an alternate diskstats file.
833 * Only used when "-p ALL" has been entered on the command line.
836 * @curr Index in array for current sample statistics.
837 ***************************************************************************
839 void read_diskstats_stat(int curr)
841 char diskstats[MAX_PF_NAME];
843 if (!alt_dir[0] || USE_ALL_DIR(flags)) {
844 /* Read stats from /proc/diskstats */
845 read_diskstats_stat_work(curr, DISKSTATS);
849 snprintf(diskstats, sizeof(diskstats), "%s/%s", alt_dir, __DISKSTATS);
850 diskstats[sizeof(diskstats) - 1] = '\0';
851 /* Read stats from an alternate diskstats file */
852 read_diskstats_stat_work(curr, diskstats);
857 ***************************************************************************
858 * Add current device statistics to corresponding group.
861 * @curr Index in array for current sample statistics.
862 * @iodev_nr Number of devices and partitions.
863 ***************************************************************************
865 void compute_device_groups_stats(int curr, struct io_device *d, struct io_device *g)
867 if (!DISPLAY_UNFILTERED(flags)) {
868 if (!d->dev_stats[curr]->rd_ios &&
869 !d->dev_stats[curr]->wr_ios &&
870 !d->dev_stats[curr]->dc_ios &&
871 !d->dev_stats[curr]->fl_ios)
875 g->dev_stats[curr]->rd_ios += d->dev_stats[curr]->rd_ios;
876 g->dev_stats[curr]->rd_merges += d->dev_stats[curr]->rd_merges;
877 g->dev_stats[curr]->rd_sectors += d->dev_stats[curr]->rd_sectors;
878 g->dev_stats[curr]->rd_ticks += d->dev_stats[curr]->rd_ticks;
879 g->dev_stats[curr]->wr_ios += d->dev_stats[curr]->wr_ios;
880 g->dev_stats[curr]->wr_merges += d->dev_stats[curr]->wr_merges;
881 g->dev_stats[curr]->wr_sectors += d->dev_stats[curr]->wr_sectors;
882 g->dev_stats[curr]->wr_ticks += d->dev_stats[curr]->wr_ticks;
883 g->dev_stats[curr]->dc_ios += d->dev_stats[curr]->dc_ios;
884 g->dev_stats[curr]->dc_merges += d->dev_stats[curr]->dc_merges;
885 g->dev_stats[curr]->dc_sectors += d->dev_stats[curr]->dc_sectors;
886 g->dev_stats[curr]->dc_ticks += d->dev_stats[curr]->dc_ticks;
887 g->dev_stats[curr]->fl_ios += d->dev_stats[curr]->fl_ios;
888 g->dev_stats[curr]->fl_ticks += d->dev_stats[curr]->fl_ticks;
889 g->dev_stats[curr]->ios_pgr += d->dev_stats[curr]->ios_pgr;
890 g->dev_stats[curr]->tot_ticks += d->dev_stats[curr]->tot_ticks;
891 g->dev_stats[curr]->rq_ticks += d->dev_stats[curr]->rq_ticks;
895 ***************************************************************************
896 * Write current sample's timestamp, either in plain or JSON format.
899 * @tab Number of tabs to print.
900 * @rectime Current date and time.
901 ***************************************************************************
903 void write_sample_timestamp(int tab, struct tm *rectime)
905 if (DISPLAY_ISO(flags)) {
906 strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime);
909 strftime(timestamp, sizeof(timestamp), "%x %X", rectime);
911 if (DISPLAY_JSON_OUTPUT(flags)) {
912 xprintf(tab, "\"timestamp\": \"%s\",", timestamp);
915 printf("%s\n", timestamp);
920 ***************************************************************************
921 * Display CPU utilization in plain format.
924 * @curr Index in array for current sample statistics.
926 * Number of jiffies spent on the interval by all processors.
927 ***************************************************************************
929 void write_plain_cpu_stat(int curr, unsigned long long deltot_jiffies)
931 printf("avg-cpu: %%user %%nice %%system %%iowait %%steal %%idle\n");
934 cprintf_pc(DISPLAY_UNIT(flags), 6, 7, 2,
935 ll_sp_value(st_cpu[!curr]->cpu_user, st_cpu[curr]->cpu_user, deltot_jiffies),
936 ll_sp_value(st_cpu[!curr]->cpu_nice, st_cpu[curr]->cpu_nice, deltot_jiffies),
938 * Time spent in system mode also includes time spent servicing
939 * hard and soft interrupts.
941 ll_sp_value(st_cpu[!curr]->cpu_sys + st_cpu[!curr]->cpu_softirq +
942 st_cpu[!curr]->cpu_hardirq,
943 st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_softirq +
944 st_cpu[curr]->cpu_hardirq, deltot_jiffies),
945 ll_sp_value(st_cpu[!curr]->cpu_iowait, st_cpu[curr]->cpu_iowait, deltot_jiffies),
946 ll_sp_value(st_cpu[!curr]->cpu_steal, st_cpu[curr]->cpu_steal, deltot_jiffies),
947 (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ?
949 ll_sp_value(st_cpu[!curr]->cpu_idle, st_cpu[curr]->cpu_idle, deltot_jiffies));
955 ***************************************************************************
956 * Display CPU utilization in JSON format.
959 * @tab Number of tabs to print.
960 * @curr Index in array for current sample statistics.
962 * Number of jiffies spent on the interval by all processors.
963 ***************************************************************************
965 void write_json_cpu_stat(int tab, int curr, unsigned long long deltot_jiffies)
967 xprintf0(tab, "\"avg-cpu\": {\"user\": %.2f, \"nice\": %.2f, \"system\": %.2f,"
968 " \"iowait\": %.2f, \"steal\": %.2f, \"idle\": %.2f}",
969 ll_sp_value(st_cpu[!curr]->cpu_user, st_cpu[curr]->cpu_user, deltot_jiffies),
970 ll_sp_value(st_cpu[!curr]->cpu_nice, st_cpu[curr]->cpu_nice, deltot_jiffies),
972 * Time spent in system mode also includes time spent servicing
973 * hard and soft interrupts.
975 ll_sp_value(st_cpu[!curr]->cpu_sys + st_cpu[!curr]->cpu_softirq +
976 st_cpu[!curr]->cpu_hardirq,
977 st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_softirq +
978 st_cpu[curr]->cpu_hardirq, deltot_jiffies),
979 ll_sp_value(st_cpu[!curr]->cpu_iowait, st_cpu[curr]->cpu_iowait, deltot_jiffies),
980 ll_sp_value(st_cpu[!curr]->cpu_steal, st_cpu[curr]->cpu_steal, deltot_jiffies),
981 (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ?
983 ll_sp_value(st_cpu[!curr]->cpu_idle, st_cpu[curr]->cpu_idle, deltot_jiffies));
987 ***************************************************************************
988 * Display CPU utilization in plain or JSON format.
991 * @curr Index in array for current sample statistics.
992 * @tab Number of tabs to print (JSON format only).
993 ***************************************************************************
995 void write_cpu_stat(int curr, int tab)
997 unsigned long long deltot_jiffies;
999 /* Total number of jiffies spent on the interval */
1000 deltot_jiffies = get_interval(tot_jiffies[!curr], tot_jiffies[curr]);
1003 if (DISPLAY_DEBUG(flags)) {
1005 fprintf(stderr, "deltot_jiffies=%llu st_cpu[curr]{ cpu_user=%llu cpu_nice=%llu "
1006 "cpu_sys=%llu cpu_idle=%llu cpu_iowait=%llu cpu_steal=%llu "
1007 "cpu_hardirq=%llu cpu_softirq=%llu cpu_guest=%llu "
1008 "cpu_guest_nice=%llu }\n",
1010 st_cpu[curr]->cpu_user,
1011 st_cpu[curr]->cpu_nice,
1012 st_cpu[curr]->cpu_sys,
1013 st_cpu[curr]->cpu_idle,
1014 st_cpu[curr]->cpu_iowait,
1015 st_cpu[curr]->cpu_steal,
1016 st_cpu[curr]->cpu_hardirq,
1017 st_cpu[curr]->cpu_softirq,
1018 st_cpu[curr]->cpu_guest,
1019 st_cpu[curr]->cpu_guest_nice);
1023 if (DISPLAY_JSON_OUTPUT(flags)) {
1024 write_json_cpu_stat(tab, curr, deltot_jiffies);
1027 write_plain_cpu_stat(curr, deltot_jiffies);
1032 ***************************************************************************
1033 * Display disk stats header in plain or JSON format.
1036 * @fctr Conversion factor.
1037 * @tab Number of tabs to print (JSON format only).
1038 * @hpart Indicate which part of the report should be displayed in
1039 * human mode. A value of 0 indicates that output should not be
1040 * broken in several parts.
1041 ***************************************************************************
1043 void write_disk_stat_header(int *fctr, int *tab, int hpart)
1047 if (DISPLAY_KILOBYTES(flags)) {
1052 else if (DISPLAY_MEGABYTES(flags)) {
1057 else if (DISPLAY_EXTENDED(flags)) {
1066 if (DISPLAY_JSON_OUTPUT(flags)) {
1067 xprintf((*tab)++, "\"disk\": [");
1071 if (!DISPLAY_PRETTY(flags)) {
1074 if (DISPLAY_EXTENDED(flags)) {
1075 /* Extended stats */
1076 if (DISPLAY_SHORT_OUTPUT(flags)) {
1077 printf(" tps %s%s/s rqm/s await areq-sz aqu-sz %%util",
1081 if ((hpart == 1) || !hpart) {
1082 printf(" r/s %sr%s/s rrqm/s %%rrqm r_await rareq-sz",
1085 if ((hpart == 2) || !hpart) {
1086 printf(" w/s %sw%s/s wrqm/s %%wrqm w_await wareq-sz",
1089 if ((hpart == 3) || !hpart) {
1090 printf(" d/s %sd%s/s drqm/s %%drqm d_await dareq-sz",
1093 if ((hpart == 4) || !hpart) {
1094 printf(" f/s f_await aqu-sz %%util");
1100 if (DISPLAY_SHORT_OUTPUT(flags)) {
1101 printf(" tps %s%s_read/s %s%s_w+d/s %s%s_read %s%s_w+d",
1102 spc, units, spc, units, spc, units, spc, units);
1105 printf(" tps %s%s_read/s %s%s_wrtn/s %s%s_dscd/s %s%s_read %s%s_wrtn %s%s_dscd",
1106 spc, units, spc, units, spc, units, spc, units, spc, units, spc, units);
1109 if (DISPLAY_PRETTY(flags)) {
1116 ***************************************************************************
1117 * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1121 * @itv Interval of time.
1122 * @fctr Conversion factor.
1123 * @hpart Indicate which part of the report should be displayed in
1124 * human mode. A value of 0 indicates that output should not be
1125 * broken in several parts.
1126 * @d Structure containing device description.
1127 * @ioi Current sample statistics.
1128 * @ioj Previous sample statistics.
1129 * @devname Current device name.
1130 * @xds Extended stats for current device.
1131 * @xios Additional extended statistics for current device.
1132 ***************************************************************************
1134 void write_plain_ext_stat(unsigned long long itv, int fctr, int hpart,
1135 struct io_device *d, struct io_stats *ioi,
1136 struct io_stats *ioj, char *devname, struct ext_disk_stats *xds,
1137 struct ext_io_stats *xios)
1141 /* If this is a group with no devices, skip it */
1142 if (d->dev_tp == T_GROUP)
1145 if (!DISPLAY_PRETTY(flags)) {
1146 cprintf_in(IS_STR, "%-13s", devname, 0);
1149 /* Compute number of devices in group */
1150 if (d->dev_tp > T_GROUP) {
1151 n = d->dev_tp - T_GROUP;
1157 if (DISPLAY_SHORT_OUTPUT(flags)) {
1159 /* Origin (unmerged) flush operations are counted as writes */
1160 cprintf_f(NO_UNIT, 1, 8, 2,
1161 S_VALUE(ioj->rd_ios + ioj->wr_ios + ioj->dc_ios,
1162 ioi->rd_ios + ioi->wr_ios + ioi->dc_ios, itv));
1164 if (!DISPLAY_UNIT(flags)) {
1165 xios->sectors /= fctr;
1167 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 1, 9, 2,
1170 cprintf_f(NO_UNIT, 1, 8, 2,
1171 S_VALUE(ioj->rd_merges + ioj->wr_merges + ioj->dc_merges,
1172 ioi->rd_merges + ioi->wr_merges + ioi->dc_merges, itv));
1174 cprintf_f(NO_UNIT, 1, 7, 2,
1176 /* areq-sz (in kB, not sectors) */
1177 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_KILOBYTE : NO_UNIT, 1, 8, 2,
1180 cprintf_f(NO_UNIT, 1, 7, 2,
1181 S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1184 * Again: Ticks in milliseconds.
1186 cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2, xds->util / 10.0 / (double) n);
1189 if ((hpart == 1) || !hpart) {
1191 cprintf_f(NO_UNIT, 1, 7, 2,
1192 S_VALUE(ioj->rd_ios, ioi->rd_ios, itv));
1194 if (!DISPLAY_UNIT(flags)) {
1195 xios->rsectors /= fctr;
1197 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 1, 9, 2,
1200 cprintf_f(NO_UNIT, 1, 8, 2,
1201 S_VALUE(ioj->rd_merges, ioi->rd_merges, itv));
1203 cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2,
1206 cprintf_f(NO_UNIT, 1, 7, 2,
1208 /* rareq-sz (in kB, not sectors) */
1209 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_KILOBYTE : NO_UNIT, 1, 8, 2,
1212 if ((hpart == 2) || !hpart) {
1214 cprintf_f(NO_UNIT, 1, 7, 2,
1215 S_VALUE(ioj->wr_ios, ioi->wr_ios, itv));
1217 if (!DISPLAY_UNIT(flags)) {
1218 xios->wsectors /= fctr;
1220 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 1, 9, 2,
1223 cprintf_f(NO_UNIT, 1, 8, 2,
1224 S_VALUE(ioj->wr_merges, ioi->wr_merges, itv));
1226 cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2,
1229 cprintf_f(NO_UNIT, 1, 7, 2,
1231 /* wareq-sz (in kB, not sectors) */
1232 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_KILOBYTE : NO_UNIT, 1, 8, 2,
1235 if ((hpart == 3) || !hpart) {
1237 cprintf_f(NO_UNIT, 1, 7, 2,
1238 S_VALUE(ioj->dc_ios, ioi->dc_ios, itv));
1240 if (!DISPLAY_UNIT(flags)) {
1241 xios->dsectors /= fctr;
1243 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 1, 9, 2,
1246 cprintf_f(NO_UNIT, 1, 8, 2,
1247 S_VALUE(ioj->dc_merges, ioi->dc_merges, itv));
1249 cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2,
1252 cprintf_f(NO_UNIT, 1, 7, 2,
1254 /* dareq-sz (in kB, not sectors) */
1255 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_KILOBYTE : NO_UNIT, 1, 8, 2,
1258 if ((hpart == 4) || !hpart) {
1260 cprintf_f(NO_UNIT, 1, 7, 2,
1261 S_VALUE(ioj->fl_ios, ioi->fl_ios, itv));
1263 cprintf_f(NO_UNIT, 1, 7, 2,
1266 cprintf_f(NO_UNIT, 1, 7, 2,
1267 S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1270 * Again: Ticks in milliseconds.
1272 if (d->dev_tp > T_GROUP) {
1273 n = d->dev_tp - T_GROUP;
1278 cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2, xds->util / 10.0 / (double) n);
1282 if (DISPLAY_PRETTY(flags)) {
1283 cprintf_in(IS_STR, " %s", devname, 0);
1289 ***************************************************************************
1290 * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1294 * @tab Number of tabs to print.
1295 * @itv Interval of time.
1296 * @fctr Conversion factor.
1297 * @d Structure containing the device description.
1298 * @ioi Current sample statistics.
1299 * @ioj Previous sample statistics.
1300 * @devname Current device name.
1301 * @xds Extended stats for current device.
1302 * @xios Additional extended statistics for current device.
1303 ***************************************************************************
1305 void write_json_ext_stat(int tab, unsigned long long itv, int fctr,
1306 struct io_device *d, struct io_stats *ioi,
1307 struct io_stats *ioj, char *devname, struct ext_disk_stats *xds,
1308 struct ext_io_stats *xios)
1313 /* If this is a group with no devices, skip it */
1314 if (d->dev_tp == T_GROUP)
1318 "{\"disk_device\": \"%s\", ",
1321 if (DISPLAY_SHORT_OUTPUT(flags)) {
1322 printf("\"tps\": %.2f, \"",
1323 /* Origin (unmerged) flush operations are counted as writes */
1324 S_VALUE(ioj->rd_ios + ioj->wr_ios + ioj->dc_ios,
1325 ioi->rd_ios + ioi->wr_ios + ioi->dc_ios, itv));
1326 if (DISPLAY_MEGABYTES(flags)) {
1329 else if (DISPLAY_KILOBYTES(flags)) {
1335 printf("\": %.2f, \"rqm/s\": %.2f, \"await\": %.2f, "
1336 "\"areq-sz\": %.2f, \"aqu-sz\": %.2f, ",
1337 xios->sectors /= fctr,
1338 S_VALUE(ioj->rd_merges + ioj->wr_merges + ioj->dc_merges,
1339 ioi->rd_merges + ioi->wr_merges + ioi->dc_merges, itv),
1342 S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1345 printf("\"r/s\": %.2f, \"w/s\": %.2f, \"d/s\": %.2f, \"f/s\": %.2f, ",
1346 S_VALUE(ioj->rd_ios, ioi->rd_ios, itv),
1347 S_VALUE(ioj->wr_ios, ioi->wr_ios, itv),
1348 S_VALUE(ioj->dc_ios, ioi->dc_ios, itv),
1349 S_VALUE(ioj->fl_ios, ioi->fl_ios, itv));
1350 if (DISPLAY_MEGABYTES(flags)) {
1351 sprintf(line, "\"rMB/s\": %%.2f, \"wMB/s\": %%.2f, \"dMB/s\": %%.2f, ");
1353 else if (DISPLAY_KILOBYTES(flags)) {
1354 sprintf(line, "\"rkB/s\": %%.2f, \"wkB/s\": %%.2f, \"dkB/s\": %%.2f, ");
1357 sprintf(line, "\"rsec/s\": %%.2f, \"wsec/s\": %%.2f, \"dsec/s\": %%.2f, ");
1360 xios->rsectors /= fctr,
1361 xios->wsectors /= fctr,
1362 xios->dsectors /= fctr);
1363 printf("\"rrqm/s\": %.2f, \"wrqm/s\": %.2f, \"drqm/s\": %.2f, "
1364 "\"rrqm\": %.2f, \"wrqm\": %.2f, \"drqm\": %.2f, "
1365 "\"r_await\": %.2f, \"w_await\": %.2f, \"d_await\": %.2f, \"f_await\": %.2f, "
1366 "\"rareq-sz\": %.2f, \"wareq-sz\": %.2f, \"dareq-sz\": %.2f, "
1367 "\"aqu-sz\": %.2f, ",
1368 S_VALUE(ioj->rd_merges, ioi->rd_merges, itv),
1369 S_VALUE(ioj->wr_merges, ioi->wr_merges, itv),
1370 S_VALUE(ioj->dc_merges, ioi->dc_merges, itv),
1381 S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1384 if (d->dev_tp > T_GROUP) {
1385 n = d->dev_tp - T_GROUP;
1390 printf("\"util\": %.2f}", xds->util / 10.0 / (double) n);
1394 ***************************************************************************
1395 * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1396 * in plain or JSON format.
1399 * @itv Interval of time.
1400 * @fctr Conversion factor.
1401 * @hpart Indicate which part of the report should be displayed in
1402 * human mode. A value of 0 indicates that output should not be
1403 * broken in several parts.
1404 * @d Structure containing device description.
1405 * @ioi Current sample statistics.
1406 * @ioj Previous sample statistics.
1407 * @tab Number of tabs to print (JSON output only).
1408 * @dname Name to be used for display for current device.
1409 ***************************************************************************
1411 void write_ext_stat(unsigned long long itv, int fctr, int hpart,
1412 struct io_device *d, struct io_stats *ioi,
1413 struct io_stats *ioj, int tab, char *dname)
1415 struct stats_disk sdc, sdp;
1416 struct ext_disk_stats xds;
1417 struct ext_io_stats xios;
1419 memset(&xds, 0, sizeof(struct ext_disk_stats));
1420 memset(&xios, 0, sizeof(struct ext_io_stats));
1423 * Counters overflows are possible, but don't need to be handled in
1424 * a special way: The difference is still properly calculated if the
1425 * result is of the same type as the two values.
1426 * Exception is field rq_ticks which is incremented by the number of
1427 * I/O in progress times the number of milliseconds spent doing I/O.
1428 * But the number of I/O in progress (field ios_pgr) happens to be
1429 * sometimes negative...
1432 if ((hpart == 4) || !hpart || DISPLAY_SHORT_OUTPUT(flags)) {
1433 /* Origin (unmerged) flush operations are counted as writes */
1434 sdc.nr_ios = ioi->rd_ios + ioi->wr_ios + ioi->dc_ios;
1435 sdp.nr_ios = ioj->rd_ios + ioj->wr_ios + ioj->dc_ios;
1437 sdc.tot_ticks = ioi->tot_ticks;
1438 sdp.tot_ticks = ioj->tot_ticks;
1440 sdc.rd_ticks = ioi->rd_ticks;
1441 sdp.rd_ticks = ioj->rd_ticks;
1442 sdc.wr_ticks = ioi->wr_ticks;
1443 sdp.wr_ticks = ioj->wr_ticks;
1444 sdc.dc_ticks = ioi->dc_ticks;
1445 sdp.dc_ticks = ioj->dc_ticks;
1447 sdc.rd_sect = ioi->rd_sectors;
1448 sdp.rd_sect = ioj->rd_sectors;
1449 sdc.wr_sect = ioi->wr_sectors;
1450 sdp.wr_sect = ioj->wr_sectors;
1451 sdc.dc_sect = ioi->dc_sectors;
1452 sdp.dc_sect = ioj->dc_sectors;
1454 compute_ext_disk_stats(&sdc, &sdp, itv, &xds);
1457 /* rkB/s wkB/s dkB/s */
1458 xios.rsectors = S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv);
1459 xios.wsectors = S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv);
1460 xios.dsectors = S_VALUE(ioj->dc_sectors, ioi->dc_sectors, itv);
1462 if (DISPLAY_SHORT_OUTPUT(flags)) {
1463 xios.sectors = xios.rsectors + xios.wsectors + xios.dsectors;
1466 if ((hpart == 1) || !hpart) {
1468 xios.rrqm_pc = (ioi->rd_merges - ioj->rd_merges) + (ioi->rd_ios - ioj->rd_ios) ?
1469 (double) ((ioi->rd_merges - ioj->rd_merges)) /
1470 ((ioi->rd_merges - ioj->rd_merges) + (ioi->rd_ios - ioj->rd_ios)) * 100 :
1473 xios.r_await = (ioi->rd_ios - ioj->rd_ios) ?
1474 (ioi->rd_ticks - ioj->rd_ticks) /
1475 ((double) (ioi->rd_ios - ioj->rd_ios)) : 0.0;
1476 /* rareq-sz (still in sectors, not kB) */
1477 xios.rarqsz = (ioi->rd_ios - ioj->rd_ios) ?
1478 (ioi->rd_sectors - ioj->rd_sectors) / ((double) (ioi->rd_ios - ioj->rd_ios)) :
1481 if ((hpart == 2) || !hpart) {
1483 xios.wrqm_pc = (ioi->wr_merges - ioj->wr_merges) + (ioi->wr_ios - ioj->wr_ios) ?
1484 (double) ((ioi->wr_merges - ioj->wr_merges)) /
1485 ((ioi->wr_merges - ioj->wr_merges) + (ioi->wr_ios - ioj->wr_ios)) * 100 :
1488 xios.w_await = (ioi->wr_ios - ioj->wr_ios) ?
1489 (ioi->wr_ticks - ioj->wr_ticks) /
1490 ((double) (ioi->wr_ios - ioj->wr_ios)) : 0.0;
1491 /* wareq-sz (still in sectors, not kB) */
1492 xios.warqsz = (ioi->wr_ios - ioj->wr_ios) ?
1493 (ioi->wr_sectors - ioj->wr_sectors) / ((double) (ioi->wr_ios - ioj->wr_ios)) :
1496 if ((hpart == 3) || !hpart) {
1498 xios.drqm_pc = (ioi->dc_merges - ioj->dc_merges) + (ioi->dc_ios - ioj->dc_ios) ?
1499 (double) ((ioi->dc_merges - ioj->dc_merges)) /
1500 ((ioi->dc_merges - ioj->dc_merges) + (ioi->dc_ios - ioj->dc_ios)) * 100 :
1503 xios.d_await = (ioi->dc_ios - ioj->dc_ios) ?
1504 (ioi->dc_ticks - ioj->dc_ticks) /
1505 ((double) (ioi->dc_ios - ioj->dc_ios)) : 0.0;
1506 /* dareq-sz (still in sectors, not kB) */
1507 xios.darqsz = (ioi->dc_ios - ioj->dc_ios) ?
1508 (ioi->dc_sectors - ioj->dc_sectors) / ((double) (ioi->dc_ios - ioj->dc_ios)) :
1511 if ((hpart == 4) || !hpart) {
1513 xios.f_await = (ioi->fl_ios - ioj->fl_ios) ?
1514 (ioi->fl_ticks - ioj->fl_ticks) /
1515 ((double) (ioi->fl_ios - ioj->fl_ios)) : 0.0;
1519 if (DISPLAY_JSON_OUTPUT(flags)) {
1520 write_json_ext_stat(tab, itv, fctr, d, ioi, ioj, dname, &xds, &xios);
1523 write_plain_ext_stat(itv, fctr, hpart, d, ioi, ioj, dname, &xds, &xios);
1528 ***************************************************************************
1529 * Write basic stats, read from /proc/diskstats or from sysfs, in plain
1533 * @itv Interval of time.
1534 * @fctr Conversion factor.
1535 * @ioi Current sample statistics.
1536 * @ioj Previous sample statistics.
1537 * @devname Current device name.
1538 * @rd_sec Number of sectors read.
1539 * @wr_sec Number of sectors written.
1540 * @dc_sec Number of sectors discarded.
1541 ***************************************************************************
1543 void write_plain_basic_stat(unsigned long long itv, int fctr,
1544 struct io_stats *ioi, struct io_stats *ioj,
1545 char *devname, unsigned long long rd_sec,
1546 unsigned long long wr_sec, unsigned long long dc_sec)
1548 double rsectors, wsectors, dsectors;
1550 if (!DISPLAY_PRETTY(flags)) {
1551 cprintf_in(IS_STR, "%-13s", devname, 0);
1554 rsectors = S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv);
1555 wsectors = S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv);
1556 dsectors = S_VALUE(ioj->dc_sectors, ioi->dc_sectors, itv);
1557 if (!DISPLAY_UNIT(flags)) {
1564 cprintf_f(NO_UNIT, 1, 8, 2,
1565 /* Origin (unmerged) flush operations are counted as writes */
1566 S_VALUE(ioj->rd_ios + ioj->wr_ios + ioj->dc_ios,
1567 ioi->rd_ios + ioi->wr_ios + ioi->dc_ios, itv));
1569 if (DISPLAY_SHORT_OUTPUT(flags)) {
1570 /* kB_read/s kB_w+d/s */
1571 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 2, 12, 2,
1572 rsectors, wsectors + dsectors);
1573 /* kB_read kB_w+d */
1574 cprintf_u64(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 2, 10,
1575 DISPLAY_UNIT(flags) ? (unsigned long long) rd_sec
1576 : (unsigned long long) rd_sec / fctr,
1577 DISPLAY_UNIT(flags) ? (unsigned long long) wr_sec + dc_sec
1578 : (unsigned long long) (wr_sec + dc_sec) / fctr);
1581 /* kB_read/s kB_wrtn/s kB_dscd/s */
1582 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 3, 12, 2,
1583 rsectors, wsectors, dsectors);
1584 /* kB_read kB_wrtn kB_dscd */
1585 cprintf_u64(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 3, 10,
1586 DISPLAY_UNIT(flags) ? (unsigned long long) rd_sec
1587 : (unsigned long long) rd_sec / fctr,
1588 DISPLAY_UNIT(flags) ? (unsigned long long) wr_sec
1589 : (unsigned long long) wr_sec / fctr,
1590 DISPLAY_UNIT(flags) ? (unsigned long long) dc_sec
1591 : (unsigned long long) dc_sec / fctr);
1594 if (DISPLAY_PRETTY(flags)) {
1595 cprintf_in(IS_STR, " %s", devname, 0);
1601 ***************************************************************************
1602 * Write basic stats, read from /proc/diskstats or from sysfs, in JSON
1606 * @tab Number of tabs to print.
1607 * @itv Interval of time.
1608 * @fctr Conversion factor.
1609 * @ioi Current sample statistics.
1610 * @ioj Previous sample statistics.
1611 * @devname Current device name.
1612 * @rd_sec Number of sectors read.
1613 * @wr_sec Number of sectors written.
1614 ***************************************************************************
1616 void write_json_basic_stat(int tab, unsigned long long itv, int fctr,
1617 struct io_stats *ioi, struct io_stats *ioj,
1618 char *devname, unsigned long long rd_sec,
1619 unsigned long long wr_sec, unsigned long long dc_sec)
1624 "{\"disk_device\": \"%s\", \"tps\": %.2f, ",
1626 /* Origin (unmerged) flush operations are counted as writes */
1627 S_VALUE(ioj->rd_ios + ioj->wr_ios + ioj->dc_ios,
1628 ioi->rd_ios + ioi->wr_ios + ioi->dc_ios, itv));
1629 if (DISPLAY_KILOBYTES(flags)) {
1630 sprintf(line, "\"kB_read/s\": %%.2f, \"kB_wrtn/s\": %%.2f, \"kB_dscd/s\": %%.2f, "
1631 "\"kB_read\": %%llu, \"kB_wrtn\": %%llu, \"kB_dscd\": %%llu}");
1633 else if (DISPLAY_MEGABYTES(flags)) {
1634 sprintf(line, "\"MB_read/s\": %%.2f, \"MB_wrtn/s\": %%.2f, \"MB_dscd/s\": %%.2f, "
1635 "\"MB_read\": %%llu, \"MB_wrtn\": %%llu, \"MB_dscd\": %%llu}");
1638 sprintf(line, "\"Blk_read/s\": %%.2f, \"Blk_wrtn/s\": %%.2f, \"Blk_dscd/s\": %%.2f, "
1639 "\"Blk_read\": %%llu, \"Blk_wrtn\": %%llu, \"Blk_dscd\": %%llu}");
1642 S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1643 S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr,
1644 S_VALUE(ioj->dc_sectors, ioi->dc_sectors, itv) / fctr,
1645 (unsigned long long) rd_sec / fctr,
1646 (unsigned long long) wr_sec / fctr,
1647 (unsigned long long) dc_sec / fctr);
1651 ***************************************************************************
1652 * Write basic stats, read from /proc/diskstats or from sysfs, in plain or
1656 * @itv Interval of time.
1657 * @fctr Conversion factor.
1658 * @d Structure containing device description.
1659 * @ioi Current sample statistics.
1660 * @ioj Previous sample statistics.
1661 * @tab Number of tabs to print (JSON format only).
1662 * @dname Name to be used for display for current device.
1663 ***************************************************************************
1665 void write_basic_stat(unsigned long long itv, int fctr,
1666 struct io_device *d, struct io_stats *ioi,
1667 struct io_stats *ioj, int tab, char *dname)
1669 unsigned long long rd_sec, wr_sec, dc_sec;
1671 /* Print stats coming from /sys or /proc/diskstats */
1672 rd_sec = ioi->rd_sectors - ioj->rd_sectors;
1673 if ((ioi->rd_sectors < ioj->rd_sectors) && (ioj->rd_sectors <= 0xffffffff)) {
1674 rd_sec &= 0xffffffff;
1676 wr_sec = ioi->wr_sectors - ioj->wr_sectors;
1677 if ((ioi->wr_sectors < ioj->wr_sectors) && (ioj->wr_sectors <= 0xffffffff)) {
1678 wr_sec &= 0xffffffff;
1680 dc_sec = ioi->dc_sectors - ioj->dc_sectors;
1681 if ((ioi->dc_sectors < ioj->dc_sectors) && (ioj->dc_sectors <= 0xffffffff)) {
1682 dc_sec &= 0xffffffff;
1685 if (DISPLAY_JSON_OUTPUT(flags)) {
1686 write_json_basic_stat(tab, itv, fctr, ioi, ioj, dname,
1687 rd_sec, wr_sec, dc_sec);
1690 write_plain_basic_stat(itv, fctr, ioi, ioj, dname,
1691 rd_sec, wr_sec, dc_sec);
1696 ***************************************************************************
1697 * Print everything now (stats and uptime).
1700 * @curr Index in array for current sample statistics.
1701 * @rectime Current date and time.
1702 * @skip TRUE if nothing should be displayed (option -y). We must
1703 * go through write_stats() anyway to compute groups statistics.
1704 ***************************************************************************
1706 void write_stats(int curr, struct tm *rectime, int skip)
1708 int h, hl = 0, hh = 0, fctr = 1, tab = 4, next = FALSE;
1709 unsigned long long itv;
1710 struct io_device *d, *dtmp, *g = NULL, *dnext = NULL;
1714 TEST_STDOUT(STDOUT_FILENO);
1716 if (DISPLAY_JSON_OUTPUT(flags) && !skip) {
1717 xprintf(tab++, "{");
1720 /* Print time stamp */
1721 if (DISPLAY_TIMESTAMP(flags) && !skip) {
1722 write_sample_timestamp(tab, rectime);
1724 if (DISPLAY_DEBUG(flags)) {
1725 fprintf(stderr, "%s\n", timestamp);
1730 if (DISPLAY_CPU(flags) && !skip) {
1731 /* Display CPU utilization */
1732 write_cpu_stat(curr, tab);
1734 if (DISPLAY_JSON_OUTPUT(flags)) {
1735 if (DISPLAY_DISK(flags)) {
1742 /* Calculate time interval in 1/100th of a second */
1743 itv = get_interval(uptime_cs[!curr], uptime_cs[curr]);
1745 if (DISPLAY_DISK(flags)) {
1746 struct io_stats *ioi, *ioj, iozero;
1748 memset(&iozero, 0, sizeof(struct io_stats));
1750 if (DISPLAY_PRETTY(flags) &&
1751 DISPLAY_EXTENDED(flags) &&
1752 !DISPLAY_SHORT_OUTPUT(flags) &&
1753 !DISPLAY_JSON_OUTPUT(flags)) {
1757 for (h = hl; h <= hh; h++) {
1760 /* Display disk stats header */
1761 write_disk_stat_header(&fctr, &tab, h);
1764 for (d = dev_list; ; d = dnext) {
1768 /* No group processing in progress */
1770 /* Display last group before exit */
1778 if (d->dev_tp >= T_GROUP) {
1780 * This is a new group: Save group position
1781 * and display previous one.
1787 memset(g->dev_stats[curr], 0, sizeof(struct io_stats));
1791 memset(g->dev_stats[curr], 0, sizeof(struct io_stats));
1792 continue; /* No previous group to display */
1797 if (!d->exist && (d->dev_tp < T_GROUP))
1798 /* Current device is non existent (e.g. it has been unregistered from the system */
1801 if ((g != NULL) && (h == hl) && (d->dev_tp < T_GROUP)) {
1802 /* We are within a group: Increment number of disks in the group */
1804 /* Add current device stats to group */
1805 compute_device_groups_stats(curr, d, g);
1808 if (DISPLAY_GROUP_TOTAL_ONLY(flags) && (g != NULL) && (d->dev_tp < T_GROUP))
1811 ioi = d->dev_stats[curr];
1812 ioj = d->dev_stats[!curr];
1813 /* Origin (unmerged) flush operations are counted as writes */
1814 if (!DISPLAY_UNFILTERED(flags)) {
1815 if (!ioi->rd_ios && !ioi->wr_ios && !ioi->dc_ios && !ioi->fl_ios)
1819 if (DISPLAY_ZERO_OMIT(flags)) {
1820 if ((ioi->rd_ios == ioj->rd_ios) &&
1821 (ioi->wr_ios == ioj->wr_ios) &&
1822 (ioi->dc_ios == ioj->dc_ios) &&
1823 (ioi->fl_ios == ioj->fl_ios))
1824 /* No activity: Ignore it */
1828 /* Try to detect if device has been removed then inserted again */
1829 if (((ioi->rd_ios + ioi->wr_ios + ioi->dc_ios + ioi->fl_ios) <
1830 (ioj->rd_ios + ioj->wr_ios + ioj->dc_ios + ioj->fl_ios)) &&
1831 (!ioj->rd_sectors || (ioi->rd_sectors < ioj->rd_sectors)) &&
1832 (!ioj->wr_sectors || (ioi->wr_sectors < ioj->wr_sectors)) &&
1833 (!ioj->dc_sectors || (ioi->dc_sectors < ioj->dc_sectors))) {
1837 dev_name = get_device_name(d->major, d->minor, NULL, 0,
1838 DISPLAY_DEVMAP_NAME(flags),
1839 DISPLAY_PERSIST_NAME_I(flags),
1842 if (DISPLAY_DEBUG(flags)) {
1845 "name=%s itv=%llu fctr=%d ioi{ rd_sectors=%lu "
1846 "wr_sectors=%lu dc_sectors=%lu "
1847 "rd_ios=%lu rd_merges=%lu rd_ticks=%u "
1848 "wr_ios=%lu wr_merges=%lu wr_ticks=%u "
1849 "dc_ios=%lu dc_merges=%lu dc_ticks=%u "
1850 "fl_ios=%lu fl_ticks=%u "
1851 "ios_pgr=%u tot_ticks=%u "
1877 if (DISPLAY_JSON_OUTPUT(flags) && next) {
1882 if (DISPLAY_EXTENDED(flags)) {
1883 write_ext_stat(itv, fctr, h, d, ioi, ioj, tab, dev_name);
1886 write_basic_stat(itv, fctr, d, ioi, ioj, tab, dev_name);
1891 if ((h > 0) && (h < hh) && !skip) {
1895 if (DISPLAY_JSON_OUTPUT(flags) && !skip) {
1897 xprintf(--tab, "]");
1902 if (DISPLAY_JSON_OUTPUT(flags)) {
1903 xprintf0(--tab, "}");
1912 ***************************************************************************
1913 * Main loop: Read I/O stats from the relevant sources and display them.
1916 * @count Number of reports to print.
1917 * @rectime Current date and time.
1918 ***************************************************************************
1920 void rw_io_stat_loop(long int count, struct tm *rectime)
1925 /* Should we skip first report? */
1926 if (DISPLAY_OMIT_SINCE_BOOT(flags) && interval > 0) {
1930 /* Set a handler for SIGALRM */
1931 memset(&alrm_act, 0, sizeof(alrm_act));
1932 alrm_act.sa_handler = alarm_handler;
1933 sigaction(SIGALRM, &alrm_act, NULL);
1936 /* Set a handler for SIGINT */
1937 memset(&int_act, 0, sizeof(int_act));
1938 int_act.sa_handler = int_handler;
1939 sigaction(SIGINT, &int_act, NULL);
1942 /* Every device is potentially nonexistent */
1943 set_devices_nonexistent(dev_list);
1945 /* Read system uptime */
1946 read_uptime(&(uptime_cs[curr]));
1948 /* Read stats for CPU "all" */
1949 read_stat_cpu(st_cpu[curr], 1);
1952 * Compute the total number of jiffies spent by all processors.
1953 * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
1954 * already include them.
1956 tot_jiffies[curr] = st_cpu[curr]->cpu_user + st_cpu[curr]->cpu_nice +
1957 st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_idle +
1958 st_cpu[curr]->cpu_iowait + st_cpu[curr]->cpu_hardirq +
1959 st_cpu[curr]->cpu_steal + st_cpu[curr]->cpu_softirq;
1961 if (DISPLAY_EVERYTHING(flags)) {
1962 read_diskstats_stat(curr);
1965 read_sysfs_dlist_stat(curr);
1969 get_localtime(rectime, 0);
1972 write_stats(curr, rectime, skip);
1984 if (sigint_caught) {
1985 /* SIGINT signal caught => Terminate JSON output properly */
1988 else if (DISPLAY_JSON_OUTPUT(flags) && count && !skip) {
1997 if (DISPLAY_JSON_OUTPUT(flags)) {
1998 printf("\t\t\t]\n\t\t}\n\t]\n}}\n");
2003 ***************************************************************************
2004 * Main entry to the iostat program.
2005 ***************************************************************************
2007 int main(int argc, char **argv)
2011 int i, report_set = FALSE;
2013 struct utsname header;
2015 char *t, *persist_devname, *devname;
2016 char group_name[MAX_NAME_LEN];
2019 /* Init National Language Support */
2025 /* Process args... */
2026 while (opt < argc) {
2028 /* -p option used individually. See below for grouped use */
2029 if (!strcmp(argv[opt], "-p")) {
2031 (strspn(argv[opt], DIGITS) != strlen(argv[opt])) &&
2032 (strncmp(argv[opt], "-", 1))) {
2033 flags |= I_D_UNFILTERED;
2035 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2036 if (!strcmp(t, K_ALL)) {
2037 flags |= I_D_EVERYTHING;
2040 devname = device_name(t);
2041 if (DISPLAY_PERSIST_NAME_I(flags)) {
2042 /* Get device persistent name */
2043 persist_devname = get_pretty_name_from_persistent(devname);
2044 if (persist_devname != NULL) {
2045 devname = persist_devname;
2048 /* Store device name */
2049 add_list_device(&dev_list, devname, T_PART_DEV);
2055 flags |= I_D_EVERYTHING;
2059 else if (!strcmp(argv[opt], "-g")) {
2063 flags |= I_F_GROUP_DEFINED;
2066 * MAX_NAME_LEN - 2: one char for the heading space,
2067 * and one for the trailing '\0'.
2069 snprintf(group_name, MAX_NAME_LEN, " %-.*s", MAX_NAME_LEN - 2, argv[opt++]);
2070 add_list_device(&dev_list, group_name, T_GROUP);
2073 else if (!strcmp(argv[opt], "--human")) {
2078 else if (!strcmp(argv[opt], "--pretty")) {
2079 /* Display an easy-to-read CIFS report */
2080 flags |= I_D_PRETTY;
2085 else if (!strncmp(argv[opt], "--getenv", 8)) {
2091 else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
2092 /* Get number of decimal places */
2093 dplaces_nr = atoi(argv[opt] + 6);
2094 if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
2100 else if (!strcmp(argv[opt], "-f") || !strcmp(argv[opt], "+f")) {
2101 if (alt_dir[0] || !argv[opt + 1]) {
2104 if (argv[opt++][0] == '+') {
2105 flags |= I_D_ALL_DIR;
2107 strncpy(alt_dir, argv[opt++], sizeof(alt_dir));
2108 alt_dir[sizeof(alt_dir) - 1] = '\0';
2109 if (!check_dir(alt_dir)) {
2114 else if (!strcmp(argv[opt], "-j")) {
2118 if (strnlen(argv[opt], sizeof(persistent_name_type)) >= sizeof(persistent_name_type) - 1) {
2121 strncpy(persistent_name_type, argv[opt], sizeof(persistent_name_type) - 1);
2122 persistent_name_type[sizeof(persistent_name_type) - 1] = '\0';
2123 strtolower(persistent_name_type);
2124 /* Check that this is a valid type of persistent device name */
2125 if (!get_persistent_type_dir(persistent_name_type)) {
2126 fprintf(stderr, _("Invalid type of persistent device name\n"));
2129 /* Persistent names are usually long: Pretty display them */
2130 flags |= I_D_PERSIST_NAME + I_D_PRETTY;
2134 else if (!strcmp(argv[opt], "-o")) {
2135 /* Select output format */
2136 if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2137 flags |= I_D_JSON_OUTPUT;
2146 else if (!strcmp(argv[opt], "--debuginfo")) {
2152 else if (!strncmp(argv[opt], "-", 1)) {
2153 for (i = 1; *(argv[opt] + i); i++) {
2155 switch (*(argv[opt] + i)) {
2158 /* Display cpu usage */
2164 /* Display disk utilization */
2170 /* Display stats only for the groups */
2171 flags |= I_D_GROUP_TOTAL_ONLY;
2175 /* Option -h is equivalent to --pretty --human */
2176 flags |= I_D_PRETTY + I_D_UNIT;
2180 if (DISPLAY_MEGABYTES(flags)) {
2183 /* Display stats in kB/s */
2184 flags |= I_D_KILOBYTES;
2188 if (DISPLAY_KILOBYTES(flags)) {
2191 /* Display stats in MB/s */
2192 flags |= I_D_MEGABYTES;
2196 /* Display device mapper logical name */
2197 flags |= I_D_DEVMAP_NAME;
2201 /* If option -p is grouped then it cannot take an arg */
2202 flags |= I_D_EVERYTHING;
2206 /* Display short output */
2207 flags |= I_D_SHORT_OUTPUT;
2211 /* Display timestamp */
2212 flags |= I_D_TIMESTAMP;
2216 /* Display extended stats */
2217 flags |= I_D_EXTENDED;
2221 /* Don't display stats since system restart */
2222 flags |= I_D_OMIT_SINCE_BOOT;
2226 /* Omit output for devices with no activity */
2227 flags |= I_D_ZERO_OMIT;
2231 /* Print version number and exit */
2242 else if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2244 * By default iostat doesn't display unused devices.
2245 * If some devices are explicitly entered on the command line
2246 * then don't apply this rule any more.
2248 flags |= I_D_UNFILTERED;
2250 if (strcmp(argv[opt], K_ALL)) {
2251 /* Store device name entered on the command line */
2252 devname = device_name(argv[opt++]);
2253 if (DISPLAY_PERSIST_NAME_I(flags)) {
2254 persist_devname = get_pretty_name_from_persistent(devname);
2255 if (persist_devname != NULL) {
2256 devname = persist_devname;
2259 add_list_device(&dev_list, devname, 0);
2262 flags |= I_D_ALL_DEVICES;
2268 interval = atol(argv[opt++]);
2277 count = atol(argv[opt++]);
2278 if ((count < 1) || !interval) {
2292 /* Init color strings */
2295 /* Default: Display CPU and DISK reports */
2297 flags |= I_D_CPU + I_D_DISK;
2300 * Also display DISK reports if options -p, -x or a device has been entered
2301 * on the command line.
2303 if (DISPLAY_EVERYTHING(flags) || DISPLAY_EXTENDED(flags) ||
2304 DISPLAY_UNFILTERED(flags)) {
2308 if (!DISPLAY_UNFILTERED(flags)) {
2309 flags |= I_D_ALL_DEVICES;
2311 /* Option -H can only be used with option -g */
2312 if (DISPLAY_GROUP_TOTAL_ONLY(flags) && !GROUP_DEFINED(flags)) {
2316 /* Select disk output unit (kB/s or blocks/s) */
2317 set_disk_output_unit();
2319 if (DISPLAY_JSON_OUTPUT(flags)) {
2320 /* Use a decimal point to make JSON code compliant with RFC7159 */
2321 setlocale(LC_NUMERIC, "C");
2324 /* Allocate and init stat common counters */
2327 /* How many processors on this machine? */
2328 cpu_nr = get_cpu_nr(~0, FALSE);
2330 get_localtime(&rectime, 0);
2333 * Don't buffer data if redirected to a pipe.
2334 * Note: With musl-c, the behavior of this function is undefined except
2335 * when it is the first operation on the stream.
2337 setbuf(stdout, NULL);
2339 /* Get system name, release number and hostname */
2341 if (print_gal_header(&rectime, header.sysname, header.release,
2342 header.nodename, header.machine, cpu_nr,
2343 DISPLAY_JSON_OUTPUT(flags))) {
2346 if (!DISPLAY_JSON_OUTPUT(flags)) {
2351 rw_io_stat_loop(count, &rectime);