/*
* mpstat: per-processor statistics
* (C) 2000-2022 by Sebastien GODARD (sysstat <at> orange.fr)
- * Copyright (c) 2022, Oracle and/or its affiliates.
++ * Copyright (C) 2022 Oracle and/or its affiliates.
*
***************************************************************************
* This program is free software; you can redistribute it and/or modify it *
unsigned long long uptime_cs[3] = {0, 0, 0};
/* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/
--unsigned char *cpu_bitmap; /* Bit 0: Global; Bit 1: 1st proc; etc. */
--unsigned char *node_bitmap; /* Bit 0: Global; Bit 1: 1st NUMA node; etc. */
++unsigned char *cpu_bitmap = NULL; /* Bit 0: Global; Bit 1: 1st proc; etc. */
++unsigned char *node_bitmap = NULL; /* Bit 0: Global; Bit 1: 1st NUMA node; etc. */
/* Structures used to save CPU and NUMA nodes CPU stats */
--struct stats_cpu *st_cpu[3];
--struct stats_cpu *st_node[3];
++struct stats_cpu *st_cpu[3] = {NULL, NULL, NULL};
++struct stats_cpu *st_node[3] = {NULL, NULL, NULL};
/*
* Structure used to save total number of interrupts received
* among all CPU and for each CPU.
*/
--struct stats_global_irq *st_irq[3];
++struct stats_global_irq *st_irq[3] = {NULL, NULL, NULL};
/*
* Structures used to save, for each interrupt, the number
* received by each CPU.
*/
--struct stats_irqcpu *st_irqcpu[3];
--struct stats_irqcpu *st_softirqcpu[3];
++struct stats_irqcpu *st_irqcpu[3] = {NULL, NULL, NULL};
++struct stats_irqcpu *st_softirqcpu[3] = {NULL, NULL, NULL};
/*
* Number of CPU per node, e.g.:
* cpu_per_node[1]: nr of CPU for node 0
* etc.
*/
--int *cpu_per_node;
++int *cpu_per_node = NULL;
/*
* Node number the CPU belongs to, e.g.:
* cpu2node[0]: node nr for CPU 0
*/
--int *cpu2node;
++int *cpu2node = NULL;
/* CPU topology */
--struct cpu_topology *st_cpu_topology;
++struct cpu_topology *st_cpu_topology = NULL;
struct tm mp_tstamp[3];
progname);
fprintf(stderr, _("Options are:\n"
- "[ -A ] [ -n ] [ -T ] [ -u ] [ -V ]\n"
- "[ -A ] [ -n ] [ -T ] [ -u ] [ -V ] [ -H ]\n"
++ "[ -A ] [ -H ] [ -n ] [ -T ] [ -u ] [ -V ]\n"
"[ -I { SUM | CPU | SCPU | ALL } ] [ -N { <node_list> | ALL } ]\n"
"[ --dec={ 0 | 1 | 2 } ] [ -o JSON ] [ -P { <cpu_list> | ALL } ]\n"));
exit(1);
* IN:
* @nr_cpus Number of CPUs. This is the real number of available CPUs + 1
* because we also have to allocate a structure for CPU 'all'.
- * @reset reset the memory only when set to TRUE
++ * @reset Reset the memory only when set to TRUE.
***************************************************************************
*/
- void salloc_mp_struct(int nr_cpus)
+ void salloc_mp_struct(int nr_cpus, int reset)
{
int i;
for (i = 0; i < 3; i++) {
- if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
+ if ((st_cpu[i] = (struct stats_cpu *) realloc(st_cpu[i], STATS_CPU_SIZE * nr_cpus))
== NULL) {
- perror("malloc");
+ perror("realloc");
exit(4);
}
- memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
- if ((st_node[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
+ if ((st_node[i] = (struct stats_cpu *) realloc(st_node[i], STATS_CPU_SIZE * nr_cpus))
== NULL) {
- perror("malloc");
+ perror("realloc");
exit(4);
}
- memset(st_node[i], 0, STATS_CPU_SIZE * nr_cpus);
- if ((st_irq[i] = (struct stats_global_irq *) malloc(STATS_GLOBAL_IRQ_SIZE * nr_cpus))
- if ((st_irq[i] = (struct stats_global_irq *) realloc(st_irq[i], STATS_GLOBAL_IRQ_SIZE * nr_cpus))
++ if ((st_irq[i] = (struct stats_global_irq *) realloc(st_irq[i],
++ STATS_GLOBAL_IRQ_SIZE * nr_cpus))
== NULL) {
- perror("malloc");
+ perror("realloc");
exit(4);
}
- memset(st_irq[i], 0, STATS_GLOBAL_IRQ_SIZE * nr_cpus);
- if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
- if ((st_irqcpu[i] = (struct stats_irqcpu *) realloc(st_irqcpu[i], STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
++ if ((st_irqcpu[i] = (struct stats_irqcpu *) realloc(st_irqcpu[i],
++ STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
== NULL) {
- perror("malloc");
+ perror("realloc");
exit(4);
}
- memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
- if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
- if ((st_softirqcpu[i] = (struct stats_irqcpu *) realloc(st_softirqcpu[i], STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
++ if ((st_softirqcpu[i] = (struct stats_irqcpu *) realloc(st_softirqcpu[i],
++ STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
== NULL) {
- perror("malloc");
+ perror("realloc");
exit(4);
}
- memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
}
- if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
- perror("malloc");
+ if ((cpu_bitmap = (unsigned char *) realloc(cpu_bitmap, (nr_cpus >> 3) + 1)) == NULL) {
+ perror("realloc");
exit(4);
}
- memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
- if ((node_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
- perror("malloc");
+ if ((node_bitmap = (unsigned char *) realloc(node_bitmap, (nr_cpus >> 3) + 1)) == NULL) {
+ perror("realloc");
exit(4);
}
- memset(node_bitmap, 0, (nr_cpus >> 3) + 1);
- if ((cpu_per_node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
- perror("malloc");
+ if ((cpu_per_node = (int *) realloc(cpu_per_node, sizeof(int) * nr_cpus)) == NULL) {
+ perror("realloc");
exit(4);
}
exit(4);
}
- if ((st_cpu_topology = (struct cpu_topology *) malloc(sizeof(struct cpu_topology) * nr_cpus)) == NULL) {
- perror("malloc");
- if ((st_cpu_topology = (struct cpu_topology *) realloc(st_cpu_topology, sizeof(struct cpu_topology) * nr_cpus)) == NULL) {
++ if ((st_cpu_topology = (struct cpu_topology *) realloc(st_cpu_topology,
++ sizeof(struct cpu_topology) * nr_cpus)) == NULL) {
+ perror("realloc");
exit(4);
}
+
+ if (reset == TRUE) {
+ for (i = 0; i < 3; i++) {
+ memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
+ memset(st_node[i], 0, STATS_CPU_SIZE * nr_cpus);
+ memset(st_irq[i], 0, STATS_GLOBAL_IRQ_SIZE * nr_cpus);
+ memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
+ memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
+ }
+ memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
+ memset(node_bitmap, 0, (nr_cpus >> 3) + 1);
+ }
}
/*
* IN:
* @dis_hdr Set to TRUE if the header line must always be printed.
* @rows Number of rows of screen.
- * OUT:
- * @new_cpu_nr Return 0 as default.
- * Return new_cpu_nr (!=0) if physical vCPU hotplug occured.
+ *
++ * RETURNS:
++ * Total number of physical CPUs if a least one new (virtual) CPU has been
++ * hotplugged, and 0 otherwise.
***************************************************************************
*/
- void rw_mpstat_loop(int dis_hdr, int rows)
+ int rw_mpstat_loop(int dis_hdr, int rows)
{
struct stats_cpu *scc;
-- int i;
++ int i, new_cpu_nr;
int curr = 1, dis = 1;
- int new_cpu_nr = 0;
unsigned long lines = rows;
/* Read system uptime and CPU stats */
curr ^= 1;
}
}
- /* -H option is given and vCPU physical hotplug occured */
- if (USE_OPTION_H(flags)) {
+
- if (new_cpu_nr > cpu_nr) {
++ if (count && USE_OPTION_H(flags)) {
++ /* Check if a vCPU has been physically hotplugged */
+ new_cpu_nr = get_cpu_nr(~0, TRUE);
- }
++ if (new_cpu_nr > cpu_nr)
+ return new_cpu_nr;
+ }
}
while (count);
else {
write_stats_avg(curr, dis_hdr);
}
- * Detect physical vCPU hotplug and call rw_mpstat_loop to display stats
+ return 0;
+ }
+
+ /*
+ ***************************************************************************
- int new_cpu_nr = 0;
++ * Start mpstat loop until end of count or when a vCPU has been physically
++ * hotplugged.
+ *
+ * IN:
+ * @dis_hdr Set to TRUE if the header line must always be printed.
+ * @rows Number of rows of screen.
+ ***************************************************************************
+ */
+ void mpstat_loop(int dis_hdr, int rows)
+ {
- while (1) {
++ int new_cpu_nr = 1;
+
- if (new_cpu_nr == 0) {
- return;
- }
- else {
++ while (new_cpu_nr) {
+ /* Main loop for reading-writing stats */
+ new_cpu_nr = rw_mpstat_loop(dis_hdr, rows);
+
+ /* Handle vCPU physical hotplug */
- NR_IRQCPU_PREALLOC;
++ if (new_cpu_nr) {
+ /* Update the highest processor number */
+ cpu_nr = new_cpu_nr;
+
+ /* Recalculate number of interrupts per processor */
+ irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
++ NR_IRQCPU_PREALLOC;
+ /* Recalculate number of soft interrupts per processor */
+ softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
+ NR_IRQCPU_PREALLOC;
+
+ /*
+ * Reallocate cpu stats structs :
+ * global, proc0, proc1, ..., proc$(prev_cpu_nr-1).
+ * global, proc0, proc1, ..., proc$(prev_cpu_nr-1), ..., proc$(cpu_nr-1).
+ */
+ salloc_mp_struct(cpu_nr + 1, FALSE);
+
+ /* Get NUMA node placement */
+ node_nr = get_node_placement(cpu_nr, cpu_per_node, cpu2node);
+ }
+ }
}
/*
actset = TRUE;
break;
++ case 'H':
++ /* Display physically hotplugged vCPU */
++ flags |= F_OPTION_H;
++ break;
++
case 'n':
/* Display CPU stats based on NUMA node placement */
if (node_nr >= 0) {