diff --git a/SOURCES/0033-Move-all-curses-calls-into-display-threads.patch b/SOURCES/0038-Move-all-curses-calls-into-display-threads.patch similarity index 98% rename from SOURCES/0033-Move-all-curses-calls-into-display-threads.patch rename to SOURCES/0038-Move-all-curses-calls-into-display-threads.patch index c2375e0..1f2e0b9 100644 --- a/SOURCES/0033-Move-all-curses-calls-into-display-threads.patch +++ b/SOURCES/0038-Move-all-curses-calls-into-display-threads.patch @@ -1,7 +1,7 @@ From eb42e7eb07892e91939e3875a124d5f485697ae9 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 18 Nov 2024 08:04:04 -0800 -Subject: [PATCH] Move all curses calls into display threads +Subject: [PATCH 1/5] Move all curses calls into display threads Curses is not thread safe, but currently both the cons and the disp thread can issue curses calls concurrently. @@ -256,5 +256,5 @@ index f9d28de..f934406 100644 typedef struct _disp_ctl { -- -2.41.0 +2.49.0 diff --git a/SOURCES/0034-Avoid-race-on-submitting-display-commands.patch b/SOURCES/0039-Avoid-race-on-submitting-display-commands.patch similarity index 92% rename from SOURCES/0034-Avoid-race-on-submitting-display-commands.patch rename to SOURCES/0039-Avoid-race-on-submitting-display-commands.patch index 92e52bf..4abb880 100644 --- a/SOURCES/0034-Avoid-race-on-submitting-display-commands.patch +++ b/SOURCES/0039-Avoid-race-on-submitting-display-commands.patch @@ -1,7 +1,7 @@ From 8dfa30ea03111981ce5cbc793960688d93f17b68 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 19 Nov 2024 11:02:35 -0800 -Subject: [PATCH] Avoid race on submitting display commands +Subject: [PATCH 3/5] Avoid race on submitting display commands Doesn't work for quitting, but we can ignore it here. --- @@ -28,5 +28,5 @@ index 78bf9e9..c542b77 100644 (void) pthread_cond_signal(&s_disp_ctl.cond); } -- -2.41.0 +2.49.0 diff --git a/SOURCES/0040-Increase-PID-column-width.patch b/SOURCES/0040-Increase-PID-column-width.patch new file mode 100644 index 0000000..908b77c --- /dev/null +++ b/SOURCES/0040-Increase-PID-column-width.patch @@ -0,0 +1,210 @@ +From 5f303ce5c19c5d2f17970797ab467aa32dc93cdc Mon Sep 17 00:00:00 2001 +From: Andi Kleen +Date: Tue, 19 Nov 2024 10:29:44 -0800 +Subject: [PATCH 4/5] Increase PID column width + +Newer Linux distributions enable a >16bit pid_t, so need more digits to +display. + +Fixes #94 +--- + common/win.c | 44 ++++++++++++++++++++++---------------------- + 1 file changed, 22 insertions(+), 22 deletions(-) + +diff --git a/common/win.c b/common/win.c +index c3e8492..03d096d 100644 +--- a/common/win.c ++++ b/common/win.c +@@ -68,7 +68,7 @@ topnproc_caption_build(char *buf, int size) + case SORT_KEY_CPU: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_CPU); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RPI, + CAPTION_LPI, CAPTION_RL, CAPTION_CPI, tmp); + break; +@@ -76,7 +76,7 @@ topnproc_caption_build(char *buf, int size) + case SORT_KEY_CPI: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_CPI); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RPI, + CAPTION_LPI, CAPTION_RL, tmp, CAPTION_CPU); + break; +@@ -84,7 +84,7 @@ topnproc_caption_build(char *buf, int size) + case SORT_KEY_RPI: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_RPI); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, tmp, + CAPTION_LPI, CAPTION_RL, CAPTION_CPI, CAPTION_CPU); + break; +@@ -92,7 +92,7 @@ topnproc_caption_build(char *buf, int size) + case SORT_KEY_LPI: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_LPI); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RPI, + tmp, CAPTION_RL, CAPTION_CPI, CAPTION_CPU); + break; +@@ -100,14 +100,14 @@ topnproc_caption_build(char *buf, int size) + case SORT_KEY_RL: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_RL); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RPI, + CAPTION_LPI, tmp, CAPTION_CPI, CAPTION_CPU); + break; + + default: + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RPI, + CAPTION_LPI, CAPTION_RL, CAPTION_CPI, CAPTION_CPU); + break; +@@ -120,7 +120,7 @@ topnproc_data_build(char *buf, int size, topnproc_line_t *line) + win_countvalue_t *value = &line->value; + + (void) snprintf(buf, size, +- "%6d%15s%11.1f%11.1f%11.1f%11.2f%10.1f", ++ "%10d%15s%11.1f%11.1f%11.1f%11.2f%10.1f", + line->pid, line->proc_name, value->rpi, value->lpi, + value->rl, value->cpi, value->cpu * 100); + } +@@ -164,7 +164,7 @@ rawnum_caption_build(char *buf, int size) + case SORT_KEY_CPU: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_CPU); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RMA, + CAPTION_LMA, CAPTION_RL, CAPTION_CPI, tmp); + break; +@@ -172,7 +172,7 @@ rawnum_caption_build(char *buf, int size) + case SORT_KEY_CPI: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_CPI); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RMA, + CAPTION_LMA, CAPTION_RL, tmp, CAPTION_CPU); + break; +@@ -180,7 +180,7 @@ rawnum_caption_build(char *buf, int size) + case SORT_KEY_RMA: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_RMA); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, tmp, + CAPTION_LMA, CAPTION_RL, CAPTION_CPI, CAPTION_CPU); + break; +@@ -188,7 +188,7 @@ rawnum_caption_build(char *buf, int size) + case SORT_KEY_LMA: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_LMA); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RMA, + tmp, CAPTION_RL, CAPTION_CPI, CAPTION_CPU); + break; +@@ -196,14 +196,14 @@ rawnum_caption_build(char *buf, int size) + case SORT_KEY_RL: + (void) snprintf(tmp, sizeof (tmp), "*%s", CAPTION_RL); + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RMA, + CAPTION_LMA, tmp, CAPTION_CPI, CAPTION_CPU); + break; + + default: + (void) snprintf(buf, size, +- "%6s%15s%11s%11s%11s%11s%11s", ++ "%10s%15s%11s%11s%11s%11s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RMA, + CAPTION_LMA, CAPTION_RL, CAPTION_CPI, CAPTION_CPU); + break; +@@ -216,7 +216,7 @@ rawnum_data_build(char *buf, int size, topnproc_line_t *line) + win_countvalue_t *value = &line->value; + + (void) snprintf(buf, size, +- "%6d%15s%11.1f%11.1f%11.1f%11.2f%10.1f", ++ "%10d%15s%11.1f%11.1f%11.1f%11.2f%10.1f", + line->pid, line->proc_name, value->rma, value->lma, + value->rl, value->cpi, value->cpu * 100); + } +@@ -1154,7 +1154,7 @@ static void + topnlwp_caption_build(char *buf, int size) + { + (void) snprintf(buf, size, +- "%6s%10s%10s%11s%11s%10s%10s%10s", ++ "%10s%10s%10s%11s%11s%10s%10s%10s", + CAPTION_LWP, CAPTION_RPI, CAPTION_LPI, + CAPTION_RMA, CAPTION_LMA, CAPTION_RL, + CAPTION_CPI, CAPTION_CPU); +@@ -1169,7 +1169,7 @@ topnlwp_data_build(char *buf, int size, topnlwp_line_t *line) + (void) snprintf(tmp, sizeof (tmp), "%d", line->lwpid); + + (void) snprintf(buf, size, +- "%6s%10.1f%10.1f%11.1f%11.1f%10.1f%10.2f%9.1f", ++ "%10s%10.1f%10.1f%11.1f%11.1f%10.1f%10.2f%9.1f", + tmp, value->rpi, value->lpi, value->rma, + value->lma, value->rl, value->cpi, value->cpu * 100); + } +@@ -2859,7 +2859,7 @@ pqos_cmt_proc_data_build(char *buf, int size, + snprintf(tmp, sizeof(tmp), "*%s", id); + + snprintf(buf, size, +- "%6s%15s%11.1f%11.1f%21.1f%10.1f", ++ "%10s%15s%11.1f%11.1f%21.1f%10.1f", + tmp, line->proc_name, + value->rma, value->lma, + ratio(line->llc_occupancy, +@@ -2970,12 +2970,12 @@ pqos_cmt_caption_build(int lwpid, char *buf, int size) + { + if (lwpid == 0) + snprintf(buf, size, +- "%6s%15s%11s%11s%21s%11s", ++ "%10s%15s%11s%11s%21s%11s", + CAPTION_PID, CAPTION_PROC, CAPTION_RMA, CAPTION_LMA, + CAPTION_LLC_OCCUPANCY, CAPTION_CPU); + else + snprintf(buf, size, +- "%6s%15s%11s%11s%21s%11s", ++ "%10s%15s%11s%11s%21s%11s", + CAPTION_LWP, CAPTION_PROC, CAPTION_RMA, CAPTION_LMA, + CAPTION_LLC_OCCUPANCY, CAPTION_CPU); + } +@@ -3183,7 +3183,7 @@ pqos_mbm_proc_data_build(char *buf, int size, + ratio(line->localbw_scaled, 1048576)); + + snprintf(buf, size, +- "%6s%15s%10.1f%10.1f%14s%14s%9.1f", ++ "%10s%15s%10.1f%10.1f%14s%14s%9.1f", + id, line->proc_name, + value->rma, value->lma, + total_bw, local_bw, +@@ -3295,12 +3295,12 @@ pqos_mbm_caption_build(int lwpid, char *buf, int size) + { + if (lwpid == 0) + snprintf(buf, size, +- "%6s%15s%10s%10s%14s%14s%10s", ++ "%10s%15s%10s%10s%14s%14s%10s", + CAPTION_PID, CAPTION_PROC, CAPTION_RMA, CAPTION_LMA, + CAPTION_TOTAL_BW, CAPTION_LOCAL_BW, CAPTION_CPU); + else + snprintf(buf, size, +- "%6s%15s%10s%10s%14s%14s%10s", ++ "%10s%15s%10s%10s%14s%14s%10s", + CAPTION_LWP, CAPTION_PROC, CAPTION_RMA, CAPTION_LMA, + CAPTION_TOTAL_BW, CAPTION_LOCAL_BW, CAPTION_CPU); + } +-- +2.49.0 + diff --git a/SOURCES/0041-common-Ignore-samples-for-exiting-tasks.patch b/SOURCES/0041-common-Ignore-samples-for-exiting-tasks.patch new file mode 100644 index 0000000..339d7df --- /dev/null +++ b/SOURCES/0041-common-Ignore-samples-for-exiting-tasks.patch @@ -0,0 +1,37 @@ +From 636bf0ee924034d51e63a20325353f2e9384b3de Mon Sep 17 00:00:00 2001 +From: Sandipan Das +Date: Thu, 10 Jul 2025 11:57:03 +0530 +Subject: [PATCH 5/5] common: Ignore samples for exiting tasks + +After the inclusion of Linux commit 1d953111b648 ("perf/core: Don't +report zero PIDs for exiting tasks"), perf samples will report PID as +-1 for exiting tasks. + +Such samples lead to segmentation faults during process lookup when +proc_find_nolock() is called with -1 as the PID. Process data at the +the hash table index returned by PROC_HASHTBL_INDEX() is invalid and +any dereference of the corresponding track_proc_t pointer results in +a bad access. Hence, ignore samples for exiting tasks. + +Fixes: 972a9d0 ("Reconstruct code for better OS-independent.") +Signed-off-by: Sandipan Das +--- + common/os/pfwrapper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/common/os/pfwrapper.c b/common/os/pfwrapper.c +index 10042d9..780458e 100644 +--- a/common/os/pfwrapper.c ++++ b/common/os/pfwrapper.c +@@ -497,7 +497,7 @@ ll_sample_read(struct perf_event_mmap_page *mhdr, int size, + * { u64 data_src; } + * }; + */ +- if (mmap_buffer_read(mhdr, &id, sizeof (id)) == -1) { ++ if (mmap_buffer_read(mhdr, &id, sizeof (id)) == -1 || id.pid == -1U) { + debug_print(NULL, 2, "ll_sample_read: read pid/tid failed.\n"); + goto L_EXIT; + } +-- +2.49.0 + diff --git a/SOURCES/0042-common-Fix-upper-bound-for-nodes.patch b/SOURCES/0042-common-Fix-upper-bound-for-nodes.patch new file mode 100644 index 0000000..528892d --- /dev/null +++ b/SOURCES/0042-common-Fix-upper-bound-for-nodes.patch @@ -0,0 +1,31 @@ +From 69333ce658e1895241f91f187e12e4996147e196 Mon Sep 17 00:00:00 2001 +From: Sandipan Das +Date: Mon, 30 Jun 2025 12:08:28 +0530 +Subject: [PATCH 1/6] common: Fix upper bound for nodes + +os_sysfs_node_enum() sets num to the number of NUMA nodes discovered. +The upper bound for num is NNODES_MAX so fail only for cases where +num is strictly greater than the upper bound. + +Fixes: 972a9d0 ("Reconstruct code for better OS-independent.") +Signed-off-by: Sandipan Das +--- + common/os/node.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/common/os/node.c b/common/os/node.c +index f384e3b..10db693 100644 +--- a/common/os/node.c ++++ b/common/os/node.c +@@ -228,7 +228,7 @@ node_group_refresh(boolean_t init) + if (!os_sysfs_node_enum(node_arr, NNODES_MAX, &num)) { + goto L_EXIT; + } +- if (num < 0 || num >= NNODES_MAX) { ++ if (num < 0 || num > NNODES_MAX) { + goto L_EXIT; + } + +-- +2.49.0 + diff --git a/SOURCES/0043-common-Fix-upper-bound-for-CPUs-per-node.patch b/SOURCES/0043-common-Fix-upper-bound-for-CPUs-per-node.patch new file mode 100644 index 0000000..874acd4 --- /dev/null +++ b/SOURCES/0043-common-Fix-upper-bound-for-CPUs-per-node.patch @@ -0,0 +1,31 @@ +From 700351ff9e11840caa42b7b9f56c2400116dc30b Mon Sep 17 00:00:00 2001 +From: Sandipan Das +Date: Mon, 30 Jun 2025 11:16:49 +0530 +Subject: [PATCH 2/6] common: Fix upper bound for CPUs per node + +os_sysfs_cpu_enum() sets num to the number of online CPUs discovered. +The upper bound for num is NCPUS_NODE_MAX so fail only for cases where +num is strictly greater than NCPUS_NODE_MAX. + +Fixes: 972a9d0 ("Reconstruct code for better OS-independent.") +Signed-off-by: Sandipan Das +--- + common/os/node.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/common/os/node.c b/common/os/node.c +index 10db693..ab0c90d 100644 +--- a/common/os/node.c ++++ b/common/os/node.c +@@ -167,7 +167,7 @@ cpu_refresh(boolean_t init) + if (!os_sysfs_cpu_enum(node->nid, cpu_arr, NCPUS_NODE_MAX, &num)) { + return (-1); + } +- if (num < 0 || num >= NCPUS_NODE_MAX) { ++ if (num < 0 || num > NCPUS_NODE_MAX) { + return (-1); + } + +-- +2.49.0 + diff --git a/SOURCES/0044-common-Resolve-max-count-of-nodes-at-runtime.patch b/SOURCES/0044-common-Resolve-max-count-of-nodes-at-runtime.patch new file mode 100644 index 0000000..2e42254 --- /dev/null +++ b/SOURCES/0044-common-Resolve-max-count-of-nodes-at-runtime.patch @@ -0,0 +1,345 @@ +From 4740ef47cf753420244111df4878cd7128380f17 Mon Sep 17 00:00:00 2001 +From: Sandipan Das +Date: Fri, 27 Jun 2025 15:24:42 +0530 +Subject: [PATCH 3/6] common: Resolve max count of nodes at runtime + +Replace statically defined NNODES_MAX with a variable which is set at +runtime. Use libnuma helpers to determine the OS-defined limits for the +maximum possible number of NUMA nodes in the the system. + +Signed-off-by: Sandipan Das +--- + common/include/os/node.h | 2 +- + common/include/types.h | 5 ++-- + common/numatop.c | 2 +- + common/os/node.c | 52 +++++++++++++++++++++++++++------------- + common/os/os_perf.c | 4 ++-- + common/os/os_util.c | 2 +- + common/win.c | 15 ++++++++---- + 7 files changed, 54 insertions(+), 28 deletions(-) + +diff --git a/common/include/os/node.h b/common/include/os/node.h +index da1ba7c..2c21556 100644 +--- a/common/include/os/node.h ++++ b/common/include/os/node.h +@@ -101,7 +101,7 @@ typedef struct _node { + + typedef struct _node_group { + pthread_mutex_t mutex; +- node_t nodes[NNODES_MAX]; ++ node_t *nodes; + int nnodes; + int cpuid_max; + int intval_ms; +diff --git a/common/include/types.h b/common/include/types.h +index 05b411a..e688225 100644 +--- a/common/include/types.h ++++ b/common/include/types.h +@@ -115,13 +115,14 @@ typedef enum { + + #define UI_COUNT_NUM 5 + +-#define NNODES_MAX 64 + #define NCPUS_NODE_MAX 256 +-#define NCPUS_MAX (NNODES_MAX * NCPUS_NODE_MAX) ++#define NCPUS_MAX (nnodes_max * NCPUS_NODE_MAX) + #define NPROCS_NAX 4096 + #define LL_THRESH 128 + #define LL_PERIOD 1000 + ++extern int nnodes_max; ++ + typedef struct _count_value { + uint64_t counts[PERF_COUNT_NUM]; + } count_value_t; +diff --git a/common/numatop.c b/common/numatop.c +index 122c187..c5c0580 100644 +--- a/common/numatop.c ++++ b/common/numatop.c +@@ -236,7 +236,7 @@ main(int argc, char *argv[]) + if (node_group_init() != 0) { + stderr_print("The node/cpu number is out of range, \n" + "numatop supports up to %d nodes and %d CPUs\n", +- NNODES_MAX, NCPUS_MAX); ++ nnodes_max, NCPUS_MAX); + goto L_EXIT5; + } + +diff --git a/common/os/node.c b/common/os/node.c +index ab0c90d..c2ca7a7 100644 +--- a/common/os/node.c ++++ b/common/os/node.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include "../include/types.h" + #include "../include/util.h" + #include "../include/ui_perf_map.h" +@@ -46,6 +47,8 @@ + static node_group_t s_node_group; + int g_ncpus; + ++int nnodes_max; ++ + static void + node_init(node_t *node, int nid, boolean_t hotadd) + { +@@ -79,13 +82,22 @@ node_group_init(void) + int i; + node_t *node; + ++ if (numa_available() < 0) ++ return (-1); ++ ++ nnodes_max = numa_num_possible_nodes(); ++ + (void) memset(&s_node_group, 0, sizeof (node_group_t)); + if (pthread_mutex_init(&s_node_group.mutex, NULL) != 0) { + return (-1); + } + ++ if ((s_node_group.nodes = zalloc(nnodes_max * sizeof(node_t))) == NULL) { ++ return (-1); ++ } ++ + s_node_group.inited = B_TRUE; +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + node_init(node, INVALID_NID, B_FALSE); + } +@@ -102,12 +114,13 @@ node_group_reset(void) + node_t *node; + int i; + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + node_fini(node); + } + + s_node_group.nnodes = 0; ++ free(s_node_group.nodes); + } + + /* +@@ -161,7 +174,7 @@ cpu_refresh(boolean_t init) + int cpu_arr[NCPUS_NODE_MAX]; + node_t *node; + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (NODE_VALID(node)) { + if (!os_sysfs_cpu_enum(node->nid, cpu_arr, NCPUS_NODE_MAX, &num)) { +@@ -199,7 +212,7 @@ meminfo_refresh(void) + int i; + node_t *node; + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (NODE_VALID(node)) { + if (!os_sysfs_meminfo(node->nid, &node->meminfo)) { +@@ -220,19 +233,23 @@ meminfo_refresh(void) + int + node_group_refresh(boolean_t init) + { +- int node_arr[NNODES_MAX]; +- int num, i, j, ret = -1; ++ int *node_arr, num, i, j, ret = -1; + node_t *node; + + node_group_lock(); +- if (!os_sysfs_node_enum(node_arr, NNODES_MAX, &num)) { ++ ++ if ((node_arr = zalloc(nnodes_max * sizeof(int))) == NULL) { ++ goto L_EXIT; ++ } ++ ++ if (!os_sysfs_node_enum(node_arr, nnodes_max, &num)) { + goto L_EXIT; + } +- if (num < 0 || num > NNODES_MAX) { ++ if (num < 0 || num > nnodes_max) { + goto L_EXIT; + } + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (NODE_VALID(node)) { + if ((j = nid_find(node->nid, node_arr, num)) == -1) { +@@ -244,7 +261,7 @@ node_group_refresh(boolean_t init) + } + } + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (!NODE_VALID(node)) { + if ((j = nid_find(i, node_arr, num)) >= 0) { +@@ -272,6 +289,7 @@ node_group_refresh(boolean_t init) + ret = 0; + + L_EXIT: ++ free(node_arr); + node_group_unlock(); + return (ret); + } +@@ -313,7 +331,7 @@ node_by_cpu(int cpuid) + return (NULL); + } + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (!NODE_VALID(node)) { + continue; +@@ -386,7 +404,7 @@ node_cpu_traverse(pfn_perf_cpu_op_t func, void *arg, boolean_t err_ret, + perf_cpu_t *cpu; + int i, j, ret; + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (!NODE_VALID(node)) { + continue; +@@ -461,7 +479,7 @@ node_countval_sum(count_value_t *countval_arr, int nid, + return (countval_sum(countval_arr, nid, ui_count_id)); + } + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + value += countval_sum(countval_arr, i, ui_count_id); + } + +@@ -486,7 +504,7 @@ node_profiling_clear(void) + node_t *node; + int i; + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + (void) memset(&node->countval, 0, sizeof (count_value_t)); + } +@@ -498,7 +516,7 @@ node_valid_get(int node_idx) + int i, nvalid = 0; + node_t *node; + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (NODE_VALID(node)) { + if (node_idx == nvalid) { +@@ -537,7 +555,7 @@ node_qpi_init(void) + + node_group_lock(); + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (NODE_VALID(node) && (qpi_num > 0)) { + memcpy(node->qpi.qpi_info, qpi_tmp, +@@ -566,7 +584,7 @@ node_imc_init(void) + + node_group_lock(); + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (NODE_VALID(node) && (imc_num > 0)) { + memcpy(node->imc.imc_info, imc_tmp, +diff --git a/common/os/os_perf.c b/common/os/os_perf.c +index d8d634f..9ea93ea 100644 +--- a/common/os/os_perf.c ++++ b/common/os/os_perf.c +@@ -1025,7 +1025,7 @@ uncore_stop_all(void) + node_t *node; + int i; + +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (NODE_VALID(node)) { + if (node->qpi.qpi_num > 0) +@@ -1455,7 +1455,7 @@ int os_uncore_stop(perf_ctl_t *ctl __attribute__((unused)), + pf_uncoreimc_free(node); + } + } else { +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (NODE_VALID(node)) { + if (node->qpi.qpi_num > 0) +diff --git a/common/os/os_util.c b/common/os/os_util.c +index 0b862c2..ec3f6e5 100644 +--- a/common/os/os_util.c ++++ b/common/os/os_util.c +@@ -863,7 +863,7 @@ static uint64_t cmt_field_value(char *dir, const char *field, int nid) + int i; + + if (nid == -1) { +- for (i = 0; i < NNODES_MAX; i++) { ++ for (i = 0; i < nnodes_max; i++) { + if (cmt_task_node_value(dir, i, field, + &tmp) == 0) + val += tmp; +diff --git a/common/win.c b/common/win.c +index 03d096d..dad13d1 100644 +--- a/common/win.c ++++ b/common/win.c +@@ -2714,7 +2714,7 @@ accdst_data_show(track_proc_t *proc, dyn_accdst_t *dyn, boolean_t *note_out) + void **addr_arr = NULL; + int *lat_arr = NULL; + int addr_num, i, nnodes, naccess_total = 0; +- map_nodedst_t nodedst_arr[NNODES_MAX]; ++ map_nodedst_t *nodedst_arr; + accdst_line_t *lines; + char content[WIN_LINECHAR_MAX], intval_buf[16]; + boolean_t ret = B_FALSE; +@@ -2728,14 +2728,19 @@ accdst_data_show(track_proc_t *proc, dyn_accdst_t *dyn, boolean_t *note_out) + return (B_FALSE); + } + ++ nodedst_arr = (map_nodedst_t *) malloc(sizeof (map_nodedst_t) * nnodes_max); ++ if (!nodedst_arr) { ++ goto L_EXIT; ++ } ++ + if (llrec2addr(proc, lwp, &addr_arr, &lat_arr, &addr_num) != 0) { + goto L_EXIT; + } + +- (void) memset(nodedst_arr, 0, sizeof (map_nodedst_t) * NNODES_MAX); ++ (void) memset(nodedst_arr, 0, sizeof (map_nodedst_t) * nnodes_max); + if (addr_num > 0) { + if (map_addr2nodedst(proc->pid, addr_arr, lat_arr, addr_num, +- nodedst_arr, NNODES_MAX, &naccess_total) != 0) { ++ nodedst_arr, nnodes_max, &naccess_total) != 0) { + goto L_EXIT; + } + } +@@ -2784,7 +2789,7 @@ accdst_data_show(track_proc_t *proc, dyn_accdst_t *dyn, boolean_t *note_out) + * Save the per-node data with metrics in scrolling buffer. + */ + for (i = 0; i < nnodes; i++) { +- accdst_data_save(nodedst_arr, NNODES_MAX, naccess_total, i, ++ accdst_data_save(nodedst_arr, nnodes_max, naccess_total, i, + &lines[i]); + } + +@@ -2799,6 +2804,8 @@ accdst_data_show(track_proc_t *proc, dyn_accdst_t *dyn, boolean_t *note_out) + reg_refresh_nout(r); + + L_EXIT: ++ free(nodedst_arr); ++ + if (lwp != NULL) { + lwp_refcount_dec(lwp); + } +-- +2.49.0 + diff --git a/SOURCES/0045-common-Resolve-max-count-of-CPUs-at-runtime.patch b/SOURCES/0045-common-Resolve-max-count-of-CPUs-at-runtime.patch new file mode 100644 index 0000000..47bba4b --- /dev/null +++ b/SOURCES/0045-common-Resolve-max-count-of-CPUs-at-runtime.patch @@ -0,0 +1,105 @@ +From ebe98ffcc2517fa7e0a251914c52274e8a378b1c Mon Sep 17 00:00:00 2001 +From: Sandipan Das +Date: Fri, 27 Jun 2025 15:47:59 +0530 +Subject: [PATCH 4/6] common: Resolve max count of CPUs at runtime + +Replace statically defined NCPUS_MAX with a variable which is set at +runtime. Use libnuma helpers to determine the OS-defined limits for the +maximum possible number of CPUs in the the system. + +Signed-off-by: Sandipan Das +--- + common/include/types.h | 2 +- + common/numatop.c | 2 +- + common/os/node.c | 2 ++ + common/os/os_util.c | 16 ++++++++++------ + 4 files changed, 14 insertions(+), 8 deletions(-) + +diff --git a/common/include/types.h b/common/include/types.h +index e688225..eb64fb1 100644 +--- a/common/include/types.h ++++ b/common/include/types.h +@@ -116,12 +116,12 @@ typedef enum { + #define UI_COUNT_NUM 5 + + #define NCPUS_NODE_MAX 256 +-#define NCPUS_MAX (nnodes_max * NCPUS_NODE_MAX) + #define NPROCS_NAX 4096 + #define LL_THRESH 128 + #define LL_PERIOD 1000 + + extern int nnodes_max; ++extern int ncpus_max; + + typedef struct _count_value { + uint64_t counts[PERF_COUNT_NUM]; +diff --git a/common/numatop.c b/common/numatop.c +index c5c0580..2e95378 100644 +--- a/common/numatop.c ++++ b/common/numatop.c +@@ -236,7 +236,7 @@ main(int argc, char *argv[]) + if (node_group_init() != 0) { + stderr_print("The node/cpu number is out of range, \n" + "numatop supports up to %d nodes and %d CPUs\n", +- nnodes_max, NCPUS_MAX); ++ nnodes_max, ncpus_max); + goto L_EXIT5; + } + +diff --git a/common/os/node.c b/common/os/node.c +index c2ca7a7..f79bcdf 100644 +--- a/common/os/node.c ++++ b/common/os/node.c +@@ -48,6 +48,7 @@ static node_group_t s_node_group; + int g_ncpus; + + int nnodes_max; ++int ncpus_max; + + static void + node_init(node_t *node, int nid, boolean_t hotadd) +@@ -86,6 +87,7 @@ node_group_init(void) + return (-1); + + nnodes_max = numa_num_possible_nodes(); ++ ncpus_max = numa_num_possible_cpus(); + + (void) memset(&s_node_group, 0, sizeof (node_group_t)); + if (pthread_mutex_init(&s_node_group.mutex, NULL) != 0) { +diff --git a/common/os/os_util.c b/common/os/os_util.c +index ec3f6e5..c836e89 100644 +--- a/common/os/os_util.c ++++ b/common/os/os_util.c +@@ -470,19 +470,23 @@ os_sysfs_cpu_enum(int nid, int *cpu_arr, int arr_size, int *num) + int + os_sysfs_online_ncpus(void) + { +- int cpu_arr[NCPUS_MAX], num; ++ int *cpu_arr, num, ret = -1; + char path[PATH_MAX]; + +- if (sysconf(_SC_NPROCESSORS_CONF) > NCPUS_MAX) { ++ cpu_arr = (int *) malloc(ncpus_max * sizeof(int)); ++ if (!cpu_arr) + return (-1); +- } + + snprintf(path, PATH_MAX, "/sys/devices/system/cpu/online"); +- if (!file_int_extract(path, cpu_arr, NCPUS_MAX, &num)) { +- return (-1); ++ if (!file_int_extract(path, cpu_arr, ncpus_max, &num)) { ++ goto L_EXIT; + } + +- return (num); ++ ret = num; ++ ++L_EXIT: ++ free(cpu_arr); ++ return (ret); + } + + static boolean_t +-- +2.49.0 + diff --git a/SOURCES/0046-common-Resolve-max-count-of-CPUs-per-node-at-runtime.patch b/SOURCES/0046-common-Resolve-max-count-of-CPUs-per-node-at-runtime.patch new file mode 100644 index 0000000..071fc03 --- /dev/null +++ b/SOURCES/0046-common-Resolve-max-count-of-CPUs-per-node-at-runtime.patch @@ -0,0 +1,223 @@ +From 00128bb30fb1b88bf2c7421b2a5a759dcffacb32 Mon Sep 17 00:00:00 2001 +From: Sandipan Das +Date: Mon, 30 Jun 2025 18:42:33 +0530 +Subject: [PATCH 5/6] common: Resolve max count of CPUs per node at runtime + +Replace statically defined NCPUS_NODE_MAX with the previously introduced +ncpus_max. Technically, ncpus_max denotes the maximum possible number of +CPUs in a system but it can also serve as the maximum possible number of +CPUs per NUMA node because of the following reasons. + * CPUs may not be uniformly distributed across NUMA nodes. + * Some NUMA nodes may not have any CPUs associated with them. + +Signed-off-by: Sandipan Das +--- + common/include/os/node.h | 2 +- + common/include/types.h | 1 - + common/os/node.c | 72 ++++++++++++++++++++++++++++------------ + common/os/os_win.c | 2 +- + 4 files changed, 53 insertions(+), 24 deletions(-) + +diff --git a/common/include/os/node.h b/common/include/os/node.h +index 2c21556..0b3c362 100644 +--- a/common/include/os/node.h ++++ b/common/include/os/node.h +@@ -90,7 +90,7 @@ typedef struct _node_imc { + typedef struct _node { + int nid; + int ncpus; +- perf_cpu_t cpus[NCPUS_NODE_MAX]; ++ perf_cpu_t *cpus; + count_value_t countval; + node_meminfo_t meminfo; + node_qpi_t qpi; +diff --git a/common/include/types.h b/common/include/types.h +index eb64fb1..1d1545d 100644 +--- a/common/include/types.h ++++ b/common/include/types.h +@@ -115,7 +115,6 @@ typedef enum { + + #define UI_COUNT_NUM 5 + +-#define NCPUS_NODE_MAX 256 + #define NPROCS_NAX 4096 + #define LL_THRESH 128 + #define LL_PERIOD 1000 +diff --git a/common/os/node.c b/common/os/node.c +index f79bcdf..cb8c38a 100644 +--- a/common/os/node.c ++++ b/common/os/node.c +@@ -50,20 +50,34 @@ int g_ncpus; + int nnodes_max; + int ncpus_max; + +-static void ++static int + node_init(node_t *node, int nid, boolean_t hotadd) + { + memset(node, 0, sizeof (node_t)); +- os_perf_cpuarr_init(node->cpus, NCPUS_NODE_MAX, hotadd); + node->nid = nid; + node->hotadd = hotadd; ++ if (!NODE_VALID(node)) { ++ return 0; ++ } ++ ++ if ((node->cpus = zalloc(ncpus_max * sizeof(perf_cpu_t))) == NULL) { ++ return (-1); ++ } ++ ++ os_perf_cpuarr_init(node->cpus, ncpus_max, hotadd); ++ return 0; + } + + static void + node_fini(node_t *node) + { +- os_perf_cpuarr_fini(node->cpus, NCPUS_NODE_MAX, B_FALSE); ++ if (!NODE_VALID(node)) { ++ return; ++ } ++ ++ os_perf_cpuarr_fini(node->cpus, ncpus_max, B_FALSE); + node->ncpus = 0; ++ free(node->cpus); + node->nid = INVALID_NID; + } + +@@ -71,7 +85,7 @@ static void + node_hotremove(node_t *node) + { + node->hotremove = B_TRUE; +- os_perf_cpuarr_fini(node->cpus, NCPUS_NODE_MAX, B_TRUE); ++ os_perf_cpuarr_fini(node->cpus, ncpus_max, B_TRUE); + } + + /* +@@ -101,10 +115,20 @@ node_group_init(void) + s_node_group.inited = B_TRUE; + for (i = 0; i < nnodes_max; i++) { + node = node_get(i); +- node_init(node, INVALID_NID, B_FALSE); ++ if (node_init(node, INVALID_NID, B_FALSE)) { ++ goto L_EXIT; ++ } + } + + return (node_group_refresh(B_TRUE)); ++ ++L_EXIT: ++ for (i = i - 1; i >= 0; i--) { ++ node = node_get(i); ++ node_fini(node); ++ } ++ ++ return (-1); + } + + /* +@@ -172,23 +196,27 @@ cpuid_max_get(int *cpu_arr, int num) + static int + cpu_refresh(boolean_t init) + { +- int i, j, num, cpuid_max = -1; +- int cpu_arr[NCPUS_NODE_MAX]; ++ int i, j, num, cpuid_max = -1, ret = -1; ++ int *cpu_arr; + node_t *node; + ++ if ((cpu_arr = zalloc(ncpus_max * sizeof(int))) == NULL) { ++ return (-1); ++ } ++ + for (i = 0; i < nnodes_max; i++) { + node = node_get(i); + if (NODE_VALID(node)) { +- if (!os_sysfs_cpu_enum(node->nid, cpu_arr, NCPUS_NODE_MAX, &num)) { +- return (-1); ++ if (!os_sysfs_cpu_enum(node->nid, cpu_arr, ncpus_max, &num)) { ++ goto L_EXIT; + } +- if (num < 0 || num > NCPUS_NODE_MAX) { +- return (-1); ++ if (num < 0 || num > ncpus_max) { ++ goto L_EXIT; + } + +- if (os_perf_cpuarr_refresh(node->cpus, NCPUS_NODE_MAX, cpu_arr, ++ if (os_perf_cpuarr_refresh(node->cpus, ncpus_max, cpu_arr, + num, init) != 0) { +- return (-1); ++ goto L_EXIT; + } + + node->ncpus = num; +@@ -205,7 +233,11 @@ cpu_refresh(boolean_t init) + + /* Refresh the number of online CPUs */ + g_ncpus = os_sysfs_online_ncpus(); +- return (0); ++ ret = 0; ++ ++L_EXIT: ++ free(cpu_arr); ++ return (ret); + } + + static int +@@ -268,10 +300,8 @@ node_group_refresh(boolean_t init) + if (!NODE_VALID(node)) { + if ((j = nid_find(i, node_arr, num)) >= 0) { + ASSERT(node_arr[j] == i); +- if (init) { +- node_init(node, i, B_FALSE); +- } else { +- node_init(node, i, B_TRUE); ++ if (node_init(node, i, init ? B_FALSE : B_TRUE)) { ++ goto L_EXIT; + } + + s_node_group.nnodes++; +@@ -339,7 +369,7 @@ node_by_cpu(int cpuid) + continue; + } + +- for (j = 0; j < NCPUS_NODE_MAX; j++) { ++ for (j = 0; j < ncpus_max; j++) { + if (cpuid == node->cpus[j].cpuid) { + return (node); + } +@@ -412,7 +442,7 @@ node_cpu_traverse(pfn_perf_cpu_op_t func, void *arg, boolean_t err_ret, + continue; + } + +- for (j = 0; j < NCPUS_NODE_MAX; j++) { ++ for (j = 0; j < ncpus_max; j++) { + cpu = &node->cpus[j]; + if (cpu->hotremove) { + pf_resource_free(cpu); +@@ -455,7 +485,7 @@ countval_sum(count_value_t *countval_arr, int nid, + return (0); + } + +- for (i = 0; i < NCPUS_NODE_MAX; i++) { ++ for (i = 0; i < ncpus_max; i++) { + if (num >= node->ncpus) { + break; + } +diff --git a/common/os/os_win.c b/common/os/os_win.c +index 9aaefae..bd34388 100644 +--- a/common/os/os_win.c ++++ b/common/os/os_win.c +@@ -152,7 +152,7 @@ node_cpu_string(node_t *node, char *s1, int size) + } + + j = 0; +- for (i = 0; (i < NCPUS_NODE_MAX) && (j < ncpus); i++) { ++ for (i = 0; (i < ncpus_max) && (j < ncpus); i++) { + if ((cpus[i].cpuid != INVALID_CPUID) && (!cpus[i].hotremove)) { + cpuid_arr[j++] = cpus[i].cpuid; + } +-- +2.49.0 + diff --git a/SOURCES/0047-common-Remove-unused-NPROCS_NAX.patch b/SOURCES/0047-common-Remove-unused-NPROCS_NAX.patch new file mode 100644 index 0000000..c13cef4 --- /dev/null +++ b/SOURCES/0047-common-Remove-unused-NPROCS_NAX.patch @@ -0,0 +1,27 @@ +From 50b24cd2c9bdd524b8a9d842831e46b176de3265 Mon Sep 17 00:00:00 2001 +From: Sandipan Das +Date: Mon, 30 Jun 2025 19:03:47 +0530 +Subject: [PATCH 6/6] common: Remove unused NPROCS_NAX + +Remove the definition of NPROCS_NAX as it is unused. + +Signed-off-by: Sandipan Das +--- + common/include/types.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/common/include/types.h b/common/include/types.h +index 1d1545d..221b06d 100644 +--- a/common/include/types.h ++++ b/common/include/types.h +@@ -115,7 +115,6 @@ typedef enum { + + #define UI_COUNT_NUM 5 + +-#define NPROCS_NAX 4096 + #define LL_THRESH 128 + #define LL_PERIOD 1000 + +-- +2.49.0 + diff --git a/SOURCES/0048-Avoid-deadlock-on-quitting.patch b/SOURCES/0048-Avoid-deadlock-on-quitting.patch new file mode 100644 index 0000000..86158d2 --- /dev/null +++ b/SOURCES/0048-Avoid-deadlock-on-quitting.patch @@ -0,0 +1,29 @@ +From 1550c9925f98754c7af99d01df460eb6dabb4b0e Mon Sep 17 00:00:00 2001 +From: Andi Kleen +Date: Tue, 2 Dec 2025 22:06:32 -0800 +Subject: [PATCH] Avoid deadlock on quitting + +by resetting the display command mailbox when the display thread exits. + +Originally introduced with 8dfa30ea0311 + +Fixes #98 +--- + common/disp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/common/disp.c b/common/disp.c +index c542b77..75eda9d 100644 +--- a/common/disp.c ++++ b/common/disp.c +@@ -640,6 +640,7 @@ L_EXIT: + perf_fini(); + + debug_print(NULL, 2, "disp thread is exiting\n"); ++ s_disp_ctl.flag = DISP_FLAG_NONE; + return (NULL); + } + +-- +2.49.0 + diff --git a/SPECS/numatop.spec b/SPECS/numatop.spec index a5fecdd..b833d9a 100644 --- a/SPECS/numatop.spec +++ b/SPECS/numatop.spec @@ -3,10 +3,10 @@ Name: numatop Version: 2.4 -Release: 6%{?dist} +Release: 9%{?dist} Summary: Memory access locality characterization and analysis -License: BSD +License: BSD-3-Clause URL: https://01.org/numatop Source: https://github.com/intel/numatop/archive/refs/tags/v%{version}.tar.gz # Patch0: format.patch @@ -42,12 +42,20 @@ Patch29: 0029-common-use-mount-umount-system-calls-rather-than-usi.patch Patch30: 0030-common-remove-executing-commands-for-directory-and-f.patch Patch31: 0031-powerpc-util-fix-build-warning-cast-LHS-of-expressio.patch Patch32: 0032-common-os-map-Fix-overflow-warning.patch -Patch33: 0033-Move-all-curses-calls-into-display-threads.patch -Patch34: 0034-Avoid-race-on-submitting-display-commands.patch Patch35: 0035-Remove-EMR-specific-events-configuration.patch Patch36: 0036-Support-Intel-Granite-Rapids-platform.patch Patch37: 0037-Support-Intel-Sierra-Forest-platform.patch - +Patch38: 0038-Move-all-curses-calls-into-display-threads.patch +Patch39: 0039-Avoid-race-on-submitting-display-commands.patch +Patch40: 0040-Increase-PID-column-width.patch +Patch41: 0041-common-Ignore-samples-for-exiting-tasks.patch +Patch42: 0042-common-Fix-upper-bound-for-nodes.patch +Patch43: 0043-common-Fix-upper-bound-for-CPUs-per-node.patch +Patch44: 0044-common-Resolve-max-count-of-nodes-at-runtime.patch +Patch45: 0045-common-Resolve-max-count-of-CPUs-at-runtime.patch +Patch46: 0046-common-Resolve-max-count-of-CPUs-per-node-at-runtime.patch +Patch47: 0047-common-Remove-unused-NPROCS_NAX.patch +Patch48: 0048-Avoid-deadlock-on-quitting.patch BuildRequires: autoconf