From nobody Thu Apr 2 20:17:59 2026 Received: from mail-dy1-f201.google.com (mail-dy1-f201.google.com [74.125.82.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 385FC39182E for ; Thu, 26 Mar 2026 17:45:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774547130; cv=none; b=qwPTQMj8xFq8aUuuE7d7KXOkj61BiDJmEBzgeo8Xv0EZT1aVIj1h1a44ZrbgBFf8GzAdXoj9XyPdjzAurv/JHPXv80kt1EStpBrCgGUWZ8raaHBWHC4GXhZRJiyNECuvjcySAj5UfqH7e+378CQhVpfvW3cjSozQ2m5YfIcvhfY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774547130; c=relaxed/simple; bh=j6rgEXApqjZizFGFXtuk1RkCvFKzS+Zod19klE5fm4w=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=guZV4DSA7kjyNnfLHvrH0sd5MkeJeJ82D16EnM9HF4EW2krU6qRdrIgSI+alCK1ASnCH7W4vXBPFWzRkrE34/wAA5kiIBSus3Z8hzrmt5Lq/gSXoh1R+0Mh5hj6MB8e8slM72LcaDyGFQI1RTsmJo9zpU5A/4W6NSIKtRiD0Z54= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=DuWnx/DT; arc=none smtp.client-ip=74.125.82.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="DuWnx/DT" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-2c1631e6189so8601865eec.0 for ; Thu, 26 Mar 2026 10:45:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1774547127; x=1775151927; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=3hQPlIkV5UQpTmKo/dttZUaxWmixCoCT0jtakDd3Tn4=; b=DuWnx/DTxNW7olGMWPQtYwvIiUISpZEZtzXECEegHxS1GaKAYop0QjYVuByfXhPHS2 L5irZET00zeuwNygTgKxtrhsN73GLpNcqDnLM7Y/Jx5FQNOvXoZlgPCIo82Rr/mC6yDr Wcnpjw34S7jxB70RbFIlq8QVe9+y3Rvx1u+LhN+3Hs2TItrVp9sZKqoZge6ShJT+2MTJ J52mQUJwf1avaZZKzrn3KJr3hHFHsWAWMqFJjkAjcewYwFu/ZHlORdo3gavCBgaWD7cb v7I774XYJZ6erXq3LN7J+JQ980B22zFL9kbH9Swn3rEWIwbCTCvJ9GbvTJcmp+2WyKyC qf+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774547127; x=1775151927; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=3hQPlIkV5UQpTmKo/dttZUaxWmixCoCT0jtakDd3Tn4=; b=F7cuoelW2atsIGMB92Ai9VPyQnc9ng2C3OtasljWIS1UqYuzvKGiVI8e8+QTw9XM9H ZGFycGDyf34G1fZzex+6cd82M5rh4d0dZguZy5KnHDqRNYAtG/PyEtbB15N+rG8YazDJ X4FmgaLkVp9gdAsZVs1qZ1NTwFwPAquTjsK+wW2jgQUODU6I9lHgN5vKiy9S2X8qi+dO q0Mn5BIdYEoLtW6KJI3Mw3K4SMEhLd6Sz9yUq9qrhTH1GU2F4ANjQz3CyGWjVqcYCRyt 4nshFxUpx3Cyp01U4L9gOEkp0Mm5u46P20sYcDzMuGP5RAWlQajCLlol12DbqjE1sbcC +7hA== X-Forwarded-Encrypted: i=1; AJvYcCXwyPqyuFHfG32ikA9OfLTwCqEFlF1WwLf1eU83AgJUB8GHLywsuTlDQsng2nvYbyt3Ze02VqYgs5mcKvc=@vger.kernel.org X-Gm-Message-State: AOJu0YxzqllKk7pkgVF+SRFM39CRqNqd0cSVEX4UwezOZg9yWfdonqYW lm/gxAcZvVJ7/3RlC2sfEeaCMGmcoGol94AwmKpDM8wO/EnY0CfQuihE2/DMb33L6Qa3djdKhV/ qlFlMVYa6HQ== X-Received: from dybod2.prod.google.com ([2002:a05:7301:3f82:b0:2c0:be02:79e8]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:60b:b0:2be:884e:17af with SMTP id 5a478bee46e88-2c15d2b6ef1mr4509661eec.2.1774547127178; Thu, 26 Mar 2026 10:45:27 -0700 (PDT) Date: Thu, 26 Mar 2026 10:45:20 -0700 In-Reply-To: <20260326174521.1829203-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260326174521.1829203-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.1018.g2bb0e51243-goog Message-ID: <20260326174521.1829203-2-irogers@google.com> Subject: [PATCH v3 1/2] perf env: Add perf_env__e_machine helper and use in perf_env__arch From: Ian Rogers To: irogers@google.com Cc: acme@kernel.org, agordeev@linux.ibm.com, gor@linux.ibm.com, hca@linux.ibm.com, jameshongleiwang@126.com, japo@linux.ibm.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, linux-s390@vger.kernel.org, namhyung@kernel.org, sumanthk@linux.ibm.com, tmricht@linux.ibm.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a helper that lazily computes the e_machine and falls back of EM_HOST. Use the perf_env's arch to compute the e_machine if available. Use a binary search for some efficiency in this, but handle somewhat complex duplicate rules. Switch perf_env__arch to be derived the e_machine for consistency. This switches arch from being uname derived to matching that of the perf binary (via EM_HOST). Update session to use the helper, which may mean using EM_HOST when no threads are available. This also updates the perf data file header that gets the e_machine/e_flags from the session. Signed-off-by: Ian Rogers --- tools/perf/util/env.c | 179 ++++++++++++++++++++++++++++++-------- tools/perf/util/env.h | 1 + tools/perf/util/session.c | 14 +-- 3 files changed, 151 insertions(+), 43 deletions(-) diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 93d475a80f14..304bd8245485 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include "cpumap.h" +#include "dwarf-regs.h" #include "debug.h" #include "env.h" #include "util/header.h" #include "util/rwsem.h" #include +#include #include #include #include @@ -588,51 +590,154 @@ void cpu_cache_level__free(struct cpu_cache_level *c= ache) zfree(&cache->size); } =20 +struct arch_to_e_machine { + const char *prefix; + uint16_t e_machine; +}; + /* - * Return architecture name in a normalized form. - * The conversion logic comes from the Makefile. + * A mapping from an arch prefix string to an ELF machine that can be used= in a + * bsearch. Some arch prefixes are shared an need additional processing as + * marked next to the architecture. The prefixes handle both perf's archit= ecture + * naming and those from uname. */ -static const char *normalize_arch(char *arch) -{ - if (!strcmp(arch, "x86_64")) - return "x86"; - if (arch[0] =3D=3D 'i' && arch[2] =3D=3D '8' && arch[3] =3D=3D '6') - return "x86"; - if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5)) - return "sparc"; - if (!strncmp(arch, "aarch64", 7) || !strncmp(arch, "arm64", 5)) - return "arm64"; - if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110")) - return "arm"; - if (!strncmp(arch, "s390", 4)) - return "s390"; - if (!strncmp(arch, "parisc", 6)) - return "parisc"; - if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3)) - return "powerpc"; - if (!strncmp(arch, "mips", 4)) - return "mips"; - if (!strncmp(arch, "sh", 2) && isdigit(arch[2])) - return "sh"; - if (!strncmp(arch, "loongarch", 9)) - return "loongarch"; - - return arch; +static const struct arch_to_e_machine prefix_to_e_machine[] =3D { + {"aarch64", EM_AARCH64}, + {"alpha", EM_ALPHA}, + {"arc", EM_ARC}, + {"arm", EM_ARM}, /* Check also for EM_AARCH64. */ + {"avr", EM_AVR}, /* Check also for EM_AVR32. */ + {"bfin", EM_BLACKFIN}, + {"blackfin", EM_BLACKFIN}, + {"cris", EM_CRIS}, + {"csky", EM_CSKY}, + {"hppa", EM_PARISC}, + {"i386", EM_386}, + {"i486", EM_386}, + {"i586", EM_386}, + {"i686", EM_386}, + {"loongarch", EM_LOONGARCH}, + {"m32r", EM_M32R}, + {"m68k", EM_68K}, + {"microblaze", EM_MICROBLAZE}, + {"mips", EM_MIPS}, + {"msp430", EM_MSP430}, + {"parisc", EM_PARISC}, + {"powerpc", EM_PPC}, /* Check also for EM_PPC64. */ + {"ppc", EM_PPC}, /* Check also for EM_PPC64. */ + {"riscv", EM_RISCV}, + {"sa110", EM_ARM}, + {"s390", EM_S390}, + {"sh", EM_SH}, + {"sparc", EM_SPARC}, /* Check also for EM_SPARCV9. */ + {"sun4u", EM_SPARC}, + {"x86", EM_X86_64}, /* Check also for EM_386. */ + {"xtensa", EM_XTENSA}, +}; + +static int compare_prefix(const void *key, const void *element) +{ + const char *search_key =3D key; + const struct arch_to_e_machine *map_element =3D element; + size_t prefix_len =3D strlen(map_element->prefix); + + return strncmp(search_key, map_element->prefix, prefix_len); +} + +static uint16_t perf_arch_to_e_machine(const char *perf_arch, bool is_64_b= it) +{ + /* Binary search for a matching prefix. */ + const struct arch_to_e_machine *result; + + if (!perf_arch) + return EM_HOST; + + result =3D bsearch(perf_arch, + prefix_to_e_machine, ARRAY_SIZE(prefix_to_e_machine), + sizeof(prefix_to_e_machine[0]), + compare_prefix); + + if (!result) { + pr_debug("Unknown perf arch for ELF machine mapping: %s\n", perf_arch); + return EM_NONE; + } + + /* Handle conflicting prefixes. */ + switch (result->e_machine) { + case EM_ARM: + return !strcmp(perf_arch, "arm64") ? EM_AARCH64 : EM_ARM; + case EM_AVR: + return !strcmp(perf_arch, "avr32") ? EM_AVR32 : EM_AVR; + case EM_PPC: + return is_64_bit || strstarts(perf_arch, "ppc64") ? EM_PPC64 : EM_PPC; + case EM_SPARC: + return is_64_bit || !strcmp(perf_arch, "sparc64") ? EM_SPARCV9 : EM_SPAR= C; + case EM_X86_64: + return is_64_bit || !strcmp(perf_arch, "x86_64") ? EM_X86_64 : EM_386; + default: + return result->e_machine; + } +} + +static const char *e_machine_to_perf_arch(uint16_t e_machine) +{ + /* + * Table for if either the perf arch string differs from uname or there + * are >1 ELF machine with the prefix. + */ + static const struct arch_to_e_machine extras[] =3D { + {"arm64", EM_AARCH64}, + {"avr32", EM_AVR32}, + {"powerpc", EM_PPC}, + {"powerpc", EM_PPC64}, + {"sparc", EM_SPARCV9}, + {"x86", EM_386}, + {"x86", EM_X86_64}, + {"none", EM_NONE}, + }; + + for (size_t i =3D 0; i < ARRAY_SIZE(extras); i++) { + if (extras[i].e_machine =3D=3D e_machine) + return extras[i].prefix; + } + + for (size_t i =3D 0; i < ARRAY_SIZE(prefix_to_e_machine); i++) { + if (prefix_to_e_machine[i].e_machine =3D=3D e_machine) + return prefix_to_e_machine[i].prefix; + + } + return "unknown"; +} + +uint16_t perf_env__e_machine(struct perf_env *env, uint32_t *e_flags) +{ + if (!env) { + if (e_flags) + *e_flags =3D EF_HOST; + + return EM_HOST; + } + if (env->e_machine =3D=3D EM_NONE) { + env->e_machine =3D perf_arch_to_e_machine(env->arch, env->kernel_is_64_b= it); + + if (env->e_machine =3D=3D EM_HOST) + env->e_flags =3D EF_HOST; + } + if (e_flags) + *e_flags =3D EF_HOST; + + return env->e_machine; } =20 const char *perf_env__arch(struct perf_env *env) { - char *arch_name; + if (!env) + return e_machine_to_perf_arch(EM_HOST); =20 - if (!env || !env->arch) { /* Assume local operation */ - static struct utsname uts =3D { .machine[0] =3D '\0', }; - if (uts.machine[0] =3D=3D '\0' && uname(&uts) < 0) - return NULL; - arch_name =3D uts.machine; - } else - arch_name =3D env->arch; + if (!env->arch) + env->arch =3D strdup(e_machine_to_perf_arch(perf_env__e_machine(env, /*e= _flags=3D*/NULL))); =20 - return normalize_arch(arch_name); + return env->arch; } =20 #if defined(HAVE_LIBTRACEEVENT) diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index a4501cbca375..91ff252712f4 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -186,6 +186,7 @@ int perf_env__read_cpu_topology_map(struct perf_env *en= v); =20 void cpu_cache_level__free(struct cpu_cache_level *cache); =20 +uint16_t perf_env__e_machine(struct perf_env *env, uint32_t *e_flags); const char *perf_env__arch(struct perf_env *env); const char *perf_env__arch_strerrno(struct perf_env *env, int err); const char *perf_env__cpuid(struct perf_env *env); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4b465abfa36c..dcc9bef303aa 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -2996,14 +2996,16 @@ uint16_t perf_session__e_machine(struct perf_sessio= n *session, uint32_t *e_flags return EM_HOST; } =20 + /* Is the env caching an e_machine? */ env =3D perf_session__env(session); - if (env && env->e_machine !=3D EM_NONE) { - if (e_flags) - *e_flags =3D env->e_flags; - - return env->e_machine; - } + if (env && env->e_machine !=3D EM_NONE) + return perf_env__e_machine(env, e_flags); =20 + /* + * Compute from threads, note this is more accurate than + * perf_env__e_machine that falls back on EM_HOST and doesn't consider + * mixed 32-bit and 64-bit threads. + */ machines__for_each_thread(&session->machines, perf_session__e_machine_cb, &args); --=20 2.53.0.1018.g2bb0e51243-goog