'/proc/schedstat' gives the info about load balancing statistics within
a given domain. It also contains the cpu_mask giving information about
the sibling cpus and domain names after schedstat version 17. Storing
this information in perf header will help tools like `perf sched stats`
for better analysis.
Signed-off-by: Swapnil Sapkal <swapnil.sapkal@amd.com>
---
.../Documentation/perf.data-file-format.txt | 17 +
tools/perf/builtin-inject.c | 1 +
tools/perf/util/env.h | 16 +
tools/perf/util/header.c | 304 ++++++++++++++++++
tools/perf/util/header.h | 1 +
tools/perf/util/util.c | 42 +++
tools/perf/util/util.h | 3 +
7 files changed, 384 insertions(+)
diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
index cd95ba09f727..92dbba1003cf 100644
--- a/tools/perf/Documentation/perf.data-file-format.txt
+++ b/tools/perf/Documentation/perf.data-file-format.txt
@@ -437,6 +437,23 @@ struct {
} [nr_pmu];
};
+ HEADER_CPU_DOMAIN_INFO = 32,
+
+List of cpu-domain relation info. The format of the data is as below.
+
+struct domain_info {
+ int domain;
+ char dname[];
+ char cpumask[];
+ char cpulist[];
+};
+
+struct cpu_domain_info {
+ int cpu;
+ int nr_domains;
+ struct domain_info domains[];
+};
+
other bits are reserved and should ignored for now
HEADER_FEAT_BITS = 256,
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index a114b3fa1bea..f43a7ec44b5f 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -2058,6 +2058,7 @@ static bool keep_feat(int feat)
case HEADER_CLOCK_DATA:
case HEADER_HYBRID_TOPOLOGY:
case HEADER_PMU_CAPS:
+ case HEADER_CPU_DOMAIN_INFO:
return true;
/* Information that can be updated */
case HEADER_BUILD_ID:
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index e00179787a34..71034c4b4488 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -54,6 +54,19 @@ struct pmu_caps {
char *pmu_name;
};
+struct domain_info {
+ u32 domain;
+ char *dname;
+ char *cpumask;
+ char *cpulist;
+};
+
+struct cpu_domain_map {
+ u32 cpu;
+ u32 nr_domains;
+ struct domain_info **domains;
+};
+
typedef const char *(arch_syscalls__strerrno_t)(int err);
struct perf_env {
@@ -70,6 +83,8 @@ struct perf_env {
unsigned int max_branches;
unsigned int br_cntr_nr;
unsigned int br_cntr_width;
+ unsigned int schedstat_version;
+ unsigned int max_sched_domains;
int kernel_is_64_bit;
int nr_cmdline;
@@ -92,6 +107,7 @@ struct perf_env {
char **cpu_pmu_caps;
struct cpu_topology_map *cpu;
struct cpu_cache_level *caches;
+ struct cpu_domain_map **cpu_domain;
int caches_cnt;
u32 comp_ratio;
u32 comp_ver;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4f2a6e10ed5c..7ff7434bac2c 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1621,6 +1621,184 @@ static int write_pmu_caps(struct feat_fd *ff,
return 0;
}
+static void free_cpu_domain_info(struct cpu_domain_map **cd_map, u32 schedstat_version, u32 nr)
+{
+ for (u32 i = 0; i < nr; i++) {
+ if (cd_map[i]->domains) {
+ for (u32 j = 0; j < cd_map[i]->nr_domains; j++) {
+ struct domain_info *d_info = cd_map[i]->domains[j];
+
+ if (schedstat_version >= 17)
+ free(d_info->dname);
+
+ free(d_info->cpumask);
+ free(d_info->cpulist);
+ }
+ free(cd_map[i]->domains);
+ }
+ }
+
+ free(cd_map);
+}
+
+static struct cpu_domain_map **build_cpu_domain_map(u32 *schedstat_version, u32 *max_sched_domains,
+ u32 nr)
+{
+ struct domain_info *domain_info;
+ struct cpu_domain_map **cd_map;
+ char dname[16], cpumask[256];
+ char cpulist[1024];
+ char *line = NULL;
+ u32 cpu, domain;
+ u32 dcount = 0;
+ size_t len;
+ FILE *fp;
+
+ fp = fopen("/proc/schedstat", "r");
+ if (!fp) {
+ pr_err("Failed to open /proc/schedstat\n");
+ return NULL;
+ }
+
+ cd_map = calloc(nr, sizeof(*cd_map));
+ if (!cd_map)
+ goto out;
+
+ while (getline(&line, &len, fp) > 0) {
+ int retval;
+
+ if (strncmp(line, "version", 7) == 0) {
+ retval = sscanf(line, "version %d\n", schedstat_version);
+ if (retval != 1)
+ continue;
+
+ } else if (strncmp(line, "cpu", 3) == 0) {
+ retval = sscanf(line, "cpu%u %*s", &cpu);
+ if (retval == 1) {
+ cd_map[cpu] = calloc(1, sizeof(*cd_map[cpu]));
+ if (!cd_map[cpu])
+ goto out_free_line;
+ cd_map[cpu]->cpu = cpu;
+ } else
+ continue;
+
+ dcount = 0;
+ } else if (strncmp(line, "domain", 6) == 0) {
+ dcount++;
+
+ cd_map[cpu]->domains = realloc(cd_map[cpu]->domains,
+ dcount * sizeof(domain_info));
+ if (!cd_map[cpu]->domains)
+ goto out_free_line;
+
+ domain_info = calloc(1, sizeof(*domain_info));
+ if (!domain_info)
+ goto out_free_line;
+
+ cd_map[cpu]->domains[dcount - 1] = domain_info;
+
+ if (*schedstat_version >= 17) {
+ retval = sscanf(line, "domain%u %s %s %*s", &domain, dname,
+ cpumask);
+ if (retval != 3)
+ continue;
+
+ domain_info->dname = calloc(strlen(dname) + 1, sizeof(char));
+ if (!domain_info->dname)
+ goto out_free_line;
+
+ strcpy(domain_info->dname, dname);
+ } else {
+ retval = sscanf(line, "domain%u %s %*s", &domain, cpumask);
+ if (retval != 2)
+ continue;
+ }
+
+ domain_info->domain = domain;
+ if (domain > *max_sched_domains)
+ *max_sched_domains = domain;
+
+ domain_info->cpumask = calloc(strlen(cpumask) + 1, sizeof(char));
+ if (!domain_info->cpumask)
+ goto out_free_line;
+
+ strcpy(domain_info->cpumask, cpumask);
+
+ cpumask_to_cpulist(cpumask, cpulist);
+ domain_info->cpulist = calloc(strlen(cpulist) + 1, sizeof(char));
+ if (!domain_info->cpulist)
+ goto out_free_line;
+
+ strcpy(domain_info->cpulist, cpulist);
+ cd_map[cpu]->nr_domains = dcount;
+ }
+ }
+
+out_free_line:
+ free(line);
+out:
+ fclose(fp);
+ return cd_map;
+}
+
+static int write_cpu_domain_info(struct feat_fd *ff,
+ struct evlist *evlist __maybe_unused)
+{
+ u32 max_sched_domains = 0, schedstat_version = 0;
+ struct cpu_domain_map **cd_map;
+ u32 i, j, nr, ret;
+
+ nr = cpu__max_present_cpu().cpu;
+
+ cd_map = build_cpu_domain_map(&schedstat_version, &max_sched_domains, nr);
+ if (!cd_map)
+ return -1;
+
+ ret = do_write(ff, &schedstat_version, sizeof(u32));
+ if (ret < 0)
+ goto out;
+
+ max_sched_domains += 1;
+ ret = do_write(ff, &max_sched_domains, sizeof(u32));
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < nr; i++) {
+ if (cd_map[i]->domains) {
+ ret = do_write(ff, &cd_map[i]->cpu, sizeof(u32));
+ if (ret < 0)
+ goto out;
+
+ ret = do_write(ff, &cd_map[i]->nr_domains, sizeof(u32));
+ if (ret < 0)
+ goto out;
+
+ for (j = 0; j < cd_map[i]->nr_domains; j++) {
+ ret = do_write(ff, &cd_map[i]->domains[j]->domain, sizeof(u32));
+ if (ret < 0)
+ goto out;
+ if (schedstat_version >= 17) {
+ ret = do_write_string(ff, cd_map[i]->domains[j]->dname);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = do_write_string(ff, cd_map[i]->domains[j]->cpumask);
+ if (ret < 0)
+ goto out;
+
+ ret = do_write_string(ff, cd_map[i]->domains[j]->cpulist);
+ if (ret < 0)
+ goto out;
+ }
+ }
+ }
+
+out:
+ free_cpu_domain_info(cd_map, schedstat_version, nr);
+ return ret;
+}
+
static void print_hostname(struct feat_fd *ff, FILE *fp)
{
fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
@@ -2254,6 +2432,35 @@ static void print_mem_topology(struct feat_fd *ff, FILE *fp)
}
}
+static void print_cpu_domain_info(struct feat_fd *ff, FILE *fp)
+{
+ struct cpu_domain_map **cd_map = ff->ph->env.cpu_domain;
+ u32 nr = ff->ph->env.nr_cpus_avail;
+ struct domain_info *d_info;
+ u32 i, j;
+
+ fprintf(fp, "# schedstat version : %u\n", ff->ph->env.schedstat_version);
+ fprintf(fp, "# Maximum sched domains : %u\n", ff->ph->env.max_sched_domains);
+
+ for (i = 0; i < nr; i++) {
+ if (cd_map[i]->domains) {
+ fprintf(fp, "# cpu : %u\n", cd_map[i]->cpu);
+ fprintf(fp, "# nr_domains : %u\n", cd_map[i]->nr_domains);
+
+ for (j = 0; j < cd_map[i]->nr_domains; j++) {
+ d_info = cd_map[i]->domains[j];
+ fprintf(fp, "# Domain : %u\n", d_info->domain);
+
+ if (ff->ph->env.schedstat_version >= 17)
+ fprintf(fp, "# Domain name : %s\n", d_info->dname);
+
+ fprintf(fp, "# Domain cpu map : %s\n", d_info->cpumask);
+ fprintf(fp, "# Domain cpu list : %s\n", d_info->cpulist);
+ }
+ }
+ }
+}
+
static int __event_process_build_id(struct perf_record_header_build_id *bev,
char *filename,
struct perf_session *session)
@@ -3395,6 +3602,102 @@ static int process_pmu_caps(struct feat_fd *ff, void *data __maybe_unused)
return ret;
}
+static int process_cpu_domain_info(struct feat_fd *ff, void *data __maybe_unused)
+{
+ u32 schedstat_version, max_sched_domains, cpu, domain, nr_domains;
+ struct perf_env *env = &ff->ph->env;
+ char *dname, *cpumask, *cpulist;
+ struct cpu_domain_map **cd_map;
+ struct domain_info *d_info;
+ u32 nra, nr, i, j;
+ int ret;
+
+ nra = env->nr_cpus_avail;
+ nr = env->nr_cpus_online;
+
+ cd_map = calloc(nra, sizeof(*cd_map));
+ if (!cd_map)
+ return -1;
+
+ env->cpu_domain = cd_map;
+
+ ret = do_read_u32(ff, &schedstat_version);
+ if (ret)
+ return ret;
+
+ env->schedstat_version = schedstat_version;
+
+ ret = do_read_u32(ff, &max_sched_domains);
+ if (ret)
+ return ret;
+
+ env->max_sched_domains = max_sched_domains;
+
+ for (i = 0; i < nr; i++) {
+ if (do_read_u32(ff, &cpu))
+ return -1;
+
+ cd_map[cpu] = calloc(1, sizeof(*cd_map[cpu]));
+ if (!cd_map[cpu])
+ return -1;
+
+ cd_map[cpu]->cpu = cpu;
+
+ if (do_read_u32(ff, &nr_domains))
+ return -1;
+
+ cd_map[cpu]->nr_domains = nr_domains;
+
+ cd_map[cpu]->domains = calloc(max_sched_domains, sizeof(*d_info));
+ if (!cd_map[cpu]->domains)
+ return -1;
+
+ for (j = 0; j < nr_domains; j++) {
+ if (do_read_u32(ff, &domain))
+ return -1;
+
+ d_info = calloc(1, sizeof(*d_info));
+ if (!d_info)
+ return -1;
+
+ cd_map[cpu]->domains[domain] = d_info;
+ d_info->domain = domain;
+
+ if (schedstat_version >= 17) {
+ dname = do_read_string(ff);
+ if (!dname)
+ return -1;
+
+ d_info->dname = calloc(strlen(dname) + 1, sizeof(char));
+ if (!d_info->dname)
+ return -1;
+
+ strcpy(d_info->dname, dname);
+ }
+
+ cpumask = do_read_string(ff);
+ if (!cpumask)
+ return -1;
+
+ d_info->cpumask = calloc(strlen(cpumask) + 1, sizeof(char));
+ if (!d_info->cpumask)
+ return -1;
+ strcpy(d_info->cpumask, cpumask);
+
+ cpulist = do_read_string(ff);
+ if (!cpulist)
+ return -1;
+
+ d_info->cpulist = calloc(strlen(cpulist) + 1, sizeof(char));
+ if (!d_info->cpulist)
+ return -1;
+ strcpy(d_info->cpulist, cpulist);
+ }
+ }
+
+ return ret;
+}
+
#define FEAT_OPR(n, func, __full_only) \
[HEADER_##n] = { \
.name = __stringify(n), \
@@ -3460,6 +3763,7 @@ const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPR(CLOCK_DATA, clock_data, false),
FEAT_OPN(HYBRID_TOPOLOGY, hybrid_topology, true),
FEAT_OPR(PMU_CAPS, pmu_caps, false),
+ FEAT_OPR(CPU_DOMAIN_INFO, cpu_domain_info, true),
};
struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d16dfceccd74..edcb95e0dc49 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -53,6 +53,7 @@ enum {
HEADER_CLOCK_DATA,
HEADER_HYBRID_TOPOLOGY,
HEADER_PMU_CAPS,
+ HEADER_CPU_DOMAIN_INFO,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 1b91834e11de..47bfc0259b0e 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -263,6 +263,48 @@ void print_separator(int pre_dash_cnt, const char *s, int post_dash_cnt)
graph_dotted_line);
}
+void cpumask_to_cpulist(char *cpumask, char *cpulist)
+{
+ int i, j, bm_size, nbits;
+ int len = strlen(cpumask);
+ unsigned long *bm;
+ char cpus[1024];
+
+ for (i = 0; i < len; i++) {
+ if (cpumask[i] == ',') {
+ for (j = i; j < len; j++)
+ cpumask[j] = cpumask[j + 1];
+ }
+ }
+
+ len = strlen(cpumask);
+ bm_size = (len + 15) / 16;
+ nbits = bm_size * 64;
+ if (nbits <= 0)
+ return;
+
+ bm = calloc(bm_size, sizeof(unsigned long));
+ if (!cpumask)
+ goto free_bm;
+
+ for (i = 0; i < bm_size; i++) {
+ char blk[17];
+ int blklen = len > 16 ? 16 : len;
+
+ strncpy(blk, cpumask + len - blklen, blklen);
+ blk[len] = '\0';
+ bm[i] = strtoul(blk, NULL, 16);
+ cpumask[len - blklen] = '\0';
+ len = strlen(cpumask);
+ }
+
+ bitmap_scnprintf(bm, nbits, cpus, sizeof(cpus));
+ strcpy(cpulist, cpus);
+
+free_bm:
+ free(bm);
+}
+
int rm_rf_perf_data(const char *path)
{
const char *pat[] = {
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index de69384380c2..90a8b4d2e59c 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -11,6 +11,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <linux/compiler.h>
+#include <linux/bitmap.h>
#include <sys/types.h>
#ifndef __cplusplus
#include <internal/cpumap.h>
@@ -50,6 +51,8 @@ int perf_tip(char **strp, const char *dirpath);
void print_separator(int pre_dash_cnt, const char *s, int post_dash_cnt);
+void cpumask_to_cpulist(char *cpumask, char *cpulist);
+
#ifndef HAVE_SCHED_GETCPU_SUPPORT
int sched_getcpu(void);
#endif
--
2.43.0
On Tue, Sep 09, 2025 at 11:42:19AM +0000, Swapnil Sapkal wrote:
> '/proc/schedstat' gives the info about load balancing statistics within
> a given domain. It also contains the cpu_mask giving information about
> the sibling cpus and domain names after schedstat version 17. Storing
> this information in perf header will help tools like `perf sched stats`
> for better analysis.
>
> Signed-off-by: Swapnil Sapkal <swapnil.sapkal@amd.com>
> ---
> .../Documentation/perf.data-file-format.txt | 17 +
> tools/perf/builtin-inject.c | 1 +
> tools/perf/util/env.h | 16 +
> tools/perf/util/header.c | 304 ++++++++++++++++++
> tools/perf/util/header.h | 1 +
> tools/perf/util/util.c | 42 +++
> tools/perf/util/util.h | 3 +
> 7 files changed, 384 insertions(+)
>
> diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
> index cd95ba09f727..92dbba1003cf 100644
> --- a/tools/perf/Documentation/perf.data-file-format.txt
> +++ b/tools/perf/Documentation/perf.data-file-format.txt
> @@ -437,6 +437,23 @@ struct {
> } [nr_pmu];
> };
>
> + HEADER_CPU_DOMAIN_INFO = 32,
> +
> +List of cpu-domain relation info. The format of the data is as below.
> +
> +struct domain_info {
> + int domain;
> + char dname[];
> + char cpumask[];
> + char cpulist[];
> +};
> +
> +struct cpu_domain_info {
> + int cpu;
> + int nr_domains;
> + struct domain_info domains[];
> +};
> +
> other bits are reserved and should ignored for now
> HEADER_FEAT_BITS = 256,
>
> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> index a114b3fa1bea..f43a7ec44b5f 100644
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c
> @@ -2058,6 +2058,7 @@ static bool keep_feat(int feat)
> case HEADER_CLOCK_DATA:
> case HEADER_HYBRID_TOPOLOGY:
> case HEADER_PMU_CAPS:
> + case HEADER_CPU_DOMAIN_INFO:
> return true;
> /* Information that can be updated */
> case HEADER_BUILD_ID:
> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
> index e00179787a34..71034c4b4488 100644
> --- a/tools/perf/util/env.h
> +++ b/tools/perf/util/env.h
> @@ -54,6 +54,19 @@ struct pmu_caps {
> char *pmu_name;
> };
>
> +struct domain_info {
> + u32 domain;
> + char *dname;
> + char *cpumask;
> + char *cpulist;
> +};
> +
> +struct cpu_domain_map {
> + u32 cpu;
> + u32 nr_domains;
> + struct domain_info **domains;
> +};
> +
> typedef const char *(arch_syscalls__strerrno_t)(int err);
>
> struct perf_env {
> @@ -70,6 +83,8 @@ struct perf_env {
> unsigned int max_branches;
> unsigned int br_cntr_nr;
> unsigned int br_cntr_width;
> + unsigned int schedstat_version;
> + unsigned int max_sched_domains;
> int kernel_is_64_bit;
>
> int nr_cmdline;
> @@ -92,6 +107,7 @@ struct perf_env {
> char **cpu_pmu_caps;
> struct cpu_topology_map *cpu;
> struct cpu_cache_level *caches;
> + struct cpu_domain_map **cpu_domain;
> int caches_cnt;
> u32 comp_ratio;
> u32 comp_ver;
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index 4f2a6e10ed5c..7ff7434bac2c 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -1621,6 +1621,184 @@ static int write_pmu_caps(struct feat_fd *ff,
> return 0;
> }
>
> +static void free_cpu_domain_info(struct cpu_domain_map **cd_map, u32 schedstat_version, u32 nr)
> +{
> + for (u32 i = 0; i < nr; i++) {
> + if (cd_map[i]->domains) {
> + for (u32 j = 0; j < cd_map[i]->nr_domains; j++) {
> + struct domain_info *d_info = cd_map[i]->domains[j];
> +
I'm not sure if it needs a NULL check for d_info before access.
> + if (schedstat_version >= 17)
> + free(d_info->dname);
> +
> + free(d_info->cpumask);
> + free(d_info->cpulist);
> + }
> + free(cd_map[i]->domains);
> + }
> + }
> +
> + free(cd_map);
> +}
> +
> +static struct cpu_domain_map **build_cpu_domain_map(u32 *schedstat_version, u32 *max_sched_domains,
> + u32 nr)
> +{
> + struct domain_info *domain_info;
> + struct cpu_domain_map **cd_map;
> + char dname[16], cpumask[256];
> + char cpulist[1024];
> + char *line = NULL;
> + u32 cpu, domain;
> + u32 dcount = 0;
> + size_t len;
> + FILE *fp;
> +
> + fp = fopen("/proc/schedstat", "r");
> + if (!fp) {
> + pr_err("Failed to open /proc/schedstat\n");
> + return NULL;
> + }
> +
> + cd_map = calloc(nr, sizeof(*cd_map));
> + if (!cd_map)
> + goto out;
> +
> + while (getline(&line, &len, fp) > 0) {
> + int retval;
> +
> + if (strncmp(line, "version", 7) == 0) {
> + retval = sscanf(line, "version %d\n", schedstat_version);
> + if (retval != 1)
> + continue;
> +
> + } else if (strncmp(line, "cpu", 3) == 0) {
> + retval = sscanf(line, "cpu%u %*s", &cpu);
> + if (retval == 1) {
> + cd_map[cpu] = calloc(1, sizeof(*cd_map[cpu]));
> + if (!cd_map[cpu])
> + goto out_free_line;
> + cd_map[cpu]->cpu = cpu;
> + } else
> + continue;
> +
> + dcount = 0;
> + } else if (strncmp(line, "domain", 6) == 0) {
> + dcount++;
> +
> + cd_map[cpu]->domains = realloc(cd_map[cpu]->domains,
> + dcount * sizeof(domain_info));
> + if (!cd_map[cpu]->domains)
> + goto out_free_line;
Please use a temporary variable to save the result in order to not lose
the original pointer in case of failure.
> +
> + domain_info = calloc(1, sizeof(*domain_info));
> + if (!domain_info)
> + goto out_free_line;
> +
> + cd_map[cpu]->domains[dcount - 1] = domain_info;
> +
> + if (*schedstat_version >= 17) {
> + retval = sscanf(line, "domain%u %s %s %*s", &domain, dname,
> + cpumask);
> + if (retval != 3)
> + continue;
> +
> + domain_info->dname = calloc(strlen(dname) + 1, sizeof(char));
> + if (!domain_info->dname)
> + goto out_free_line;
> +
> + strcpy(domain_info->dname, dname);
This can be simply:
domain_info->dname = strdup(dname);
> + } else {
> + retval = sscanf(line, "domain%u %s %*s", &domain, cpumask);
> + if (retval != 2)
> + continue;
> + }
> +
> + domain_info->domain = domain;
> + if (domain > *max_sched_domains)
> + *max_sched_domains = domain;
> +
> + domain_info->cpumask = calloc(strlen(cpumask) + 1, sizeof(char));
> + if (!domain_info->cpumask)
> + goto out_free_line;
> +
> + strcpy(domain_info->cpumask, cpumask);
> +
> + cpumask_to_cpulist(cpumask, cpulist);
> + domain_info->cpulist = calloc(strlen(cpulist) + 1, sizeof(char));
> + if (!domain_info->cpulist)
> + goto out_free_line;
All error paths should call free_cpu_domain_info() at some point and
free the intermediate domain_info properly.
> +
> + strcpy(domain_info->cpulist, cpulist);
> + cd_map[cpu]->nr_domains = dcount;
> + }
> + }
> +
> +out_free_line:
> + free(line);
> +out:
> + fclose(fp);
> + return cd_map;
> +}
> +
> +static int write_cpu_domain_info(struct feat_fd *ff,
> + struct evlist *evlist __maybe_unused)
> +{
> + u32 max_sched_domains = 0, schedstat_version = 0;
> + struct cpu_domain_map **cd_map;
> + u32 i, j, nr, ret;
> +
> + nr = cpu__max_present_cpu().cpu;
> +
> + cd_map = build_cpu_domain_map(&schedstat_version, &max_sched_domains, nr);
> + if (!cd_map)
> + return -1;
> +
> + ret = do_write(ff, &schedstat_version, sizeof(u32));
> + if (ret < 0)
> + goto out;
> +
> + max_sched_domains += 1;
> + ret = do_write(ff, &max_sched_domains, sizeof(u32));
> + if (ret < 0)
> + goto out;
> +
> + for (i = 0; i < nr; i++) {
> + if (cd_map[i]->domains) {
Is it supposed to have NULL domains? Anyway it'd be nice if you can
skip the case like with 'continue' statement to reduce the indentation
level.
> + ret = do_write(ff, &cd_map[i]->cpu, sizeof(u32));
> + if (ret < 0)
> + goto out;
> +
> + ret = do_write(ff, &cd_map[i]->nr_domains, sizeof(u32));
> + if (ret < 0)
> + goto out;
> +
> + for (j = 0; j < cd_map[i]->nr_domains; j++) {
> + ret = do_write(ff, &cd_map[i]->domains[j]->domain, sizeof(u32));
> + if (ret < 0)
> + goto out;
> + if (schedstat_version >= 17) {
> + ret = do_write_string(ff, cd_map[i]->domains[j]->dname);
> + if (ret < 0)
> + goto out;
> + }
> +
> + ret = do_write_string(ff, cd_map[i]->domains[j]->cpumask);
> + if (ret < 0)
> + goto out;
> +
> + ret = do_write_string(ff, cd_map[i]->domains[j]->cpulist);
> + if (ret < 0)
> + goto out;
> + }
> + }
> + }
> +
> +out:
> + free_cpu_domain_info(cd_map, schedstat_version, nr);
> + return ret;
> +}
> +
> static void print_hostname(struct feat_fd *ff, FILE *fp)
> {
> fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
> @@ -2254,6 +2432,35 @@ static void print_mem_topology(struct feat_fd *ff, FILE *fp)
> }
> }
>
> +static void print_cpu_domain_info(struct feat_fd *ff, FILE *fp)
> +{
> + struct cpu_domain_map **cd_map = ff->ph->env.cpu_domain;
> + u32 nr = ff->ph->env.nr_cpus_avail;
> + struct domain_info *d_info;
> + u32 i, j;
> +
> + fprintf(fp, "# schedstat version : %u\n", ff->ph->env.schedstat_version);
> + fprintf(fp, "# Maximum sched domains : %u\n", ff->ph->env.max_sched_domains);
> +
> + for (i = 0; i < nr; i++) {
> + if (cd_map[i]->domains) {
Ditto.
> + fprintf(fp, "# cpu : %u\n", cd_map[i]->cpu);
> + fprintf(fp, "# nr_domains : %u\n", cd_map[i]->nr_domains);
> +
> + for (j = 0; j < cd_map[i]->nr_domains; j++) {
> + d_info = cd_map[i]->domains[j];
> + fprintf(fp, "# Domain : %u\n", d_info->domain);
> +
> + if (ff->ph->env.schedstat_version >= 17)
> + fprintf(fp, "# Domain name : %s\n", d_info->dname);
> +
> + fprintf(fp, "# Domain cpu map : %s\n", d_info->cpumask);
> + fprintf(fp, "# Domain cpu list : %s\n", d_info->cpulist);
> + }
> + }
> + }
> +}
> +
> static int __event_process_build_id(struct perf_record_header_build_id *bev,
> char *filename,
> struct perf_session *session)
> @@ -3395,6 +3602,102 @@ static int process_pmu_caps(struct feat_fd *ff, void *data __maybe_unused)
> return ret;
> }
>
> +static int process_cpu_domain_info(struct feat_fd *ff, void *data __maybe_unused)
> +{
> + u32 schedstat_version, max_sched_domains, cpu, domain, nr_domains;
> + struct perf_env *env = &ff->ph->env;
> + char *dname, *cpumask, *cpulist;
> + struct cpu_domain_map **cd_map;
> + struct domain_info *d_info;
> + u32 nra, nr, i, j;
> + int ret;
> +
> + nra = env->nr_cpus_avail;
> + nr = env->nr_cpus_online;
> +
> + cd_map = calloc(nra, sizeof(*cd_map));
> + if (!cd_map)
> + return -1;
> +
> + env->cpu_domain = cd_map;
Where is it freed?
Thanks,
Namhyung
> +
> + ret = do_read_u32(ff, &schedstat_version);
> + if (ret)
> + return ret;
> +
> + env->schedstat_version = schedstat_version;
> +
> + ret = do_read_u32(ff, &max_sched_domains);
> + if (ret)
> + return ret;
> +
> + env->max_sched_domains = max_sched_domains;
> +
> + for (i = 0; i < nr; i++) {
> + if (do_read_u32(ff, &cpu))
> + return -1;
> +
> + cd_map[cpu] = calloc(1, sizeof(*cd_map[cpu]));
> + if (!cd_map[cpu])
> + return -1;
> +
> + cd_map[cpu]->cpu = cpu;
> +
> + if (do_read_u32(ff, &nr_domains))
> + return -1;
> +
> + cd_map[cpu]->nr_domains = nr_domains;
> +
> + cd_map[cpu]->domains = calloc(max_sched_domains, sizeof(*d_info));
> + if (!cd_map[cpu]->domains)
> + return -1;
> +
> + for (j = 0; j < nr_domains; j++) {
> + if (do_read_u32(ff, &domain))
> + return -1;
> +
> + d_info = calloc(1, sizeof(*d_info));
> + if (!d_info)
> + return -1;
> +
> + cd_map[cpu]->domains[domain] = d_info;
> + d_info->domain = domain;
> +
> + if (schedstat_version >= 17) {
> + dname = do_read_string(ff);
> + if (!dname)
> + return -1;
> +
> + d_info->dname = calloc(strlen(dname) + 1, sizeof(char));
> + if (!d_info->dname)
> + return -1;
> +
> + strcpy(d_info->dname, dname);
> + }
> +
> + cpumask = do_read_string(ff);
> + if (!cpumask)
> + return -1;
> +
> + d_info->cpumask = calloc(strlen(cpumask) + 1, sizeof(char));
> + if (!d_info->cpumask)
> + return -1;
> + strcpy(d_info->cpumask, cpumask);
> +
> + cpulist = do_read_string(ff);
> + if (!cpulist)
> + return -1;
> +
> + d_info->cpulist = calloc(strlen(cpulist) + 1, sizeof(char));
> + if (!d_info->cpulist)
> + return -1;
> + strcpy(d_info->cpulist, cpulist);
> + }
> + }
> +
> + return ret;
> +}
> +
> #define FEAT_OPR(n, func, __full_only) \
> [HEADER_##n] = { \
> .name = __stringify(n), \
> @@ -3460,6 +3763,7 @@ const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
> FEAT_OPR(CLOCK_DATA, clock_data, false),
> FEAT_OPN(HYBRID_TOPOLOGY, hybrid_topology, true),
> FEAT_OPR(PMU_CAPS, pmu_caps, false),
> + FEAT_OPR(CPU_DOMAIN_INFO, cpu_domain_info, true),
> };
>
> struct header_print_data {
> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
> index d16dfceccd74..edcb95e0dc49 100644
> --- a/tools/perf/util/header.h
> +++ b/tools/perf/util/header.h
> @@ -53,6 +53,7 @@ enum {
> HEADER_CLOCK_DATA,
> HEADER_HYBRID_TOPOLOGY,
> HEADER_PMU_CAPS,
> + HEADER_CPU_DOMAIN_INFO,
> HEADER_LAST_FEATURE,
> HEADER_FEAT_BITS = 256,
> };
> diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
> index 1b91834e11de..47bfc0259b0e 100644
> --- a/tools/perf/util/util.c
> +++ b/tools/perf/util/util.c
> @@ -263,6 +263,48 @@ void print_separator(int pre_dash_cnt, const char *s, int post_dash_cnt)
> graph_dotted_line);
> }
>
> +void cpumask_to_cpulist(char *cpumask, char *cpulist)
> +{
> + int i, j, bm_size, nbits;
> + int len = strlen(cpumask);
> + unsigned long *bm;
> + char cpus[1024];
> +
> + for (i = 0; i < len; i++) {
> + if (cpumask[i] == ',') {
> + for (j = i; j < len; j++)
> + cpumask[j] = cpumask[j + 1];
> + }
> + }
> +
> + len = strlen(cpumask);
> + bm_size = (len + 15) / 16;
> + nbits = bm_size * 64;
> + if (nbits <= 0)
> + return;
> +
> + bm = calloc(bm_size, sizeof(unsigned long));
> + if (!cpumask)
> + goto free_bm;
> +
> + for (i = 0; i < bm_size; i++) {
> + char blk[17];
> + int blklen = len > 16 ? 16 : len;
> +
> + strncpy(blk, cpumask + len - blklen, blklen);
> + blk[len] = '\0';
> + bm[i] = strtoul(blk, NULL, 16);
> + cpumask[len - blklen] = '\0';
> + len = strlen(cpumask);
> + }
> +
> + bitmap_scnprintf(bm, nbits, cpus, sizeof(cpus));
> + strcpy(cpulist, cpus);
> +
> +free_bm:
> + free(bm);
> +}
> +
> int rm_rf_perf_data(const char *path)
> {
> const char *pat[] = {
> diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
> index de69384380c2..90a8b4d2e59c 100644
> --- a/tools/perf/util/util.h
> +++ b/tools/perf/util/util.h
> @@ -11,6 +11,7 @@
> #include <stdbool.h>
> #include <stddef.h>
> #include <linux/compiler.h>
> +#include <linux/bitmap.h>
> #include <sys/types.h>
> #ifndef __cplusplus
> #include <internal/cpumap.h>
> @@ -50,6 +51,8 @@ int perf_tip(char **strp, const char *dirpath);
>
> void print_separator(int pre_dash_cnt, const char *s, int post_dash_cnt);
>
> +void cpumask_to_cpulist(char *cpumask, char *cpulist);
> +
> #ifndef HAVE_SCHED_GETCPU_SUPPORT
> int sched_getcpu(void);
> #endif
> --
> 2.43.0
>
Hello Namhyung,
On 03-01-2026 03:56, Namhyung Kim wrote:
> On Tue, Sep 09, 2025 at 11:42:19AM +0000, Swapnil Sapkal wrote:
>> '/proc/schedstat' gives the info about load balancing statistics within
>> a given domain. It also contains the cpu_mask giving information about
>> the sibling cpus and domain names after schedstat version 17. Storing
>> this information in perf header will help tools like `perf sched stats`
>> for better analysis.
>>
>> Signed-off-by: Swapnil Sapkal <swapnil.sapkal@amd.com>
>> ---
>> .../Documentation/perf.data-file-format.txt | 17 +
>> tools/perf/builtin-inject.c | 1 +
>> tools/perf/util/env.h | 16 +
>> tools/perf/util/header.c | 304 ++++++++++++++++++
>> tools/perf/util/header.h | 1 +
>> tools/perf/util/util.c | 42 +++
>> tools/perf/util/util.h | 3 +
>> 7 files changed, 384 insertions(+)
>>
>> diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
>> index cd95ba09f727..92dbba1003cf 100644
>> --- a/tools/perf/Documentation/perf.data-file-format.txt
>> +++ b/tools/perf/Documentation/perf.data-file-format.txt
>> @@ -437,6 +437,23 @@ struct {
>> } [nr_pmu];
>> };
>>
>> + HEADER_CPU_DOMAIN_INFO = 32,
>> +
>> +List of cpu-domain relation info. The format of the data is as below.
>> +
>> +struct domain_info {
>> + int domain;
>> + char dname[];
>> + char cpumask[];
>> + char cpulist[];
>> +};
>> +
>> +struct cpu_domain_info {
>> + int cpu;
>> + int nr_domains;
>> + struct domain_info domains[];
>> +};
>> +
>> other bits are reserved and should ignored for now
>> HEADER_FEAT_BITS = 256,
>>
>> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
>> index a114b3fa1bea..f43a7ec44b5f 100644
>> --- a/tools/perf/builtin-inject.c
>> +++ b/tools/perf/builtin-inject.c
>> @@ -2058,6 +2058,7 @@ static bool keep_feat(int feat)
>> case HEADER_CLOCK_DATA:
>> case HEADER_HYBRID_TOPOLOGY:
>> case HEADER_PMU_CAPS:
>> + case HEADER_CPU_DOMAIN_INFO:
>> return true;
>> /* Information that can be updated */
>> case HEADER_BUILD_ID:
>> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
>> index e00179787a34..71034c4b4488 100644
>> --- a/tools/perf/util/env.h
>> +++ b/tools/perf/util/env.h
>> @@ -54,6 +54,19 @@ struct pmu_caps {
>> char *pmu_name;
>> };
>>
>> +struct domain_info {
>> + u32 domain;
>> + char *dname;
>> + char *cpumask;
>> + char *cpulist;
>> +};
>> +
>> +struct cpu_domain_map {
>> + u32 cpu;
>> + u32 nr_domains;
>> + struct domain_info **domains;
>> +};
>> +
>> typedef const char *(arch_syscalls__strerrno_t)(int err);
>>
>> struct perf_env {
>> @@ -70,6 +83,8 @@ struct perf_env {
>> unsigned int max_branches;
>> unsigned int br_cntr_nr;
>> unsigned int br_cntr_width;
>> + unsigned int schedstat_version;
>> + unsigned int max_sched_domains;
>> int kernel_is_64_bit;
>>
>> int nr_cmdline;
>> @@ -92,6 +107,7 @@ struct perf_env {
>> char **cpu_pmu_caps;
>> struct cpu_topology_map *cpu;
>> struct cpu_cache_level *caches;
>> + struct cpu_domain_map **cpu_domain;
>> int caches_cnt;
>> u32 comp_ratio;
>> u32 comp_ver;
>> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
>> index 4f2a6e10ed5c..7ff7434bac2c 100644
>> --- a/tools/perf/util/header.c
>> +++ b/tools/perf/util/header.c
>> @@ -1621,6 +1621,184 @@ static int write_pmu_caps(struct feat_fd *ff,
>> return 0;
>> }
>>
>> +static void free_cpu_domain_info(struct cpu_domain_map **cd_map, u32 schedstat_version, u32 nr)
>> +{
>> + for (u32 i = 0; i < nr; i++) {
>> + if (cd_map[i]->domains) {
>> + for (u32 j = 0; j < cd_map[i]->nr_domains; j++) {
>> + struct domain_info *d_info = cd_map[i]->domains[j];
>> +
>
> I'm not sure if it needs a NULL check for d_info before access.
>
Thanks for catching this. Yes we need a NULL check here.
If some of the cpus are offline then it is possible that some sched
domains can be degenerated and for some cpus.
for e.g. cpu0, cpu128 are smt siblings. If cpu 128 is offline then SMT
domain will be degenerated for cpu0 alone. All the other cpus will have
a valid SMT domain. Thus SMT for the d_info can be NULL.
>
>> + if (schedstat_version >= 17)
>> + free(d_info->dname);
>> +
>> + free(d_info->cpumask);
>> + free(d_info->cpulist);
>> + }
>> + free(cd_map[i]->domains);
>> + }
>> + }
>> +
>> + free(cd_map);
>> +}
>> +
>> +static struct cpu_domain_map **build_cpu_domain_map(u32 *schedstat_version, u32 *max_sched_domains,
>> + u32 nr)
>> +{
>> + struct domain_info *domain_info;
>> + struct cpu_domain_map **cd_map;
>> + char dname[16], cpumask[256];
>> + char cpulist[1024];
>> + char *line = NULL;
>> + u32 cpu, domain;
>> + u32 dcount = 0;
>> + size_t len;
>> + FILE *fp;
>> +
>> + fp = fopen("/proc/schedstat", "r");
>> + if (!fp) {
>> + pr_err("Failed to open /proc/schedstat\n");
>> + return NULL;
>> + }
>> +
>> + cd_map = calloc(nr, sizeof(*cd_map));
>> + if (!cd_map)
>> + goto out;
>> +
>> + while (getline(&line, &len, fp) > 0) {
>> + int retval;
>> +
>> + if (strncmp(line, "version", 7) == 0) {
>> + retval = sscanf(line, "version %d\n", schedstat_version);
>> + if (retval != 1)
>> + continue;
>> +
>> + } else if (strncmp(line, "cpu", 3) == 0) {
>> + retval = sscanf(line, "cpu%u %*s", &cpu);
>> + if (retval == 1) {
>> + cd_map[cpu] = calloc(1, sizeof(*cd_map[cpu]));
>> + if (!cd_map[cpu])
>> + goto out_free_line;
>> + cd_map[cpu]->cpu = cpu;
>> + } else
>> + continue;
>> +
>> + dcount = 0;
>> + } else if (strncmp(line, "domain", 6) == 0) {
>> + dcount++;
>> +
>> + cd_map[cpu]->domains = realloc(cd_map[cpu]->domains,
>> + dcount * sizeof(domain_info));
>> + if (!cd_map[cpu]->domains)
>> + goto out_free_line;
>
> Please use a temporary variable to save the result in order to not lose
> the original pointer in case of failure.
>
Sure, will do.
>> +
>> + domain_info = calloc(1, sizeof(*domain_info));
>> + if (!domain_info)
>> + goto out_free_line;
>> +
>> + cd_map[cpu]->domains[dcount - 1] = domain_info;
>> +
>> + if (*schedstat_version >= 17) {
>> + retval = sscanf(line, "domain%u %s %s %*s", &domain, dname,
>> + cpumask);
>> + if (retval != 3)
>> + continue;
>> +
>> + domain_info->dname = calloc(strlen(dname) + 1, sizeof(char));
>> + if (!domain_info->dname)
>> + goto out_free_line;
>> +
>> + strcpy(domain_info->dname, dname);
>
> This can be simply:
> domain_info->dname = strdup(dname);
>
Sure, will do.
>
>> + } else {
>> + retval = sscanf(line, "domain%u %s %*s", &domain, cpumask);
>> + if (retval != 2)
>> + continue;
>> + }
>> +
>> + domain_info->domain = domain;
>> + if (domain > *max_sched_domains)
>> + *max_sched_domains = domain;
>> +
>> + domain_info->cpumask = calloc(strlen(cpumask) + 1, sizeof(char));
>> + if (!domain_info->cpumask)
>> + goto out_free_line;
>> +
>> + strcpy(domain_info->cpumask, cpumask);
>> +
>> + cpumask_to_cpulist(cpumask, cpulist);
>> + domain_info->cpulist = calloc(strlen(cpulist) + 1, sizeof(char));
>> + if (!domain_info->cpulist)
>> + goto out_free_line;
>
> All error paths should call free_cpu_domain_info() at some point and
> free the intermediate domain_info properly.
>
Sure, will do.
>> +
>> + strcpy(domain_info->cpulist, cpulist);
>> + cd_map[cpu]->nr_domains = dcount;
>> + }
>> + }
>> +
>> +out_free_line:
>> + free(line);
>> +out:
>> + fclose(fp);
>> + return cd_map;
>> +}
>> +
>> +static int write_cpu_domain_info(struct feat_fd *ff,
>> + struct evlist *evlist __maybe_unused)
>> +{
>> + u32 max_sched_domains = 0, schedstat_version = 0;
>> + struct cpu_domain_map **cd_map;
>> + u32 i, j, nr, ret;
>> +
>> + nr = cpu__max_present_cpu().cpu;
>> +
>> + cd_map = build_cpu_domain_map(&schedstat_version, &max_sched_domains, nr);
>> + if (!cd_map)
>> + return -1;
>> +
>> + ret = do_write(ff, &schedstat_version, sizeof(u32));
>> + if (ret < 0)
>> + goto out;
>> +
>> + max_sched_domains += 1;
>> + ret = do_write(ff, &max_sched_domains, sizeof(u32));
>> + if (ret < 0)
>> + goto out;
>> +
>> + for (i = 0; i < nr; i++) {
>> + if (cd_map[i]->domains) {
>
> Is it supposed to have NULL domains?
Yes, It is possible to have NULL domains if the cmdline has isolcpus. I
will also add NULL check for cd_map[i] to handle offline cpu.
> Anyway it'd be nice if you can
> skip the case like with 'continue' statement to reduce the indentation
> level.
>
Sure, will do this.
>> + ret = do_write(ff, &cd_map[i]->cpu, sizeof(u32));
>> + if (ret < 0)
>> + goto out;
>> +
>> + ret = do_write(ff, &cd_map[i]->nr_domains, sizeof(u32));
>> + if (ret < 0)
>> + goto out;
>> +
>> + for (j = 0; j < cd_map[i]->nr_domains; j++) {
>> + ret = do_write(ff, &cd_map[i]->domains[j]->domain, sizeof(u32));
>> + if (ret < 0)
>> + goto out;
>> + if (schedstat_version >= 17) {
>> + ret = do_write_string(ff, cd_map[i]->domains[j]->dname);
>> + if (ret < 0)
>> + goto out;
>> + }
>> +
>> + ret = do_write_string(ff, cd_map[i]->domains[j]->cpumask);
>> + if (ret < 0)
>> + goto out;
>> +
>> + ret = do_write_string(ff, cd_map[i]->domains[j]->cpulist);
>> + if (ret < 0)
>> + goto out;
>> + }
>> + }
>> + }
>> +
>> +out:
>> + free_cpu_domain_info(cd_map, schedstat_version, nr);
>> + return ret;
>> +}
>> +
>> static void print_hostname(struct feat_fd *ff, FILE *fp)
>> {
>> fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
>> @@ -2254,6 +2432,35 @@ static void print_mem_topology(struct feat_fd *ff, FILE *fp)
>> }
>> }
>>
>> +static void print_cpu_domain_info(struct feat_fd *ff, FILE *fp)
>> +{
>> + struct cpu_domain_map **cd_map = ff->ph->env.cpu_domain;
>> + u32 nr = ff->ph->env.nr_cpus_avail;
>> + struct domain_info *d_info;
>> + u32 i, j;
>> +
>> + fprintf(fp, "# schedstat version : %u\n", ff->ph->env.schedstat_version);
>> + fprintf(fp, "# Maximum sched domains : %u\n", ff->ph->env.max_sched_domains);
>> +
>> + for (i = 0; i < nr; i++) {
>> + if (cd_map[i]->domains) {
>
> Ditto.
Ack.
>
>> + fprintf(fp, "# cpu : %u\n", cd_map[i]->cpu);
>> + fprintf(fp, "# nr_domains : %u\n", cd_map[i]->nr_domains);
>> +
>> + for (j = 0; j < cd_map[i]->nr_domains; j++) {
>> + d_info = cd_map[i]->domains[j];
>> + fprintf(fp, "# Domain : %u\n", d_info->domain);
>> +
>> + if (ff->ph->env.schedstat_version >= 17)
>> + fprintf(fp, "# Domain name : %s\n", d_info->dname);
>> +
>> + fprintf(fp, "# Domain cpu map : %s\n", d_info->cpumask);
>> + fprintf(fp, "# Domain cpu list : %s\n", d_info->cpulist);
>> + }
>> + }
>> + }
>> +}
>> +
>> static int __event_process_build_id(struct perf_record_header_build_id *bev,
>> char *filename,
>> struct perf_session *session)
>> @@ -3395,6 +3602,102 @@ static int process_pmu_caps(struct feat_fd *ff, void *data __maybe_unused)
>> return ret;
>> }
>>
>> +static int process_cpu_domain_info(struct feat_fd *ff, void *data __maybe_unused)
>> +{
>> + u32 schedstat_version, max_sched_domains, cpu, domain, nr_domains;
>> + struct perf_env *env = &ff->ph->env;
>> + char *dname, *cpumask, *cpulist;
>> + struct cpu_domain_map **cd_map;
>> + struct domain_info *d_info;
>> + u32 nra, nr, i, j;
>> + int ret;
>> +
>> + nra = env->nr_cpus_avail;
>> + nr = env->nr_cpus_online;
>> +
>> + cd_map = calloc(nra, sizeof(*cd_map));
>> + if (!cd_map)
>> + return -1;
>> +
>> + env->cpu_domain = cd_map;
>
> Where is it freed?
>
I missed freeing this. This needs to be freed in perf_env__exit().
Please correct me if I am missing something.
--
Thanks and Regards,
Swapnil
> Thanks,
> Namhyung
Hi Namhyung,
On 09-01-2026 16:54, Swapnil Sapkal wrote:
> Hello Namhyung,
>
> On 03-01-2026 03:56, Namhyung Kim wrote:
>> On Tue, Sep 09, 2025 at 11:42:19AM +0000, Swapnil Sapkal wrote:
>>> '/proc/schedstat' gives the info about load balancing statistics within
>>> a given domain. It also contains the cpu_mask giving information about
>>> the sibling cpus and domain names after schedstat version 17. Storing
>>> this information in perf header will help tools like `perf sched stats`
>>> for better analysis.
>>>
>>> Signed-off-by: Swapnil Sapkal <swapnil.sapkal@amd.com>
>>> ---
>>> .../Documentation/perf.data-file-format.txt | 17 +
>>> tools/perf/builtin-inject.c | 1 +
>>> tools/perf/util/env.h | 16 +
>>> tools/perf/util/header.c | 304 ++++++++++++++++++
>>> tools/perf/util/header.h | 1 +
>>> tools/perf/util/util.c | 42 +++
>>> tools/perf/util/util.h | 3 +
>>> 7 files changed, 384 insertions(+)
>>>
>>> diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/
>>> tools/perf/Documentation/perf.data-file-format.txt
>>> index cd95ba09f727..92dbba1003cf 100644
>>> --- a/tools/perf/Documentation/perf.data-file-format.txt
>>> +++ b/tools/perf/Documentation/perf.data-file-format.txt
>>> @@ -437,6 +437,23 @@ struct {
>>> } [nr_pmu];
>>> };
>>> + HEADER_CPU_DOMAIN_INFO = 32,
>>> +
>>> +List of cpu-domain relation info. The format of the data is as below.
>>> +
>>> +struct domain_info {
>>> + int domain;
>>> + char dname[];
>>> + char cpumask[];
>>> + char cpulist[];
>>> +};
>>> +
>>> +struct cpu_domain_info {
>>> + int cpu;
>>> + int nr_domains;
>>> + struct domain_info domains[];
>>> +};
>>> +
>>> other bits are reserved and should ignored for now
>>> HEADER_FEAT_BITS = 256,
>>> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
>>> index a114b3fa1bea..f43a7ec44b5f 100644
>>> --- a/tools/perf/builtin-inject.c
>>> +++ b/tools/perf/builtin-inject.c
>>> @@ -2058,6 +2058,7 @@ static bool keep_feat(int feat)
>>> case HEADER_CLOCK_DATA:
>>> case HEADER_HYBRID_TOPOLOGY:
>>> case HEADER_PMU_CAPS:
>>> + case HEADER_CPU_DOMAIN_INFO:
>>> return true;
>>> /* Information that can be updated */
>>> case HEADER_BUILD_ID:
>>> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
>>> index e00179787a34..71034c4b4488 100644
>>> --- a/tools/perf/util/env.h
>>> +++ b/tools/perf/util/env.h
>>> @@ -54,6 +54,19 @@ struct pmu_caps {
>>> char *pmu_name;
>>> };
>>> +struct domain_info {
>>> + u32 domain;
>>> + char *dname;
>>> + char *cpumask;
>>> + char *cpulist;
>>> +};
>>> +
>>> +struct cpu_domain_map {
>>> + u32 cpu;
>>> + u32 nr_domains;
>>> + struct domain_info **domains;
>>> +};
>>> +
>>> typedef const char *(arch_syscalls__strerrno_t)(int err);
>>> struct perf_env {
>>> @@ -70,6 +83,8 @@ struct perf_env {
>>> unsigned int max_branches;
>>> unsigned int br_cntr_nr;
>>> unsigned int br_cntr_width;
>>> + unsigned int schedstat_version;
>>> + unsigned int max_sched_domains;
>>> int kernel_is_64_bit;
>>> int nr_cmdline;
>>> @@ -92,6 +107,7 @@ struct perf_env {
>>> char **cpu_pmu_caps;
>>> struct cpu_topology_map *cpu;
>>> struct cpu_cache_level *caches;
>>> + struct cpu_domain_map **cpu_domain;
>>> int caches_cnt;
>>> u32 comp_ratio;
>>> u32 comp_ver;
>>> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
>>> index 4f2a6e10ed5c..7ff7434bac2c 100644
>>> --- a/tools/perf/util/header.c
>>> +++ b/tools/perf/util/header.c
>>> @@ -1621,6 +1621,184 @@ static int write_pmu_caps(struct feat_fd *ff,
>>> return 0;
>>> }
>>> +static void free_cpu_domain_info(struct cpu_domain_map **cd_map, u32
>>> schedstat_version, u32 nr)
>>> +{
>>> + for (u32 i = 0; i < nr; i++) {
>>> + if (cd_map[i]->domains) {
>>> + for (u32 j = 0; j < cd_map[i]->nr_domains; j++) {
>>> + struct domain_info *d_info = cd_map[i]->domains[j];
>>> +
>>
>> I'm not sure if it needs a NULL check for d_info before access.
>>
>
> Thanks for catching this. Yes we need a NULL check here.
>
> If some of the cpus are offline then it is possible that some sched
> domains can be degenerated and for some cpus.
>
> for e.g. cpu0, cpu128 are smt siblings. If cpu 128 is offline then SMT
> domain will be degenerated for cpu0 alone. All the other cpus will have
> a valid SMT domain. Thus SMT for the d_info can be NULL.
>
>>
>>> + if (schedstat_version >= 17)
>>> + free(d_info->dname);
>>> +
>>> + free(d_info->cpumask);
>>> + free(d_info->cpulist);
>>> + }
>>> + free(cd_map[i]->domains);
>>> + }
>>> + }
>>> +
>>> + free(cd_map);
>>> +}
>>> +
>>> +static struct cpu_domain_map **build_cpu_domain_map(u32
>>> *schedstat_version, u32 *max_sched_domains,
>>> + u32 nr)
>>> +{
>>> + struct domain_info *domain_info;
>>> + struct cpu_domain_map **cd_map;
>>> + char dname[16], cpumask[256];
>>> + char cpulist[1024];
>>> + char *line = NULL;
>>> + u32 cpu, domain;
>>> + u32 dcount = 0;
>>> + size_t len;
>>> + FILE *fp;
>>> +
>>> + fp = fopen("/proc/schedstat", "r");
>>> + if (!fp) {
>>> + pr_err("Failed to open /proc/schedstat\n");
>>> + return NULL;
>>> + }
>>> +
>>> + cd_map = calloc(nr, sizeof(*cd_map));
>>> + if (!cd_map)
>>> + goto out;
>>> +
>>> + while (getline(&line, &len, fp) > 0) {
>>> + int retval;
>>> +
>>> + if (strncmp(line, "version", 7) == 0) {
>>> + retval = sscanf(line, "version %d\n", schedstat_version);
>>> + if (retval != 1)
>>> + continue;
>>> +
>>> + } else if (strncmp(line, "cpu", 3) == 0) {
>>> + retval = sscanf(line, "cpu%u %*s", &cpu);
>>> + if (retval == 1) {
>>> + cd_map[cpu] = calloc(1, sizeof(*cd_map[cpu]));
>>> + if (!cd_map[cpu])
>>> + goto out_free_line;
>>> + cd_map[cpu]->cpu = cpu;
>>> + } else
>>> + continue;
>>> +
>>> + dcount = 0;
>>> + } else if (strncmp(line, "domain", 6) == 0) {
>>> + dcount++;
>>> +
>>> + cd_map[cpu]->domains = realloc(cd_map[cpu]->domains,
>>> + dcount * sizeof(domain_info));
>>> + if (!cd_map[cpu]->domains)
>>> + goto out_free_line;
>>
>> Please use a temporary variable to save the result in order to not lose
>> the original pointer in case of failure.
>>
>
> Sure, will do.
>
>>> +
>>> + domain_info = calloc(1, sizeof(*domain_info));
>>> + if (!domain_info)
>>> + goto out_free_line;
>>> +
>>> + cd_map[cpu]->domains[dcount - 1] = domain_info;
>>> +
>>> + if (*schedstat_version >= 17) {
>>> + retval = sscanf(line, "domain%u %s %s %*s", &domain,
>>> dname,
>>> + cpumask);
>>> + if (retval != 3)
>>> + continue;
>>> +
>>> + domain_info->dname = calloc(strlen(dname) + 1,
>>> sizeof(char));
>>> + if (!domain_info->dname)
>>> + goto out_free_line;
>>> +
>>> + strcpy(domain_info->dname, dname);
>>
>> This can be simply:
>> domain_info->dname = strdup(dname);
>>
>
> Sure, will do.
>
>>
>>> + } else {
>>> + retval = sscanf(line, "domain%u %s %*s", &domain,
>>> cpumask);
>>> + if (retval != 2)
>>> + continue;
>>> + }
>>> +
>>> + domain_info->domain = domain;
>>> + if (domain > *max_sched_domains)
>>> + *max_sched_domains = domain;
>>> +
>>> + domain_info->cpumask = calloc(strlen(cpumask) + 1,
>>> sizeof(char));
>>> + if (!domain_info->cpumask)
>>> + goto out_free_line;
>>> +
>>> + strcpy(domain_info->cpumask, cpumask);
>>> +
>>> + cpumask_to_cpulist(cpumask, cpulist);
>>> + domain_info->cpulist = calloc(strlen(cpulist) + 1,
>>> sizeof(char));
>>> + if (!domain_info->cpulist)
>>> + goto out_free_line;
>>
>> All error paths should call free_cpu_domain_info() at some point and
>> free the intermediate domain_info properly.
>>
>
> Sure, will do.
Sorry, I missed to mention here that the parent function is taking care
of freeing the memory by calling free_cpu_domain_info() in case of error
path also. Because of which I have not addressed this in the next version.
--
Thanks and Regards,
Swapnil
Hello,
kernel test robot noticed "perf-sanity-tests.perf_pipe_recording_and_injection_test.fail" on:
commit: 01c79e2544b044e2c01ab435a28a03c3f0d63be3 ("[PATCH RESEND v4 03/11] perf header: Support CPU DOMAIN relation info")
url: https://github.com/intel-lab-lkp/linux/commits/Swapnil-Sapkal/perf-Add-print_separator-to-util/20250909-195256
base: https://git.kernel.org/cgit/linux/kernel/git/perf/perf-tools-next.git perf-tools-next
patch link: https://lore.kernel.org/all/20250909114227.58802-4-swapnil.sapkal@amd.com/
patch subject: [PATCH RESEND v4 03/11] perf header: Support CPU DOMAIN relation info
in testcase: perf-sanity-tests
version:
with following parameters:
perf_compiler: gcc
group: group-02
config: x86_64-rhel-9.4-bpf
compiler: gcc-14
test machine: 256 threads 2 sockets GENUINE INTEL(R) XEON(R) (Sierra Forest) with 128G memory
(please refer to attached dmesg/kmsg for entire log/backtrace)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <oliver.sang@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202509171303.b892ad4b-lkp@intel.com
we also observed failure of perf-sanity-tests.Zstd_perf.data_compression/decompression
which can pass on parent.
138d89b6ba9cd79a 01c79e2544b044e2c01ab435a28
---------------- ---------------------------
fail:runs %reproduction fail:runs
| | |
:6 100% 6:6 perf-sanity-tests.Zstd_perf.data_compression/decompression.fail
:6 100% 6:6 perf-sanity-tests.perf_pipe_recording_and_injection_test.fail
2025-09-15 14:22:07 sudo /usr/src/linux-perf-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf test 88 -v
88: perf pipe recording and injection test : Running (1 active)
--- start ---
test child forked, pid 16787
140175e-1401871 l noploop
perf does have symbol 'noploop'
Record+report pipe test
util/util.c:295:6: runtime error: index 64 out of bounds for type 'char [17]'
util/util.c:295:12: runtime error: store to address 0x7f4b418a1060 with insufficient space for an object of type 'char'
0x7f4b418a1060: note: pointer points here
00 00 00 00 01 00 00 00 00 00 00 00 18 00 04 2e 00 00 00 00 9d 77 00 00 00 00 00 00 02 00 00 00
^
=================================================================
==16803==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7f4b418a1050 at pc 0x561dc13e9257 bp 0x7ffe75d35540 sp 0x7ffe75d35538
WRITE of size 1 at 0x7f4b418a1050 thread T0
#0 0x561dc13e9256 in cpumask_to_cpulist util/util.c:295
#1 0x561dc11fb37b in build_cpu_domain_map util/header.c:1727
#2 0x561dc11fb91f in write_cpu_domain_info util/header.c:1753
#3 0x561dc145a9ef in perf_event__synthesize_features util/synthetic-events.c:2419
#4 0x561dc145b224 in perf_event__synthesize_for_pipe util/synthetic-events.c:2471
#5 0x561dc0bc2085 in record__synthesize /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2063
#6 0x561dc0bc9ded in __cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2581
#7 0x561dc0bda8cb in cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:4376
#8 0x561dc0de7aac in run_builtin /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:349
#9 0x561dc0de839d in handle_internal_command /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:401
#10 0x561dc0de88f3 in run_argv /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:445
#11 0x561dc0de909a in main /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:553
#12 0x7f4b4efc7ca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#13 0x7f4b4efc7d64 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29d64) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#14 0x561dc0b58470 in _start (/usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf+0xf9b470) (BuildId: 7c6fd1162dbb1e721de92bbfd9fc751e2178f1fa)
Address 0x7f4b418a1050 is located in stack of thread T0 at offset 80 in frame
#0 0x561dc13e8c26 in cpumask_to_cpulist util/util.c:267
This frame has 2 object(s):
[32, 49) 'blk' (line 291)
[96, 1120) 'cpus' (line 271) <== Memory access at offset 80 underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow util/util.c:295 in cpumask_to_cpulist
Shadow bytes around the buggy address:
0x7f4b418a0d80: 00 00 00 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3
0x7f4b418a0e00: f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 00 00 00 00
0x7f4b418a0e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f4b418a0f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f4b418a0f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7f4b418a1000: f1 f1 f1 f1 00 00 01 f2 f2 f2[f2]f2 00 00 00 00
0x7f4b418a1080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f4b418a1100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f4b418a1180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f4b418a1200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f4b418a1280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==16803==ABORTING
Record+report pipe test [Failed - cannot find the test file in the perf report #1]
Inject -B build-ids test
util/util.c:295:6: runtime error: index 64 out of bounds for type 'char [17]'
util/util.c:295:12: runtime error: store to address 0x7faa03ca1060 with insufficient space for an object of type 'char'
0x7faa03ca1060: note: pointer points here
00 00 00 00 01 00 00 00 00 00 00 00 18 00 04 2e 00 00 00 00 9d 77 00 00 00 00 00 00 02 00 00 00
^
=================================================================
==16818==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7faa03ca1050 at pc 0x5613ca51a257 bp 0x7ffde4af7240 sp 0x7ffde4af7238
WRITE of size 1 at 0x7faa03ca1050 thread T0
#0 0x5613ca51a256 in cpumask_to_cpulist util/util.c:295
#1 0x5613ca32c37b in build_cpu_domain_map util/header.c:1727
#2 0x5613ca32c91f in write_cpu_domain_info util/header.c:1753
#3 0x5613ca58b9ef in perf_event__synthesize_features util/synthetic-events.c:2419
#4 0x5613ca58c224 in perf_event__synthesize_for_pipe util/synthetic-events.c:2471
#5 0x5613c9cf3085 in record__synthesize /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2063
#6 0x5613c9cfaded in __cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2581
#7 0x5613c9d0b8cb in cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:4376
#8 0x5613c9f18aac in run_builtin /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:349
#9 0x5613c9f1939d in handle_internal_command /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:401
#10 0x5613c9f198f3 in run_argv /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:445
#11 0x5613c9f1a09a in main /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:553
#12 0x7faa11387ca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#13 0x7faa11387d64 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29d64) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#14 0x5613c9c89470 in _start (/usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf+0xf9b470) (BuildId: 7c6fd1162dbb1e721de92bbfd9fc751e2178f1fa)
Address 0x7faa03ca1050 is located in stack of thread T0 at offset 80 in frame
#0 0x5613ca519c26 in cpumask_to_cpulist util/util.c:267
This frame has 2 object(s):
[32, 49) 'blk' (line 291)
[96, 1120) 'cpus' (line 271) <== Memory access at offset 80 underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow util/util.c:295 in cpumask_to_cpulist
Shadow bytes around the buggy address:
0x7faa03ca0d80: 00 00 00 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3
0x7faa03ca0e00: f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 00 00 00 00
0x7faa03ca0e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7faa03ca0f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7faa03ca0f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7faa03ca1000: f1 f1 f1 f1 00 00 01 f2 f2 f2[f2]f2 00 00 00 00
0x7faa03ca1080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7faa03ca1100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7faa03ca1180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7faa03ca1200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7faa03ca1280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==16818==ABORTING
Error:
The - data has no samples!
Inject build-ids test [Failed - cannot find noploop function in pipe #1]
Inject -b build-ids test
util/util.c:295:6: runtime error: index 64 out of bounds for type 'char [17]'
util/util.c:295:12: runtime error: store to address 0x7fad986a1060 with insufficient space for an object of type 'char'
0x7fad986a1060: note: pointer points here
00 00 00 00 01 00 00 00 00 00 00 00 18 00 04 2e 00 00 00 00 9d 77 00 00 00 00 00 00 02 00 00 00
^
=================================================================
==16835==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fad986a1050 at pc 0x563c459e2257 bp 0x7ffe9db4ac80 sp 0x7ffe9db4ac78
WRITE of size 1 at 0x7fad986a1050 thread T0
#0 0x563c459e2256 in cpumask_to_cpulist util/util.c:295
#1 0x563c457f437b in build_cpu_domain_map util/header.c:1727
#2 0x563c457f491f in write_cpu_domain_info util/header.c:1753
#3 0x563c45a539ef in perf_event__synthesize_features util/synthetic-events.c:2419
#4 0x563c45a54224 in perf_event__synthesize_for_pipe util/synthetic-events.c:2471
#5 0x563c451bb085 in record__synthesize /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2063
#6 0x563c451c2ded in __cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2581
#7 0x563c451d38cb in cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:4376
#8 0x563c453e0aac in run_builtin /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:349
#9 0x563c453e139d in handle_internal_command /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:401
#10 0x563c453e18f3 in run_argv /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:445
#11 0x563c453e209a in main /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:553
#12 0x7fada5de9ca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#13 0x7fada5de9d64 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29d64) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#14 0x563c45151470 in _start (/usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf+0xf9b470) (BuildId: 7c6fd1162dbb1e721de92bbfd9fc751e2178f1fa)
Address 0x7fad986a1050 is located in stack of thread T0 at offset 80 in frame
#0 0x563c459e1c26 in cpumask_to_cpulist util/util.c:267
This frame has 2 object(s):
[32, 49) 'blk' (line 291)
[96, 1120) 'cpus' (line 271) <== Memory access at offset 80 underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow util/util.c:295 in cpumask_to_cpulist
Shadow bytes around the buggy address:
0x7fad986a0d80: 00 00 00 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3
0x7fad986a0e00: f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 00 00 00 00
0x7fad986a0e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fad986a0f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fad986a0f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7fad986a1000: f1 f1 f1 f1 00 00 01 f2 f2 f2[f2]f2 00 00 00 00
0x7fad986a1080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fad986a1100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fad986a1180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fad986a1200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fad986a1280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==16835==ABORTING
Error:
The - data has no samples!
Inject build-ids test [Failed - cannot find noploop function in pipe #1]
Inject --buildid-all build-ids test
util/util.c:295:6: runtime error: index 64 out of bounds for type 'char [17]'
util/util.c:295:12: runtime error: store to address 0x7fb708ca1060 with insufficient space for an object of type 'char'
0x7fb708ca1060: note: pointer points here
00 00 00 00 01 00 00 00 00 00 00 00 18 00 04 2e 00 00 00 00 9d 77 00 00 00 00 00 00 02 00 00 00
^
=================================================================
==16849==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fb708ca1050 at pc 0x55677eb40257 bp 0x7ffe5b049bd0 sp 0x7ffe5b049bc8
WRITE of size 1 at 0x7fb708ca1050 thread T0
#0 0x55677eb40256 in cpumask_to_cpulist util/util.c:295
#1 0x55677e95237b in build_cpu_domain_map util/header.c:1727
#2 0x55677e95291f in write_cpu_domain_info util/header.c:1753
#3 0x55677ebb19ef in perf_event__synthesize_features util/synthetic-events.c:2419
#4 0x55677ebb2224 in perf_event__synthesize_for_pipe util/synthetic-events.c:2471
#5 0x55677e319085 in record__synthesize /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2063
#6 0x55677e320ded in __cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2581
#7 0x55677e3318cb in cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:4376
#8 0x55677e53eaac in run_builtin /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:349
#9 0x55677e53f39d in handle_internal_command /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:401
#10 0x55677e53f8f3 in run_argv /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:445
#11 0x55677e54009a in main /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:553
#12 0x7fb716412ca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#13 0x7fb716412d64 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29d64) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#14 0x55677e2af470 in _start (/usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf+0xf9b470) (BuildId: 7c6fd1162dbb1e721de92bbfd9fc751e2178f1fa)
Address 0x7fb708ca1050 is located in stack of thread T0 at offset 80 in frame
#0 0x55677eb3fc26 in cpumask_to_cpulist util/util.c:267
This frame has 2 object(s):
[32, 49) 'blk' (line 291)
[96, 1120) 'cpus' (line 271) <== Memory access at offset 80 underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow util/util.c:295 in cpumask_to_cpulist
Shadow bytes around the buggy address:
0x7fb708ca0d80: 00 00 00 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3
0x7fb708ca0e00: f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 00 00 00 00
0x7fb708ca0e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fb708ca0f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fb708ca0f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7fb708ca1000: f1 f1 f1 f1 00 00 01 f2 f2 f2[f2]f2 00 00 00 00
0x7fb708ca1080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fb708ca1100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fb708ca1180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fb708ca1200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fb708ca1280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==16849==ABORTING
Error:
The - data has no samples!
Inject build-ids test [Failed - cannot find noploop function in pipe #1]
Inject --mmap2-buildid-all build-ids test
util/util.c:295:6: runtime error: index 64 out of bounds for type 'char [17]'
util/util.c:295:12: runtime error: store to address 0x7f790f8a1060 with insufficient space for an object of type 'char'
0x7f790f8a1060: note: pointer points here
00 00 00 00 01 00 00 00 00 00 00 00 18 00 04 2e 00 00 00 00 9d 77 00 00 00 00 00 00 02 00 00 00
^
=================================================================
==16869==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7f790f8a1050 at pc 0x5602d1c61257 bp 0x7ffc6a01f190 sp 0x7ffc6a01f188
WRITE of size 1 at 0x7f790f8a1050 thread T0
#0 0x5602d1c61256 in cpumask_to_cpulist util/util.c:295
#1 0x5602d1a7337b in build_cpu_domain_map util/header.c:1727
#2 0x5602d1a7391f in write_cpu_domain_info util/header.c:1753
#3 0x5602d1cd29ef in perf_event__synthesize_features util/synthetic-events.c:2419
#4 0x5602d1cd3224 in perf_event__synthesize_for_pipe util/synthetic-events.c:2471
#5 0x5602d143a085 in record__synthesize /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2063
#6 0x5602d1441ded in __cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2581
#7 0x5602d14528cb in cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:4376
#8 0x5602d165faac in run_builtin /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:349
#9 0x5602d166039d in handle_internal_command /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:401
#10 0x5602d16608f3 in run_argv /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:445
#11 0x5602d166109a in main /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:553
#12 0x7f791cfd5ca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#13 0x7f791cfd5d64 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29d64) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#14 0x5602d13d0470 in _start (/usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf+0xf9b470) (BuildId: 7c6fd1162dbb1e721de92bbfd9fc751e2178f1fa)
Address 0x7f790f8a1050 is located in stack of thread T0 at offset 80 in frame
#0 0x5602d1c60c26 in cpumask_to_cpulist util/util.c:267
This frame has 2 object(s):
[32, 49) 'blk' (line 291)
[96, 1120) 'cpus' (line 271) <== Memory access at offset 80 underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow util/util.c:295 in cpumask_to_cpulist
Shadow bytes around the buggy address:
0x7f790f8a0d80: 00 00 00 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3
0x7f790f8a0e00: f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 00 00 00 00
0x7f790f8a0e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f790f8a0f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f790f8a0f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7f790f8a1000: f1 f1 f1 f1 00 00 01 f2 f2 f2[f2]f2 00 00 00 00
0x7f790f8a1080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f790f8a1100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f790f8a1180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f790f8a1200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f790f8a1280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==16869==ABORTING
Error:
The - data has no samples!
Inject build-ids test [Failed - cannot find noploop function in pipe #1]
---- end(-1) ----
88: perf pipe recording and injection test : FAILED!
2025-09-15 14:22:22 sudo /usr/src/linux-perf-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf test 89 -v
89: Zstd perf.data compression/decompression : Running (1 active)
--- start ---
test child forked, pid 16896
Collecting compressed record file:
500+0 records in
500+0 records out
256000 bytes (256 kB, 250 KiB) copied, 0.00308355 s, 83.0 MB/s
[ perf record: Woken up 2 times to write data ]
util/util.c:295:6: runtime error: index 64 out of bounds for type 'char [17]'
util/util.c:295:12: runtime error: store to address 0x7f9ffdca2060 with insufficient space for an object of type 'char'
0x7f9ffdca2060: note: pointer points here
00 00 00 00 01 00 00 00 00 00 00 00 18 00 04 2e 00 00 00 00 9d 77 00 00 00 00 00 00 02 00 00 00
^
=================================================================
==16904==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7f9ffdca2050 at pc 0x564af4570257 bp 0x7ffd6f117510 sp 0x7ffd6f117508
WRITE of size 1 at 0x7f9ffdca2050 thread T0
#0 0x564af4570256 in cpumask_to_cpulist util/util.c:295
#1 0x564af438237b in build_cpu_domain_map util/header.c:1727
#2 0x564af438291f in write_cpu_domain_info util/header.c:1753
#3 0x564af439cc44 in do_write_feat util/header.c:3892
#4 0x564af439d65f in perf_header__adds_write util/header.c:3936
#5 0x564af439f14a in perf_session__do_write_header util/header.c:4060
#6 0x564af439f72c in perf_session__write_header util/header.c:4100
#7 0x564af3d46044 in record__finish_output /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:1826
#8 0x564af3d53e54 in __cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:2894
#9 0x564af3d618cb in cmd_record /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/builtin-record.c:4376
#10 0x564af3f6eaac in run_builtin /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:349
#11 0x564af3f6f39d in handle_internal_command /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:401
#12 0x564af3f6f8f3 in run_argv /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:445
#13 0x564af3f7009a in main /usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf.c:553
#14 0x7fa00b28eca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#15 0x7fa00b28ed64 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29d64) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
#16 0x564af3cdf470 in _start (/usr/src/perf_selftests-x86_64-rhel-9.4-bpf-01c79e2544b044e2c01ab435a28a03c3f0d63be3/tools/perf/perf+0xf9b470) (BuildId: 7c6fd1162dbb1e721de92bbfd9fc751e2178f1fa)
Address 0x7f9ffdca2050 is located in stack of thread T0 at offset 80 in frame
#0 0x564af456fc26 in cpumask_to_cpulist util/util.c:267
This frame has 2 object(s):
[32, 49) 'blk' (line 291)
[96, 1120) 'cpus' (line 271) <== Memory access at offset 80 underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow util/util.c:295 in cpumask_to_cpulist
Shadow bytes around the buggy address:
0x7f9ffdca1d80: 00 00 00 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3
0x7f9ffdca1e00: f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 00 00 00 00
0x7f9ffdca1e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f9ffdca1f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f9ffdca1f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7f9ffdca2000: f1 f1 f1 f1 00 00 01 f2 f2 f2[f2]f2 00 00 00 00
0x7f9ffdca2080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f9ffdca2100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f9ffdca2180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f9ffdca2200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f9ffdca2280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==16904==ABORTING
---- end(-1) ----
89: Zstd perf.data compression/decompression : FAILED!
The kernel config and materials to reproduce are available at:
https://download.01.org/0day-ci/archive/20250917/202509171303.b892ad4b-lkp@intel.com
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.