From: Sebastien GODARD Date: Sun, 9 Oct 2022 15:06:26 +0000 (+0200) Subject: Merge branch 'shaleen-bathla-master' X-Git-Tag: v12.7.1~10 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f500355f6a878b8bf902de14464997dba8a72722;p=sysstat Merge branch 'shaleen-bathla-master' Signed-off-by: Sebastien GODARD --- f500355f6a878b8bf902de14464997dba8a72722 diff --cc man/mpstat.1 index 08e45a5,31ad487..29086c7 --- a/man/mpstat.1 +++ b/man/mpstat.1 @@@ -1,10 -1,10 +1,10 @@@ .\" mpstat manual page - (C) 2000-2020 Sebastien Godard (sysstat orange.fr) --.TH MPSTAT 1 "AUGUST 2020" Linux "Linux User's Manual" -*- nroff -*- ++.TH MPSTAT 1 "OCTOBER 2022" Linux "Linux User's Manual" -*- nroff -*- .SH NAME mpstat \- Report processors related statistics. .SH SYNOPSIS - .B mpstat [ -A ] [ --dec={ 0 | 1 | 2 } ] [ -n ] [ -u ] [ -T ] [ -V ] [ -I { -.B mpstat [ -A ] [ --dec={ 0 | 1 | 2 } ] [ -n ] [ -u ] [ -T ] [ -V ] [ -H ] [ -I { ++.B mpstat [ -A ] [ --dec={ 0 | 1 | 2 } ] [ -H ] [ -n ] [ -u ] [ -T ] [ -V ] [ -I { .IB "keyword" "[,...] | ALL } ] [ -N { " "node_list " "| ALL } ] [ -o JSON ] [ -P {" .IB "cpu_list " "| ALL } ] [ " "interval " "[ " "count " "] ]" @@@ -44,6 -44,8 +44,9 @@@ unless these options are explicitly se .B --dec={ 0 | 1 | 2 } Specify the number of decimal places to use (0 to 2, default value is 2). .TP + .B -H -Detect and Display stats of physically hotplugged vCPUs also ++Also detect and display statistics for physically hotplugged vCPUs. ++.TP .BI "-I { " "keyword" "[,...] | ALL }" Report interrupts statistics. .RI "Possible " "keywords " "are" diff --cc mpstat.c index 1032410,8f7957d..ab478c5 --- a/mpstat.c +++ b/mpstat.c @@@ -1,6 -1,7 +1,7 @@@ /* * mpstat: per-processor statistics * (C) 2000-2022 by Sebastien GODARD (sysstat 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 * @@@ -49,25 -50,25 +50,25 @@@ char *sccsid(void) { return (SCCSID); 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.: @@@ -75,16 -76,16 +76,16 @@@ * 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]; @@@ -134,7 -135,7 +135,7 @@@ void usage(char *progname 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 { | ALL } ]\n" "[ --dec={ 0 | 1 | 2 } ] [ -o JSON ] [ -P { | ALL } ]\n")); exit(1); @@@ -175,64 -176,58 +176,61 @@@ void int_handler(int sig * 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); } @@@ -241,10 -236,22 +239,23 @@@ 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); + } } /* @@@ -1951,13 -1958,18 +1962,17 @@@ void read_interrupts_stat(char *file, s * 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 */ @@@ -2125,6 -2137,14 +2140,13 @@@ curr ^= 1; } } + - /* -H option is given and vCPU physical hotplug occured */ - if (USE_OPTION_H(flags)) { ++ 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) { ++ if (new_cpu_nr > cpu_nr) + return new_cpu_nr; - } + } } while (count); @@@ -2135,6 -2155,52 +2157,50 @@@ else { write_stats_avg(curr, dis_hdr); } + return 0; + } + + /* + *************************************************************************** - * Detect physical vCPU hotplug and call rw_mpstat_loop to display stats ++ * 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) + { - int new_cpu_nr = 0; ++ int new_cpu_nr = 1; + - while (1) { ++ while (new_cpu_nr) { + /* Main loop for reading-writing stats */ + new_cpu_nr = rw_mpstat_loop(dis_hdr, rows); + + /* Handle vCPU physical hotplug */ - if (new_cpu_nr == 0) { - return; - } - else { ++ 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; ++ 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); + } + } } /* @@@ -2270,6 -2336,6 +2336,11 @@@ int main(int argc, char **argv 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) {