.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
.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,
#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,
.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,
.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,
.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,
.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,
.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,
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
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
/* 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) {
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);
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
__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");
}
}
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 */
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 */
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 */
{
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
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
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;
}
/* Array of CPU frequency no longer needed: Free it! */
free(avg_cpufreq);
avg_cpufreq = NULL;
+ nr_alloc = 0;
}
}
{
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]);
free(avg_fan_min);
avg_fan = NULL;
avg_fan_min = NULL;
+ nr_alloc = 0;
}
}
{
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]);
avg_temp = NULL;
avg_temp_min = NULL;
avg_temp_max = NULL;
+ nr_alloc = 0;
}
}
{
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]);
avg_in = NULL;
avg_in_min = NULL;
avg_in_max = NULL;
+ nr_alloc = 0;
}
}
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
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,
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) &&
*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;
}
}
}
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,
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) ||
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;
+ }
}
}
}
__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,
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
*
* 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;
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))) {
}
}
}
- count++;
}
}
}
+
+ return fan_read;
+#else
+ return 0;
#endif /* HAVE_SENSORS */
}
*
* 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;
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))) {
}
}
}
- count++;
}
}
}
+
+ return temp_read;
+#else
+ return 0;
#endif /* HAVE_SENSORS */
}
*
* 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;
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))) {
}
}
}
- count++;
}
}
}
+
+ return in_read;
+#else
+ return 0;
#endif /* HAVE_SENSORS */
}
#define _RD_SENSORS_H
#include "common.h"
+#include "rd_stats.h"
/*
***************************************************************************
***************************************************************************
*/
-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);
/*
***************************************************************************
/*
***************************************************************************
* 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));
&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) {
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;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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];
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",
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;
/* Read nr of tasks blocked from /proc/stat */
if ((fp = fopen(STAT, "r")) == NULL)
- return;
+ return 0;
while (fgets(line, sizeof(line), fp) != NULL) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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;
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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",
/* 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;
}
fclose(fp);
+ return dsk_read;
}
/*
*
* 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)++;
/*
if ((p = strstr(line, "oe:")) != NULL) {
sscanf(p + 3, "%u", &st_serial_i->overrun);
}
-
- sl++;
}
}
fclose(fp);
+ return sl_read;
}
/*
*
* 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;
st_ktables->pty_nr = 0;
}
}
+
+ return 1;
}
/*
*
* 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 */
&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;
}
/*
*
* 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.
*
* 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 */
&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;
}
/*
*
* 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);
}
fclose(fp);
+ return 1;
}
/*
*
* 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);
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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];
int sw = FALSE;
if ((fp = fopen(NET_SNMP, "r")) == NULL)
- return;
+ return 0;
while (fgets(line, sizeof(line), fp) != NULL) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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) {
}
fclose(fp);
+ return 1;
}
/*
*
* 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 */
!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;
}
}
}
/* Compute average CPU frequency for this machine */
st_pwr_cpufreq->cpufreq /= nr;
}
+ return cpu_read;
}
/*
*
* 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) {
/* 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;
}
/*
*
* 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;
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) {
}
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;
}
/*
*
* 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;
}
/*
*
* 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
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;
}
fclose(fp);
+ return fs_read;
}
/*
*
* 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"))) {
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;
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;
}
/*
*
* 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".
*/
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,
}
fclose(fp);
+ return cpu_read;
}
/*------------------ END: FUNCTIONS USED BY SADC ONLY ---------------------*/
#ifndef _RD_STATS_H
#define _RD_STATS_H
-
/*
***************************************************************************
* Miscellaneous constants
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 */
/*
***************************************************************************
- * 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:
* __
* | |
* | 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
/*
* 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)));
/*
*/
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.
*/
#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 */
#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 {
*/
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
* 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
(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 *);
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
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;
}
}
}
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.
* 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.
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;
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.
*/
return -2;
- return index;
+ return j;
}
- index++;
+ j++;
}
+ while (j != j0);
/* This is a newly registered interface */
return -1;
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)) {
/*
/* Same device registered again */
return -2;
- return index;
+ return j;
}
- index++;
+ j++;
}
+ while (j != j0);
/* This is a newly registered device */
return -1;
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];
}
}
* @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);
}
* 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,
/* 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);
}
}
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;
/* 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 */
/*
* 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);
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.
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))
/*
***************************************************************************
- * 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.
* @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;
}
/*
/*
***************************************************************************
* 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.
{
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))
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;
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.
{
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;
}
{
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;
}
{
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;
}
{
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;
}
{
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;
}
{
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;
}
{
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;
}
{
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;
}
{
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;
}
{
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;
}
* @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;
}
{
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;
}
{
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;
}
{
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;
}
{
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;
}
*
* 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.
***************************************************************************
*/
* 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)
/* 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;
}
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;
}
}
}
/*
* 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);
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;
}
}
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();
}
}
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();
}
}
(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;
* 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;
}
/*
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;
/* 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 */
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 */
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);
}
/*
***************************************************************************
* 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.
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);
}
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);
}
}
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);
}
}
BITMAP_SIZE(act[p]->bitmap->b_size));
}
else {
- inc = act[p]->nr;
+ inc = act[p]->nr[*curr];
}
reset_cd = 1;
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) {
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) {
* 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))
/*
* 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++) {
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 */