linux/tools/perf/arch/arm64/util/header.c
Ian Rogers 83c338369a libperf cpumap: Make index and nr types unsigned
The index into the cpumap array and the number of entries within the
array can never be negative, so let's make them unsigned. This is
prompted by reports that gcc 13 with -O6 is giving a
alloc-size-larger-than errors. The change makes the cpumap changes and
then updates the declaration of index variables throughout perf and
libperf to be unsigned. The two things are hard to separate as
compiler warnings about mixing signed and unsigned types breaks the
build.

Reported-by: Chingbin Li <liqb365@163.com>
Closes: https://lore.kernel.org/lkml/20260212025127.841090-1-liqb365@163.com/
Tested-by: Chingbin Li <liqb365@163.com>
Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2026-04-01 14:50:53 -07:00

126 lines
2.9 KiB
C

#include <linux/bits.h>
#include <linux/bitfield.h>
#include <stdio.h>
#include <stdlib.h>
#include <perf/cpumap.h>
#include <api/fs/fs.h>
#include <errno.h>
#include "debug.h"
#include "header.h"
#define MIDR "/regs/identification/midr_el1"
#define MIDR_SIZE 19
#define MIDR_REVISION_MASK GENMASK(3, 0)
#define MIDR_VARIANT_MASK GENMASK(23, 20)
static int _get_cpuid(char *buf, size_t sz, struct perf_cpu cpu)
{
char path[PATH_MAX];
FILE *file;
const char *sysfs = sysfs__mountpoint();
assert(cpu.cpu != -1);
if (!sysfs || sz < MIDR_SIZE)
return EINVAL;
scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d" MIDR, sysfs, cpu.cpu);
file = fopen(path, "r");
if (!file) {
pr_debug("fopen failed for file %s\n", path);
return EINVAL;
}
if (!fgets(buf, MIDR_SIZE, file)) {
pr_debug("Failed to read file %s\n", path);
fclose(file);
return EINVAL;
}
fclose(file);
return 0;
}
int get_cpuid(char *buf, size_t sz, struct perf_cpu cpu)
{
struct perf_cpu_map *cpus;
unsigned int idx;
if (cpu.cpu != -1)
return _get_cpuid(buf, sz, cpu);
cpus = perf_cpu_map__new_online_cpus();
if (!cpus)
return EINVAL;
perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
int ret = _get_cpuid(buf, sz, cpu);
if (ret == 0)
return 0;
}
return EINVAL;
}
char *get_cpuid_str(struct perf_cpu cpu)
{
char *buf = malloc(MIDR_SIZE);
int res;
if (!buf)
return NULL;
/* read midr from list of cpus mapped to this pmu */
res = get_cpuid(buf, MIDR_SIZE, cpu);
if (res) {
pr_err("failed to get cpuid string for CPU %d\n", cpu.cpu);
free(buf);
buf = NULL;
}
return buf;
}
/*
* Return 0 if idstr is a higher or equal to version of the same part as
* mapcpuid. Therefore, if mapcpuid has 0 for revision and variant then any
* version of idstr will match as long as it's the same CPU type.
*
* Return 1 if the CPU type is different or the version of idstr is lower.
*/
int strcmp_cpuid_str(const char *mapcpuid, const char *idstr)
{
u64 map_id = strtoull(mapcpuid, NULL, 16);
char map_id_variant = FIELD_GET(MIDR_VARIANT_MASK, map_id);
char map_id_revision = FIELD_GET(MIDR_REVISION_MASK, map_id);
u64 id = strtoull(idstr, NULL, 16);
char id_variant = FIELD_GET(MIDR_VARIANT_MASK, id);
char id_revision = FIELD_GET(MIDR_REVISION_MASK, id);
u64 id_fields = ~(MIDR_VARIANT_MASK | MIDR_REVISION_MASK);
/* Compare without version first */
if ((map_id & id_fields) != (id & id_fields))
return 1;
/*
* ID matches, now compare version.
*
* Arm revisions (like r0p0) are compared here like two digit semver
* values eg. 1.3 < 2.0 < 2.1 < 2.2.
*
* r = high value = 'Variant' field in MIDR
* p = low value = 'Revision' field in MIDR
*
*/
if (id_variant > map_id_variant)
return 0;
if (id_variant == map_id_variant && id_revision >= map_id_revision)
return 0;
/*
* variant is less than mapfile variant or variants are the same but
* the revision doesn't match. Return no match.
*/
return 1;
}