]> granicus.if.org Git - sysstat/blobdiff - pr_stats.c
sar/sadc: Add stable identifier support for disks statistics
[sysstat] / pr_stats.c
index e1d668af2e50d15fc93fbc01adfe56202d4e477a..72c9a67cdcf8b287051e35755f891d354689b28e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * pr_stats.c: Functions used by sar to display statistics
- * (C) 1999-2017 by Sebastien GODARD (sysstat <at> orange.fr)
+ * (C) 1999-2019 by Sebastien GODARD (sysstat <at> orange.fr)
  *
  ***************************************************************************
  * This program is free software; you can redistribute it and/or modify it *
 #endif
 
 extern unsigned int flags;
-extern unsigned int dm_major;
-extern int  dis;
+extern int  dish;
 extern char timestamp[][TIMESTAMP_LEN];
 extern unsigned long avg_count;
 
-
 /*
  ***************************************************************************
  * Display current activity header line.
  *
  * IN:
- * @timestamp  Timestamp for previous stat sample.
+ * @p_timestamp        Timestamp for previous stat sample.
  * @a          Activity structure.
  * @pos                Index in @.hdr_line string, 0 being the first one (header
  *             are delimited by the '|' character).
@@ -58,7 +56,7 @@ extern unsigned long avg_count;
  * @vwidth     Column width for stats values.
  ***************************************************************************
  */
-void print_hdr_line(char *timestamp, struct activity *a, int pos, int iwidth, int vwidth)
+void print_hdr_line(char *p_timestamp, struct activity *a, int pos, int iwidth, int vwidth)
 {
        char hline[HEADER_LINE_LEN] = "";
        char *hl, *tk, *it = NULL;
@@ -72,7 +70,7 @@ void print_hdr_line(char *timestamp, struct activity *a, int pos, int iwidth, in
                /* Bad @pos arg given to function */
                return;
 
-       printf("\n%-11s", timestamp);
+       printf("\n%-11s", p_timestamp);
 
        if (strchr(hl, '&')) {
                j = strcspn(hl, "&");
@@ -126,11 +124,11 @@ __print_funct_t print_cpu_stats(struct activity *a, int prev, int curr,
                                unsigned long long itv)
 {
        int i;
-       unsigned long long tot_jiffies_c, tot_jiffies_p;
-       unsigned long long deltot_jiffies;
+       unsigned long long deltot_jiffies = 1;
        struct stats_cpu *scc, *scp;
+       unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST + DISPLAY_CPU_ALL(a->opt_flags), 7, 9);
        }
 
@@ -147,83 +145,54 @@ __print_funct_t print_cpu_stats(struct activity *a, int prev, int curr,
                a->nr_ini = a->nr[curr];
        }
 
-       for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
+       /*
+        * Compute CPU "all" as sum of all individual CPU (on SMP machines)
+        * and look for offline CPU.
+        */
+       if (a->nr_ini > 1) {
+               deltot_jiffies = get_global_cpu_statistics(a, prev, curr,
+                                                          flags, offline_cpu_bitmap);
+       }
 
-               /*
-                * The size of a->buf[...] CPU structure may be different from the default
-                * sizeof(struct stats_cpu) value if data have been read from a file!
-                * That's why we don't use a syntax like:
-                * scc = (struct stats_cpu *) a->buf[...] + i;
-                */
-               scc = (struct stats_cpu *) ((char *) a->buf[curr] + i * a->msize);
-               scp = (struct stats_cpu *) ((char *) a->buf[prev] + i * a->msize);
+       /*
+        * Now display CPU statistics (including CPU "all"),
+        * except for offline CPU or CPU that the user doesn't want to see.
+        */
+       for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
 
                /*
+                * Should current CPU (including CPU "all") be displayed?
                 * Note: @nr[curr] is in [1, NR_CPUS + 1].
                 * Bitmap size is provided for (NR_CPUS + 1) CPUs.
                 * Anyway, NR_CPUS may vary between the version of sysstat
                 * used by sadc to create a file, and the version of sysstat
                 * used by sar to read it...
                 */
-
-               /* Should current CPU (including CPU "all") be displayed? */
-               if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
-                       /* No */
+               if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))) ||
+                   offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
+                       /* Don't display CPU */
                        continue;
 
-               /*
-                * Yes: Compute the total number of jiffies spent by current processor.
-                * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
-                * already include them.
-                */
-               tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
-                               scc->cpu_sys + scc->cpu_idle +
-                               scc->cpu_iowait + scc->cpu_hardirq +
-                               scc->cpu_steal + scc->cpu_softirq;
-               tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
-                               scp->cpu_sys + scp->cpu_idle +
-                               scp->cpu_iowait + scp->cpu_hardirq +
-                               scp->cpu_steal + scp->cpu_softirq;
-
-               /* Total number of jiffies spent on the interval */
-               deltot_jiffies = get_interval(tot_jiffies_p, tot_jiffies_c);
-
-               /*
-                * If the CPU is offline then it is omited from /proc/stat:
-                * All the fields couldn't have been read and the sum of them is zero.
-                */
-               if (tot_jiffies_c == 0) {
-                       /*
-                        * CPU is currently offline.
-                        * Set current struct fields (which have been set to zero)
-                        * to values from previous iteration. Hence their values won't
-                        * jump from zero when the CPU comes back online.
-                        * Note that this workaround is no longer enough with recent kernels,
-                        * as I have noticed that when a CPU comes back online, some fields
-                        * restart from their previous value (e.g. user, nice, system)
-                        * whereas others restart from zero (idle, iowait)!
-                        */
-                       *scc = *scp;
-
-                       /* An offline CPU is not displayed */
-                       continue;
-               }
-               if ((tot_jiffies_p == 0) && !WANT_SINCE_BOOT(flags))
-                       /*
-                        * CPU has just come back online.
-                        * Unfortunately, no reference values are available
-                        * from a previous iteration, probably because it was
-                        * already offline when the first sample has been taken.
-                        * So don't display that CPU to prevent "jump-from-zero"
-                        * output syndrome.
-                        */
-                       continue;
+               scc = (struct stats_cpu *) ((char *) a->buf[curr] + i * a->msize);
+               scp = (struct stats_cpu *) ((char *) a->buf[prev] + i * a->msize);
 
                printf("%-11s", timestamp[curr]);
 
-               if (!i) {
+               if (i == 0) {
                        /* This is CPU "all" */
                        cprintf_in(IS_STR, " %s", "    all", 0);
+
+                       if (a->nr_ini == 1) {
+                               /*
+                                * This is a UP machine. In this case
+                                * interval has still not been calculated.
+                                */
+                               deltot_jiffies = get_per_cpu_interval(scc, scp);
+                       }
+                       if (!deltot_jiffies) {
+                               /* CPU "all" cannot be tickless */
+                               deltot_jiffies = 1;
+                       }
                }
                else {
                        cprintf_in(IS_INT, " %7d", "", i - 1);
@@ -249,8 +218,8 @@ __print_funct_t print_cpu_stats(struct activity *a, int prev, int curr,
                                 * %irq, %soft, %guest, %gnice.
                                 */
                                else if (DISPLAY_CPU_ALL(a->opt_flags)) {
-                                       cprintf_pc(DISPLAY_UNIT(flags), 4, 9, 2,
-                                                  0.0, 0.0, 0.0, 100.0);
+                                       cprintf_pc(DISPLAY_UNIT(flags), 5, 9, 2,
+                                                  0.0, 0.0, 0.0, 0.0, 100.0);
                                        printf("\n");
                                }
                                continue;
@@ -314,7 +283,7 @@ __print_funct_t print_pcsw_stats(struct activity *a, int prev, int curr,
                *spc = (struct stats_pcsw *) a->buf[curr],
                *spp = (struct stats_pcsw *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -342,7 +311,7 @@ __print_funct_t print_irq_stats(struct activity *a, int prev, int curr,
        int i;
        struct stats_irq *sic, *sip;
 
-       if (dis) {
+       if (dish || DISPLAY_ZERO_OMIT(flags)) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -366,6 +335,9 @@ __print_funct_t print_irq_stats(struct activity *a, int prev, int curr,
                /* Should current interrupt (including int "sum") be displayed? */
                if (a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))) {
 
+                       if (DISPLAY_ZERO_OMIT(flags) && !memcmp(sip, sic, STATS_IRQ_SIZE))
+                               continue;
+
                        /* Yes: Display it */
                        printf("%-11s", timestamp[curr]);
                        if (!i) {
@@ -400,7 +372,7 @@ __print_funct_t print_swap_stats(struct activity *a, int prev, int curr,
                *ssc = (struct stats_swap *) a->buf[curr],
                *ssp = (struct stats_swap *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -429,7 +401,7 @@ __print_funct_t print_paging_stats(struct activity *a, int prev, int curr,
                *spc = (struct stats_paging *) a->buf[curr],
                *spp = (struct stats_paging *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -471,7 +443,7 @@ __print_funct_t print_io_stats(struct activity *a, int prev, int curr,
                *sic = (struct stats_io *) a->buf[curr],
                *sip = (struct stats_io *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -482,17 +454,21 @@ __print_funct_t print_io_stats(struct activity *a, int prev, int curr,
         * We display 0.0 in this case though we should rather tell
         * the user that the value cannot be calculated here.
         */
-       cprintf_f(NO_UNIT, 5, 9, 2,
+       cprintf_f(NO_UNIT, 7, 9, 2,
                  sic->dk_drive < sip->dk_drive ? 0.0 :
                  S_VALUE(sip->dk_drive, sic->dk_drive, itv),
                  sic->dk_drive_rio < sip->dk_drive_rio ? 0.0 :
                  S_VALUE(sip->dk_drive_rio, sic->dk_drive_rio, itv),
                  sic->dk_drive_wio < sip->dk_drive_wio ? 0.0 :
                  S_VALUE(sip->dk_drive_wio, sic->dk_drive_wio, itv),
+                 sic->dk_drive_dio < sip->dk_drive_dio ? 0.0 :
+                 S_VALUE(sip->dk_drive_dio, sic->dk_drive_dio, itv),
                  sic->dk_drive_rblk < sip->dk_drive_rblk ? 0.0 :
                  S_VALUE(sip->dk_drive_rblk, sic->dk_drive_rblk, itv),
                  sic->dk_drive_wblk < sip->dk_drive_wblk ? 0.0 :
-                 S_VALUE(sip->dk_drive_wblk, sic->dk_drive_wblk, itv));
+                 S_VALUE(sip->dk_drive_wblk, sic->dk_drive_wblk, itv),
+                 sic->dk_drive_dblk < sip->dk_drive_dblk ? 0.0 :
+                 S_VALUE(sip->dk_drive_dblk, sic->dk_drive_dblk, itv));
        printf("\n");
 }
 
@@ -531,6 +507,7 @@ void stub_print_memory_stats(struct activity *a, int prev, int curr, int dispavg
                avg_tlskb = 0,
                avg_caskb = 0;
        int unit = NO_UNIT;
+       unsigned long long nousedmem;
 
        if (DISPLAY_UNIT(flags)) {
                /* Default values unit is kB */
@@ -538,20 +515,24 @@ void stub_print_memory_stats(struct activity *a, int prev, int curr, int dispavg
        }
 
        if (DISPLAY_MEMORY(a->opt_flags)) {
-               if (dis) {
+               if (dish) {
                        print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
                }
 
                if (!dispavg) {
                        /* Display instantaneous values */
+                       nousedmem = smc->frmkb + smc->bufkb + smc->camkb + smc->slabkb;
+                       if (nousedmem > smc->tlmkb) {
+                               nousedmem = smc->tlmkb;
+                       }
                        printf("%-11s", timestamp[curr]);
                        cprintf_u64(unit, 3, 9,
                                    (unsigned long long) smc->frmkb,
                                    (unsigned long long) smc->availablekb,
-                                   (unsigned long long) (smc->tlmkb - smc->frmkb));
+                                   (unsigned long long) (smc->tlmkb - nousedmem));
                        cprintf_pc(DISPLAY_UNIT(flags), 1, 9, 2,
                                   smc->tlmkb ?
-                                  SP_VALUE(smc->frmkb, smc->tlmkb, smc->tlmkb)
+                                  SP_VALUE(nousedmem, smc->tlmkb, smc->tlmkb)
                                   : 0.0);
                        cprintf_u64(unit, 3, 9,
                                    (unsigned long long) smc->bufkb,
@@ -599,14 +580,15 @@ void stub_print_memory_stats(struct activity *a, int prev, int curr, int dispavg
                }
                else {
                        /* Display average values */
+                       nousedmem = avg_frmkb + avg_bufkb + avg_camkb + avg_slabkb;
                        printf("%-11s", timestamp[curr]);
                        cprintf_f(unit, 3, 9, 0,
                                  (double) avg_frmkb / avg_count,
                                  (double) avg_availablekb / avg_count,
-                                 (double) smc->tlmkb - ((double) avg_frmkb / avg_count));
+                                 (double) smc->tlmkb - ((double) nousedmem / avg_count));
                        cprintf_pc(DISPLAY_UNIT(flags), 1, 9, 2,
                                   smc->tlmkb ?
-                                  SP_VALUE((double) (avg_frmkb / avg_count), smc->tlmkb, smc->tlmkb)
+                                  SP_VALUE((double) (nousedmem / avg_count), smc->tlmkb, smc->tlmkb)
                                   : 0.0);
                        cprintf_f(unit, 3, 9, 0,
                                  (double) avg_bufkb / avg_count,
@@ -641,7 +623,7 @@ void stub_print_memory_stats(struct activity *a, int prev, int curr, int dispavg
        }
 
        if (DISPLAY_SWAP(a->opt_flags)) {
-               if (dis) {
+               if (dish) {
                        print_hdr_line(timestamp[!curr], a, SECOND, 0, 9);
                }
 
@@ -757,7 +739,7 @@ void stub_print_ktables_stats(struct activity *a, int curr, int dispavg)
                avg_pty_nr      = 0;
 
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -852,7 +834,7 @@ void stub_print_queue_stats(struct activity *a, int curr, int dispavg)
                avg_load_avg_15   = 0,
                avg_procs_blocked = 0;
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -950,7 +932,7 @@ __print_funct_t print_serial_stats(struct activity *a, int prev, int curr,
        int i, j, j0, found;
        struct stats_serial *ssc, *ssp;
 
-       if (dis) {
+       if (dish || DISPLAY_ZERO_OMIT(flags)) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -999,6 +981,9 @@ __print_funct_t print_serial_stats(struct activity *a, int prev, int curr,
                if (!found)
                        continue;
 
+               if (DISPLAY_ZERO_OMIT(flags) && !memcmp(ssp, ssc, STATS_SERIAL_SIZE))
+                       continue;
+
                printf("%-11s", timestamp[curr]);
                cprintf_in(IS_INT, "       %3d", "", ssc->line);
 
@@ -1030,7 +1015,7 @@ __print_funct_t print_disk_stats(struct activity *a, int prev, int curr,
        int i, j;
        struct stats_disk *sdc, *sdp, sdpzero;
        struct ext_disk_stats xds;
-       char *dev_name, *persist_dev_name;
+       char *dev_name;
        int unit = NO_UNIT;
 
        memset(&sdpzero, 0, STATS_DISK_SIZE);
@@ -1040,8 +1025,8 @@ __print_funct_t print_disk_stats(struct activity *a, int prev, int curr,
                unit = UNIT_KILOBYTE;
        }
 
-       if (dis) {
-               print_hdr_line(timestamp[!curr], a, FIRST, -1, 9);
+       if (dish || DISPLAY_ZERO_OMIT(flags)) {
+               print_hdr_line(timestamp[!curr], a, FIRST, DISPLAY_HUMAN_READ(flags) ? -1 : 0, 9);
        }
 
        for (i = 0; i < a->nr[curr]; i++) {
@@ -1064,47 +1049,45 @@ __print_funct_t print_disk_stats(struct activity *a, int prev, int curr,
                        sdp = (struct stats_disk *) ((char *) a->buf[prev] + j * a->msize);
                }
 
-               /* Compute service time, etc. */
-               compute_ext_disk_stats(sdc, sdp, itv, &xds);
-
-               dev_name = NULL;
-               persist_dev_name = NULL;
+               if (DISPLAY_ZERO_OMIT(flags) && !memcmp(sdp, sdc, STATS_DISK_SIZE))
+                       continue;
 
-               if (DISPLAY_PERSIST_NAME_S(flags)) {
-                       persist_dev_name = get_persistent_name_from_pretty(get_devname(sdc->major, sdc->minor, TRUE));
-               }
+               /* Get device name */
+               dev_name = get_sa_devname(sdc->major, sdc->minor, sdc->wwn, sdc->part_nr, flags);
 
-               if (persist_dev_name) {
-                       dev_name = persist_dev_name;
+               if (a->item_list != NULL) {
+                       /* A list of devices has been entered on the command line */
+                       if (!search_list_item(a->item_list, dev_name))
+                               /* Device not found */
+                               continue;
                }
-               else {
-                       if ((USE_PRETTY_OPTION(flags)) && (sdc->major == dm_major)) {
-                               dev_name = transform_devmapname(sdc->major, sdc->minor);
-                       }
 
-                       if (!dev_name) {
-                               dev_name = get_devname(sdc->major, sdc->minor,
-                                                      USE_PRETTY_OPTION(flags));
-                       }
-               }
+               /* Compute service time, etc. */
+               compute_ext_disk_stats(sdc, sdp, itv, &xds);
 
                printf("%-11s", timestamp[curr]);
 
+               if (!DISPLAY_HUMAN_READ(flags)) {
+                       cprintf_in(IS_STR, " %9s", dev_name, 0);
+               }
                cprintf_f(NO_UNIT, 1, 9, 2,
                          S_VALUE(sdp->nr_ios, sdc->nr_ios,  itv));
-               cprintf_f(unit, 2, 9, 2,
+               cprintf_f(unit, 3, 9, 2,
                          S_VALUE(sdp->rd_sect, sdc->rd_sect, itv) / 2,
-                         S_VALUE(sdp->wr_sect, sdc->wr_sect, itv) / 2);
+                         S_VALUE(sdp->wr_sect, sdc->wr_sect, itv) / 2,
+                         S_VALUE(sdp->dc_sect, sdc->dc_sect, itv) / 2);
                /* See iostat for explanations */
                cprintf_f(unit, 1, 9, 2,
                          xds.arqsz / 2);
-               cprintf_f(NO_UNIT, 3, 9, 2,
+               cprintf_f(NO_UNIT, 2, 9, 2,
                          S_VALUE(sdp->rq_ticks, sdc->rq_ticks, itv) / 1000.0,
-                         xds.await,
-                         xds.svctm);
+                         xds.await);
                cprintf_pc(DISPLAY_UNIT(flags), 1, 9, 2,
                           xds.util / 10.0);
-               cprintf_in(IS_STR, " %s\n", dev_name, 0);
+               if (DISPLAY_HUMAN_READ(flags)) {
+                       cprintf_in(IS_STR, " %s", dev_name, 0);
+               }
+               printf("\n");
        }
 }
 
@@ -1134,13 +1117,20 @@ __print_funct_t print_net_dev_stats(struct activity *a, int prev, int curr,
                unit = UNIT_BYTE;
        }
 
-       if (dis) {
-               print_hdr_line(timestamp[!curr], a, FIRST, -1, 9);
+       if (dish || DISPLAY_ZERO_OMIT(flags)) {
+               print_hdr_line(timestamp[!curr], a, FIRST, DISPLAY_HUMAN_READ(flags) ? -1 : 0, 9);
        }
 
        for (i = 0; i < a->nr[curr]; i++) {
                sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + i * a->msize);
 
+               if (a->item_list != NULL) {
+                       /* A list of devices has been entered on the command line */
+                       if (!search_list_item(a->item_list, sndc->interface))
+                               /* Device not found */
+                               continue;
+               }
+
                if (!WANT_SINCE_BOOT(flags)) {
                        j = check_net_dev_reg(a, curr, prev, i);
                }
@@ -1158,8 +1148,14 @@ __print_funct_t print_net_dev_stats(struct activity *a, int prev, int curr,
                        sndp = (struct stats_net_dev *) ((char *) a->buf[prev] + j * a->msize);
                }
 
+               if (DISPLAY_ZERO_OMIT(flags) && !memcmp(sndp, sndc, STATS_NET_DEV_SIZE2CMP))
+                       continue;
+
                printf("%-11s", timestamp[curr]);
 
+               if (!DISPLAY_HUMAN_READ(flags)) {
+                       cprintf_in(IS_STR, " %9s", sndc->interface, 0);
+               }
                rxkb = S_VALUE(sndp->rx_bytes, sndc->rx_bytes, itv);
                txkb = S_VALUE(sndp->tx_bytes, sndc->tx_bytes, itv);
 
@@ -1175,7 +1171,10 @@ __print_funct_t print_net_dev_stats(struct activity *a, int prev, int curr,
                          S_VALUE(sndp->multicast,     sndc->multicast,     itv));
                ifutil = compute_ifutil(sndc, rxkb, txkb);
                cprintf_pc(DISPLAY_UNIT(flags), 1, 9, 2, ifutil);
-               cprintf_in(IS_STR, " %s\n", sndc->interface, 0);
+               if (DISPLAY_HUMAN_READ(flags)) {
+                       cprintf_in(IS_STR, " %s", sndc->interface, 0);
+               }
+               printf("\n");
        }
 }
 
@@ -1198,13 +1197,20 @@ __print_funct_t print_net_edev_stats(struct activity *a, int prev, int curr,
 
        memset(&snedzero, 0, STATS_NET_EDEV_SIZE);
 
-       if (dis) {
-               print_hdr_line(timestamp[!curr], a, FIRST, -1, 9);
+       if (dish || DISPLAY_ZERO_OMIT(flags)) {
+               print_hdr_line(timestamp[!curr], a, FIRST, DISPLAY_HUMAN_READ(flags) ? -1 : 0, 9);
        }
 
        for (i = 0; i < a->nr[curr]; i++) {
                snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + i * a->msize);
 
+               if (a->item_list != NULL) {
+                       /* A list of devices has been entered on the command line */
+                       if (!search_list_item(a->item_list, snedc->interface))
+                               /* Device not found */
+                               continue;
+               }
+
                if (!WANT_SINCE_BOOT(flags)) {
                        j = check_net_edev_reg(a, curr, prev, i);
                }
@@ -1222,8 +1228,14 @@ __print_funct_t print_net_edev_stats(struct activity *a, int prev, int curr,
                        snedp = (struct stats_net_edev *) ((char *) a->buf[prev] + j * a->msize);
                }
 
+               if (DISPLAY_ZERO_OMIT(flags) && !memcmp(snedp, snedc, STATS_NET_EDEV_SIZE2CMP))
+                       continue;
+
                printf("%-11s", timestamp[curr]);
 
+               if (!DISPLAY_HUMAN_READ(flags)) {
+                       cprintf_in(IS_STR, " %9s", snedc->interface, 0);
+               }
                cprintf_f(NO_UNIT, 9, 9, 2,
                          S_VALUE(snedp->rx_errors,         snedc->rx_errors,         itv),
                          S_VALUE(snedp->tx_errors,         snedc->tx_errors,         itv),
@@ -1234,7 +1246,10 @@ __print_funct_t print_net_edev_stats(struct activity *a, int prev, int curr,
                          S_VALUE(snedp->rx_frame_errors,   snedc->rx_frame_errors,   itv),
                          S_VALUE(snedp->rx_fifo_errors,    snedc->rx_fifo_errors,    itv),
                          S_VALUE(snedp->tx_fifo_errors,    snedc->tx_fifo_errors,    itv));
-               cprintf_in(IS_STR, " %s\n", snedc->interface, 0);
+               if (DISPLAY_HUMAN_READ(flags)) {
+                       cprintf_in(IS_STR, " %s", snedc->interface, 0);
+               }
+               printf("\n");
        }
 }
 
@@ -1256,7 +1271,7 @@ __print_funct_t print_net_nfs_stats(struct activity *a, int prev, int curr,
                *snnc = (struct stats_net_nfs *) a->buf[curr],
                *snnp = (struct stats_net_nfs *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1289,7 +1304,7 @@ __print_funct_t print_net_nfsd_stats(struct activity *a, int prev, int curr,
                *snndc = (struct stats_net_nfsd *) a->buf[curr],
                *snndp = (struct stats_net_nfsd *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1332,7 +1347,7 @@ void stub_print_net_sock_stats(struct activity *a, int curr, int dispavg)
                avg_frag_inuse = 0,
                avg_tcp_tw     = 0;
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1426,7 +1441,7 @@ __print_funct_t print_net_ip_stats(struct activity *a, int prev, int curr,
                *snic = (struct stats_net_ip *) a->buf[curr],
                *snip = (struct stats_net_ip *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1461,7 +1476,7 @@ __print_funct_t print_net_eip_stats(struct activity *a, int prev, int curr,
                *sneic = (struct stats_net_eip *) a->buf[curr],
                *sneip = (struct stats_net_eip *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1496,7 +1511,7 @@ __print_funct_t print_net_icmp_stats(struct activity *a, int prev, int curr,
                *snic = (struct stats_net_icmp *) a->buf[curr],
                *snip = (struct stats_net_icmp *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1537,7 +1552,7 @@ __print_funct_t print_net_eicmp_stats(struct activity *a, int prev, int curr,
                *sneic = (struct stats_net_eicmp *) a->buf[curr],
                *sneip = (struct stats_net_eicmp *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1576,7 +1591,7 @@ __print_funct_t print_net_tcp_stats(struct activity *a, int prev, int curr,
                *sntc = (struct stats_net_tcp *) a->buf[curr],
                *sntp = (struct stats_net_tcp *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1607,7 +1622,7 @@ __print_funct_t print_net_etcp_stats(struct activity *a, int prev, int curr,
                *snetc = (struct stats_net_etcp *) a->buf[curr],
                *snetp = (struct stats_net_etcp *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1639,7 +1654,7 @@ __print_funct_t print_net_udp_stats(struct activity *a, int prev, int curr,
                *snuc = (struct stats_net_udp *) a->buf[curr],
                *snup = (struct stats_net_udp *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1673,7 +1688,7 @@ void stub_print_net_sock6_stats(struct activity *a, int curr, int dispavg)
                avg_raw6_inuse  = 0,
                avg_frag6_inuse = 0;
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1760,7 +1775,7 @@ __print_funct_t print_net_ip6_stats(struct activity *a, int prev, int curr,
                *snic = (struct stats_net_ip6 *) a->buf[curr],
                *snip = (struct stats_net_ip6 *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1797,7 +1812,7 @@ __print_funct_t print_net_eip6_stats(struct activity *a, int prev, int curr,
                *sneic = (struct stats_net_eip6 *) a->buf[curr],
                *sneip = (struct stats_net_eip6 *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1835,7 +1850,7 @@ __print_funct_t print_net_icmp6_stats(struct activity *a, int prev, int curr,
                *snic = (struct stats_net_icmp6 *) a->buf[curr],
                *snip = (struct stats_net_icmp6 *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1879,7 +1894,7 @@ __print_funct_t print_net_eicmp6_stats(struct activity *a, int prev, int curr,
                *sneic = (struct stats_net_eicmp6 *) a->buf[curr],
                *sneip = (struct stats_net_eicmp6 *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1917,7 +1932,7 @@ __print_funct_t print_net_udp6_stats(struct activity *a, int prev, int curr,
                *snuc = (struct stats_net_udp6 *) a->buf[curr],
                *snup = (struct stats_net_udp6 *) a->buf[prev];
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -1960,7 +1975,7 @@ void stub_print_pwr_cpufreq_stats(struct activity *a, int curr, int dispavg)
                nr_alloc = a->nr[curr];
        }
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 7, 9);
        }
 
@@ -2096,7 +2111,7 @@ void stub_print_pwr_fan_stats(struct activity *a, int curr, int dispavg)
                nr_alloc = a->nr[curr];
        }
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, -2, 9);
        }
 
@@ -2204,7 +2219,7 @@ void stub_print_pwr_temp_stats(struct activity *a, int curr, int dispavg)
                nr_alloc = a->nr[curr];
        }
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, -2, 9);
        }
 
@@ -2320,7 +2335,7 @@ void stub_print_pwr_in_stats(struct activity *a, int curr, int dispavg)
                nr_alloc = a->nr[curr];
        }
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, -2, 9);
        }
 
@@ -2416,7 +2431,9 @@ void stub_print_huge_stats(struct activity *a, int curr, int dispavg)
                *smc = (struct stats_huge *) a->buf[curr];
        static unsigned long long
                avg_frhkb = 0,
-               avg_tlhkb = 0;
+               avg_tlhkb = 0,
+               avg_rsvdhkb = 0,
+               avg_surphkb = 0;
        int unit = NO_UNIT;
 
        if (DISPLAY_UNIT(flags)) {
@@ -2424,7 +2441,7 @@ void stub_print_huge_stats(struct activity *a, int curr, int dispavg)
                unit = UNIT_KILOBYTE;
        }
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
@@ -2437,11 +2454,16 @@ void stub_print_huge_stats(struct activity *a, int curr, int dispavg)
                cprintf_pc(DISPLAY_UNIT(flags), 1, 9, 2,
                           smc->tlhkb ?
                           SP_VALUE(smc->frhkb, smc->tlhkb, smc->tlhkb) : 0.0);
+               cprintf_u64(unit, 2, 9,
+                           (unsigned long long) smc->rsvdhkb,
+                           (unsigned long long) (smc->surphkb));
                printf("\n");
 
                /* Will be used to compute the average */
                avg_frhkb += smc->frhkb;
                avg_tlhkb += smc->tlhkb;
+               avg_rsvdhkb += smc->rsvdhkb;
+               avg_surphkb += smc->surphkb;
        }
        else {
                /* Display average values */
@@ -2455,10 +2477,13 @@ void stub_print_huge_stats(struct activity *a, int curr, int dispavg)
                           SP_VALUE((double) avg_frhkb / avg_count,
                                    (double) avg_tlhkb / avg_count,
                                    (double) avg_tlhkb / avg_count) : 0.0);
+               cprintf_f(unit, 2, 9, 0,
+                         (double) avg_rsvdhkb / avg_count,
+                         (double) avg_surphkb / avg_count);
                printf("\n");
 
                /* Reset average counters */
-               avg_frhkb = avg_tlhkb = 0;
+               avg_frhkb = avg_tlhkb = avg_rsvdhkb = avg_surphkb = 0;
        }
 }
 
@@ -2515,7 +2540,7 @@ void print_pwr_wghfreq_stats(struct activity *a, int prev, int curr,
        struct stats_pwr_wghfreq *spc, *spp, *spc_k, *spp_k;
        unsigned long long tis, tisfreq;
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, 7, 9);
        }
 
@@ -2593,7 +2618,7 @@ void stub_print_pwr_usb_stats(struct activity *a, int curr, int dispavg)
        char fmt[16];
        struct stats_pwr_usb *suc, *sum;
 
-       if (dis) {
+       if (dish) {
                printf("\n%-11s     BUS  idvendor    idprod  maxpower",
                       (dispavg ? _("Summary:") : timestamp[!curr]));
                printf(" %-*s product\n", MAX_MANUF_LEN - 1, "manufact");
@@ -2631,6 +2656,7 @@ void stub_print_pwr_usb_stats(struct activity *a, int curr, int dispavg)
                                         * Save USB device in summary list.
                                         */
                                        *sum = *suc;
+                                       a->nr[2] = j + 1;
                                        break;
                                }
                        }
@@ -2639,9 +2665,10 @@ void stub_print_pwr_usb_stats(struct activity *a, int curr, int dispavg)
                                 * No free slot has been found for current device.
                                 * So enlarge buffers then save device in list.
                                 */
-                               reallocate_all_buffers(a);
+                               reallocate_all_buffers(a, j);
                                sum = (struct stats_pwr_usb *) ((char *) a->buf[2] + j * a->msize);
                                *sum = *suc;
+                               a->nr[2] = j + 1;
                        }
                }
        }
@@ -2688,14 +2715,15 @@ __print_funct_t print_avg_pwr_usb_stats(struct activity *a, int prev, int curr,
  *
  * IN:
  * @a          Activity structure with statistics.
+ * @prev       Index in array where stats used as reference are.
  * @curr       Index in array for current sample statistics.
  * @dispavg    TRUE if displaying average statistics.
  ***************************************************************************
  */
-__print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int dispavg)
+__print_funct_t stub_print_filesystem_stats(struct activity *a, int prev, int curr, int dispavg)
 {
-       int i, j;
-       struct stats_filesystem *sfc, *sfm;
+       int i, j, j0, found;
+       struct stats_filesystem *sfc, *sfp, *sfm;
        int unit = NO_UNIT;
 
        if (DISPLAY_UNIT(flags)) {
@@ -2703,7 +2731,7 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di
                unit = UNIT_BYTE;
        }
 
-       if (dis) {
+       if (dish || DISPLAY_ZERO_OMIT(flags)) {
                print_hdr_line((dispavg ? _("Summary:") : timestamp[!curr]),
                               a, FIRST + DISPLAY_MOUNT(a->opt_flags), -1, 9);
        }
@@ -2711,25 +2739,64 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di
        for (i = 0; i < a->nr[curr]; i++) {
                sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize);
 
-               printf("%-11s", (dispavg ? _("Summary:") : timestamp[curr]));
-               cprintf_f(unit, 2, 9, 0,
-                         unit < 0 ? (double) sfc->f_bfree / 1024 / 1024 : (double) sfc->f_bfree,
-                         unit < 0 ? (double) (sfc->f_blocks - sfc->f_bfree) / 1024 / 1024 :
-                                    (double) (sfc->f_blocks - sfc->f_bfree));
-               cprintf_pc(DISPLAY_UNIT(flags), 2, 9, 2,
-                          /* f_blocks is not zero. But test it anyway ;-) */
-                          sfc->f_blocks ? SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks)
-                          : 0.0,
-                          sfc->f_blocks ? SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks)
-                          : 0.0);
-               cprintf_u64(NO_UNIT, 2, 9,
-                           (unsigned long long) sfc->f_ffree,
-                           (unsigned long long) (sfc->f_files - sfc->f_ffree));
-               cprintf_pc(DISPLAY_UNIT(flags), 1, 9, 2,
-                          sfc->f_files ? SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files)
-                          : 0.0);
-               cprintf_in(IS_STR, " %s\n",
-                          DISPLAY_MOUNT(a->opt_flags) ? sfc->mountp : sfc->fs_name, 0);
+               if (a->item_list != NULL) {
+                       /* A list of devices has been entered on the command line */
+                       if (!search_list_item(a->item_list,
+                                             DISPLAY_MOUNT(a->opt_flags) ? sfc->mountp : sfc->fs_name))
+                               /* Device not found */
+                               continue;
+               }
+
+               found = FALSE;
+               if (DISPLAY_ZERO_OMIT(flags) && !dispavg) {
+
+                       if (a->nr[prev] > 0) {
+                               /* Look for corresponding fs in previous iteration */
+                               j = i;
+
+                               if (j >= a->nr[prev]) {
+                                       j = a->nr[prev] - 1;
+                               }
+
+                               j0 = j;
+
+                               do {
+                                       sfp = (struct stats_filesystem *) ((char *) a->buf[prev] + j * a->msize);
+                                       if (!strcmp(sfp->fs_name, sfc->fs_name)) {
+                                               found = TRUE;
+                                               break;
+                                       }
+                                       if (++j >= a->nr[prev]) {
+                                               j = 0;
+                                       }
+                               }
+                               while (j != j0);
+                       }
+               }
+
+               if (!DISPLAY_ZERO_OMIT(flags) || dispavg || WANT_SINCE_BOOT(flags) || !found ||
+                   (found && memcmp(sfp, sfc, STATS_FILESYSTEM_SIZE2CMP))) {
+
+                       printf("%-11s", (dispavg ? _("Summary:") : timestamp[curr]));
+                       cprintf_f(unit, 2, 9, 0,
+                                 unit < 0 ? (double) sfc->f_bfree / 1024 / 1024 : (double) sfc->f_bfree,
+                                 unit < 0 ? (double) (sfc->f_blocks - sfc->f_bfree) / 1024 / 1024 :
+                                            (double) (sfc->f_blocks - sfc->f_bfree));
+                       cprintf_pc(DISPLAY_UNIT(flags), 2, 9, 2,
+                                  /* f_blocks is not zero. But test it anyway ;-) */
+                                  sfc->f_blocks ? SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks)
+                                  : 0.0,
+                                  sfc->f_blocks ? SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks)
+                                  : 0.0);
+                       cprintf_u64(NO_UNIT, 2, 9,
+                                   (unsigned long long) sfc->f_ffree,
+                                   (unsigned long long) (sfc->f_files - sfc->f_ffree));
+                       cprintf_pc(DISPLAY_UNIT(flags), 1, 9, 2,
+                                  sfc->f_files ? SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files)
+                                  : 0.0);
+                       cprintf_in(IS_STR, " %s\n",
+                                  DISPLAY_MOUNT(a->opt_flags) ? sfc->mountp : sfc->fs_name, 0);
+               }
 
                if (!dispavg) {
                        /* Save current filesystem in summary list */
@@ -2743,6 +2810,9 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di
                                         * or free slot (end of list).
                                         */
                                        *sfm = *sfc;
+                                       if (j >= a->nr[2]) {
+                                               a->nr[2] = j + 1;
+                                       }
                                        break;
                                }
                        }
@@ -2751,9 +2821,10 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di
                                 * No free slot has been found for current filesystem.
                                 * So enlarge buffers then save filesystem in list.
                                 */
-                               reallocate_all_buffers(a);
+                               reallocate_all_buffers(a, j);
                                sfm = (struct stats_filesystem *) ((char *) a->buf[2] + j * a->msize);
                                *sfm = *sfc;
+                               a->nr[2] = j + 1;
                        }
                }
        }
@@ -2773,7 +2844,7 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di
 __print_funct_t print_filesystem_stats(struct activity *a, int prev, int curr,
                                       unsigned long long itv)
 {
-       stub_print_filesystem_stats(a, curr, FALSE);
+       stub_print_filesystem_stats(a, prev, curr, FALSE);
 }
 
 /*
@@ -2790,7 +2861,7 @@ __print_funct_t print_filesystem_stats(struct activity *a, int prev, int curr,
 __print_funct_t print_avg_filesystem_stats(struct activity *a, int prev, int curr,
                                           unsigned long long itv)
 {
-       stub_print_filesystem_stats(a, 2, TRUE);
+       stub_print_filesystem_stats(a, prev, 2, TRUE);
 }
 
 /*
@@ -2808,9 +2879,11 @@ __print_funct_t print_fchost_stats(struct activity *a, int prev, int curr,
                                   unsigned long long itv)
 {
        int i, j, j0, found;
-       struct stats_fchost *sfcc,*sfcp;
+       struct stats_fchost *sfcc, *sfcp, sfczero;
+
+       memset(&sfczero, 0, sizeof(struct stats_fchost));
 
-       if (dis) {
+       if (dish) {
                print_hdr_line(timestamp[!curr], a, FIRST, -1, 9);
        }
 
@@ -2849,8 +2922,10 @@ __print_funct_t print_fchost_stats(struct activity *a, int prev, int curr,
                        }
                }
 
-               if (!found)
-                       continue;
+               if (!found) {
+                       /* This is a newly registered host */
+                       sfcp = &sfczero;
+               }
 
                printf("%-11s", timestamp[curr]);
                cprintf_f(NO_UNIT, 4, 9, 2,
@@ -2876,38 +2951,55 @@ __print_funct_t print_fchost_stats(struct activity *a, int prev, int curr,
 __print_funct_t print_softnet_stats(struct activity *a, int prev, int curr,
                                    unsigned long long itv)
 {
+       int i;
        struct stats_softnet
                *ssnc = (struct stats_softnet *) a->buf[curr],
                *ssnp = (struct stats_softnet *) a->buf[prev];
-       int i;
+       unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
 
-       if (dis) {
+       if (dish || DISPLAY_ZERO_OMIT(flags)) {
                print_hdr_line(timestamp[!curr], a, FIRST, 7, 9);
        }
 
-       for (i = 0; (i < a->nr[curr]) && (i < a->bitmap->b_size + 1); i++) {
+       /*
+        * @nr[curr] cannot normally be greater than @nr_ini
+        * (since @nr_ini counts up all CPU, even those offline).
+        * If this happens, it may be because the machine has been
+        * restarted with more CPU and no LINUX_RESTART has been
+        * inserted in file.
+        */
+       if (a->nr[curr] > a->nr_ini) {
+               a->nr_ini = a->nr[curr];
+       }
 
-               /*
-                * The size of a->buf[...] CPU structure may be different from the default
-                * sizeof(struct stats_pwr_cpufreq) value if data have been read from a file!
-                * That's why we don't use a syntax like:
-                * ssnc = (struct stats_softnet *) a->buf[...] + i;
-                 */
-                ssnc = (struct stats_softnet *) ((char *) a->buf[curr] + i * a->msize);
-                ssnp = (struct stats_softnet *) ((char *) a->buf[prev] + i * a->msize);
+       /* Compute statistics for CPU "all" */
+       get_global_soft_statistics(a, prev, curr, flags, offline_cpu_bitmap);
+
+       for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
 
                /*
+                * Should current CPU (including CPU "all") be displayed?
                 * Note: a->nr is in [1, NR_CPUS + 1].
                 * Bitmap size is provided for (NR_CPUS + 1) CPUs.
                 * Anyway, NR_CPUS may vary between the version of sysstat
                 * used by sadc to create a file, and the version of sysstat
                 * used by sar to read it...
                 */
-
-               /* Should current CPU (including CPU "all") be displayed? */
-               if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
+               if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))) ||
+                   offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
                        /* No */
                        continue;
+               /*
+                * The size of a->buf[...] CPU structure may be different from the default
+                * sizeof(struct stats_pwr_cpufreq) value if data have been read from a file!
+                * That's why we don't use a syntax like:
+                * ssnc = (struct stats_softnet *) a->buf[...] + i;
+                 */
+                ssnc = (struct stats_softnet *) ((char *) a->buf[curr] + i * a->msize);
+                ssnp = (struct stats_softnet *) ((char *) a->buf[prev] + i * a->msize);
+
+               if (DISPLAY_ZERO_OMIT(flags) && !memcmp(ssnp, ssnc, STATS_SOFTNET_SIZE))
+                       continue;
 
                printf("%-11s", timestamp[curr]);