From git@z Thu Jan  1 00:00:00 1970
Subject: [PATCH v1 1/8] perf: Increase MAX_NR_CPUS to 4096
From: Kyle Meyer <kyle.meyer@hpe.com>
Date: Thu, 05 Dec 2024 20:40:28 -0800
Message-Id: <20241206044035.1062032-2-irogers@google.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit

Systems have surpassed 2048 CPUs. Increase MAX_NR_CPUS to 4096.

Bitmaps declared with MAX_NR_CPUS bits will increase from 256B to 512B,
cpus_runtime will increase from 81960B to 163880B, and max_entries will
increase from 8192B to 16384B.

Signed-off-by: Kyle Meyer <kyle.meyer@hpe.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Reviewed-by: Leo Yan <leo.yan@arm.com>
---
 tools/lib/perf/include/internal/cpumap.h | 2 +-
 tools/perf/perf.h                        | 2 +-
 tools/perf/util/bpf_skel/kwork_top.bpf.c | 4 +++-
 3 files changed, 5 insertions(+), 3 deletions(-)

Index: perf-6.4.0.git26920.4570763476/tools/lib/perf/include/internal/cpumap.h
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/lib/perf/include/internal/cpumap.h
+++ perf-6.4.0.git26920.4570763476/tools/lib/perf/include/internal/cpumap.h
@@ -21,10 +21,6 @@ DECLARE_RC_STRUCT(perf_cpu_map) {
 	struct perf_cpu	map[];
 };
 
-#ifndef MAX_NR_CPUS
-#define MAX_NR_CPUS	2048
-#endif
-
 struct perf_cpu_map *perf_cpu_map__alloc(int nr_cpus);
 int perf_cpu_map__idx(const struct perf_cpu_map *cpus, struct perf_cpu cpu);
 bool perf_cpu_map__is_subset(const struct perf_cpu_map *a, const struct perf_cpu_map *b);
Index: perf-6.4.0.git26920.4570763476/tools/perf/perf.h
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/perf.h
+++ perf-6.4.0.git26920.4570763476/tools/perf/perf.h
@@ -3,7 +3,7 @@
 #define _PERF_PERF_H
 
 #ifndef MAX_NR_CPUS
-#define MAX_NR_CPUS			2048
+#define MAX_NR_CPUS			4096
 #endif
 
 enum perf_affinity {
Index: perf-6.4.0.git26920.4570763476/tools/perf/util/bpf_skel/kwork_top.bpf.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/util/bpf_skel/kwork_top.bpf.c
+++ perf-6.4.0.git26920.4570763476/tools/perf/util/bpf_skel/kwork_top.bpf.c
@@ -18,7 +18,9 @@ enum kwork_class_type {
 };
 
 #define MAX_ENTRIES     102400
-#define MAX_NR_CPUS     2048
+#ifndef MAX_NR_CPUS
+#define MAX_NR_CPUS     4096
+#endif
 #define PF_KTHREAD      0x00200000
 #define MAX_COMMAND_LEN 16
 
Index: perf-6.4.0.git26920.4570763476/tools/perf/builtin-annotate.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/builtin-annotate.c
+++ perf-6.4.0.git26920.4570763476/tools/perf/builtin-annotate.c
@@ -7,6 +7,7 @@
  * a histogram of results, along various sorting keys.
  */
 #include "builtin.h"
+#include "perf.h"
 
 #include "util/color.h"
 #include <linux/list.h>
Index: perf-6.4.0.git26920.4570763476/tools/perf/builtin-diff.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/builtin-diff.c
+++ perf-6.4.0.git26920.4570763476/tools/perf/builtin-diff.c
@@ -6,6 +6,7 @@
  * DSOs and symbol information, sort them and produce a diff.
  */
 #include "builtin.h"
+#include "perf.h"
 
 #include "util/debug.h"
 #include "util/event.h"
Index: perf-6.4.0.git26920.4570763476/tools/perf/builtin-kwork.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/builtin-kwork.c
+++ perf-6.4.0.git26920.4570763476/tools/perf/builtin-kwork.c
@@ -6,6 +6,7 @@
  */
 
 #include "builtin.h"
+#include "perf.h"
 
 #include "util/data.h"
 #include "util/evlist.h"
Index: perf-6.4.0.git26920.4570763476/tools/perf/builtin-mem.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/builtin-mem.c
+++ perf-6.4.0.git26920.4570763476/tools/perf/builtin-mem.c
@@ -4,6 +4,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include "builtin.h"
+#include "perf.h"
 
 #include <subcmd/parse-options.h>
 #include "util/auxtrace.h"
Index: perf-6.4.0.git26920.4570763476/tools/perf/builtin-sched.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/builtin-sched.c
+++ perf-6.4.0.git26920.4570763476/tools/perf/builtin-sched.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "builtin.h"
+#include "perf.h"
 #include "perf-sys.h"
 
 #include "util/cpumap.h"
Index: perf-6.4.0.git26920.4570763476/tools/perf/util/kwork.h
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/util/kwork.h
+++ perf-6.4.0.git26920.4570763476/tools/perf/util/kwork.h
@@ -1,6 +1,7 @@
 #ifndef PERF_UTIL_KWORK_H
 #define PERF_UTIL_KWORK_H
 
+#include "perf.h"
 #include "util/tool.h"
 #include "util/time-utils.h"
 
Index: perf-6.4.0.git26920.4570763476/tools/perf/util/session.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/util/session.c
+++ perf-6.4.0.git26920.4570763476/tools/perf/util/session.c
@@ -36,6 +36,7 @@
 #include "util.h"
 #include "arch/common.h"
 #include "units.h"
+#include "perf.h"
 #include <internal/lib.h>
 
 #ifdef HAVE_ZSTD_SUPPORT
Index: perf-6.4.0.git26920.4570763476/tools/perf/util/svghelper.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/util/svghelper.c
+++ perf-6.4.0.git26920.4570763476/tools/perf/util/svghelper.c
@@ -21,6 +21,7 @@
 #include <perf/cpumap.h>
 
 #include "env.h"
+#include "perf.h"
 #include "svghelper.h"
 
 static u64 first_time, last_time;
Index: perf-6.4.0.git26920.4570763476/tools/lib/perf/cpumap.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/lib/perf/cpumap.c
+++ perf-6.4.0.git26920.4570763476/tools/lib/perf/cpumap.c
@@ -9,6 +9,9 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <limits.h>
+#include <api/fs/fs.h>
+
+#define MAX_NR_CPUS 4096
 
 void perf_cpu_map__set_nr(struct perf_cpu_map *map, int nr_cpus)
 {
@@ -129,75 +132,16 @@ static struct perf_cpu_map *cpu_map__tri
 	return cpus;
 }
 
-struct perf_cpu_map *perf_cpu_map__read(FILE *file)
-{
-	struct perf_cpu_map *cpus = NULL;
-	int nr_cpus = 0;
-	struct perf_cpu *tmp_cpus = NULL, *tmp;
-	int max_entries = 0;
-	int n, cpu, prev;
-	char sep;
-
-	sep = 0;
-	prev = -1;
-	for (;;) {
-		n = fscanf(file, "%u%c", &cpu, &sep);
-		if (n <= 0)
-			break;
-		if (prev >= 0) {
-			int new_max = nr_cpus + cpu - prev - 1;
-
-			WARN_ONCE(new_max >= MAX_NR_CPUS, "Perf can support %d CPUs. "
-							  "Consider raising MAX_NR_CPUS\n", MAX_NR_CPUS);
-
-			if (new_max >= max_entries) {
-				max_entries = new_max + MAX_NR_CPUS / 2;
-				tmp = realloc(tmp_cpus, max_entries * sizeof(struct perf_cpu));
-				if (tmp == NULL)
-					goto out_free_tmp;
-				tmp_cpus = tmp;
-			}
-
-			while (++prev < cpu)
-				tmp_cpus[nr_cpus++].cpu = prev;
-		}
-		if (nr_cpus == max_entries) {
-			max_entries += MAX_NR_CPUS;
-			tmp = realloc(tmp_cpus, max_entries * sizeof(struct perf_cpu));
-			if (tmp == NULL)
-				goto out_free_tmp;
-			tmp_cpus = tmp;
-		}
-
-		tmp_cpus[nr_cpus++].cpu = cpu;
-		if (n == 2 && sep == '-')
-			prev = cpu;
-		else
-			prev = -1;
-		if (n == 1 || sep == '\n')
-			break;
-	}
-
-	if (nr_cpus > 0)
-		cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
-	else
-		cpus = cpu_map__default_new();
-out_free_tmp:
-	free(tmp_cpus);
-	return cpus;
-}
-
 static struct perf_cpu_map *cpu_map__read_all_cpu_map(void)
 {
 	struct perf_cpu_map *cpus = NULL;
-	FILE *onlnf;
+	char *buf = NULL;
+	size_t buf_len;
 
-	onlnf = fopen("/sys/devices/system/cpu/online", "r");
-	if (!onlnf)
-		return cpu_map__default_new();
-
-	cpus = perf_cpu_map__read(onlnf);
-	fclose(onlnf);
+	if (sysfs__read_str("devices/system/cpu/online", &buf, &buf_len) >= 0) {
+		cpus = perf_cpu_map__new(buf);
+		free(buf);
+	}
 	return cpus;
 }
 
@@ -225,7 +169,7 @@ struct perf_cpu_map *perf_cpu_map__new(c
 		p = NULL;
 		start_cpu = strtoul(cpu_list, &p, 0);
 		if (start_cpu >= INT_MAX
-		    || (*p != '\0' && *p != ',' && *p != '-'))
+		    || (*p != '\0' && *p != ',' && *p != '-' && *p != '\n'))
 			goto invalid;
 
 		if (*p == '-') {
@@ -233,7 +177,7 @@ struct perf_cpu_map *perf_cpu_map__new(c
 			p = NULL;
 			end_cpu = strtoul(cpu_list, &p, 0);
 
-			if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
+			if (end_cpu >= INT_MAX || (*p != '\0' && *p != ',' && *p != '\n'))
 				goto invalid;
 
 			if (end_cpu < start_cpu)
@@ -252,7 +196,7 @@ struct perf_cpu_map *perf_cpu_map__new(c
 					goto invalid;
 
 			if (nr_cpus == max_entries) {
-				max_entries += MAX_NR_CPUS;
+				max_entries += max(end_cpu - start_cpu + 1, 16UL);
 				tmp = realloc(tmp_cpus, max_entries * sizeof(struct perf_cpu));
 				if (tmp == NULL)
 					goto invalid;
Index: perf-6.4.0.git26920.4570763476/tools/perf/util/pmu.c
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/perf/util/pmu.c
+++ perf-6.4.0.git26920.4570763476/tools/perf/util/pmu.c
@@ -12,6 +12,7 @@
 #include <stdbool.h>
 #include <dirent.h>
 #include <api/fs/fs.h>
+#include <api/io.h>
 #include <locale.h>
 #include <fnmatch.h>
 #include <math.h>
@@ -725,26 +726,35 @@ static int pmu_alias_terms(struct perf_p
  * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
  * may have a "cpus" file.
  */
-static struct perf_cpu_map *pmu_cpumask(int dirfd, const char *name, bool is_core)
+static struct perf_cpu_map *pmu_cpumask(int dirfd, const char *pmu_name, bool is_core)
 {
-	struct perf_cpu_map *cpus;
 	const char *templates[] = {
 		"cpumask",
 		"cpus",
 		NULL
 	};
 	const char **template;
-	char pmu_name[PATH_MAX];
-	struct perf_pmu pmu = {.name = pmu_name};
-	FILE *file;
 
-	strlcpy(pmu_name, name, sizeof(pmu_name));
 	for (template = templates; *template; template++) {
-		file = perf_pmu__open_file_at(&pmu, dirfd, *template);
-		if (!file)
+		struct io io;
+		char buf[128];
+		char *cpumask = NULL;
+		size_t cpumask_len;
+		ssize_t ret;
+		struct perf_cpu_map *cpus;
+
+		io.fd = perf_pmu__pathname_fd(dirfd, pmu_name, *template, O_RDONLY);
+		if (io.fd < 0)
 			continue;
-		cpus = perf_cpu_map__read(file);
-		fclose(file);
+
+		io__init(&io, io.fd, buf, sizeof(buf));
+		ret = io__getline(&io, &cpumask, &cpumask_len);
+		close(io.fd);
+		if (ret < 0)
+			continue;
+
+		cpus = perf_cpu_map__new(cpumask);
+		free(cpumask);
 		if (cpus)
 			return cpus;
 	}
Index: perf-6.4.0.git26920.4570763476/tools/lib/perf/Documentation/libperf.txt
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/lib/perf/Documentation/libperf.txt
+++ perf-6.4.0.git26920.4570763476/tools/lib/perf/Documentation/libperf.txt
@@ -39,7 +39,6 @@ SYNOPSIS
 
   struct perf_cpu_map *perf_cpu_map__dummy_new(void);
   struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
-  struct perf_cpu_map *perf_cpu_map__read(FILE *file);
   struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
   struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
                                            struct perf_cpu_map *other);
Index: perf-6.4.0.git26920.4570763476/tools/lib/perf/include/perf/cpumap.h
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/lib/perf/include/perf/cpumap.h
+++ perf-6.4.0.git26920.4570763476/tools/lib/perf/include/perf/cpumap.h
@@ -3,7 +3,6 @@
 #define __LIBPERF_CPUMAP_H
 
 #include <perf/core.h>
-#include <stdio.h>
 #include <stdbool.h>
 
 /** A wrapper around a CPU to avoid confusion with the perf_cpu_map's map's indices. */
@@ -24,7 +23,6 @@ struct perf_cpu_map;
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
-LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
 						     struct perf_cpu_map *other);
Index: perf-6.4.0.git26920.4570763476/tools/lib/perf/libperf.map
===================================================================
--- perf-6.4.0.git26920.4570763476.orig/tools/lib/perf/libperf.map
+++ perf-6.4.0.git26920.4570763476/tools/lib/perf/libperf.map
@@ -6,7 +6,6 @@ LIBPERF_0.0.1 {
 		perf_cpu_map__get;
 		perf_cpu_map__put;
 		perf_cpu_map__new;
-		perf_cpu_map__read;
 		perf_cpu_map__nr;
 		perf_cpu_map__cpu;
 		perf_cpu_map__empty;
