]> granicus.if.org Git - sysstat/commitdiff
sadc/sar: New format (part 7): Allocate structures dynamically
authorSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 22 Dec 2017 07:49:56 +0000 (08:49 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 22 Dec 2017 07:49:56 +0000 (08:49 +0100)
The goal of this patch is to make sar and sadc able to deal with any
number of devices which may be registered by the system, even if this
number is much higher than the intial one when the datafile was created.

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
activity.c
pr_stats.c
rd_sensors.c
rd_sensors.h
rd_stats.c
rd_stats.h
sa.h
sa_common.c
sa_wrap.c
sadc.c
sar.c

index 526e2c45ac24901405aa37ef30a906e42a5c34eb..a8dd165837da7e21a3f71014c525ea2ddc4dfd57 100644 (file)
@@ -99,9 +99,11 @@ struct activity cpu_act = {
        .name           = "A_CPU",
        .g_nr           = 1,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = NR_CPUS + 1,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_CPU_SIZE,
        .msize          = STATS_CPU_SIZE,
        .opt_flags      = AO_F_CPU_DEF,
@@ -138,9 +140,11 @@ struct activity pcsw_act = {
        .name           = "A_PCSW",
        .g_nr           = 2,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_PCSW_SIZE,
        .msize          = STATS_PCSW_SIZE,
        .opt_flags      = 0,
@@ -177,9 +181,11 @@ struct activity irq_act = {
        .name           = "A_IRQ",
        .g_nr           = 0,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = NR_IRQS + 1,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_IRQ_SIZE,
        .msize          = STATS_IRQ_SIZE,
        .opt_flags      = 0,
@@ -216,9 +222,11 @@ struct activity swap_act = {
        .name           = "A_SWAP",
        .g_nr           = 1,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_SWAP_SIZE,
        .msize          = STATS_SWAP_SIZE,
        .opt_flags      = 0,
@@ -256,9 +264,11 @@ struct activity paging_act = {
        .name           = "A_PAGE",
        .g_nr           = 3,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_PAGING_SIZE,
        .msize          = STATS_PAGING_SIZE,
        .opt_flags      = 0,
@@ -295,9 +305,11 @@ struct activity io_act = {
        .name           = "A_IO",
        .g_nr           = 2,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_IO_SIZE,
        .msize          = STATS_IO_SIZE,
        .opt_flags      = 0,
@@ -335,9 +347,11 @@ struct activity memory_act = {
        .name           = "A_MEMORY",
        .g_nr           = 9,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_MEMORY_SIZE,
        .msize          = STATS_MEMORY_SIZE,
        .opt_flags      = 0,
@@ -374,9 +388,11 @@ struct activity ktables_act = {
        .name           = "A_KTABLES",
        .g_nr           = 2,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_KTABLES_SIZE,
        .msize          = STATS_KTABLES_SIZE,
        .opt_flags      = 0,
@@ -413,9 +429,11 @@ struct activity queue_act = {
        .name           = "A_QUEUE",
        .g_nr           = 3,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_QUEUE_SIZE,
        .msize          = STATS_QUEUE_SIZE,
        .opt_flags      = 0,
@@ -452,9 +470,11 @@ struct activity serial_act = {
        .name           = "A_SERIAL",
        .g_nr           = 0,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_SERIAL_LINES,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_SERIAL_SIZE,
        .msize          = STATS_SERIAL_SIZE,
        .opt_flags      = 0,
@@ -491,9 +511,11 @@ struct activity disk_act = {
        .name           = "A_DISK",
        .g_nr           = 5,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_DISKS,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_DISK_SIZE,
        .msize          = STATS_DISK_SIZE,
        .opt_flags      = 0,
@@ -530,9 +552,11 @@ struct activity net_dev_act = {
        .name           = "A_NET_DEV",
        .g_nr           = 4,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_IFACES,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_DEV_SIZE,
        .msize          = STATS_NET_DEV_SIZE,
        .opt_flags      = 0,
@@ -570,9 +594,11 @@ struct activity net_edev_act = {
        .name           = "A_NET_EDEV",
        .g_nr           = 4,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_IFACES,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_EDEV_SIZE,
        .msize          = STATS_NET_EDEV_SIZE,
        .opt_flags      = 0,
@@ -609,9 +635,11 @@ struct activity net_nfs_act = {
        .name           = "A_NET_NFS",
        .g_nr           = 3,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_NFS_SIZE,
        .msize          = STATS_NET_NFS_SIZE,
        .opt_flags      = 0,
@@ -649,9 +677,11 @@ struct activity net_nfsd_act = {
        .name           = "A_NET_NFSD",
        .g_nr           = 5,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_NFSD_SIZE,
        .msize          = STATS_NET_NFSD_SIZE,
        .opt_flags      = 0,
@@ -688,9 +718,11 @@ struct activity net_sock_act = {
        .name           = "A_NET_SOCK",
        .g_nr           = 2,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_SOCK_SIZE,
        .msize          = STATS_NET_SOCK_SIZE,
        .opt_flags      = 0,
@@ -727,9 +759,11 @@ struct activity net_ip_act = {
        .name           = "A_NET_IP",
        .g_nr           = 3,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_IP_SIZE,
        .msize          = STATS_NET_IP_SIZE,
        .opt_flags      = 0,
@@ -766,9 +800,11 @@ struct activity net_eip_act = {
        .name           = "A_NET_EIP",
        .g_nr           = 3,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_EIP_SIZE,
        .msize          = STATS_NET_EIP_SIZE,
        .opt_flags      = 0,
@@ -806,9 +842,11 @@ struct activity net_icmp_act = {
        .name           = "A_NET_ICMP",
        .g_nr           = 4,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_ICMP_SIZE,
        .msize          = STATS_NET_ICMP_SIZE,
        .opt_flags      = 0,
@@ -846,9 +884,11 @@ struct activity net_eicmp_act = {
        .name           = "A_NET_EICMP",
        .g_nr           = 6,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_EICMP_SIZE,
        .msize          = STATS_NET_EICMP_SIZE,
        .opt_flags      = 0,
@@ -885,9 +925,11 @@ struct activity net_tcp_act = {
        .name           = "A_NET_TCP",
        .g_nr           = 2,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_TCP_SIZE,
        .msize          = STATS_NET_TCP_SIZE,
        .opt_flags      = 0,
@@ -924,9 +966,11 @@ struct activity net_etcp_act = {
        .name           = "A_NET_ETCP",
        .g_nr           = 2,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_ETCP_SIZE,
        .msize          = STATS_NET_ETCP_SIZE,
        .opt_flags      = 0,
@@ -963,9 +1007,11 @@ struct activity net_udp_act = {
        .name           = "A_NET_UDP",
        .g_nr           = 2,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_UDP_SIZE,
        .msize          = STATS_NET_UDP_SIZE,
        .opt_flags      = 0,
@@ -1002,9 +1048,11 @@ struct activity net_sock6_act = {
        .name           = "A_NET_SOCK6",
        .g_nr           = 1,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_SOCK6_SIZE,
        .msize          = STATS_NET_SOCK6_SIZE,
        .opt_flags      = 0,
@@ -1042,9 +1090,11 @@ struct activity net_ip6_act = {
        .name           = "A_NET_IP6",
        .g_nr           = 4,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_IP6_SIZE,
        .msize          = STATS_NET_IP6_SIZE,
        .opt_flags      = 0,
@@ -1082,9 +1132,11 @@ struct activity net_eip6_act = {
        .name           = "A_NET_EIP6",
        .g_nr           = 4,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_EIP6_SIZE,
        .msize          = STATS_NET_EIP6_SIZE,
        .opt_flags      = 0,
@@ -1123,9 +1175,11 @@ struct activity net_icmp6_act = {
        .name           = "A_NET_ICMP6",
        .g_nr           = 5,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_ICMP6_SIZE,
        .msize          = STATS_NET_ICMP6_SIZE,
        .opt_flags      = 0,
@@ -1163,9 +1217,11 @@ struct activity net_eicmp6_act = {
        .name           = "A_NET_EICMP6",
        .g_nr           = 6,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_EICMP6_SIZE,
        .msize          = STATS_NET_EICMP6_SIZE,
        .opt_flags      = 0,
@@ -1202,9 +1258,11 @@ struct activity net_udp6_act = {
        .name           = "A_NET_UDP6",
        .g_nr           = 2,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_NET_UDP6_SIZE,
        .msize          = STATS_NET_UDP6_SIZE,
        .opt_flags      = 0,
@@ -1241,9 +1299,11 @@ struct activity pwr_cpufreq_act = {
        .name           = "A_PWR_CPUFREQ",
        .g_nr           = 1,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = NR_CPUS + 1,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_PWR_CPUFREQ_SIZE,
        .msize          = STATS_PWR_CPUFREQ_SIZE,
        .opt_flags      = 0,
@@ -1280,9 +1340,11 @@ struct activity pwr_fan_act = {
        .name           = "A_PWR_FAN",
        .g_nr           = 1,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_FANS,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_PWR_FAN_SIZE,
        .msize          = STATS_PWR_FAN_SIZE,
        .opt_flags      = 0,
@@ -1319,9 +1381,11 @@ struct activity pwr_temp_act = {
        .name           = "A_PWR_TEMP",
        .g_nr           = 2,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_TEMP_SENSORS,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_PWR_TEMP_SIZE,
        .msize          = STATS_PWR_TEMP_SIZE,
        .opt_flags      = 0,
@@ -1358,9 +1422,11 @@ struct activity pwr_in_act = {
        .name           = "A_PWR_IN",
        .g_nr           = 2,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_IN_SENSORS,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_PWR_IN_SIZE,
        .msize          = STATS_PWR_IN_SIZE,
        .opt_flags      = 0,
@@ -1397,9 +1463,11 @@ struct activity huge_act = {
        .name           = "A_HUGE",
        .g_nr           = 2,
 #endif
-       .nr             = 1,
+       .nr_ini         = 1,
        .nr2            = 1,
        .nr_max         = 1,
+       .nr             = {1, 1, 1},
+       .nr_allocated   = 0,
        .fsize          = STATS_HUGE_SIZE,
        .msize          = STATS_HUGE_SIZE,
        .opt_flags      = 0,
@@ -1416,7 +1484,7 @@ struct activity pwr_wghfreq_act = {
 #ifdef SOURCE_SADC
        .f_count_index  = 0,    /* wrap_get_cpu_nr() */
        .f_count2       = wrap_get_freq_nr,
-       .f_read         = wrap_read_time_in_state,
+       .f_read         = wrap_read_cpu_wghfreq,
 #endif
 #ifdef SOURCE_SAR
        .f_print        = print_pwr_wghfreq_stats,
@@ -1436,9 +1504,11 @@ struct activity pwr_wghfreq_act = {
        .name           = "A_PWR_WGHFREQ",
        .g_nr           = 0,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = -1,
        .nr_max         = NR_CPUS + 1,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_PWR_WGHFREQ_SIZE,
        .msize          = STATS_PWR_WGHFREQ_SIZE,
        .opt_flags      = 0,
@@ -1475,9 +1545,11 @@ struct activity pwr_usb_act = {
        .name           = "A_PWR_USB",
        .g_nr           = 0,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_USB,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_PWR_USB_SIZE,
        .msize          = STATS_PWR_USB_SIZE,
        .opt_flags      = 0,
@@ -1515,9 +1587,11 @@ struct activity filesystem_act = {
        .name           = "A_FILESYSTEM",
        .g_nr           = 4,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_FS,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_FILESYSTEM_SIZE,
        .msize          = STATS_FILESYSTEM_SIZE,
        .opt_flags      = 0,
@@ -1554,9 +1628,11 @@ struct activity fchost_act = {
        .name           = "A_FCHOST",
        .g_nr           = 2,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = MAX_NR_FCHOSTS,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_FCHOST_SIZE,
        .msize          = STATS_FCHOST_SIZE,
        .opt_flags      = 0,
@@ -1594,9 +1670,11 @@ struct activity softnet_act = {
        .name           = "A_NET_SOFT",
        .g_nr           = 2,
 #endif
-       .nr             = -1,
+       .nr_ini         = -1,
        .nr2            = 1,
        .nr_max         = NR_CPUS + 1,
+       .nr             = {-1, -1, -1},
+       .nr_allocated   = 0,
        .fsize          = STATS_SOFTNET_SIZE,
        .msize          = STATS_SOFTNET_SIZE,
        .opt_flags      = 0,
index bf45b95455c60ff3fab6104f0092023c10294597..94dfa7ebb6401354d6d05c74971097cf6aa3f039 100644 (file)
@@ -134,7 +134,20 @@ __print_funct_t print_cpu_stats(struct activity *a, int prev, int curr,
                print_hdr_line(timestamp[!curr], a, FIRST + DISPLAY_CPU_ALL(a->opt_flags), 7, 9);
        }
 
-       for (i = 0; (i < a->nr) && (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.
+        * No problem here with @nr_allocated. Having been able to
+        * read @nr[curr] structures shows that buffers are large enough.
+        */
+       if (a->nr[curr] > a->nr_ini) {
+               a->nr_ini = a->nr[curr];
+       }
+
+       for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
 
                /*
                 * The size of a->buf[...] CPU structure may be different from the default
@@ -146,7 +159,7 @@ __print_funct_t print_cpu_stats(struct activity *a, int prev, int curr,
                scp = (struct stats_cpu *) ((char *) a->buf[prev] + i * a->msize);
 
                /*
-                * Note: a->nr is in [1, NR_CPUS + 1].
+                * 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
@@ -175,6 +188,37 @@ __print_funct_t print_cpu_stats(struct activity *a, int prev, int curr,
                /* 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)
+                       /*
+                        * 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;
+
                printf("%-11s", timestamp[curr]);
 
                if (!i) {
@@ -184,36 +228,6 @@ __print_funct_t print_cpu_stats(struct activity *a, int prev, int curr,
                else {
                        cprintf_in(IS_INT, " %7d", "", i - 1);
 
-                       /*
-                        * 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.
-                        * (Remember that guest/guest_nice times are already included in
-                        * user/nice modes.)
-                        */
-                       if (tot_jiffies_c == 0) {
-                               /*
-                                * 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.
-                                */
-                               *scc = *scp;
-
-                               /* %user, %nice, %system, %iowait, %steal, ..., %idle */
-                               cprintf_pc(DISPLAY_UNIT(flags), 6, 9, 2,
-                                          0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
-
-                               if (DISPLAY_CPU_ALL(a->opt_flags)) {
-                                       /*
-                                        * Four additional fields to display:
-                                        * %irq, %soft, %guest, %gnice.
-                                        */
-                                       cprintf_pc(DISPLAY_UNIT(flags), 4, 9, 2,
-                                                  0.0, 0.0, 0.0, 0.0);
-                               }
-                               printf("\n");
-                               continue;
-                       }
-
                        /* Recalculate interval for current proc */
                        deltot_jiffies = get_per_cpu_interval(scc, scp);
 
@@ -332,13 +346,17 @@ __print_funct_t print_irq_stats(struct activity *a, int prev, int curr,
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
-       for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+       for (i = 0; (i < a->nr[curr]) && (i < a->bitmap->b_size + 1); i++) {
 
+               /*
+                * If @nr[curr] > @nr[prev] then we consider that previous
+                * interrupt value was 0.
+                */
                sic = (struct stats_irq *) ((char *) a->buf[curr] + i * a->msize);
                sip = (struct stats_irq *) ((char *) a->buf[prev] + i * a->msize);
 
                /*
-                * Note: a->nr is in [0, NR_IRQS + 1].
+                * Note: @nr[curr] gives the number of interrupts read (1 .. NR_IRQS + 1).
                 * Bitmap size is provided for (NR_IRQS + 1) interrupts.
                 * Anyway, NR_IRQS may vary between the version of sysstat
                 * used by sadc to create a file, and the version of sysstat
@@ -929,38 +947,53 @@ __print_funct_t print_avg_queue_stats(struct activity *a, int prev, int curr,
 __print_funct_t print_serial_stats(struct activity *a, int prev, int curr,
                                   unsigned long long itv)
 {
-       int i;
+       int i, j, j0, found;
        struct stats_serial *ssc, *ssp;
 
        if (dis) {
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
 
                ssc = (struct stats_serial *) ((char *) a->buf[curr] + i * a->msize);
-               ssp = (struct stats_serial *) ((char *) a->buf[prev] + i * a->msize);
 
-               if (ssc->line == 0)
+               /* Look for corresponding serial line in previous iteration */
+               j = i;
+               if (j > a->nr[prev]) {
+                       j = a->nr[prev];
+               }
+
+               j0 = j;
+               found = FALSE;
+
+               do {
+                       if (j > a->nr[prev]) {
+                               j = 0;
+                       }
+                       ssp = (struct stats_serial *) ((char *) a->buf[prev] + j * a->msize);
+                       if ((ssc->line == ssp->line) || WANT_SINCE_BOOT(flags)) {
+                               found = TRUE;
+                               break;
+                       }
+                       j++;
+               }
+               while (j != j0);
+
+               if (!found)
                        continue;
 
                printf("%-11s", timestamp[curr]);
                cprintf_in(IS_INT, "       %3d", "", ssc->line - 1);
 
-               if ((ssc->line == ssp->line) || WANT_SINCE_BOOT(flags)) {
-                       cprintf_f(NO_UNIT, 6, 9, 2,
-                                 S_VALUE(ssp->rx,      ssc->rx,      itv),
-                                 S_VALUE(ssp->tx,      ssc->tx,      itv),
-                                 S_VALUE(ssp->frame,   ssc->frame,   itv),
-                                 S_VALUE(ssp->parity,  ssc->parity,  itv),
-                                 S_VALUE(ssp->brk,     ssc->brk,     itv),
-                                 S_VALUE(ssp->overrun, ssc->overrun, itv));
-                       printf("\n");
-               }
-               else {
-                       printf("       N/A       N/A       N/A       N/A"
-                              "       N/A       N/A\n");
-               }
+               cprintf_f(NO_UNIT, 6, 9, 2,
+                         S_VALUE(ssp->rx,      ssc->rx,      itv),
+                         S_VALUE(ssp->tx,      ssc->tx,      itv),
+                         S_VALUE(ssp->frame,   ssc->frame,   itv),
+                         S_VALUE(ssp->parity,  ssc->parity,  itv),
+                         S_VALUE(ssp->brk,     ssc->brk,     itv),
+                         S_VALUE(ssp->overrun, ssc->overrun, itv));
+               printf("\n");
        }
 }
 
@@ -995,13 +1028,10 @@ __print_funct_t print_disk_stats(struct activity *a, int prev, int curr,
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
 
                sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
 
-               if (!(sdc->major + sdc->minor))
-                       continue;
-
                j = check_disk_reg(a, curr, prev, i);
                if (j < 0) {
                        /* This is a newly registered interface. Previous stats are zero */
@@ -1086,13 +1116,10 @@ __print_funct_t print_net_dev_stats(struct activity *a, int prev, int curr,
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
 
                sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + i * a->msize);
 
-               if (!strcmp(sndc->interface, ""))
-                       break;
-
                j = check_net_dev_reg(a, curr, prev, i);
                if (j < 0) {
                        /* This is a newly registered interface. Previous stats are zero */
@@ -1147,13 +1174,10 @@ __print_funct_t print_net_edev_stats(struct activity *a, int prev, int curr,
                print_hdr_line(timestamp[!curr], a, FIRST, 0, 9);
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
 
                snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + i * a->msize);
 
-               if (!strcmp(snedc->interface, ""))
-                       break;
-
                j = check_net_edev_reg(a, curr, prev, i);
                if (j < 0) {
                        /* This is a newly registered interface. Previous stats are zero */
@@ -1887,24 +1911,26 @@ void stub_print_pwr_cpufreq_stats(struct activity *a, int curr, int dispavg)
 {
        int i;
        struct stats_pwr_cpufreq *spc;
+       static __nr_t nr_alloc = 0;
        static unsigned long long
                *avg_cpufreq = NULL;
 
-       if (!avg_cpufreq) {
+       if (!avg_cpufreq || (a->nr[curr] > nr_alloc)) {
                /* Allocate array of CPU frequency */
-               if ((avg_cpufreq = (unsigned long long *) malloc(sizeof(unsigned long long) * a->nr))
-                   == NULL) {
-                       perror("malloc");
-                       exit(4);
+               SREALLOC(avg_cpufreq, unsigned long long, sizeof(unsigned long long) * a->nr[curr]);
+               if (a->nr[curr] > nr_alloc) {
+                       /* Init additional space allocated */
+                       memset(avg_cpufreq + nr_alloc, 0,
+                              sizeof(unsigned long long) * (a->nr[curr] - nr_alloc));
                }
-               memset(avg_cpufreq, 0, sizeof(unsigned long long) * a->nr);
+               nr_alloc = a->nr[curr];
        }
 
        if (dis) {
                print_hdr_line(timestamp[!curr], a, FIRST, 7, 9);
        }
 
-       for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+       for (i = 0; (i < a->nr[curr]) && (i < a->bitmap->b_size + 1); i++) {
 
                /*
                 * The size of a->buf[...] CPU structure may be different from the default
@@ -1919,7 +1945,7 @@ void stub_print_pwr_cpufreq_stats(struct activity *a, int curr, int dispavg)
                        continue;
 
                /*
-                * Note: a->nr is in [1, NR_CPUS + 1].
+                * 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
@@ -1947,7 +1973,7 @@ void stub_print_pwr_cpufreq_stats(struct activity *a, int curr, int dispavg)
                                printf("\n");
                                /*
                                 * Will be used to compute the average.
-                                * Note: overflow unlikely to happen but not impossible...
+                                * Note: Overflow unlikely to happen but not impossible...
                                 */
                                avg_cpufreq[i] += spc->cpufreq;
                        }
@@ -1964,6 +1990,7 @@ void stub_print_pwr_cpufreq_stats(struct activity *a, int curr, int dispavg)
                /* Array of CPU frequency no longer needed: Free it! */
                free(avg_cpufreq);
                avg_cpufreq = NULL;
+               nr_alloc = 0;
        }
 }
 
@@ -2016,29 +2043,30 @@ void stub_print_pwr_fan_stats(struct activity *a, int curr, int dispavg)
 {
        int i;
        struct stats_pwr_fan *spc;
+       static __nr_t nr_alloc = 0;
        static double *avg_fan = NULL;
        static double *avg_fan_min = NULL;
 
        /* Allocate arrays of fan RPMs */
-       if (!avg_fan) {
-               if ((avg_fan = (double *) malloc(sizeof(double) * a->nr)) == NULL) {
-                       perror("malloc");
-                       exit(4);
-               }
-               memset(avg_fan, 0, sizeof(double) * a->nr);
-
-               if ((avg_fan_min = (double *) malloc(sizeof(double) * a->nr)) == NULL) {
-                       perror("malloc");
-                       exit(4);
+       if (!avg_fan || (a->nr[curr] > nr_alloc)) {
+               SREALLOC(avg_fan, double, sizeof(double) * a->nr[curr]);
+               SREALLOC(avg_fan_min, double, sizeof(double) * a->nr[curr]);
+
+               if (a->nr[curr] > nr_alloc) {
+                       /* Init additional space allocated */
+                       memset(avg_fan + nr_alloc, 0,
+                              sizeof(double) * (a->nr[curr] - nr_alloc));
+                       memset(avg_fan_min + nr_alloc, 0,
+                              sizeof(double) * (a->nr[curr] - nr_alloc));
                }
-               memset(avg_fan_min, 0, sizeof(double) * a->nr);
+               nr_alloc = a->nr[curr];
        }
 
        if (dis) {
                print_hdr_line(timestamp[!curr], a, FIRST, -2, 9);
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
                spc = (struct stats_pwr_fan *) ((char *) a->buf[curr] + i * a->msize);
 
                printf("%-11s", timestamp[curr]);
@@ -2067,6 +2095,7 @@ void stub_print_pwr_fan_stats(struct activity *a, int curr, int dispavg)
                free(avg_fan_min);
                avg_fan = NULL;
                avg_fan_min = NULL;
+               nr_alloc = 0;
        }
 }
 
@@ -2119,35 +2148,33 @@ void stub_print_pwr_temp_stats(struct activity *a, int curr, int dispavg)
 {
        int i;
        struct stats_pwr_temp *spc;
+       static __nr_t nr_alloc = 0;
        static double *avg_temp = NULL;
        static double *avg_temp_min = NULL, *avg_temp_max = NULL;
 
        /* Allocate arrays of temperatures */
-       if (!avg_temp) {
-               if ((avg_temp = (double *) malloc(sizeof(double) * a->nr)) == NULL) {
-                       perror("malloc");
-                       exit(4);
+       if (!avg_temp || (a->nr[curr] > nr_alloc)) {
+               SREALLOC(avg_temp, double, sizeof(double) * a->nr[curr]);
+               SREALLOC(avg_temp_min, double, sizeof(double) * a->nr[curr]);
+               SREALLOC(avg_temp_max, double, sizeof(double) * a->nr[curr]);
+
+               if (a->nr[curr] > nr_alloc) {
+                       /* Init additional space allocated */
+                       memset(avg_temp + nr_alloc, 0,
+                              sizeof(double) * (a->nr[curr] - nr_alloc));
+                       memset(avg_temp_min + nr_alloc, 0,
+                              sizeof(double) * (a->nr[curr] - nr_alloc));
+                       memset(avg_temp_max + nr_alloc, 0,
+                              sizeof(double) * (a->nr[curr] - nr_alloc));
                }
-               memset(avg_temp, 0, sizeof(double) * a->nr);
-
-               if ((avg_temp_min = (double *) malloc(sizeof(double) * a->nr)) == NULL) {
-                       perror("malloc");
-                       exit(4);
-               }
-               memset(avg_temp_min, 0, sizeof(double) * a->nr);
-
-               if ((avg_temp_max = (double *) malloc(sizeof(double) * a->nr)) == NULL) {
-                       perror("malloc");
-                       exit(4);
-               }
-               memset(avg_temp_max, 0, sizeof(double) * a->nr);
+               nr_alloc = a->nr[curr];
        }
 
        if (dis) {
                print_hdr_line(timestamp[!curr], a, FIRST, -2, 9);
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
                spc = (struct stats_pwr_temp *) ((char *) a->buf[curr] + i * a->msize);
 
                printf("%-11s", timestamp[curr]);
@@ -2184,6 +2211,7 @@ void stub_print_pwr_temp_stats(struct activity *a, int curr, int dispavg)
                avg_temp = NULL;
                avg_temp_min = NULL;
                avg_temp_max = NULL;
+               nr_alloc = 0;
        }
 }
 
@@ -2236,35 +2264,33 @@ void stub_print_pwr_in_stats(struct activity *a, int curr, int dispavg)
 {
        int i;
        struct stats_pwr_in *spc;
+       static __nr_t nr_alloc = 0;
        static double *avg_in = NULL;
        static double *avg_in_min = NULL, *avg_in_max = NULL;
 
        /* Allocate arrays of voltage inputs */
-       if (!avg_in) {
-               if ((avg_in = (double *) malloc(sizeof(double) * a->nr)) == NULL) {
-                       perror("malloc");
-                       exit(4);
-               }
-               memset(avg_in, 0, sizeof(double) * a->nr);
-
-               if ((avg_in_min = (double *) malloc(sizeof(double) * a->nr)) == NULL) {
-                       perror("malloc");
-                       exit(4);
-               }
-               memset(avg_in_min, 0, sizeof(double) * a->nr);
-
-               if ((avg_in_max = (double *) malloc(sizeof(double) * a->nr)) == NULL) {
-                       perror("malloc");
-                       exit(4);
+       if (!avg_in || (a->nr[curr] > nr_alloc)) {
+               SREALLOC(avg_in, double, sizeof(double) * a->nr[curr]);
+               SREALLOC(avg_in_min, double, sizeof(double) * a->nr[curr]);
+               SREALLOC(avg_in_max, double, sizeof(double) * a->nr[curr]);
+
+               if (a->nr[curr] > nr_alloc) {
+                       /* Init additional space allocated */
+                       memset(avg_in + nr_alloc, 0,
+                              sizeof(double) * (a->nr[curr] - nr_alloc));
+                       memset(avg_in_min + nr_alloc, 0,
+                              sizeof(double) * (a->nr[curr] - nr_alloc));
+                       memset(avg_in_max + nr_alloc, 0,
+                              sizeof(double) * (a->nr[curr] - nr_alloc));
                }
-               memset(avg_in_max, 0, sizeof(double) * a->nr);
+               nr_alloc = a->nr[curr];
        }
 
        if (dis) {
                print_hdr_line(timestamp[!curr], a, FIRST, -2, 9);
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
                spc = (struct stats_pwr_in *) ((char *) a->buf[curr] + i * a->msize);
 
                printf("%-11s", timestamp[curr]);
@@ -2301,6 +2327,7 @@ void stub_print_pwr_in_stats(struct activity *a, int curr, int dispavg)
                avg_in = NULL;
                avg_in_min = NULL;
                avg_in_max = NULL;
+               nr_alloc = 0;
        }
 }
 
@@ -2458,7 +2485,7 @@ void print_pwr_wghfreq_stats(struct activity *a, int prev, int curr,
                print_hdr_line(timestamp[!curr], a, FIRST, 7, 9);
        }
 
-       for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+       for (i = 0; (i < a->nr[curr]) && (i < a->bitmap->b_size + 1); i++) {
 
                /*
                 * The size of a->buf[...] CPU structure may be different from the default
@@ -2538,13 +2565,9 @@ void stub_print_pwr_usb_stats(struct activity *a, int curr, int dispavg)
                printf(" %-*s product\n", MAX_MANUF_LEN - 1, "manufact");
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
                suc = (struct stats_pwr_usb *) ((char *) a->buf[curr] + i * a->msize);
 
-               if (!suc->bus_nr)
-                       /* Bus#0 doesn't exist: We are at the end of the list */
-                       break;
-
                printf("%-11s", (dispavg ? _("Summary:") : timestamp[curr]));
                cprintf_in(IS_INT, "  %6d", "", suc->bus_nr);
                cprintf_x(2, 9,
@@ -2560,7 +2583,7 @@ void stub_print_pwr_usb_stats(struct activity *a, int curr, int dispavg)
 
                if (!dispavg) {
                        /* Save current USB device in summary list */
-                       for (j = 0; j < a->nr; j++) {
+                       for (j = 0; j < a->nr_allocated; j++) {
                                sum = (struct stats_pwr_usb *) ((char *) a->buf[2] + j * a->msize);
 
                                if ((sum->bus_nr     == suc->bus_nr) &&
@@ -2576,20 +2599,15 @@ void stub_print_pwr_usb_stats(struct activity *a, int curr, int dispavg)
                                        *sum = *suc;
                                        break;
                                }
-                               if (j == a->nr - 1) {
-                                       /*
-                                        * This is the last slot and
-                                        * we still havent't found the device.
-                                        * So create a dummy device here.
-                                        */
-                                       sum->bus_nr = ~0;
-                                       sum->vendor_id = sum->product_id = 0;
-                                       sum->bmaxpower = 0;
-                                       sum->manufacturer[0] = '\0';
-                                       snprintf(sum->product, MAX_PROD_LEN, "%s",
-                                                _("Other devices not listed here"));
-                                       sum->product[MAX_PROD_LEN - 1] = '\0';
-                               }
+                       }
+                       if (j == a->nr_allocated) {
+                               /*
+                                * No free slot has been found for current device.
+                                * So enlarge buffers then save device in list.
+                                */
+                               reallocate_all_buffers(a);
+                               sum = (struct stats_pwr_usb *) ((char *) a->buf[2] + j * a->msize);
+                               *sum = *suc;
                        }
                }
        }
@@ -2656,13 +2674,9 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di
                               a, FIRST + DISPLAY_MOUNT(a->opt_flags), -1, 9);
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
                sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize);
 
-               if (!sfc->f_blocks)
-                       /* Size of filesystem is zero: We are at the end of the list */
-                       break;
-
                printf("%-11s", (dispavg ? _("Summary:") : timestamp[curr]));
                cprintf_f(unit, 2, 9, 0,
                          unit < 0 ? (double) sfc->f_bfree / 1024 / 1024 : (double) sfc->f_bfree,
@@ -2685,7 +2699,7 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di
 
                if (!dispavg) {
                        /* Save current filesystem in summary list */
-                       for (j = 0; j < a->nr; j++) {
+                       for (j = 0; j < a->nr_allocated; j++) {
                                sfm = (struct stats_filesystem *) ((char *) a->buf[2] + j * a->msize);
 
                                if (!strcmp(sfm->fs_name, sfc->fs_name) ||
@@ -2698,6 +2712,15 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di
                                        break;
                                }
                        }
+                       if (j == a->nr_allocated) {
+                               /*
+                                * No free slot has been found for current filesystem.
+                                * So enlarge buffers then save filesystem in list.
+                                */
+                               reallocate_all_buffers(a);
+                               sfm = (struct stats_filesystem *) ((char *) a->buf[2] + j * a->msize);
+                               *sfm = *sfc;
+                       }
                }
        }
 }
@@ -2750,21 +2773,41 @@ __print_funct_t print_avg_filesystem_stats(struct activity *a, int prev, int cur
 __print_funct_t print_fchost_stats(struct activity *a, int prev, int curr,
                                   unsigned long long itv)
 {
-       int i;
+       int i, j, j0, found;
        struct stats_fchost *sfcc,*sfcp;
 
        if (dis) {
                print_hdr_line(timestamp[!curr], a, FIRST, -1, 9);
        }
 
-       for (i = 0; i < a->nr; i++) {
+       for (i = 0; i < a->nr[curr]; i++) {
 
                sfcc = (struct stats_fchost *) ((char *) a->buf[curr] + i * a->msize);
-               sfcp = (struct stats_fchost *) ((char *) a->buf[prev] + i * a->msize);
 
-               if (!sfcc->fchost_name[0])
-                       /* We are at the end of the list */
-                       break;
+               /* Look for corresponding structure in previous iteration */
+               j = i;
+               if (j > a->nr[prev]) {
+                       j = a->nr[prev];
+               }
+
+               j0 = j;
+               found = FALSE;
+
+               do {
+                       if (j > a->nr[prev]) {
+                               j = 0;
+                       }
+                       sfcp = (struct stats_fchost *) ((char *) a->buf[prev] + j * a->msize);
+                       if (!strcmp(sfcc->fchost_name, sfcp->fchost_name)) {
+                               found = TRUE;
+                               break;
+                       }
+                       j++;
+               }
+               while (j != j0);
+
+               if (!found)
+                       continue;
 
                printf("%-11s", timestamp[curr]);
                cprintf_f(NO_UNIT, 4, 9, 2,
@@ -2799,7 +2842,7 @@ __print_funct_t print_softnet_stats(struct activity *a, int prev, int curr,
                print_hdr_line(timestamp[!curr], a, FIRST, 7, 9);
        }
 
-       for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+       for (i = 0; (i < a->nr[curr]) && (i < a->bitmap->b_size + 1); i++) {
 
                /*
                 * The size of a->buf[...] CPU structure may be different from the default
index 9395cc73141e4ae689a744202b560b235707a4ee..45269e365f01e309b35940bd3e9641fa1e71a082 100644 (file)
  *
  * IN:
  * @st_pwr_fan Structure where stats will be saved.
- * @nbr                Total number of fans.
+ * @nr_alloc   Total number of structures allocated. Value is >= 1.
  *
  * OUT:
  * @st_pwr_fan Structure with statistics.
+ *
+ * RETURNS:
+ * Number of fans read, or -1 if the buffer was too small and needs to be
+ * reallocated.
  ***************************************************************************
  */
-void read_fan(struct stats_pwr_fan *st_pwr_fan, int nbr)
+__nr_t read_fan(struct stats_pwr_fan *st_pwr_fan, __nr_t nr_alloc)
 {
 #ifdef HAVE_SENSORS
-       int count = 0;
+       __nr_t fan_read = 0;
        const sensors_chip_name *chip;
        const sensors_feature *feature;
        const sensors_subfeature *sub;
@@ -65,9 +69,11 @@ void read_fan(struct stats_pwr_fan *st_pwr_fan, int nbr)
        while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
                i = 0;
                while ((feature = sensors_get_features(chip, &i))) {
-                       if ((feature->type == SENSORS_FEATURE_FAN) && (count < nbr)) {
+                       if (feature->type == SENSORS_FEATURE_FAN) {
                                j = 0;
-                               st_pwr_fan_i = st_pwr_fan + count;
+                               if (fan_read + 1 > nr_alloc)
+                                       return -1;
+                               st_pwr_fan_i = st_pwr_fan + fan_read++;
                                sensors_snprintf_chip_name(st_pwr_fan_i->device, MAX_SENSORS_DEV_LEN, chip);
 
                                while ((sub = sensors_get_all_subfeatures(chip, feature, &j))) {
@@ -83,10 +89,13 @@ void read_fan(struct stats_pwr_fan *st_pwr_fan, int nbr)
                                                }
                                        }
                                }
-                               count++;
                        }
                }
        }
+
+       return fan_read;
+#else
+       return 0;
 #endif /* HAVE_SENSORS */
 }
 
@@ -96,16 +105,20 @@ void read_fan(struct stats_pwr_fan *st_pwr_fan, int nbr)
  *
  * IN:
  * @st_pwr_temp        Structure where stats will be saved.
- * @nbr                Total number of fans.
+ * @nr_alloc   Total number of structures allocated. Value is >= 1.
  *
  * OUT:
  * @st_pwr_temp        Structure with statistics.
+ *
+ * RETURNS:
+ * Number of devices read, or -1 if the buffer was too small and needs to be
+ * reallocated.
  ***************************************************************************
  */
-void read_temp(struct stats_pwr_temp *st_pwr_temp, int nbr)
+__nr_t read_temp(struct stats_pwr_temp *st_pwr_temp, __nr_t nr_alloc)
 {
 #ifdef HAVE_SENSORS
-       int count = 0;
+       __nr_t temp_read = 0;
        const sensors_chip_name *chip;
        const sensors_feature *feature;
        const sensors_subfeature *sub;
@@ -118,9 +131,11 @@ void read_temp(struct stats_pwr_temp *st_pwr_temp, int nbr)
        while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
                i = 0;
                while ((feature = sensors_get_features(chip, &i))) {
-                       if ((feature->type == SENSORS_FEATURE_TEMP) && (count < nbr)) {
+                       if (feature->type == SENSORS_FEATURE_TEMP) {
                                j = 0;
-                               st_pwr_temp_i = st_pwr_temp + count;
+                               if (temp_read + 1 > nr_alloc)
+                                       return -1;
+                               st_pwr_temp_i = st_pwr_temp + temp_read++;
                                sensors_snprintf_chip_name(st_pwr_temp_i->device, MAX_SENSORS_DEV_LEN, chip);
 
                                while ((sub = sensors_get_all_subfeatures(chip, feature, &j))) {
@@ -141,10 +156,13 @@ void read_temp(struct stats_pwr_temp *st_pwr_temp, int nbr)
                                                }
                                        }
                                }
-                               count++;
                        }
                }
        }
+
+       return temp_read;
+#else
+       return 0;
 #endif /* HAVE_SENSORS */
 }
 
@@ -154,16 +172,20 @@ void read_temp(struct stats_pwr_temp *st_pwr_temp, int nbr)
  *
  * IN:
  * @st_pwr_in  Structure where stats will be saved.
- * @nbr                Total number of voltage inputs.
+ * @nr_alloc   Total number of structures allocated. Value is >= 1.
  *
  * OUT:
  * @st_pwr_in  Structure with statistics.
+ *
+ * RETURNS:
+ * Number of devices read, or -1 if the buffer was too small and needs to be
+ * reallocated.
  ***************************************************************************
  */
-void read_in(struct stats_pwr_in *st_pwr_in, int nbr)
+__nr_t read_in(struct stats_pwr_in *st_pwr_in, __nr_t nr_alloc)
 {
 #ifdef HAVE_SENSORS
-       int count = 0;
+       __nr_t in_read = 0;
        const sensors_chip_name *chip;
        const sensors_feature *feature;
        const sensors_subfeature *sub;
@@ -176,9 +198,11 @@ void read_in(struct stats_pwr_in *st_pwr_in, int nbr)
        while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
                i = 0;
                while ((feature = sensors_get_features(chip, &i))) {
-                       if ((feature->type == SENSORS_FEATURE_IN) && (count < nbr)) {
+                       if (feature->type == SENSORS_FEATURE_IN) {
                                j = 0;
-                               st_pwr_in_i = st_pwr_in + count;
+                               if (in_read + 1 > nr_alloc)
+                                       return -1;
+                               st_pwr_in_i = st_pwr_in + in_read++;
                                sensors_snprintf_chip_name(st_pwr_in_i->device, MAX_SENSORS_DEV_LEN, chip);
 
                                while ((sub = sensors_get_all_subfeatures(chip, feature, &j))) {
@@ -199,10 +223,13 @@ void read_in(struct stats_pwr_in *st_pwr_in, int nbr)
                                                }
                                        }
                                }
-                               count++;
                        }
                }
        }
+
+       return in_read;
+#else
+       return 0;
 #endif /* HAVE_SENSORS */
 }
 
index 51d058aaf5e24c1cb875fea447952569574319ff..d0c26a77b81dfa4178204dd47bc93334b7f2f2ea 100644 (file)
@@ -7,6 +7,7 @@
 #define _RD_SENSORS_H
 
 #include "common.h"
+#include "rd_stats.h"
 
 /*
  ***************************************************************************
@@ -55,12 +56,12 @@ struct stats_pwr_in {
  ***************************************************************************
  */
 
-void read_fan
-       (struct stats_pwr_fan *, int);
-void read_temp
-       (struct stats_pwr_temp *, int);
-void read_in
-       (struct stats_pwr_in *, int);
+__nr_t read_fan
+       (struct stats_pwr_fan *, __nr_t);
+__nr_t read_temp
+       (struct stats_pwr_temp *, __nr_t);
+__nr_t read_in
+       (struct stats_pwr_in *, __nr_t);
 
 /*
  ***************************************************************************
index a62d65e4e0954926e712433f83a255af4b899089..3314d0c34149484b0c66430a774d0bd299fc2183 100644 (file)
 /*
  ***************************************************************************
  * Read CPU statistics.
+ * Remember that this function is used by several sysstat commands!
  *
  * IN:
- * @st_cpu     Structure where stats will be saved.
- * @nbr                Total number of CPU (including cpu "all").
+ * @st_cpu     Buffer where structures containing stats will be saved.
+ * @nr_alloc   Total number of structures allocated. Value is >= 1.
  *
  * OUT:
- * @st_cpu     Structure with statistics.
+ * @st_cpu     Buffer with statistics.
+ *
+ * RETURNS:
+ * Highest CPU number(*) for which statistics have been read.
+ * 1 means CPU "all", 2 means CPU 0, 3 means CPU 1, etc.
+ * Or -1 if the buffer was too small and needs to be reallocated.
+ *
+ * (*)This doesn't account for all processors in the machine in the case
+ * where some CPU are offline and located at the end of the list.
  ***************************************************************************
  */
-void read_stat_cpu(struct stats_cpu *st_cpu, int nbr)
+__nr_t read_stat_cpu(struct stats_cpu *st_cpu, __nr_t nr_alloc)
 {
        FILE *fp;
        struct stats_cpu *st_cpu_i;
        struct stats_cpu sc;
        char line[8192];
-       int proc_nb;
+       int proc_nr;
+       __nr_t cpu_read = 0;
 
        if ((fp = fopen(STAT, "r")) == NULL) {
                fprintf(stderr, _("Cannot open %s: %s\n"), STAT, strerror(errno));
@@ -93,67 +103,83 @@ void read_stat_cpu(struct stats_cpu *st_cpu, int nbr)
                               &st_cpu->cpu_steal,
                               &st_cpu->cpu_guest,
                               &st_cpu->cpu_guest_nice);
+
+                       if (!cpu_read) {
+                               cpu_read = 1;
+                       }
+
+                       if (nr_alloc == 1)
+                               /* We just want to read stats for CPU "all" */
+                               break;
                }
 
                else if (!strncmp(line, "cpu", 3)) {
-                       if (nbr > 1) {
-                               /* All the fields don't necessarily exist */
-                               memset(&sc, 0, STATS_CPU_SIZE);
-                               /*
-                                * Read the number of jiffies spent in the different modes
-                                * (user, nice, etc) for current proc.
-                                * This is done only on SMP machines.
-                                */
-                               sscanf(line + 3, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
-                                      &proc_nb,
-                                      &sc.cpu_user,
-                                      &sc.cpu_nice,
-                                      &sc.cpu_sys,
-                                      &sc.cpu_idle,
-                                      &sc.cpu_iowait,
-                                      &sc.cpu_hardirq,
-                                      &sc.cpu_softirq,
-                                      &sc.cpu_steal,
-                                      &sc.cpu_guest,
-                                      &sc.cpu_guest_nice);
-
-                               if (proc_nb < (nbr - 1)) {
-                                       st_cpu_i = st_cpu + proc_nb + 1;
-                                       *st_cpu_i = sc;
-                               }
-                               /*
-                                * else additional CPUs have been dynamically registered
-                                * in /proc/stat.
-                                */
+                       /* All the fields don't necessarily exist */
+                       memset(&sc, 0, STATS_CPU_SIZE);
+                       /*
+                        * Read the number of jiffies spent in the different modes
+                        * (user, nice, etc) for current proc.
+                        * This is done only on SMP machines.
+                        */
+                       sscanf(line + 3, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
+                              &proc_nr,
+                              &sc.cpu_user,
+                              &sc.cpu_nice,
+                              &sc.cpu_sys,
+                              &sc.cpu_idle,
+                              &sc.cpu_iowait,
+                              &sc.cpu_hardirq,
+                              &sc.cpu_softirq,
+                              &sc.cpu_steal,
+                              &sc.cpu_guest,
+                              &sc.cpu_guest_nice);
+
+                       if (proc_nr + 2 > nr_alloc) {
+                               cpu_read = -1;
+                               break;
+                       }
+
+                       st_cpu_i = st_cpu + proc_nr + 1;
+                       *st_cpu_i = sc;
+
+                       if (proc_nr + 2 > cpu_read) {
+                               cpu_read = proc_nr + 2;
                        }
                }
        }
 
        fclose(fp);
+       return cpu_read;
 }
 
 /*
  ***************************************************************************
  * Read interrupts statistics from /proc/stat.
+ * Remember that this function is used by several sysstat commands!
  *
  * IN:
  * @st_irq     Structure where stats will be saved.
- * @nbr                Number of interrupts to read, including the total number
- *             of interrupts.
+ * @nr_alloc   Number of structures allocated. Value is >= 1.
  *
  * OUT:
  * @st_irq     Structure with statistics.
+ *
+ * RETURNS:
+ * Number of interrupts read, or -1 if the buffer was too small and
+ * needs to be reallocated.
  ***************************************************************************
  */
-void read_stat_irq(struct stats_irq *st_irq, int nbr)
+__nr_t read_stat_irq(struct stats_irq *st_irq, __nr_t nr_alloc)
 {
        FILE *fp;
        struct stats_irq *st_irq_i;
        char line[8192];
        int i, pos;
+       unsigned long long irq_nr;
+       __nr_t irq_read = 0;
 
        if ((fp = fopen(STAT, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -162,15 +188,41 @@ void read_stat_irq(struct stats_irq *st_irq, int nbr)
                        sscanf(line + 5, "%llu", &st_irq->irq_nr);
                        pos = strcspn(line + 5, " ") + 5;
 
+                       irq_read++;
+                       if (nr_alloc == 1)
+                               /* We just want to read the total number of interrupts */
+                               break;
+
+                       do {
+                               i = sscanf(line + pos, " %llu", &irq_nr);
+                               if (i < 1)
+                                       break;
+
+                               if (irq_read + 1 > nr_alloc) {
+                                       irq_read = -1;
+                                       break;
+                               }
+                               st_irq_i = st_irq + irq_read++;
+                               st_irq_i->irq_nr = irq_nr;
+
+                               i = strcspn(line + pos + 1, " ");
+                               pos += i + 1;
+                       }
+                       while ((i > 0) && (pos < sizeof(line)));
+
+                       break;
+#if 0
                        for (i = 1; i < nbr; i++) {
                                st_irq_i = st_irq + i;
                                sscanf(line + pos, " %llu", &st_irq_i->irq_nr);
                                pos += strcspn(line + pos + 1, " ") + 1;
                        }
+#endif
                }
        }
 
        fclose(fp);
+       return irq_read;
 }
 
 /*
@@ -182,15 +234,18 @@ void read_stat_irq(struct stats_irq *st_irq, int nbr)
  *
  * OUT:
  * @st_memory  Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_meminfo(struct stats_memory *st_memory)
+__nr_t read_meminfo(struct stats_memory *st_memory)
 {
        FILE *fp;
        char line[128];
 
        if ((fp = fopen(MEMINFO, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -265,6 +320,7 @@ void read_meminfo(struct stats_memory *st_memory)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -354,15 +410,18 @@ void oct2chr(char *str)
  *
  * OUT:
  * @st_pcsw    Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_stat_pcsw(struct stats_pcsw *st_pcsw)
+__nr_t read_stat_pcsw(struct stats_pcsw *st_pcsw)
 {
        FILE *fp;
        char line[8192];
 
        if ((fp = fopen(STAT, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -378,6 +437,7 @@ void read_stat_pcsw(struct stats_pcsw *st_pcsw)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -389,9 +449,12 @@ void read_stat_pcsw(struct stats_pcsw *st_pcsw)
  *
  * OUT:
  * @st_queue   Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_loadavg(struct stats_queue *st_queue)
+__nr_t read_loadavg(struct stats_queue *st_queue)
 {
        FILE *fp;
        char line[8192];
@@ -399,7 +462,7 @@ void read_loadavg(struct stats_queue *st_queue)
        int rc;
 
        if ((fp = fopen(LOADAVG, "r")) == NULL)
-               return;
+               return 0;
 
        /* Read load averages and queue length */
        rc = fscanf(fp, "%d.%u %d.%u %d.%u %lu/%u %*d\n",
@@ -412,7 +475,7 @@ void read_loadavg(struct stats_queue *st_queue)
        fclose(fp);
 
        if (rc < 8)
-               return;
+               return 0;
 
        st_queue->load_avg_1  += load_tmp[0] * 100;
        st_queue->load_avg_5  += load_tmp[1] * 100;
@@ -425,7 +488,7 @@ void read_loadavg(struct stats_queue *st_queue)
 
        /* Read nr of tasks blocked from /proc/stat */
        if ((fp = fopen(STAT, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -437,6 +500,7 @@ void read_loadavg(struct stats_queue *st_queue)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -448,15 +512,18 @@ void read_loadavg(struct stats_queue *st_queue)
  *
  * OUT:
  * @st_swap    Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_vmstat_swap(struct stats_swap *st_swap)
+__nr_t read_vmstat_swap(struct stats_swap *st_swap)
 {
        FILE *fp;
        char line[128];
 
        if ((fp = fopen(VMSTAT, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -471,6 +538,7 @@ void read_vmstat_swap(struct stats_swap *st_swap)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -482,16 +550,19 @@ void read_vmstat_swap(struct stats_swap *st_swap)
  *
  * OUT:
  * @st_paging  Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_vmstat_paging(struct stats_paging *st_paging)
+__nr_t read_vmstat_paging(struct stats_paging *st_paging)
 {
        FILE *fp;
        char line[128];
        unsigned long pgtmp;
 
        if ((fp = fopen(VMSTAT, "r")) == NULL)
-               return;
+               return 0;
 
        st_paging->pgsteal = 0;
        st_paging->pgscan_kswapd = st_paging->pgscan_direct = 0;
@@ -536,6 +607,7 @@ void read_vmstat_paging(struct stats_paging *st_paging)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -547,18 +619,21 @@ void read_vmstat_paging(struct stats_paging *st_paging)
  *
  * OUT:
  * @st_io      Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_diskstats_io(struct stats_io *st_io)
+__nr_t read_diskstats_io(struct stats_io *st_io)
 {
        FILE *fp;
-       char line[256];
+       char line[1024];
        char dev_name[MAX_NAME_LEN];
        unsigned int major, minor;
        unsigned long rd_ios, wr_ios, rd_sec, wr_sec;
 
        if ((fp = fopen(DISKSTATS, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -581,6 +656,7 @@ void read_diskstats_io(struct stats_io *st_io)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -589,28 +665,33 @@ void read_diskstats_io(struct stats_io *st_io)
  *
  * IN:
  * @st_disk    Structure where stats will be saved.
- * @nbr                Maximum number of block devices.
+ * @nr_alloc   Total number of structures allocated. Value is >= 1.
  * @read_part  True if disks *and* partitions should be read; False if only
  *             disks are read.
  *
  * OUT:
  * @st_disk    Structure with statistics.
+ *
+ * RETURNS:
+ * Number of block devices read, or -1 if the buffer was too small and
+ * needs to be reallocated.
  ***************************************************************************
  */
-void read_diskstats_disk(struct stats_disk *st_disk, int nbr, int read_part)
+__nr_t read_diskstats_disk(struct stats_disk *st_disk, __nr_t nr_alloc,
+                          int read_part)
 {
        FILE *fp;
-       char line[256];
+       char line[1024];
        char dev_name[MAX_NAME_LEN];
-       int dsk = 0;
        struct stats_disk *st_disk_i;
        unsigned int major, minor, rd_ticks, wr_ticks, tot_ticks, rq_ticks;
        unsigned long rd_ios, wr_ios, rd_sec, wr_sec;
+       __nr_t dsk_read = 0;
 
        if ((fp = fopen(DISKSTATS, "r")) == NULL)
-               return;
+               return 0;
 
-       while ((fgets(line, sizeof(line), fp) != NULL) && (dsk < nbr)) {
+       while (fgets(line, sizeof(line), fp) != NULL) {
 
                if (sscanf(line, "%u %u %s %lu %*u %lu %u %lu %*u %lu"
                           " %u %*u %u %u",
@@ -622,7 +703,13 @@ void read_diskstats_disk(struct stats_disk *st_disk, int nbr, int read_part)
                                /* Unused device: Ignore it */
                                continue;
                        if (read_part || is_device(dev_name, ACCEPT_VIRTUAL_DEVICES)) {
-                               st_disk_i = st_disk + dsk++;
+
+                               if (dsk_read + 1 > nr_alloc) {
+                                       dsk_read = -1;
+                                       break;
+                               }
+
+                               st_disk_i = st_disk + dsk_read++;
                                st_disk_i->major     = major;
                                st_disk_i->minor     = minor;
                                st_disk_i->nr_ios    = (unsigned long long) rd_ios + (unsigned long long) wr_ios;
@@ -637,6 +724,7 @@ void read_diskstats_disk(struct stats_disk *st_disk, int nbr, int read_part)
        }
 
        fclose(fp);
+       return dsk_read;
 }
 
 /*
@@ -645,31 +733,43 @@ void read_diskstats_disk(struct stats_disk *st_disk, int nbr, int read_part)
  *
  * IN:
  * @st_serial  Structure where stats will be saved.
- * @nbr                Maximum number of serial lines.
+ * @nr_alloc   Total number of structures allocated. Value is >= 1.
  *
  * OUT:
  * @st_serial  Structure with statistics.
+ *
+ * RETURNS:
+ * Number of serial lines read, or -1 if the buffer was too small and
+ * needs to be reallocated.
  ***************************************************************************
  */
-void read_tty_driver_serial(struct stats_serial *st_serial, int nbr)
+__nr_t read_tty_driver_serial(struct stats_serial *st_serial, __nr_t nr_alloc)
 {
        FILE *fp;
        struct stats_serial *st_serial_i;
-       int sl = 0;
        char line[256];
        char *p;
+       __nr_t sl_read = 0;
 
        if ((fp = fopen(SERIAL, "r")) == NULL)
-               return;
+               return 0;
 
-       while ((fgets(line, sizeof(line), fp) != NULL) && (sl < nbr)) {
+       while (fgets(line, sizeof(line), fp) != NULL ) {
 
                if ((p = strstr(line, "tx:")) != NULL) {
-                       st_serial_i = st_serial + sl;
+
+                       if (sl_read + 1 > nr_alloc) {
+                               sl_read = -1;
+                               break;
+                       }
+
+                       st_serial_i = st_serial + sl_read++;
+                       /* Read serial line number */
                        sscanf(line, "%u", &st_serial_i->line);
                        /*
                         * A value of 0 means an unused structure.
-                        * So increment it to make sure it is not zero.
+                        * So increment the value we have just read
+                        * to make sure it is not zero.
                         */
                        (st_serial_i->line)++;
                        /*
@@ -692,12 +792,11 @@ void read_tty_driver_serial(struct stats_serial *st_serial, int nbr)
                        if ((p = strstr(line, "oe:")) != NULL) {
                                sscanf(p + 3, "%u", &st_serial_i->overrun);
                        }
-
-                       sl++;
                }
        }
 
        fclose(fp);
+       return sl_read;
 }
 
 /*
@@ -709,9 +808,12 @@ void read_tty_driver_serial(struct stats_serial *st_serial, int nbr)
  *
  * OUT:
  * @st_ktables Structure with statistics.
+ *
+ * RETURNS:
+ * 1 (always success).
  ***************************************************************************
  */
-void read_kernel_tables(struct stats_ktables *st_ktables)
+__nr_t read_kernel_tables(struct stats_ktables *st_ktables)
 {
        FILE *fp;
        unsigned int parm;
@@ -770,6 +872,8 @@ void read_kernel_tables(struct stats_ktables *st_ktables)
                        st_ktables->pty_nr = 0;
                }
        }
+
+       return 1;
 }
 
 /*
@@ -778,32 +882,39 @@ void read_kernel_tables(struct stats_ktables *st_ktables)
  *
  * IN:
  * @st_net_dev Structure where stats will be saved.
- * @nbr                Maximum number of network interfaces.
+ * @nr_alloc   Total number of structures allocated. Value is >= 1.
  *
  * OUT:
  * @st_net_dev Structure with statistics.
  *
  * RETURNS:
- * Number of interfaces for which stats have been read.
+ * Number of interfaces read, or -1 if the buffer was too small and
+ * needs to be reallocated.
  ***************************************************************************
  */
-int read_net_dev(struct stats_net_dev *st_net_dev, int nbr)
+__nr_t read_net_dev(struct stats_net_dev *st_net_dev, __nr_t nr_alloc)
 {
        FILE *fp;
        struct stats_net_dev *st_net_dev_i;
        char line[256];
        char iface[MAX_IFACE_LEN];
-       int dev = 0;
+       __nr_t dev_read = 0;
        int pos;
 
        if ((fp = fopen(NET_DEV, "r")) == NULL)
                return 0;
 
-       while ((fgets(line, sizeof(line), fp) != NULL) && (dev < nbr)) {
+       while (fgets(line, sizeof(line), fp) != NULL) {
 
                pos = strcspn(line, ":");
                if (pos < strlen(line)) {
-                       st_net_dev_i = st_net_dev + dev;
+
+                       if (dev_read + 1 > nr_alloc) {
+                               dev_read = -1;
+                               break;
+                       }
+
+                       st_net_dev_i = st_net_dev + dev_read++;
                        strncpy(iface, line, MINIMUM(pos, MAX_IFACE_LEN - 1));
                        iface[MINIMUM(pos, MAX_IFACE_LEN - 1)] = '\0';
                        sscanf(iface, "%s", st_net_dev_i->interface); /* Skip heading spaces */
@@ -816,13 +927,11 @@ int read_net_dev(struct stats_net_dev *st_net_dev, int nbr)
                               &st_net_dev_i->tx_bytes,
                               &st_net_dev_i->tx_packets,
                               &st_net_dev_i->tx_compressed);
-                       dev++;
                }
        }
 
        fclose(fp);
-
-       return dev;
+       return dev_read;
 }
 
 /*
@@ -831,7 +940,7 @@ int read_net_dev(struct stats_net_dev *st_net_dev, int nbr)
  *
  * IN:
  * @st_net_dev Structure where stats will be saved.
- * @nbr                Real number of network interfaces available.
+ * @nbr                Number of network interfaces to read.
  *
  * OUT:
  * @st_net_dev Structure with statistics.
@@ -896,29 +1005,39 @@ void read_if_info(struct stats_net_dev *st_net_dev, int nbr)
  *
  * IN:
  * @st_net_edev        Structure where stats will be saved.
- * @nbr                Maximum number of network interfaces.
+ * @nr_alloc   Total number of structures allocated. Value is >= 1.
  *
  * OUT:
  * @st_net_edev        Structure with statistics.
+ *
+ * RETURNS:
+ * Number of interfaces read, or -1 if the buffer was too small and
+ * needs to be reallocated.
  ***************************************************************************
  */
-void read_net_edev(struct stats_net_edev *st_net_edev, int nbr)
+__nr_t read_net_edev(struct stats_net_edev *st_net_edev, __nr_t nr_alloc)
 {
        FILE *fp;
        struct stats_net_edev *st_net_edev_i;
        static char line[256];
        char iface[MAX_IFACE_LEN];
-       int dev = 0;
+       __nr_t dev_read = 0;
        int pos;
 
        if ((fp = fopen(NET_DEV, "r")) == NULL)
-               return;
+               return 0;
 
-       while ((fgets(line, sizeof(line), fp) != NULL) && (dev < nbr)) {
+       while (fgets(line, sizeof(line), fp) != NULL) {
 
                pos = strcspn(line, ":");
                if (pos < strlen(line)) {
-                       st_net_edev_i = st_net_edev + dev;
+
+                       if (dev_read + 1 > nr_alloc) {
+                               dev_read = -1;
+                               break;
+                       }
+
+                       st_net_edev_i = st_net_edev + dev_read++;
                        strncpy(iface, line, MINIMUM(pos, MAX_IFACE_LEN - 1));
                        iface[MINIMUM(pos, MAX_IFACE_LEN - 1)] = '\0';
                        sscanf(iface, "%s", st_net_edev_i->interface); /* Skip heading spaces */
@@ -933,11 +1052,11 @@ void read_net_edev(struct stats_net_edev *st_net_edev, int nbr)
                               &st_net_edev_i->tx_fifo_errors,
                               &st_net_edev_i->collisions,
                               &st_net_edev_i->tx_carrier_errors);
-                       dev++;
                }
        }
 
        fclose(fp);
+       return dev_read;
 }
 
 /*
@@ -949,16 +1068,19 @@ void read_net_edev(struct stats_net_edev *st_net_edev, int nbr)
  *
  * OUT:
  * @st_net_nfs Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_nfs(struct stats_net_nfs *st_net_nfs)
+__nr_t read_net_nfs(struct stats_net_nfs *st_net_nfs)
 {
        FILE *fp;
        char line[256];
        unsigned int getattcnt = 0, accesscnt = 0, readcnt = 0, writecnt = 0;
 
        if ((fp = fopen(NET_RPC_NFS, "r")) == NULL)
-               return;
+               return 0;
 
        memset(st_net_nfs, 0, STATS_NET_NFS_SIZE);
 
@@ -990,6 +1112,7 @@ void read_net_nfs(struct stats_net_nfs *st_net_nfs)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1001,16 +1124,19 @@ void read_net_nfs(struct stats_net_nfs *st_net_nfs)
  *
  * OUT:
  * @st_net_nfsd        Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_nfsd(struct stats_net_nfsd *st_net_nfsd)
+__nr_t read_net_nfsd(struct stats_net_nfsd *st_net_nfsd)
 {
        FILE *fp;
        char line[256];
        unsigned int getattcnt = 0, accesscnt = 0, readcnt = 0, writecnt = 0;
 
        if ((fp = fopen(NET_RPC_NFSD, "r")) == NULL)
-               return;
+               return 0;
 
        memset(st_net_nfsd, 0, STATS_NET_NFSD_SIZE);
 
@@ -1054,6 +1180,7 @@ void read_net_nfsd(struct stats_net_nfsd *st_net_nfsd)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1065,16 +1192,19 @@ void read_net_nfsd(struct stats_net_nfsd *st_net_nfsd)
  *
  * OUT:
  * @st_net_sock        Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_sock(struct stats_net_sock *st_net_sock)
+__nr_t read_net_sock(struct stats_net_sock *st_net_sock)
 {
        FILE *fp;
        char line[96];
        char *p;
 
        if ((fp = fopen(NET_SOCKSTAT, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1104,6 +1234,7 @@ void read_net_sock(struct stats_net_sock *st_net_sock)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1115,16 +1246,19 @@ void read_net_sock(struct stats_net_sock *st_net_sock)
  *
  * OUT:
  * @st_net_ip  Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_ip(struct stats_net_ip *st_net_ip)
+__nr_t read_net_ip(struct stats_net_ip *st_net_ip)
 {
        FILE *fp;
        char line[1024];
        int sw = FALSE;
 
        if ((fp = fopen(NET_SNMP, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1150,6 +1284,7 @@ void read_net_ip(struct stats_net_ip *st_net_ip)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1161,16 +1296,19 @@ void read_net_ip(struct stats_net_ip *st_net_ip)
  *
  * OUT:
  * @st_net_eip Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_eip(struct stats_net_eip *st_net_eip)
+__nr_t read_net_eip(struct stats_net_eip *st_net_eip)
 {
        FILE *fp;
        char line[1024];
        int sw = FALSE;
 
        if ((fp = fopen(NET_SNMP, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1196,6 +1334,7 @@ void read_net_eip(struct stats_net_eip *st_net_eip)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1207,9 +1346,12 @@ void read_net_eip(struct stats_net_eip *st_net_eip)
  *
  * OUT:
  * @st_net_icmp        Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_icmp(struct stats_net_icmp *st_net_icmp)
+__nr_t read_net_icmp(struct stats_net_icmp *st_net_icmp)
 {
        FILE *fp;
        char line[1024];
@@ -1217,7 +1359,7 @@ void read_net_icmp(struct stats_net_icmp *st_net_icmp)
        int sw = FALSE;
 
        if ((fp = fopen(NET_SNMP, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1268,6 +1410,7 @@ void read_net_icmp(struct stats_net_icmp *st_net_icmp)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1279,16 +1422,19 @@ void read_net_icmp(struct stats_net_icmp *st_net_icmp)
  *
  * OUT:
  * @st_net_eicmp       Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_eicmp(struct stats_net_eicmp *st_net_eicmp)
+__nr_t read_net_eicmp(struct stats_net_eicmp *st_net_eicmp)
 {
        FILE *fp;
        char line[1024];
        int sw = FALSE;
 
        if ((fp = fopen(NET_SNMP, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1318,6 +1464,7 @@ void read_net_eicmp(struct stats_net_eicmp *st_net_eicmp)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1329,16 +1476,19 @@ void read_net_eicmp(struct stats_net_eicmp *st_net_eicmp)
  *
  * OUT:
  * @st_net_tcp Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_tcp(struct stats_net_tcp *st_net_tcp)
+__nr_t read_net_tcp(struct stats_net_tcp *st_net_tcp)
 {
        FILE *fp;
        char line[1024];
        int sw = FALSE;
 
        if ((fp = fopen(NET_SNMP, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1360,6 +1510,7 @@ void read_net_tcp(struct stats_net_tcp *st_net_tcp)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1371,16 +1522,19 @@ void read_net_tcp(struct stats_net_tcp *st_net_tcp)
  *
  * OUT:
  * @st_net_etcp        Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_etcp(struct stats_net_etcp *st_net_etcp)
+__nr_t read_net_etcp(struct stats_net_etcp *st_net_etcp)
 {
        FILE *fp;
        char line[1024];
        int sw = FALSE;
 
        if ((fp = fopen(NET_SNMP, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1403,6 +1557,7 @@ void read_net_etcp(struct stats_net_etcp *st_net_etcp)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1414,16 +1569,19 @@ void read_net_etcp(struct stats_net_etcp *st_net_etcp)
  *
  * OUT:
  * @st_net_udp Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_udp(struct stats_net_udp *st_net_udp)
+__nr_t read_net_udp(struct stats_net_udp *st_net_udp)
 {
        FILE *fp;
        char line[1024];
        int sw = FALSE;
 
        if ((fp = fopen(NET_SNMP, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1444,6 +1602,7 @@ void read_net_udp(struct stats_net_udp *st_net_udp)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1455,15 +1614,18 @@ void read_net_udp(struct stats_net_udp *st_net_udp)
  *
  * OUT:
  * @st_net_sock6       Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_sock6(struct stats_net_sock6 *st_net_sock6)
+__nr_t read_net_sock6(struct stats_net_sock6 *st_net_sock6)
 {
        FILE *fp;
        char line[96];
 
        if ((fp = fopen(NET_SOCKSTAT6, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1486,6 +1648,7 @@ void read_net_sock6(struct stats_net_sock6 *st_net_sock6)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1497,15 +1660,18 @@ void read_net_sock6(struct stats_net_sock6 *st_net_sock6)
  *
  * OUT:
  * @st_net_ip6 Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_ip6(struct stats_net_ip6 *st_net_ip6)
+__nr_t read_net_ip6(struct stats_net_ip6 *st_net_ip6)
 {
        FILE *fp;
        char line[128];
 
        if ((fp = fopen(NET_SNMP6, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1542,6 +1708,7 @@ void read_net_ip6(struct stats_net_ip6 *st_net_ip6)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1553,15 +1720,18 @@ void read_net_ip6(struct stats_net_ip6 *st_net_ip6)
  *
  * OUT:
  * @st_net_eip6        Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_eip6(struct stats_net_eip6 *st_net_eip6)
+__nr_t read_net_eip6(struct stats_net_eip6 *st_net_eip6)
 {
        FILE *fp;
        char line[128];
 
        if ((fp = fopen(NET_SNMP6, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1601,6 +1771,7 @@ void read_net_eip6(struct stats_net_eip6 *st_net_eip6)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1612,15 +1783,18 @@ void read_net_eip6(struct stats_net_eip6 *st_net_eip6)
  *
  * OUT:
  * @st_net_icmp6       Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_icmp6(struct stats_net_icmp6 *st_net_icmp6)
+__nr_t read_net_icmp6(struct stats_net_icmp6 *st_net_icmp6)
 {
        FILE *fp;
        char line[128];
 
        if ((fp = fopen(NET_SNMP6, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1678,6 +1852,7 @@ void read_net_icmp6(struct stats_net_icmp6 *st_net_icmp6)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1689,15 +1864,18 @@ void read_net_icmp6(struct stats_net_icmp6 *st_net_icmp6)
  *
  * OUT:
  * @st_net_eicmp6      Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_eicmp6(struct stats_net_eicmp6 *st_net_eicmp6)
+__nr_t read_net_eicmp6(struct stats_net_eicmp6 *st_net_eicmp6)
 {
        FILE *fp;
        char line[128];
 
        if ((fp = fopen(NET_SNMP6, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1737,6 +1915,7 @@ void read_net_eicmp6(struct stats_net_eicmp6 *st_net_eicmp6)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1748,15 +1927,18 @@ void read_net_eicmp6(struct stats_net_eicmp6 *st_net_eicmp6)
  *
  * OUT:
  * @st_net_udp6        Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_net_udp6(struct stats_net_udp6 *st_net_udp6)
+__nr_t read_net_udp6(struct stats_net_udp6 *st_net_udp6)
 {
        FILE *fp;
        char line[128];
 
        if ((fp = fopen(NET_SNMP6, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1775,6 +1957,7 @@ void read_net_udp6(struct stats_net_udp6 *st_net_udp6)
        }
 
        fclose(fp);
+       return 1;
 }
 
 /*
@@ -1783,29 +1966,40 @@ void read_net_udp6(struct stats_net_udp6 *st_net_udp6)
  *
  * IN:
  * @st_pwr_cpufreq     Structure where stats will be saved.
- * @nbr                        Total number of CPU (including cpu "all").
+ * @nr_alloc           Total number of structures allocated. Value is >= 1.
  *
  * OUT:
  * @st_pwr_cpufreq     Structure with statistics.
+ *
+ * RETURNS:
+ * Highest CPU number for which statistics have been read.
+ * 1 means CPU "all", 2 means CPU 0, 3 means CPU 1, etc.
+ * Or -1 if the buffer was too small and needs to be reallocated.
  ***************************************************************************
  */
-void read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, int nbr)
+__nr_t read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, __nr_t nr_alloc)
 {
        FILE *fp;
        struct stats_pwr_cpufreq *st_pwr_cpufreq_i;
        char line[1024];
        int nr = 0;
-       unsigned int proc_nb = 0, ifreq, dfreq;
+       __nr_t cpu_read = 1;    /* For CPU "all" */
+       unsigned int proc_nr = 0, ifreq, dfreq;
 
        if ((fp = fopen(CPUINFO, "r")) == NULL)
-               return;
+               return 0;
 
        st_pwr_cpufreq->cpufreq = 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
                if (!strncmp(line, "processor\t", 10)) {
-                       sscanf(strchr(line, ':') + 1, "%u", &proc_nb);
+                       sscanf(strchr(line, ':') + 1, "%u", &proc_nr);
+
+                       if (proc_nr + 2 > nr_alloc) {
+                               cpu_read = -1;
+                               break;
+                       }
                }
 
                /* Entry in /proc/cpuinfo is different between Intel and Power architectures */
@@ -1813,24 +2007,16 @@ void read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, int nbr)
                         !strncmp(line, "clock\t", 6)) {
                        sscanf(strchr(line, ':') + 1, "%u.%u", &ifreq, &dfreq);
 
-                       if (proc_nb < (nbr - 1)) {
-                               /* Save current CPU frequency */
-                               st_pwr_cpufreq_i = st_pwr_cpufreq + proc_nb + 1;
-                               st_pwr_cpufreq_i->cpufreq = ifreq * 100 + dfreq / 10;
+                       /* Save current CPU frequency */
+                       st_pwr_cpufreq_i = st_pwr_cpufreq + proc_nr + 1;
+                       st_pwr_cpufreq_i->cpufreq = ifreq * 100 + dfreq / 10;
 
-                               /* Also save it to compute an average CPU frequency */
-                               st_pwr_cpufreq->cpufreq += st_pwr_cpufreq_i->cpufreq;
-                               nr++;
-                       }
-                       else if (!proc_nb && (nbr == 1)) {
-                               /*
-                                * We are reading freq for "Processor 0" and we have a machine
-                                * with only one processor and not an SMP kernel, with /sys not mounted
-                                * (the nr of proc has been counted using /proc/stat and there was
-                                * only one line with global CPU stats here).
-                                * This is a very specific case, I must admit...
-                                */
-                               st_pwr_cpufreq->cpufreq = ifreq * 100 + dfreq / 10;
+                       /* Also save it to compute an average CPU frequency */
+                       st_pwr_cpufreq->cpufreq += st_pwr_cpufreq_i->cpufreq;
+                       nr++;
+
+                       if (proc_nr + 2 > cpu_read) {
+                               cpu_read = proc_nr + 2;
                        }
                }
        }
@@ -1841,6 +2027,7 @@ void read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, int nbr)
                /* Compute average CPU frequency for this machine */
                st_pwr_cpufreq->cpufreq /= nr;
        }
+       return cpu_read;
 }
 
 /*
@@ -1852,16 +2039,19 @@ void read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, int nbr)
  *
  * OUT:
  * @st_huge    Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_meminfo_huge(struct stats_huge *st_huge)
+__nr_t read_meminfo_huge(struct stats_huge *st_huge)
 {
        FILE *fp;
        char line[128];
        unsigned long szhkb = 0;
 
        if ((fp = fopen(MEMINFO, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1884,6 +2074,7 @@ void read_meminfo_huge(struct stats_huge *st_huge)
        /* We want huge pages stats in kB and not expressed in a number of pages */
        st_huge->tlhkb *= szhkb;
        st_huge->frhkb *= szhkb;
+       return 1;
 }
 
 /*
@@ -1897,9 +2088,12 @@ void read_meminfo_huge(struct stats_huge *st_huge)
  *
  * OUT:
  * @st_pwr_wghfreq     Structure with statistics.
+ *
+ * RETURNS:
+ * 1 on success, 0 otherwise.
  ***************************************************************************
  */
-void read_time_in_state(struct stats_pwr_wghfreq *st_pwr_wghfreq, int cpu_nr, int nbr)
+int read_time_in_state(struct stats_pwr_wghfreq *st_pwr_wghfreq, int cpu_nr, int nbr)
 {
        FILE *fp;
        struct stats_pwr_wghfreq *st_pwr_wghfreq_j;
@@ -1912,7 +2106,7 @@ void read_time_in_state(struct stats_pwr_wghfreq *st_pwr_wghfreq, int cpu_nr, in
        snprintf(filename, MAX_PF_NAME, "%s/cpu%d/%s",
                 SYSFS_DEVCPU, cpu_nr, SYSFS_TIME_IN_STATE);
        if ((fp = fopen(filename, "r")) == NULL)
-               return;
+               return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
@@ -1928,6 +2122,67 @@ void read_time_in_state(struct stats_pwr_wghfreq *st_pwr_wghfreq, int cpu_nr, in
        }
 
        fclose(fp);
+       return 1;
+}
+
+/*
+ ***************************************************************************
+ * Read weighted CPU frequency statistics.
+ *
+ * IN:
+ * @st_pwr_wghfreq     Structure where stats will be saved.
+ * @nr_alloc           Total number of structures allocated. Value is >= 0.
+ * @nr2                        Number of sub-items allocated per structure.
+ *
+ * OUT:
+ * @st_pwr_wghfreq     Structure with statistics.
+ *
+ * RETURNS:
+ * Number of CPU for which statistics have been read.
+ * 1 means CPU "all", 2 means CPU "all" and 0, etc.
+ * Or -1 if the buffer was to small and needs to be reallocated.
+ ***************************************************************************
+ */
+__nr_t read_cpu_wghfreq(struct stats_pwr_wghfreq *st_pwr_wghfreq, __nr_t nr_alloc,
+                       __nr_t nr2)
+{
+       __nr_t cpu_read = 0;
+       int j;
+       struct stats_pwr_wghfreq *st_pwr_wghfreq_i, *st_pwr_wghfreq_j, *st_pwr_wghfreq_all_j;
+
+       do {
+               if (cpu_read + 2 > nr_alloc)
+                       return -1;
+
+               /* Read current CPU time-in-state data */
+               st_pwr_wghfreq_i = st_pwr_wghfreq + (cpu_read + 1) * nr2;
+               if (!read_time_in_state(st_pwr_wghfreq_i, cpu_read, nr2))
+                       break;
+
+               /* Also save data for CPU 'all' */
+               for (j = 0; j < nr2; j++) {
+                       st_pwr_wghfreq_j     = st_pwr_wghfreq_i + j;    /* CPU #cpu, state #j */
+                       st_pwr_wghfreq_all_j = st_pwr_wghfreq   + j;    /* CPU #all, state #j */
+                       if (!cpu_read) {
+                               /* Assume that possible frequencies are the same for all CPUs */
+                               st_pwr_wghfreq_all_j->freq = st_pwr_wghfreq_j->freq;
+                       }
+                       st_pwr_wghfreq_all_j->time_in_state += st_pwr_wghfreq_j->time_in_state;
+               }
+               cpu_read++;
+       }
+       while (1);
+
+       if (cpu_read > 0) {
+               for (j = 0; j < nr2; j++) {
+                       st_pwr_wghfreq_all_j = st_pwr_wghfreq + j;      /* CPU #all, state #j */
+                       st_pwr_wghfreq_all_j->time_in_state /= cpu_read;
+               }
+
+               return cpu_read + 1; /* For CPU "all" */
+       }
+
+       return 0;
 }
 
 /*
@@ -2023,40 +2278,46 @@ void read_usb_stats(struct stats_pwr_usb *st_pwr_usb, char *usb_device)
  *
  * IN:
  * @st_pwr_usb         Structure where stats will be saved.
- * @nbr                        Total number of USB devices.
+ * @nr_alloc           Total number of structures allocated. Value is >= 0.
  *
  * OUT:
  * @st_pwr_usb         Structure with statistics.
+ *
+ * RETURNS:
+ * Number of USB devices read, or -1 if the buffer was too small and
+ * needs to be reallocated.
  ***************************************************************************
  */
-void read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, int nbr)
+__nr_t read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, __nr_t nr_alloc)
 {
        DIR *dir;
        struct dirent *drd;
-       struct stats_pwr_usb *st_pwr_usb_j;
-       int j = 0;
+       struct stats_pwr_usb *st_pwr_usb_i;
+       __nr_t usb_read = 0;
 
        /* Open relevant /sys directory */
        if ((dir = opendir(SYSFS_USBDEV)) == NULL)
-               return;
+               return 0;
 
        /* Get current file entry */
        while ((drd = readdir(dir)) != NULL) {
 
                if (isdigit(drd->d_name[0]) && !strchr(drd->d_name, ':')) {
-                       if (j < nbr) {
-                               /* Read current USB device data */
-                               st_pwr_usb_j = st_pwr_usb + j;
-                               read_usb_stats(st_pwr_usb_j, drd->d_name);
-                               j++;
-                       }
-                       else
+
+                       if (usb_read + 1 > nr_alloc) {
+                               usb_read = -1;
                                break;
+                       }
+
+                       /* Read current USB device data */
+                       st_pwr_usb_i = st_pwr_usb + usb_read++;
+                       read_usb_stats(st_pwr_usb_i, drd->d_name);
                }
        }
 
        /* Close directory */
        closedir(dir);
+       return usb_read;
 }
 
 /*
@@ -2065,25 +2326,30 @@ void read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, int nbr)
  *
  * IN:
  * @st_filesystem      Structure where stats will be saved.
- * @nbr                        Total number of filesystems.
+ * @nr_alloc           Total number of structures allocated. Value is >= 0.
  *
  * OUT:
  * @st_filesystem      Structure with statistics.
+ *
+ * RETURNS:
+ * Number of filesystems read, or -1 if the buffer was too small and
+ * needs to be reallocated.
  ***************************************************************************
  */
-void read_filesystem(struct stats_filesystem *st_filesystem, int nbr)
+__nr_t read_filesystem(struct stats_filesystem *st_filesystem, __nr_t nr_alloc)
 {
        FILE *fp;
        char line[512], fs_name[128], mountp[256];
-       int fs = 0, skip = 0, skip_next = 0;
+       int skip = 0, skip_next = 0;
        char *pos = 0;
+       __nr_t fs_read = 0;
        struct stats_filesystem *st_filesystem_i;
        struct statvfs buf;
 
        if ((fp = fopen(MTAB, "r")) == NULL)
-               return;
+               return 0;
 
-       while ((fgets(line, sizeof(line), fp) != NULL) && (fs < nbr)) {
+       while (fgets(line, sizeof(line), fp) != NULL) {
                /*
                 * Ignore line if the preceding line did not contain '\n'.
                 * (Some very long lines may be found for instance when
@@ -2123,7 +2389,12 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr)
                        if ((statvfs(mountp, &buf) < 0) || (!buf.f_blocks))
                                continue;
 
-                       st_filesystem_i = st_filesystem + fs++;
+                       if (fs_read + 1 > nr_alloc) {
+                               fs_read = -1;
+                               break;
+                       }
+
+                       st_filesystem_i = st_filesystem + fs_read++;
                        st_filesystem_i->f_blocks = (unsigned long long) buf.f_blocks * (unsigned long long) buf.f_frsize;
                        st_filesystem_i->f_bfree  = (unsigned long long) buf.f_bfree * (unsigned long long) buf.f_frsize;
                        st_filesystem_i->f_bavail = (unsigned long long) buf.f_bavail * (unsigned long long) buf.f_frsize;
@@ -2137,6 +2408,7 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr)
        }
 
        fclose(fp);
+       return fs_read;
 }
 
 /*
@@ -2145,36 +2417,45 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr)
  *
  * IN:
  * @st_fc      Structure where stats will be saved.
- * @nbr                Total number of HBAs.
+ * @nr_alloc   Total number of structures allocated. Value is >= 0.
  *
  * OUT:
  * @st_fc      Structure with statistics.
+ *
+ * RETURNS:
+ * Number of FC hosts read, or -1 if the buffer was too small and needs to
+ * be reallocated.
  ***************************************************************************
  */
-void read_fchost(struct stats_fchost *st_fc, int nbr)
+__nr_t read_fchost(struct stats_fchost *st_fc, __nr_t nr_alloc)
 {
        DIR *dir;
        FILE *fp;
        struct dirent *drd;
        struct stats_fchost *st_fc_i;
-       int fch = 0;
+       __nr_t fch_read = 0;
        char fcstat_filename[MAX_PF_NAME];
        char line[256];
        unsigned long rx_frames, tx_frames, rx_words, tx_words;
 
        /* Each host, if present, will have its own hostX entry within SYSFS_FCHOST */
        if ((dir = opendir(SYSFS_FCHOST)) == NULL)
-               return; /* No FC hosts */
+               return 0; /* No FC hosts */
 
        /*
         * Read each of the counters via sysfs, where they are
         * returned as hex values (e.g. 0x72400).
         */
-       while (((drd = readdir(dir)) != NULL) && (fch < nbr)) {
+       while ((drd = readdir(dir)) != NULL) {
                rx_frames = tx_frames = rx_words = tx_words = 0;
 
                if (!strncmp(drd->d_name, "host", 4)) {
 
+                       if (fch_read + 1 > nr_alloc) {
+                               fch_read = -1;
+                               break;
+                       }
+
                        snprintf(fcstat_filename, MAX_PF_NAME, FC_RX_FRAMES,
                                 SYSFS_FCHOST, drd->d_name);
                        if ((fp = fopen(fcstat_filename, "r"))) {
@@ -2211,7 +2492,7 @@ void read_fchost(struct stats_fchost *st_fc, int nbr)
                                fclose(fp);
                        }
 
-                       st_fc_i = st_fc + fch++;
+                       st_fc_i = st_fc + fch_read++;
                        st_fc_i->f_rxframes = rx_frames;
                        st_fc_i->f_txframes = tx_frames;
                        st_fc_i->f_rxwords  = rx_words;
@@ -2219,9 +2500,10 @@ void read_fchost(struct stats_fchost *st_fc, int nbr)
                        strncpy(st_fc_i->fchost_name, drd->d_name, MAX_FCH_LEN);
                        st_fc_i->fchost_name[MAX_FCH_LEN - 1] = '\0';
                }
-
        }
+
        closedir(dir);
+       return fch_read;
 }
 
 /*
@@ -2230,22 +2512,27 @@ void read_fchost(struct stats_fchost *st_fc, int nbr)
  *
  * IN:
  * @st_softnet Structure where stats will be saved.
- * @nbr                Total number of CPU (including cpu "all").
+ * @nr_alloc   Total number of structures allocated. Value is >= 0.
  *
  * OUT:
  * @st_softnet Structure with statistics.
+ *
+ * RETURNS:
+ * Number of CPU for which statistics have been read.
+ * 1 means CPU "all", 2 means CPU 0, 3 means CPU 1, etc.
+ * Or -1 if the buffer was too small and needs to be reallocated.
  ***************************************************************************
  */
-void read_softnet(struct stats_softnet *st_softnet, int nbr)
+__nr_t read_softnet(struct stats_softnet *st_softnet, __nr_t nr_alloc)
 {
        FILE *fp;
        struct stats_softnet *st_softnet_i;
        char line[1024];
-       unsigned int proc_nb = 1;
+       __nr_t cpu_read = 1;    /* For CPU "all" */
 
        /* Open /proc/net/softnet_stat file */
        if ((fp = fopen(NET_SOFTNET, "r")) == NULL)
-               return;
+               return 0;
 
        /*
         * Init a structure that will contain the values for CPU "all".
@@ -2254,9 +2541,14 @@ void read_softnet(struct stats_softnet *st_softnet, int nbr)
         */
        memset(st_softnet, 0, sizeof(struct stats_softnet));
 
-       while ((fgets(line, sizeof(line), fp) != NULL) && (proc_nb < nbr)) {
+       while (fgets(line, sizeof(line), fp) != NULL) {
+
+               if (cpu_read + 1 > nr_alloc) {
+                       cpu_read = -1;
+                       break;
+               }
 
-               st_softnet_i = st_softnet + proc_nb++;
+               st_softnet_i = st_softnet + cpu_read++;
                sscanf(line, "%x %x %x %*x %*x %*x %*x %*x %*x %x %x",
                       &st_softnet_i->processed,
                       &st_softnet_i->dropped,
@@ -2272,6 +2564,7 @@ void read_softnet(struct stats_softnet *st_softnet, int nbr)
        }
 
        fclose(fp);
+       return cpu_read;
 }
 
 /*------------------ END: FUNCTIONS USED BY SADC ONLY ---------------------*/
index 8a8eeb875fc7186d3f5e4ca82f004ce3815c72b2..e6423bb127c02b6168f6d9c0b9a40892735e0dff 100644 (file)
@@ -6,7 +6,6 @@
 #ifndef _RD_STATS_H
 #define _RD_STATS_H
 
-
 /*
  ***************************************************************************
  * Miscellaneous constants
@@ -597,81 +596,81 @@ struct stats_softnet {
 
 void oct2chr
        (char *);
-void read_stat_cpu
-       (struct stats_cpu *, int);
-void read_stat_irq
-       (struct stats_irq *, int);
-void read_meminfo
+__nr_t read_stat_cpu
+       (struct stats_cpu *, __nr_t);
+__nr_t read_stat_irq
+       (struct stats_irq *, __nr_t);
+__nr_t read_meminfo
        (struct stats_memory *);
 void read_uptime
        (unsigned long long *);
-void read_stat_pcsw
+__nr_t read_stat_pcsw
        (struct stats_pcsw *);
-void read_loadavg
+__nr_t read_loadavg
        (struct stats_queue *);
-void read_vmstat_swap
+__nr_t read_vmstat_swap
        (struct stats_swap *);
-void read_vmstat_paging
+__nr_t read_vmstat_paging
        (struct stats_paging *);
-void read_diskstats_io
+__nr_t read_diskstats_io
        (struct stats_io *);
-void read_diskstats_disk
-       (struct stats_disk *, int, int);
-void read_tty_driver_serial
-       (struct stats_serial *, int);
-void read_kernel_tables
+__nr_t read_diskstats_disk
+       (struct stats_disk *, __nr_t, int);
+__nr_t read_tty_driver_serial
+       (struct stats_serial *, __nr_t);
+__nr_t read_kernel_tables
        (struct stats_ktables *);
-int read_net_dev
-       (struct stats_net_dev *, int);
+__nr_t read_net_dev
+       (struct stats_net_dev *, __nr_t);
 void read_if_info
        (struct stats_net_dev *, int);
-void read_net_edev
-       (struct stats_net_edev *, int);
-void read_net_nfs
+__nr_t read_net_edev
+       (struct stats_net_edev *, __nr_t);
+__nr_t read_net_nfs
        (struct stats_net_nfs *);
-void read_net_nfsd
+__nr_t read_net_nfsd
        (struct stats_net_nfsd *);
-void read_net_sock
+__nr_t read_net_sock
        (struct stats_net_sock *);
-void read_net_ip
+__nr_t read_net_ip
        (struct stats_net_ip *);
-void read_net_eip
+__nr_t read_net_eip
        (struct stats_net_eip *);
-void read_net_icmp
+__nr_t read_net_icmp
        (struct stats_net_icmp *);
-void read_net_eicmp
+__nr_t read_net_eicmp
        (struct stats_net_eicmp *);
-void read_net_tcp
+__nr_t read_net_tcp
        (struct stats_net_tcp *);
-void read_net_etcp
+__nr_t read_net_etcp
        (struct stats_net_etcp *);
-void read_net_udp
+__nr_t read_net_udp
        (struct stats_net_udp *);
-void read_net_sock6
+__nr_t read_net_sock6
        (struct stats_net_sock6 *);
-void read_net_ip6
+__nr_t read_net_ip6
        (struct stats_net_ip6 *);
-void read_net_eip6
+__nr_t read_net_eip6
        (struct stats_net_eip6 *);
-void read_net_icmp6
+__nr_t read_net_icmp6
        (struct stats_net_icmp6 *);
-void read_net_eicmp6
+__nr_t read_net_eicmp6
        (struct stats_net_eicmp6 *);
-void read_net_udp6
+__nr_t read_net_udp6
        (struct stats_net_udp6 *);
-void read_cpuinfo
-       (struct stats_pwr_cpufreq *, int);
-void read_meminfo_huge
+__nr_t read_cpuinfo
+       (struct stats_pwr_cpufreq *, __nr_t);
+__nr_t read_meminfo_huge
        (struct stats_huge *);
-void read_time_in_state
-       (struct stats_pwr_wghfreq *, int, int);
-void read_bus_usb_dev
-       (struct stats_pwr_usb *, int);
-void read_filesystem
-       (struct stats_filesystem *, int);
-void read_fchost
-       (struct stats_fchost *, int);
-void read_softnet
-       (struct stats_softnet *, int);
+__nr_t read_cpu_wghfreq
+       (struct stats_pwr_wghfreq *, __nr_t, __nr_t);
+__nr_t read_bus_usb_dev
+       (struct stats_pwr_usb *, __nr_t);
+__nr_t read_filesystem
+       (struct stats_filesystem *, __nr_t);
+__nr_t read_fchost
+       (struct stats_fchost *, __nr_t);
+__nr_t read_softnet
+       (struct stats_softnet *, __nr_t);
 
 #endif /* _RD_STATS_H */
diff --git a/sa.h b/sa.h
index e774b42f8f94a0897e810eac509cceac4d95f0e7..471989897266ab444e85f54db9611a9560e2687e 100644 (file)
--- a/sa.h
+++ b/sa.h
@@ -315,13 +315,14 @@ struct svg_hdr_parm {
 
 /*
  ***************************************************************************
- * Definitions of header structures.
+ * System activity data files
  *
- * The rule is: "strict writing, broad reading", meaning that sar/sadc can
+ * The rule is: "strict writing, read any", meaning that sar/sadc can
  * only append data to a datafile whose format is strictly the same as that
  * of current version (checking FORMAT_MAGIC is not enough), but sar/sadf
  * can read data from different versions, providing that FORMAT_MAGIC value
- * has not changed.
+ * has not changed (note that we are talking here of data read from a file,
+ * not data that sar reads from sadc, in which case the "strict" rule applies).
  *
  * Format of system activity data files:
  *      __
@@ -340,17 +341,28 @@ struct svg_hdr_parm {
  *     |                             |
  *     | record_header structure     |
  *     |                             |
- *     |--                         --|
- *     |(__nr_t)       * 0+          |
- *     |--                           | * <count>
+ *     |--                           |
+ *     |(__nr_t)                     |
+ *     |--                           |
+ *     |                             |
+ *     | Statistics structure(s)     | * <count>
+ *     |                             |
+ *     |--                           |
+ *     |(__nr_t)                     |
+ *     |--                           |
  *     |                             |
- *     | Statistics structures...    |
+ *     | Statistics structure(s)...  |
  *     |                             |
  *     |--                         --|
  *
- * Note: A record_header structure is followed by 0+ __nr_t values giving
- * the number of statistics structures for activities whose number of items
- * may vary (ie. activities having a positive f_count_index value).
+ * Note: For activities with varying number of items, a __nr_t value, giving
+ * the number of items, arrives before the statistics structures so that
+ * we know how many of them have to be read.
+ * NB: This value exists for all the activities even if they share the same
+ * count function (e.g. A_NET_DEV and A_NET_EDEV). Indeed, statistics are not
+ * read atomically and the number of items (e.g. network interfaces) may have
+ * varied in between.
+ *
  * If the record header's type is R_COMMENT then we find only a comment
  * following the record_header structure.
  * If the record_header's type is R_RESTART then we find only the number of CPU
@@ -439,8 +451,10 @@ struct file_header {
        /*
         * Number of [online or offline] CPU (1 .. CPU_NR + 1)
         * when the datafile has been created.
-        * When reading a datafile, this value is updated whenever
-        * a RESTART record is found.
+        * When reading a datafile, this value is updated (in memory)
+        * whenever a RESTART record is found.
+        * When writing or appending data to a file, this field is updated
+        * neither in file nor in memory.
         */
        unsigned int sa_cpu_nr          __attribute__ ((aligned (8)));
        /*
@@ -522,13 +536,19 @@ struct file_activity {
         */
        unsigned int magic;
        /*
-        * Number of items for this activity.
+        * Number of items for this activity
+        * when the data file has been created.
         */
        __nr_t nr;
        /*
         * Number of sub-items for this activity.
         */
        __nr_t nr2;
+       /*
+        * Set to TRUE if statistics are preceded by
+        * a value giving the number of structures to read.
+        */
+       int has_nr;
        /*
         * Size of an item structure.
         */
@@ -544,7 +564,7 @@ struct file_activity {
 #define MAX_FILE_ACTIVITY_SIZE 1024    /* Used for sanity check */
 #define FILE_ACTIVITY_ULL_NR   0       /* Nr of unsigned long long in file_activity structure */
 #define FILE_ACTIVITY_UL_NR    0       /* Nr of unsigned long in file_activity structure */
-#define FILE_ACTIVITY_U_NR     8       /* Nr of [unsigned] int in file_activity structure */
+#define FILE_ACTIVITY_U_NR     9       /* Nr of [unsigned] int in file_activity structure */
 
 
 /* Record type */
@@ -666,6 +686,7 @@ struct record_header {
 #define IS_MATRIX(m)           (((m) & AO_MATRIX)           == AO_MATRIX)
 
 #define _buf0  buf[0]
+#define _nr0   nr[0]
 
 /* Structure used to define a bitmap needed by an activity */
 struct act_bitmap {
@@ -799,14 +820,14 @@ struct activity {
         */
        int g_nr;
        /*
-        * Number of items on the system.
+        * Number of items on the system, as counted when the system is initialized.
         * A negative value (-1) is the default value and indicates that this number
         * has still not been calculated by the f_count() function.
         * A value of 0 means that this number has been calculated, but no items have
         * been found.
         * A positive value (>0) has either been calculated or is a constant.
         */
-       __nr_t nr;
+       __nr_t nr_ini;
        /*
         * Number of sub-items on the system.
         * @nr2 is in fact the second dimension of a matrix of items, the first
@@ -831,6 +852,16 @@ struct activity {
         * is NR2_MAX.
         */
        __nr_t nr_max;
+       /*
+        * Number of items, as read and saved in corresponding buffer (@buf: See below).
+        * The value may be zero for a particular sample if no items have been found.
+        */
+       __nr_t nr[3];
+       /*
+        * Number of structures allocated in @buf[*]. This number should be greater
+        * than or equal to @nr[*].
+        */
+       __nr_t nr_allocated;
        /*
         * Size of an item.
         * This is the size of the corresponding structure, as read from or written
@@ -1158,7 +1189,7 @@ __read_funct_t wrap_read_in
        (struct activity *);
 __read_funct_t wrap_read_meminfo_huge
        (struct activity *);
-__read_funct_t wrap_read_time_in_state
+__read_funct_t wrap_read_cpu_wghfreq
        (struct activity *);
 __read_funct_t wrap_read_bus_usb_dev
        (struct activity *);
@@ -1236,11 +1267,14 @@ int print_special_record
         int, int, struct tm *, struct tm *, char *, int, struct file_magic *,
         struct file_header *, struct activity * [], struct report_format *, int, int);
 void read_file_stat_bunch
-       (struct activity * [], int, int, int, struct file_activity *, int, int);
-__nr_t read_new_cpu_nr
-       (int, char *, struct file_magic *, int, int);
+       (struct activity * [], int, int, int, struct file_activity *, int, int,
+        char *, struct file_magic *);
+__nr_t read_nr_value
+       (int, char *, struct file_magic *, int, int, int);
 int read_record_hdr
        (int, void *, struct record_header *, struct file_header *, int, int);
+void reallocate_all_buffers
+       (struct activity *);
 void remap_struct
        (unsigned int [], unsigned int [], void *, unsigned int);
 void replace_nonprintable_char
index 4e7440da5a43cd95cc673ed08747a9de25080051..8bfbab2b248f665208003d5778386d1781d9012d 100644 (file)
@@ -68,11 +68,12 @@ void allocate_structures(struct activity *act[])
        int i, j;
 
        for (i = 0; i < NR_ACT; i++) {
-               if (act[i]->nr > 0) {
+               if (act[i]->nr_ini > 0) {
                        for (j = 0; j < 3; j++) {
                                SREALLOC(act[i]->buf[j], void,
-                                               (size_t) act[i]->msize * (size_t) act[i]->nr * (size_t) act[i]->nr2);
+                                               (size_t) act[i]->msize * (size_t) act[i]->nr_ini * (size_t) act[i]->nr2);
                        }
+                       act[i]->nr_allocated = act[i]->nr_ini;
                }
        }
 }
@@ -90,17 +91,43 @@ void free_structures(struct activity *act[])
        int i, j;
 
        for (i = 0; i < NR_ACT; i++) {
-               if (act[i]->nr > 0) {
+               if (act[i]->nr_allocated > 0) {
                        for (j = 0; j < 3; j++) {
                                if (act[i]->buf[j]) {
                                        free(act[i]->buf[j]);
                                        act[i]->buf[j] = NULL;
                                }
                        }
+                       act[i]->nr_allocated = 0;
                }
        }
 }
 
+/*
+ ***************************************************************************
+ * Reallocate all the buffers for given activity. The new size is the double
+ * of the original one.
+ * NB: nr_allocated is > 0.
+ *
+ * IN:
+ * @a  Activity whose buffers need to be reallocated.
+ ***************************************************************************
+ */
+void reallocate_all_buffers(struct activity *a)
+{
+       int j;
+
+       for (j = 0; j < 3; j++) {
+               SREALLOC(a->buf[j], void,
+                       (size_t) a->msize * (size_t) a->nr_allocated * 2 * (size_t) a->nr2);
+               /* Init additional space which has been allocated */
+               memset(a->buf[j] + a->msize * a->nr_allocated * a->nr2, 0,
+                      (size_t) a->msize * (size_t) a->nr_allocated * (size_t) a->nr2);
+       }
+
+       a->nr_allocated *= 2;
+}
+
 /*
   ***************************************************************************
   * Try to get device real name from sysfs tree.
@@ -609,23 +636,26 @@ void print_report_hdr(unsigned int flags, struct tm *rectime,
  * as reference).
  * -2 if it is a known interface but which has been unregistered then
  * registered again on the interval.
- *
- * Note: A newly registered interface, if it is supernumerary, may make the
- * last interface in the array going out of the list. Yet an interface going
- * out of the list still exists in the /proc/net/dev file. Should it go back
- * in the list (e.g. if some other interfaces have been unregistered) then
- * its counters will jump as if starting from zero.
  ***************************************************************************
  */
 int check_net_dev_reg(struct activity *a, int curr, int ref, int pos)
 {
        struct stats_net_dev *sndc, *sndp;
-       int index = 0;
+       int j0, j= pos;
+
+       if (j > a->nr[ref]) {
+               j = a->nr[ref];
+       }
+       j0 = j;
 
        sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + pos * a->msize);
 
-       while (index < a->nr) {
-               sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
+       do {
+               if (j > a->nr[ref]) {
+                       j = 0;
+               }
+               sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + j * a->msize);
+
                if (!strcmp(sndc->interface, sndp->interface)) {
                        /*
                         * Network interface found.
@@ -681,15 +711,16 @@ int check_net_dev_reg(struct activity *a, int curr, int ref, int pos)
 
                                if (!ovfw)
                                        /*
-                                        * OK: assume here that the device was
+                                        * OK: Assume here that the device was
                                         * actually unregistered.
                                         */
                                        return -2;
                        }
-                       return index;
+                       return j;
                }
-               index++;
+               j++;
        }
+       while (j != j0);
 
        /* This is a newly registered interface */
        return -1;
@@ -717,12 +748,21 @@ int check_net_dev_reg(struct activity *a, int curr, int ref, int pos)
 int check_net_edev_reg(struct activity *a, int curr, int ref, int pos)
 {
        struct stats_net_edev *snedc, *snedp;
-       int index = 0;
+       int j0, j = pos;
+
+       if (j > a->nr[ref]) {
+               j = a->nr[ref];
+       }
+       j0 = j;
 
        snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + pos * a->msize);
 
-       while (index < a->nr) {
-               snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
+       do {
+               if (j > a->nr[ref]) {
+                       j = 0;
+               }
+               snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + j * a->msize);
+
                if (!strcmp(snedc->interface, snedp->interface)) {
                        /*
                         * Network interface found.
@@ -743,10 +783,11 @@ int check_net_edev_reg(struct activity *a, int curr, int ref, int pos)
                                 */
                                return -2;
 
-                       return index;
+                       return j;
                }
-               index++;
+               j++;
        }
+       while (j != j0);
 
        /* This is a newly registered interface */
        return -1;
@@ -773,12 +814,21 @@ int check_net_edev_reg(struct activity *a, int curr, int ref, int pos)
 int check_disk_reg(struct activity *a, int curr, int ref, int pos)
 {
        struct stats_disk *sdc, *sdp;
-       int index = 0;
+       int j0, j = pos;
+
+       if (j > a->nr[ref]) {
+               j = a->nr[ref];
+       }
+       j0 = j;
 
        sdc = (struct stats_disk *) ((char *) a->buf[curr] + pos * a->msize);
 
-       while (index < a->nr) {
-               sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
+       do {
+               if (j > a->nr[ref]) {
+                       j = 0;
+               }
+               sdp = (struct stats_disk *) ((char *) a->buf[ref] + j * a->msize);
+
                if ((sdc->major == sdp->major) &&
                    (sdc->minor == sdp->minor)) {
                        /*
@@ -794,10 +844,11 @@ int check_disk_reg(struct activity *a, int curr, int ref, int pos)
                                /* Same device registered again */
                                return -2;
 
-                       return index;
+                       return j;
                }
-               index++;
+               j++;
        }
+       while (j != j0);
 
        /* This is a newly registered device */
        return -1;
@@ -1263,12 +1314,10 @@ void copy_structures(struct activity *act[], unsigned int id_seq[],
                        continue;
 
                p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
-               if ((act[p]->nr < 1) || (act[p]->nr2 < 1)) {
-                       PANIC(1);
-               }
 
                memcpy(act[p]->buf[dest], act[p]->buf[src],
-                      (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
+                      (size_t) act[p]->msize * (size_t) act[p]->nr[src] * (size_t) act[p]->nr2);
+               act[p]->nr[dest] = act[p]->nr[src];
        }
 }
 
@@ -1285,63 +1334,97 @@ void copy_structures(struct activity *act[], unsigned int id_seq[],
  * @endian_mismatch
  *             TRUE if file's data don't match current machine's endianness.
  * @arch_64    TRUE if file's data come from a 64 bit machine.
+ * @dfile      Name of system activity data file.
+ * @file_magic file_magic structure containing data read from file magic
+ *             header.
  ***************************************************************************
  */
 void read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
                          struct file_activity *file_actlst, int endian_mismatch,
-                         int arch_64)
+                         int arch_64, char *dfile, struct file_magic *file_magic)
 {
        int i, j, p;
        struct file_activity *fal = file_actlst;
        off_t offset;
+       __nr_t nr_value;
 
        for (i = 0; i < act_nr; i++, fal++) {
 
+               /* Read __nr_t value preceding statistics structures if it exists */
+               if (fal->has_nr) {
+                       nr_value = read_nr_value(ifd, dfile, file_magic,
+                                                endian_mismatch, arch_64, FALSE);
+               }
+               else {
+                       nr_value = fal->nr;
+               }
+
                if (((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) ||
                    (act[p]->magic != fal->magic)) {
                        /*
                         * Ignore current activity in file, which is unknown to
                         * current sysstat version or has an unknown format.
                         */
-                       offset = (off_t) fal->size * (off_t) fal->nr * (off_t) fal->nr2;
-                       if (lseek(ifd, offset, SEEK_CUR) < offset) {
-                               close(ifd);
-                               perror("lseek");
-                               exit(2);
+                       if (nr_value) {
+                               offset = (off_t) fal->size * (off_t) nr_value * (off_t) fal->nr2;
+                               if (lseek(ifd, offset, SEEK_CUR) < offset) {
+                                       close(ifd);
+                                       perror("lseek");
+                                       exit(2);
+                               }
                        }
                        continue;
                }
 
-               if ((act[p]->nr > 0) &&
-                        ((act[p]->nr > 1) || (act[p]->nr2 > 1)) &&
-                        (act[p]->msize > act[p]->fsize)) {
+               act[p]->nr[curr] = nr_value;
+
+               /* Reallocate buffers if needed */
+               if (nr_value > act[p]->nr_allocated) {
+                       reallocate_all_buffers(act[p]);
+               }
 
-                       for (j = 0; j < (act[p]->nr * act[p]->nr2); j++) {
+               /*
+                 * For persistent activities, we must make sure that no statistics
+                 * from a previous iteration remain, especially if the number
+                 * of structures read is smaller than @nr_ini.
+                 */
+               if (HAS_PERSISTENT_VALUES(act[p]->options)) {
+                    memset(act[p]->buf[curr], 0,
+                           (size_t) act[p]->msize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
+                }
+
+               /* OK, this is a known activity: Read the stats structures */
+               if ((nr_value > 0) &&
+                   ((nr_value > 1) || (act[p]->nr2 > 1)) &&
+                   (act[p]->msize > act[p]->fsize)) {
+
+                       for (j = 0; j < (nr_value * act[p]->nr2); j++) {
                                sa_fread(ifd, (char *) act[p]->buf[curr] + j * act[p]->msize,
                                         act[p]->fsize, HARD_SIZE);
                        }
                }
-               else if (act[p]->nr > 0) {
+               else if (nr_value > 0) {
                        /*
                         * Note: If msize was smaller than fsize,
                         * then it has been set to fsize in check_file_actlst().
                         */
-                       sa_fread(ifd, act[p]->buf[curr], act[p]->fsize * act[p]->nr * act[p]->nr2, HARD_SIZE);
+                       sa_fread(ifd, act[p]->buf[curr], act[p]->fsize * nr_value * act[p]->nr2, HARD_SIZE);
                }
                else {
-                       PANIC(p);
+                       /* nr_value == 0: Nothing to read */
+                       continue;
                }
 
                /* Normalize endianness for current activity's structures */
                if (endian_mismatch) {
-                       for (j = 0; j < (act[p]->nr * act[p]->nr2); j++) {
+                       for (j = 0; j < (nr_value * act[p]->nr2); j++) {
                                swap_struct(act[p]->ftypes_nr, (char *) act[p]->buf[curr] + j * act[p]->msize,
                                            arch_64);
                        }
                }
 
                /* Remap structure's fields to those known by current sysstat version */
-               for (j = 0; j < (act[p]->nr * act[p]->nr2); j++) {
+               for (j = 0; j < (nr_value * act[p]->nr2); j++) {
                        remap_struct(act[p]->gtypes_nr, act[p]->ftypes_nr,
                                     (char *) act[p]->buf[curr] + j * act[p]->msize, act[p]->fsize);
                }
@@ -1366,7 +1449,8 @@ void read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
  *             TRUE if file's data don't match current machine's endianness.
  *
  * RETURNS:
- * -1 if data file is a sysstat file with an old format, 0 otherwise.
+ * -1 if data file is a sysstat file with an old format (which we cannot
+ * read), 0 otherwise.
  ***************************************************************************
  */
 int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
@@ -1402,6 +1486,7 @@ int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
                /* Swap bytes for file_magic fields */
                file_magic->sysstat_magic = __builtin_bswap16(file_magic->sysstat_magic);
                file_magic->format_magic  = __builtin_bswap16(file_magic->format_magic);
+               /* Start swapping at field "header_size" position */
                swap_struct(fm_types_nr, &file_magic->header_size, 0);
        }
 
@@ -1424,7 +1509,10 @@ int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
        }
 
        if (file_magic->format_magic != FORMAT_MAGIC)
-               /* This is an old (or new) sa datafile format */
+               /*
+                * This is an old (or new) sa datafile format to
+                * be read by sadf (since @ignore was set to TRUE).
+                */
                return -1;
 
        return 0;
@@ -1467,6 +1555,10 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
 
        /* Open sa data file and read its magic structure */
        if (sa_open_read_magic(ifd, dfile, file_magic, ignore, endian_mismatch) < 0)
+               /*
+                * Not current sysstat's format.
+                * Return now so that sadf can do its job.
+                */
                return;
 
        /* We know now that we have a *compatible* sysstat datafile format */
@@ -1521,7 +1613,7 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
                /*
                * Data file_activity size (file_hdr->act_size) may be greater or
                * smaller than FILE_ACTIVITY_SIZE. Remap the fields of the file's structure
-               * then copy its contents to the expected  structure.
+               * then copy its contents to the expected structure.
                */
                remap_struct(act_types_nr, file_hdr->act_types_nr, buffer, file_hdr->act_size);
                memcpy(fal, buffer, FILE_ACTIVITY_SIZE);
@@ -1594,9 +1686,9 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
                        act[p]->msize = fal->size;
                }
 
-               act[p]->nr    = fal->nr;
-               act[p]->nr2   = fal->nr2;
-               act[p]->fsize = fal->size;
+               act[p]->nr_ini = fal->nr;
+               act[p]->nr2    = fal->nr2;
+               act[p]->fsize  = fal->size;
                /*
                 * This is a known activity with a known format
                 * (magical number). Only such activities will be displayed.
@@ -1611,7 +1703,7 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
 
        free(buffer);
 
-       /* Check that at least one selected activity is available in file */
+       /* Check that at least one activity selected by the user is available in file */
        for (i = 0; i < NR_ACT; i++) {
 
                if (!IS_SELECTED(act[i]->options))
@@ -1646,7 +1738,10 @@ format_error:
 
 /*
  ***************************************************************************
- * Read the new number of CPU saved after a RESTART record.
+ * Read an __nr_t value from file.
+ * Such a value can be the new number of CPU saved after a RESTART record,
+ * or the number of structures to read saved before the structures containing
+ * statistics for an activity with a varying number of items in file.
  *
  * IN:
  * @ifd                Input file descriptor.
@@ -1655,30 +1750,31 @@ format_error:
  * @endian_mismatch
  *             TRUE if file's data don't match current machine's endianness.
  * @arch_64    TRUE if file's data come from a 64 bit machine.
+ * @non_zero   TRUE if value should not be zero.
  *
  * RETURNS:
- * New number of CPU.
+ * __nr_t value, as read from file.
  ***************************************************************************
  */
-__nr_t read_new_cpu_nr(int ifd, char *file, struct file_magic *file_magic,
-                      int endian_mismatch, int arch_64)
+__nr_t read_nr_value(int ifd, char *file, struct file_magic *file_magic,
+                    int endian_mismatch, int arch_64, int non_zero)
 {
-       __nr_t cpu_nr;
+       __nr_t value;
 
-       sa_fread(ifd, &cpu_nr, sizeof(__nr_t), HARD_SIZE);
+       sa_fread(ifd, &value, sizeof(__nr_t), HARD_SIZE);
 
        /* Normalize endianness for file_activity structures */
        if (endian_mismatch) {
                nr_types_nr[2] = 1;
-               swap_struct(nr_types_nr, &cpu_nr, arch_64);
+               swap_struct(nr_types_nr, &value, arch_64);
        }
 
-       if (!cpu_nr) {
-               /* CPU number cannot be zero */
+       if (non_zero && !value) {
+               /* Value number cannot be zero */
                handle_invalid_sa_file(&ifd, file_magic, file, 0);
        }
 
-       return cpu_nr;
+       return value;
 }
 
 /*
@@ -2336,6 +2432,7 @@ void set_record_timestamp_string(unsigned int l_flags, struct record_header *rec
 /*
  ***************************************************************************
  * Print contents of a special (RESTART or COMMENT) record.
+ * Note: This function is called only when reading a file.
  *
  * IN:
  * @record_hdr Current record header.
@@ -2378,6 +2475,7 @@ int print_special_record(struct record_header *record_hdr, unsigned int l_flags,
 {
        char cur_date[TIMESTAMP_LEN], cur_time[TIMESTAMP_LEN];
        int dp = 1;
+       int p;
 
        /* Fill timestamp structure (rectime) for current record */
        if (sa_get_record_timestamp_struct(l_flags, record_hdr, rectime, loctime))
@@ -2402,8 +2500,20 @@ int print_special_record(struct record_header *record_hdr, unsigned int l_flags,
 
        if (rtype == R_RESTART) {
                /* Read new cpu number following RESTART record */
-               file_hdr->sa_cpu_nr = read_new_cpu_nr(ifd, file, file_magic,
-                                                     endian_mismatch, arch_64);
+               file_hdr->sa_cpu_nr = read_nr_value(ifd, file, file_magic,
+                                                   endian_mismatch, arch_64, TRUE);
+
+               /*
+                * We don't know if A_CPU activity will be displayed or not.
+                * But if it is the case, @nr_ini will be used in the loop
+                * to display all processors. So update its value here and
+                * reallocate buffers if needed.
+                */
+               p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
+               act[p]->nr_ini = file_hdr->sa_cpu_nr + 1;       /* Dont't forget to count CPU "all" */
+               if (act[p]->nr_ini > act[p]->nr_allocated) {
+                       reallocate_all_buffers(act[p]);
+               }
 
                if (!dp)
                        return 0;
index f1266036e3177ccbac886e8b15e90444a17b8571..ffd9bc248333abefbf3ce0851e454ad785211db9 100644 (file)
--- a/sa_wrap.c
+++ b/sa_wrap.c
 extern unsigned int flags;
 extern struct record_header record_hdr;
 
+/*
+ ***************************************************************************
+ * Reallocate buffer where statistics will be saved. The new size is the
+ * double of the original one.
+ * This is typically called when we find that current buffer is too small
+ * to save all the data.
+ ***************************************************************************
+ */
+void reallocate_buffer(struct activity *a)
+{
+       SREALLOC(a->_buf0, void,
+                (size_t) a->msize * (size_t) a->nr_allocated * 2);     /* a->nr2 value is 1 */
+       memset(a->_buf0, 0, (size_t) a->msize * (size_t) a->nr_allocated * 2);
+
+       a->nr_allocated *= 2;   /* NB: nr_allocated > 0 */
+}
+
 /*
  ***************************************************************************
  * Read CPU statistics.
@@ -45,9 +62,20 @@ __read_funct_t wrap_read_stat_cpu(struct activity *a)
 {
        struct stats_cpu *st_cpu
                = (struct stats_cpu *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read CPU statistics */
-       read_stat_cpu(st_cpu, a->nr);
+       do {
+               nr_read = read_stat_cpu(st_cpu, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -89,9 +117,20 @@ __read_funct_t wrap_read_stat_irq(struct activity *a)
 {
        struct stats_irq *st_irq
                = (struct stats_irq *) a->_buf0;
+       __nr_t nr_read;
 
        /* Read interrupts stats */
-       read_stat_irq(st_irq, a->nr);
+       do {
+               nr_read = read_stat_irq(st_irq, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -221,9 +260,21 @@ __read_funct_t wrap_read_disk(struct activity *a)
 {
        struct stats_disk *st_disk
                = (struct stats_disk *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read stats from /proc/diskstats */
-       read_diskstats_disk(st_disk, a->nr, COLLECT_PARTITIONS(a->opt_flags));
+       do {
+               nr_read = read_diskstats_disk(st_disk, a->nr_allocated,
+                                             COLLECT_PARTITIONS(a->opt_flags));
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -243,9 +294,20 @@ __read_funct_t wrap_read_tty_driver_serial(struct activity *a)
 {
        struct stats_serial *st_serial
                = (struct stats_serial *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read serial lines stats */
-       read_tty_driver_serial(st_serial, a->nr);
+       do {
+               nr_read = read_tty_driver_serial(st_serial, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -287,16 +349,27 @@ __read_funct_t wrap_read_net_dev(struct activity *a)
 {
        struct stats_net_dev *st_net_dev
                = (struct stats_net_dev *) a->_buf0;
-       int dev;
+       __nr_t nr_read = 0;
 
        /* Read network interfaces stats */
-       dev = read_net_dev(st_net_dev, a->nr);
-       if (!dev)
+       do {
+               nr_read = read_net_dev(st_net_dev, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
+
+       if (!nr_read)
                /* No data read. Exit */
                return;
 
        /* Read duplex and speed info for each interface */
-       read_if_info(st_net_dev, dev);
+       read_if_info(st_net_dev, nr_read);
 
        return;
 }
@@ -316,9 +389,20 @@ __read_funct_t wrap_read_net_edev(struct activity *a)
 {
        struct stats_net_edev *st_net_edev
                = (struct stats_net_edev *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read network interfaces errors stats */
-       read_net_edev(st_net_edev, a->nr);
+       do {
+               nr_read = read_net_edev(st_net_edev, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -690,9 +774,20 @@ __read_funct_t wrap_read_cpuinfo(struct activity *a)
 {
        struct stats_pwr_cpufreq *st_pwr_cpufreq
                = (struct stats_pwr_cpufreq *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read CPU frequency stats */
-       read_cpuinfo(st_pwr_cpufreq, a->nr);
+       do {
+               nr_read = read_cpuinfo(st_pwr_cpufreq, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -712,9 +807,20 @@ __read_funct_t wrap_read_fan(struct activity *a)
 {
        struct stats_pwr_fan *st_pwr_fan
                = (struct stats_pwr_fan *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read fan stats */
-       read_fan(st_pwr_fan, a->nr);
+       do {
+               nr_read = read_fan(st_pwr_fan, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -734,9 +840,20 @@ __read_funct_t wrap_read_temp(struct activity *a)
 {
        struct stats_pwr_temp *st_pwr_temp
                = (struct stats_pwr_temp *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read temperature stats */
-       read_temp(st_pwr_temp, a->nr);
+       do {
+               nr_read = read_temp(st_pwr_temp, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -756,9 +873,20 @@ __read_funct_t wrap_read_in(struct activity *a)
 {
        struct stats_pwr_in *st_pwr_in
                = (struct stats_pwr_in *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read voltage input stats */
-       read_in(st_pwr_in, a->nr);
+       do {
+               nr_read = read_in(st_pwr_in, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -796,42 +924,30 @@ __read_funct_t wrap_read_meminfo_huge(struct activity *a)
  * @a  Activity structure with statistics.
  ***************************************************************************
  */
-__read_funct_t wrap_read_time_in_state(struct activity *a)
+__read_funct_t wrap_read_cpu_wghfreq(struct activity *a)
 {
-       __nr_t  cpu = 0;
-       int j;
        struct stats_pwr_wghfreq *st_pwr_wghfreq
                = (struct stats_pwr_wghfreq *) a->_buf0;
-       struct stats_pwr_wghfreq *st_pwr_wghfreq_i, *st_pwr_wghfreq_j, *st_pwr_wghfreq_all_j;
-
-       while (cpu < (a->nr - 1)) {
-               /* Read current CPU time-in-state data */
-               st_pwr_wghfreq_i = st_pwr_wghfreq + (cpu + 1) * a->nr2;
-               read_time_in_state(st_pwr_wghfreq_i, cpu, a->nr2);
-
-               /* Also save data for CPU 'all' */
-               for (j = 0; j < a->nr2; j++) {
-                       st_pwr_wghfreq_j     = st_pwr_wghfreq_i + j;    /* CPU #cpu, state #j */
-                       st_pwr_wghfreq_all_j = st_pwr_wghfreq   + j;    /* CPU #all, state #j */
-                       if (!cpu) {
-                               /* Assume that possible frequencies are the same for all CPUs */
-                               st_pwr_wghfreq_all_j->freq = st_pwr_wghfreq_j->freq;
-                       }
-                       st_pwr_wghfreq_all_j->time_in_state += st_pwr_wghfreq_j->time_in_state;
-               }
-               cpu++;
-       }
+       __nr_t  nr_read = 0;
 
-       /* Special processing for non SMP kernels: Only CPU 'all' is available */
-       if (a->nr == 1) {
-               read_time_in_state(st_pwr_wghfreq, 0, a->nr2);
-       }
-       else {
-               for (j = 0; j < a->nr2; j++) {
-                       st_pwr_wghfreq_all_j = st_pwr_wghfreq + j;      /* CPU #all, state #j */
-                       st_pwr_wghfreq_all_j->time_in_state /= (a->nr - 1);
+       /* Read weighted CPU frequency statistics */
+       do {
+               nr_read = read_cpu_wghfreq(st_pwr_wghfreq, a->nr_allocated, a->nr2);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       SREALLOC(a->_buf0, void,
+                                (size_t) a->msize * (size_t) a->nr2 * (size_t) a->nr_allocated * 2);
+                       memset(a->_buf0, 0,
+                              (size_t) a->msize * (size_t) a->nr2 * (size_t) a->nr_allocated * 2);
+
+                       /* NB: nr_allocated > 0 */
+                       a->nr_allocated *= 2;
                }
        }
+       while(nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -851,9 +967,20 @@ __read_funct_t wrap_read_bus_usb_dev(struct activity *a)
 {
        struct stats_pwr_usb *st_pwr_usb
                = (struct stats_pwr_usb *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read USB devices stats */
-       read_bus_usb_dev(st_pwr_usb, a->nr);
+       do {
+               nr_read = read_bus_usb_dev(st_pwr_usb, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -873,9 +1000,20 @@ __read_funct_t wrap_read_filesystem(struct activity *a)
 {
        struct stats_filesystem *st_filesystem
                = (struct stats_filesystem *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read filesystems from /etc/mtab */
-       read_filesystem(st_filesystem, a->nr);
+       do {
+               nr_read = read_filesystem(st_filesystem, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -895,8 +1033,20 @@ __read_funct_t wrap_read_fchost(struct activity *a)
 {
        struct stats_fchost *st_fc
                = (struct stats_fchost *) a->_buf0;
+       __nr_t nr_read = 0;
 
-       read_fchost(st_fc, a->nr);
+       /* Read FC hosts statistics */
+       do {
+               nr_read = read_fchost(st_fc, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -916,9 +1066,20 @@ __read_funct_t wrap_read_softnet(struct activity *a)
 {
        struct stats_softnet *st_softnet
                = (struct stats_softnet *) a->_buf0;
+       __nr_t nr_read = 0;
 
        /* Read softnet stats */
-       read_softnet(st_softnet, a->nr);
+       do {
+               nr_read = read_softnet(st_softnet, a->nr_allocated);
+
+               if (nr_read < 0) {
+                       /* Buffer needs to be reallocated */
+                       reallocate_buffer(a);
+               }
+       }
+       while (nr_read < 0);
+
+       a->_nr0 = nr_read;
 
        return;
 }
@@ -1009,8 +1170,8 @@ __nr_t wrap_get_iface_nr(struct activity *a)
  *
  * RETURNS:
  * Number of structures (value in [1, NR_CPUS + 1]).
- * 1 means that there is only one proc and non SMP kernel.
- * 2 means one proc and SMP kernel.
+ * 1 means that there is only one proc and non SMP kernel (CPU "all").
+ * 2 means one proc and SMP kernel (CPU "all" and CPU 0).
  * Etc.
  ***************************************************************************
  */
diff --git a/sadc.c b/sadc.c
index 89fb934ef547b0969c4089f8dbc32c6ce3a87bba..0e59a26fdb8c92f171451b46bc23fd2d56506a5f 100644 (file)
--- a/sadc.c
+++ b/sadc.c
@@ -278,25 +278,38 @@ void p_write_error(void)
  * Init structures. All of them are init'ed first when they are allocated
  * (done by SREALLOC() macro in sa_sys_init() function).
  * Then, they are init'ed again each time before reading the various system
- * stats to make sure that no stats from a previous reading will remain (eg.
- * if some network interfaces or block devices have been unregistered).
+ * stats to make sure that no stats from a previous reading will remain.
+ * This is useful mainly for non sequential activities where some structures
+ * may remain unchanged. Such an activity is A_CPU, for which statistics
+ * for offline CPU won't be read and their corresponding stats structure
+ * won't be overwritten, giving the idea they are still online if we don't
+ * reset their structures to zero.
+ * Other activities may also assume that structure's fields are initialized
+ * when their stats are read.
  ***************************************************************************
  */
 void reset_stats(void)
 {
        int i;
 
-       for (i = 0; i < NR_ACT; i++) {
+        for (i = 0; i < NR_ACT; i++) {
                if ((act[i]->nr > 0) && act[i]->_buf0) {
                        memset(act[i]->_buf0, 0,
-                              (size_t) act[i]->msize * (size_t) act[i]->nr * (size_t) act[i]->nr2);
+                              (size_t) act[i]->msize * (size_t) act[i]->nr_allocated * (size_t) act[i]->nr2);
                }
        }
 }
 
 /*
  ***************************************************************************
- * Allocate and init structures, according to system state.
+ * Count activities items then allocate and init corresponding structures.
+ * ALL activities are always counted (thus the number of CPU will always be
+ * counted even if CPU activity is not collected), but ONLY those that will
+ * be collected have allocated structures.
+ * This function is called when sadc is started, and when a file is rotated.
+ * If a file is rotated and structures are reallocated with a larger size,
+ * additional space is not initialized: It doesn't matter as reset_stats()
+ * will do it later.
  ***************************************************************************
  */
 void sa_sys_init(void)
@@ -316,31 +329,33 @@ void sa_sys_init(void)
 
                        /* Number of items is not a constant and should be calculated */
                        if (f_count_results[idx] >= 0) {
-                               act[i]->nr = f_count_results[idx];
+                               act[i]->nr_ini = f_count_results[idx];
                        }
                        else {
-                               act[i]->nr = (f_count[idx])(act[i]);
-                               f_count_results[idx] = act[i]->nr;
+                               act[i]->nr_ini = (f_count[idx])(act[i]);
+                               f_count_results[idx] = act[i]->nr_ini;
                        }
                }
 
-               if (act[i]->nr > 0) {
+               if (act[i]->nr_ini > 0) {
                        if (act[i]->f_count2) {
                                act[i]->nr2 = (*act[i]->f_count2)(act[i]);
                        }
                        /* else act[i]->nr2 is a constant and doesn't need to be calculated */
 
                        if (!act[i]->nr2) {
-                               act[i]->nr = 0;
+                               act[i]->nr_ini = 0;
                        }
                }
 
-               if (act[i]->nr > 0) {
-                       /* Allocate structures for current activity */
+               if (IS_COLLECTED(act[i]->options) && (act[i]->nr_ini > 0)) {
+                       /* Allocate structures for current activity (using nr_ini and nr2 results) */
                        SREALLOC(act[i]->_buf0, void,
-                                (size_t) act[i]->msize * (size_t) act[i]->nr * (size_t) act[i]->nr2);
+                                (size_t) act[i]->msize * (size_t) act[i]->nr_ini * (size_t) act[i]->nr2);
+                       act[i]->nr_allocated = act[i]->nr_ini;
                }
-               else {
+
+               if (act[i]->nr_ini <= 0) {
                        /* No items found: Invalidate current activity */
                        act[i]->options &= ~AO_COLLECTED;
                }
@@ -361,10 +376,11 @@ void sa_sys_free(void)
 
        for (i = 0; i < NR_ACT; i++) {
 
-               if (act[i]->nr > 0) {
+               if (act[i]->nr_allocated > 0) {
                        if (act[i]->_buf0) {
                                free(act[i]->_buf0);
                                act[i]->_buf0 = NULL;
+                               act[i]->nr_allocated = 0;
                        }
                }
        }
@@ -522,11 +538,11 @@ void setup_file_hdr(int fd)
        /*
         * This is a new file (or stdout): Set sa_cpu_nr field to the number
         * of CPU of the machine (1 .. CPU_NR + 1). This is the number of CPU, whether
-        * online or offline, at the time of the first collected sample.
+        * online or offline, when sadc was started.
         * All activities (including A_CPU) are counted in sa_sys_init(), even
         * if they are not collected.
         */
-       file_hdr.sa_cpu_nr = act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr;
+       file_hdr.sa_cpu_nr = act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr_ini;
 
        /* Get system name, release number, hostname and machine architecture */
        uname(&header);
@@ -558,15 +574,16 @@ void setup_file_hdr(int fd)
                if (IS_COLLECTED(act[p]->options)) {
                        file_act.id    = act[p]->id;
                        file_act.magic = act[p]->magic;
-                       file_act.nr    = act[p]->nr;
+                       file_act.nr    = act[p]->nr_ini;
                        file_act.nr2   = act[p]->nr2;
                        file_act.size  = act[p]->fsize;
                        for (j = 0; j < 3; j++) {
                                file_act.types_nr[j] = act[p]->gtypes_nr[j];
                        }
 
-                       if (write_all(fd, &file_act, FILE_ACTIVITY_SIZE)
-                           != FILE_ACTIVITY_SIZE)
+                       file_act.has_nr = HAS_COUNT_FUNCTION(act[p]->options);
+
+                       if (write_all(fd, &file_act, FILE_ACTIVITY_SIZE) != FILE_ACTIVITY_SIZE)
                                goto write_error;
                }
        }
@@ -591,12 +608,10 @@ write_error:
 void write_new_cpu_nr(int ofd)
 {
        int p;
-       __nr_t cpu_nr;
 
        p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
-       cpu_nr = act[p]->nr;
 
-       if (write_all(ofd, &cpu_nr, sizeof(__nr_t)) != sizeof(__nr_t)) {
+       if (write_all(ofd, &(act[p]->nr_ini), sizeof(__nr_t)) != sizeof(__nr_t)) {
                p_write_error();
        }
 }
@@ -689,8 +704,13 @@ void write_stats(int ofd)
                        continue;
 
                if (IS_COLLECTED(act[p]->options)) {
-                       if (write_all(ofd, act[p]->_buf0, act[p]->fsize * act[p]->nr * act[p]->nr2) !=
-                           (act[p]->fsize * act[p]->nr * act[p]->nr2)) {
+                       if (act[p]->f_count_index >= 0) {
+                               if (write_all(ofd, &(act[p]->_nr0), sizeof(__nr_t)) != sizeof(__nr_t)) {
+                                       p_write_error();
+                               }
+                       }
+                       if (write_all(ofd, act[p]->_buf0, act[p]->fsize * act[p]->_nr0 * act[p]->nr2) !=
+                           (act[p]->fsize * act[p]->_nr0 * act[p]->nr2)) {
                                p_write_error();
                        }
                }
@@ -870,7 +890,8 @@ void open_ofile(int *ofd, char ofile[], int restart_mark)
                    (act[p]->magic != file_act[i].magic))
                        /*
                         * Unknown activity in list or item size has changed or
-                        * unknown activity format: Cannot append data to such a file.
+                        * unknown activity format: Cannot append data to such a file
+                        * ("strict writing" rule).
                         */
                        goto append_error;
 
@@ -891,6 +912,14 @@ void open_ofile(int *ofd, char ofile[], int restart_mark)
                         * be different from that known by current version.
                         */
                        goto append_error;
+
+               if ((file_act[i].has_nr && (act[p]->f_count_index < 0)) ||
+                   (!file_act[i].has_nr && (act[p]->f_count_index >=0)))
+                       /*
+                        * For every activity whose number of items is not a constant,
+                        * a value giving the number of structures to read should exist.
+                        */
+                       goto append_error;
        }
 
        /*
@@ -908,13 +937,14 @@ void open_ofile(int *ofd, char ofile[], int restart_mark)
                p = get_activity_position(act, file_act[i].id, EXIT_IF_NOT_FOUND);
 
                /*
-                * Force number of items (serial lines, network interfaces...)
-                * and sub-items to that of the file, and reallocate structures.
+                * Force number of sub-items to that of the file, and reallocate structures.
+                * We don't care for items as their structures will be dynamically allocated.
                 */
-               act[p]->nr  = file_act[i].nr;
-               act[p]->nr2 = file_act[i].nr2;
-               SREALLOC(act[p]->_buf0, void,
-                        (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
+               if (file_act[i].nr2 != act[p]->nr2) {
+                       act[p]->nr2 = file_act[i].nr2;
+                       SREALLOC(act[p]->_buf0, void,
+                                (size_t) act[p]->msize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
+               }
 
                /* Save activity sequence */
                id_seq[i] = file_act[i].id;
@@ -985,11 +1015,7 @@ void rw_sa_stat_loop(long count, int stdfd, int ofd, char ofile[],
        /* Main loop */
        do {
 
-               /*
-                * Init all structures.
-                * Exception for individual CPUs structures which must not be
-                * init'ed to keep values for CPU before they were disabled.
-                */
+               /* Init all structures */
                reset_stats();
 
                /* Save time */
diff --git a/sar.c b/sar.c
index cde7e77972b07bffedde215a0bc0dfd612b5d919..6a5d02140a8a27e64963d6e52cd3d4eed95ff173 100644 (file)
--- a/sar.c
+++ b/sar.c
@@ -334,7 +334,7 @@ int check_line_hdr(void)
                                        rc = TRUE;
                                }
                        }
-                       else if (act[i]->nr > 1) {
+                       else if (act[i]->nr_ini > 1) {
                                rc = TRUE;
                        }
                        /* Stop now since we have only one selected activity */
@@ -378,7 +378,7 @@ void write_stats_avg(int curr, int read_from_file, unsigned int act_id)
                if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
                        continue;
 
-               if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
+               if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
                        /* Display current average activity statistics */
                        (*act[i]->f_print_avg)(act[i], 2, curr, itv);
                }
@@ -396,6 +396,7 @@ void write_stats_avg(int curr, int read_from_file, unsigned int act_id)
 /*
  ***************************************************************************
  * Print system statistics.
+ * This is called when we read stats either from a file or from sadc.
  *
  * IN:
  * @curr               Index in array for current sample statistics.
@@ -505,7 +506,7 @@ int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start,
                if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
                        continue;
 
-               if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
+               if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
                        /* Display current activity statistics */
                        (*act[i]->f_print)(act[i], !curr, curr, itv);
                }
@@ -535,9 +536,16 @@ void write_stats_startup(int curr)
        record_hdr[!curr].ust_time    = record_hdr[curr].ust_time;
 
        for (i = 0; i < NR_ACT; i++) {
-               if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
+               if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
+                       /*
+                        * Using nr[curr] and not nr[!curr] below because we initialize
+                        * reference structures for each structure that has been
+                        * currently read in memory.
+                        * No problem with buffers allocation since they all have the
+                        * same size.
+                        */
                        memset(act[i]->buf[!curr], 0,
-                              (size_t) act[i]->msize * (size_t) act[i]->nr * (size_t) act[i]->nr2);
+                              (size_t) act[i]->msize * (size_t) act[i]->nr[curr] * (size_t) act[i]->nr2);
                }
        }
 
@@ -662,7 +670,29 @@ void read_sadc_stat_bunch(int curr)
                        continue;
                p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
 
-               if (sa_read(act[p]->buf[curr], act[p]->fsize * act[p]->nr * act[p]->nr2)) {
+               if (HAS_COUNT_FUNCTION(act[p]->options)) {
+                       if (sa_read(&(act[p]->nr[curr]), sizeof(__nr_t))) {
+                               print_read_error(END_OF_DATA_UNEXPECTED);
+                       }
+                       if (act[p]->nr[curr] > act[p]->nr_max) {
+                               print_read_error(INCONSISTENT_INPUT_DATA);
+                       }
+                       if (act[p]->nr[curr] > act[p]->nr_allocated) {
+                               reallocate_all_buffers(act[p]);
+                       }
+
+
+                       /*
+                        * For persistent activities, we must make sure that no statistics
+                         * from a previous iteration remain, especially if the number
+                         * of structures read is smaller than @nr_ini.
+                         */
+                        if (HAS_PERSISTENT_VALUES(act[p]->options)) {
+                            memset(act[p]->buf[curr], 0,
+                                   (size_t) act[p]->fsize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
+                        }
+                }
+               if (sa_read(act[p]->buf[curr], act[p]->fsize * act[p]->nr[curr] * act[p]->nr2)) {
                        print_read_error(END_OF_DATA_UNEXPECTED);
                }
        }
@@ -725,7 +755,7 @@ void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf
                                 BITMAP_SIZE(act[p]->bitmap->b_size));
        }
        else {
-               inc = act[p]->nr;
+               inc = act[p]->nr[*curr];
        }
 
        reset_cd = 1;
@@ -742,7 +772,7 @@ void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf
                if (!*eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
                        /* Read the extra fields since it's not a special record */
                        read_file_stat_bunch(act, *curr, ifd, file_hdr.sa_act_nr, file_actlst,
-                                            endian_mismatch, arch_64);
+                                            endian_mismatch, arch_64, file, file_magic);
                }
 
                if ((lines >= rows) || !lines) {
@@ -869,9 +899,9 @@ void read_header_data(void)
                        print_read_error(INCONSISTENT_INPUT_DATA);
                }
 
-               id_seq[i]   = file_act.id;      /* We necessarily have "i < NR_ACT" */
-               act[p]->nr  = file_act.nr;
-               act[p]->nr2 = file_act.nr2;
+               id_seq[i]      = file_act.id;   /* We necessarily have "i < NR_ACT" */
+               act[p]->nr_ini = file_act.nr;
+               act[p]->nr2    = file_act.nr2;
        }
 
        while (i < NR_ACT) {
@@ -942,7 +972,8 @@ void read_stats_from_file(char from_file[])
                                 * So read now the extra fields.
                                 */
                                read_file_stat_bunch(act, 0, ifd, file_hdr.sa_act_nr,
-                                                    file_actlst, endian_mismatch, arch_64);
+                                                    file_actlst, endian_mismatch, arch_64,
+                                                    from_file, &file_magic);
                                if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME,
                                                                   &record_hdr[0],
                                                                   &rectime, NULL))
@@ -971,6 +1002,10 @@ void read_stats_from_file(char from_file[])
                /*
                 * Read and write stats located between two possible Linux restarts.
                 * Activities that should be displayed are saved in id_seq[] array.
+                * Since we are reading from a file, we print all the stats for an
+                * activity before displaying the next activity.
+                * id_seq[] has been created in check_file_actlst(), retaining only
+                * activities known by current sysstat version.
                 */
                for (i = 0; i < NR_ACT; i++) {
 
@@ -1016,7 +1051,8 @@ void read_stats_from_file(char from_file[])
 
                                if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
                                        read_file_stat_bunch(act, curr, ifd, file_hdr.sa_act_nr,
-                                                            file_actlst, endian_mismatch, arch_64);
+                                                            file_actlst, endian_mismatch, arch_64,
+                                                            from_file, &file_magic);
                                }
                                else if (!eosaf && (rtype == R_COMMENT)) {
                                        /* This was a COMMENT record: print it */