]> granicus.if.org Git - sysstat/commitdiff
mpstat: Add new switch to display system topology
authorSebastien GODARD <sysstat@users.noreply.github.com>
Mon, 18 Nov 2019 15:30:38 +0000 (16:30 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Mon, 18 Nov 2019 15:30:38 +0000 (16:30 +0100)
Add new switch "-T", which tells mpstat to display system topology
(core, socket and node for each cpu).
See #225.

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
mpstat.c
mpstat.h

index f75c410592d15aa281c5362cc84ea3d0e9882274..b5e240532679dbc2c6fc5770e86d347ee2d02545 100644 (file)
--- a/mpstat.c
+++ b/mpstat.c
@@ -84,6 +84,9 @@ int *cpu_per_node;
  */
 int *cpu2node;
 
+/* CPU topology */
+struct cpu_topology *st_cpu_topology;
+
 struct tm mp_tstamp[3];
 
 /* Activity flag */
@@ -238,6 +241,11 @@ void salloc_mp_struct(int nr_cpus)
                perror("malloc");
                exit(4);
        }
+
+       if ((st_cpu_topology = (struct cpu_topology *) malloc(sizeof(struct cpu_topology) * nr_cpus)) == NULL) {
+               perror("malloc");
+               exit(4);
+       }
 }
 
 /*
@@ -331,6 +339,57 @@ int get_node_placement(int nr_cpus, int cpu_per_node[], int cpu2node[])
        return hi_node_nr;
 }
 
+/*
+ ***************************************************************************
+ * Read system logical topology: Socket number for each logical core is read
+ * from the /sys/devices/system/cpu/cpu{N}/topology/physical_package_id file,
+ * and the logical core id number is the first number read from the
+ * /sys/devices/system/cpu/cpu{N}/topology/thread_siblings_list file.
+ * Don't use /sys/devices/system/cpu/cpu{N}/topology/core_id as this is the
+ * physical core id (seems to be different from the number displayed by lscpu).
+ *
+ * IN:
+ * @nr_cpus    Number of CPU on this machine.
+ * @cpu_topo   Structures where socket and core id numbers will be saved.
+ *
+ * OUT:
+ * @cpu_topo   Structures where socket and core id numbers have been saved.
+ ***************************************************************************
+ */
+void read_topology(int nr_cpus, struct cpu_topology *cpu_topo)
+{
+       struct cpu_topology *cpu_topo_i;
+       FILE *fp;
+       char filename[MAX_PF_NAME];
+       int cpu;
+
+       /* Init system topology */
+       memset(st_cpu_topology, 0, sizeof(struct cpu_topology) * nr_cpus);
+
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+
+               cpu_topo_i = cpu_topo + cpu;
+
+               /* Read current CPU's socket number */
+               snprintf(filename, MAX_PF_NAME, "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, PHYS_PACK_ID);
+               filename[MAX_PF_NAME - 1] = '\0';
+
+               if ((fp = fopen(filename, "r")) != NULL) {
+                       fscanf(fp, "%d", &cpu_topo_i->phys_package_id);
+                       fclose(fp);
+               }
+
+               /* Read current CPU's logical core id number */
+               snprintf(filename, MAX_PF_NAME, "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, THREAD_SBL_LST);
+               filename[MAX_PF_NAME - 1] = '\0';
+
+               if ((fp = fopen(filename, "r")) != NULL) {
+                       fscanf(fp, "%d", &cpu_topo_i->logical_core_id);
+                       fclose(fp);
+               }
+       }
+}
+
 /*
  ***************************************************************************
  * Compute node statistics: Split CPU statistics among nodes.
@@ -554,11 +613,15 @@ void write_plain_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev,
 {
        int i;
        struct stats_cpu *scc, *scp;
+       struct cpu_topology *cpu_topo_i;
 
        if (dis) {
-               printf("\n%-11s  CPU    %%usr   %%nice    %%sys %%iowait    %%irq   "
-                      "%%soft  %%steal  %%guest  %%gnice   %%idle\n",
-                      prev_string);
+               printf("\n%-11s  CPU", prev_string);
+               if (DISPLAY_TOPOLOGY(flags)) {
+                       printf(" CORE SOCK NODE");
+               }
+               printf("    %%usr   %%nice    %%sys %%iowait    %%irq   "
+                      "%%soft  %%steal  %%guest  %%gnice   %%idle\n");
        }
 
        /*
@@ -580,10 +643,21 @@ void write_plain_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev,
                if (i == 0) {
                        /* This is CPU "all" */
                        cprintf_in(IS_STR, " %s", " all", 0);
+
+                       if (DISPLAY_TOPOLOGY(flags)) {
+                               printf("               ");
+                       }
                }
                else {
                        cprintf_in(IS_INT, " %4d", "", i - 1);
 
+                       if (DISPLAY_TOPOLOGY(flags)) {
+                               cpu_topo_i = st_cpu_topology + i - 1;
+                               cprintf_in(IS_INT, " %4d", "", cpu_topo_i->logical_core_id);
+                               cprintf_in(IS_INT, " %4d", "", cpu_topo_i->phys_package_id);
+                               cprintf_in(IS_INT, " %4d", "", cpu2node[i - 1]);
+                       }
+
                        /* Recalculate itv for current proc */
                        deltot_jiffies = get_per_cpu_interval(scc, scp);
 
@@ -651,8 +725,9 @@ void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev,
                          unsigned char offline_cpu_bitmap[])
 {
        int i, next = FALSE;
-       char cpu_name[16];
+       char cpu_name[16], topology[1024] = "";
        struct stats_cpu *scc, *scp;
+       struct cpu_topology *cpu_topo_i;
 
        xprintf(tab++, "\"cpu-load\": [");
 
@@ -679,11 +754,23 @@ void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev,
                        /* This is CPU "all" */
                        strcpy(cpu_name, "all");
 
+                       if (DISPLAY_TOPOLOGY(flags)) {
+                               snprintf(topology, 1024,
+                                        ", \"core\": \"\", \"socket\": \"\", \"node\": \"\"");
+                       }
+
                }
                else {
                        snprintf(cpu_name, 16, "%d", i - 1);
                        cpu_name[15] = '\0';
 
+                       if (DISPLAY_TOPOLOGY(flags)) {
+                               cpu_topo_i = st_cpu_topology + i - 1;
+                               snprintf(topology, 1024,
+                                        ", \"core\": \"%d\", \"socket\": \"%d\", \"node\": \"%d\"",
+                                        cpu_topo_i->logical_core_id, cpu_topo_i->phys_package_id, cpu2node[i - 1]);
+                       }
+
                        /* Recalculate itv for current proc */
                        deltot_jiffies = get_per_cpu_interval(scc, scp);
 
@@ -692,19 +779,20 @@ void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev,
                                 * If the CPU is tickless then there is no change in CPU values
                                 * but the sum of values is not zero.
                                 */
-                               xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, "
+                               xprintf0(tab, "{\"cpu\": \"%d\"%s, \"usr\": 0.00, \"nice\": 0.00, "
                                         "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
                                         "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
-                                        "\"gnice\": 0.00, \"idle\": 100.00}", i - 1);
+                                        "\"gnice\": 0.00, \"idle\": 100.00}", i - 1, topology);
                                printf("\n");
 
                                continue;
                        }
                }
 
-               xprintf0(tab, "{\"cpu\": \"%s\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
+               xprintf0(tab, "{\"cpu\": \"%s\"%s, \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
                         "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
-                        "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", cpu_name,
+                        "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
+                        cpu_name, topology,
                         (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
                         0.0 :
                         ll_sp_value(scp->cpu_user - scp->cpu_guest,
@@ -1824,6 +1912,11 @@ void rw_mpstat_loop(int dis_hdr, int rows)
                }
        }
 
+       /* Read system topology */
+       if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
+               read_topology(cpu_nr, st_cpu_topology);
+       }
+
        /*
         * Read total number of interrupts received among all CPU.
         * (this is the first value on the line "intr:" in the /proc/stat file).
@@ -1906,6 +1999,11 @@ void rw_mpstat_loop(int dis_hdr, int rows)
                read_uptime(&(uptime_cs[curr]));
                read_stat_cpu(st_cpu[curr], cpu_nr + 1);
 
+               /* Read system topology */
+               if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
+                       read_topology(cpu_nr, st_cpu_topology);
+               }
+
                /* Read total number of interrupts received among all CPU */
                if (DISPLAY_IRQ_SUM(actflags)) {
                        read_stat_irq(st_irq[curr], 1);
@@ -2104,6 +2202,11 @@ int main(int argc, char **argv)
                                        }
                                        break;
 
+                               case 'T':
+                                       /* Display logical topology */
+                                       flags |= F_TOPOLOGY;
+                                       break;
+
                                case 'u':
                                        /* Display CPU */
                                        actflags |= M_D_CPU;
index f865365d096fc6948013088792a053cb4beb6070..112174ad5d30b234ca1eeff46e296422fa8a3199 100644 (file)
--- a/mpstat.h
+++ b/mpstat.h
@@ -15,6 +15,8 @@
  */
 
 #define SOFTIRQS       PRE "/proc/softirqs"
+#define PHYS_PACK_ID   "topology/pysical_package_id"
+#define THREAD_SBL_LST "topology/thread_siblings_list"
 
 /*
  ***************************************************************************
 #define F_JSON_OUTPUT  0x04
 /* Indicate that option -N has been used */
 #define F_OPTION_N     0x08
+/* Display topology */
+#define F_TOPOLOGY     0x10
 
 #define USE_OPTION_P(m)                (((m) & F_OPTION_P) == F_OPTION_P)
 #define USE_OPTION_A(m)                (((m) & F_OPTION_A) == F_OPTION_A)
 #define DISPLAY_JSON_OUTPUT(m) (((m) & F_JSON_OUTPUT) == F_JSON_OUTPUT)
 #define USE_OPTION_N(m)                (((m) & F_OPTION_N) == F_OPTION_N)
+#define DISPLAY_TOPOLOGY(m)    (((m) & F_TOPOLOGY) == F_TOPOLOGY)
 
 #define K_SUM  "SUM"
 #define K_CPU  "CPU"
@@ -85,6 +90,11 @@ struct stats_irqcpu {
        char         irq_name[MAX_IRQ_LEN];
 };
 
+struct cpu_topology {
+       unsigned int phys_package_id;
+       unsigned int logical_core_id;
+};
+
 #define STATS_IRQCPU_SIZE      (sizeof(struct stats_irqcpu))
 
 #endif