mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00

Unlike with events, metrics can be matched by name or a list of metric groups. However, when a metric refers to another metric it isn't referring to a group but the singular metric in question. Prior to this change every "id" in a metric expression is checked to see if it is a metric by scanning all the metrics in the metrics table. As the table is sorted my metric name we can speed the search in the resolution case by binary searching for the metric. Rename some of the metricgroup functions to make it clearer whether they match a metric by name or by both name and group. Before: ``` $ time perf test -v 10 10: PMU JSON event tests : 10.1: PMU event table sanity : Ok 10.2: PMU event map aliases : Ok 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok 10.5: Parsing of metric thresholds with fake PMUs : Ok real 0m15.972s user 0m13.176s sys 0m3.001s ``` After: ``` $ time perf test -v 10 10: PMU JSON event tests : 10.1: PMU event table sanity : Ok 10.2: PMU event map aliases : Ok 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok 10.5: Parsing of metric thresholds with fake PMUs : Ok real 0m5.343s user 0m1.871s sys 0m2.128s ``` Committer testing: root@number:~# grep -m1 'model name' /proc/cpuinfo model name : AMD Ryzen 9 9950X3D 16-Core Processor root@number:~# Before: root@number:~# time perf test "Parsing of PMU event table metrics" 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok real 0m9.286s user 0m9.354s sys 0m0.062s root@number:~# After: root@number:~# time perf test "Parsing of PMU event table metrics" 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok real 0m0.689s user 0m0.766s sys 0m0.042s root@number:~# time perf test 10 10: PMU JSON event tests : 10.1: PMU event table sanity : Ok 10.2: PMU event map aliases : Ok 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok 10.5: Parsing of metric thresholds with fake PMUs : Ok real 0m0.696s user 0m0.807s sys 0m0.064s root@number:~# Signed-off-by: Ian Rogers <irogers@google.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Tested-by: Namhyung Kim <namhyung@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Cc: Thomas Richter <tmricht@linux.ibm.com> Cc: Xu Yang <xu.yang_2@nxp.com> Link: https://lore.kernel.org/r/20250512194622.33258-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
778 lines
33 KiB
C
778 lines
33 KiB
C
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* THIS FILE WAS AUTOGENERATED BY jevents.py arch=none model=none ! */
|
|
|
|
#include <pmu-events/pmu-events.h>
|
|
#include "util/header.h"
|
|
#include "util/pmu.h"
|
|
#include <string.h>
|
|
#include <stddef.h>
|
|
|
|
struct compact_pmu_event {
|
|
int offset;
|
|
};
|
|
|
|
struct pmu_table_entry {
|
|
const struct compact_pmu_event *entries;
|
|
uint32_t num_entries;
|
|
struct compact_pmu_event pmu_name;
|
|
};
|
|
|
|
static const char *const big_c_string =
|
|
/* offset=0 */ "tool\000"
|
|
/* offset=5 */ "duration_time\000tool\000Wall clock interval time in nanoseconds\000config=1\000\00000\000\000\000\000\000"
|
|
/* offset=81 */ "user_time\000tool\000User (non-kernel) time in nanoseconds\000config=2\000\00000\000\000\000\000\000"
|
|
/* offset=151 */ "system_time\000tool\000System/kernel time in nanoseconds\000config=3\000\00000\000\000\000\000\000"
|
|
/* offset=219 */ "has_pmem\000tool\0001 if persistent memory installed otherwise 0\000config=4\000\00000\000\000\000\000\000"
|
|
/* offset=295 */ "num_cores\000tool\000Number of cores. A core consists of 1 or more thread, with each thread being associated with a logical Linux CPU\000config=5\000\00000\000\000\000\000\000"
|
|
/* offset=440 */ "num_cpus\000tool\000Number of logical Linux CPUs. There may be multiple such CPUs on a core\000config=6\000\00000\000\000\000\000\000"
|
|
/* offset=543 */ "num_cpus_online\000tool\000Number of online logical Linux CPUs. There may be multiple such CPUs on a core\000config=7\000\00000\000\000\000\000\000"
|
|
/* offset=660 */ "num_dies\000tool\000Number of dies. Each die has 1 or more cores\000config=8\000\00000\000\000\000\000\000"
|
|
/* offset=736 */ "num_packages\000tool\000Number of packages. Each package has 1 or more die\000config=9\000\00000\000\000\000\000\000"
|
|
/* offset=822 */ "slots\000tool\000Number of functional units that in parallel can execute parts of an instruction\000config=0xa\000\00000\000\000\000\000\000"
|
|
/* offset=932 */ "smt_on\000tool\0001 if simultaneous multithreading (aka hyperthreading) is enable otherwise 0\000config=0xb\000\00000\000\000\000\000\000"
|
|
/* offset=1039 */ "system_tsc_freq\000tool\000The amount a Time Stamp Counter (TSC) increases per second\000config=0xc\000\00000\000\000\000\000\000"
|
|
/* offset=1138 */ "default_core\000"
|
|
/* offset=1151 */ "bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000\000\000\000"
|
|
/* offset=1213 */ "bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000\000\000\000"
|
|
/* offset=1275 */ "l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000\000\000\000Attributable Level 3 cache access, read\000"
|
|
/* offset=1373 */ "segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000\000\000\000"
|
|
/* offset=1475 */ "dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000\000\000\000"
|
|
/* offset=1608 */ "eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000\000\000\000"
|
|
/* offset=1726 */ "hisi_sccl,ddrc\000"
|
|
/* offset=1741 */ "uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000\000\000\000DDRC write commands\000"
|
|
/* offset=1830 */ "uncore_cbox\000"
|
|
/* offset=1842 */ "unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000\000\000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000"
|
|
/* offset=2076 */ "event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000\000\000\000UNC_CBO_HYPHEN\000"
|
|
/* offset=2144 */ "event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000\000\000\000UNC_CBO_TWO_HYPH\000"
|
|
/* offset=2218 */ "hisi_sccl,l3c\000"
|
|
/* offset=2232 */ "uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000\000\000\000Total read hits\000"
|
|
/* offset=2315 */ "uncore_imc_free_running\000"
|
|
/* offset=2339 */ "uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000\000\000\000Total cache misses\000"
|
|
/* offset=2437 */ "uncore_imc\000"
|
|
/* offset=2448 */ "uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000\000\000\000Total cache hits\000"
|
|
/* offset=2529 */ "uncore_sys_ddr_pmu\000"
|
|
/* offset=2548 */ "sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000\000\000\000"
|
|
/* offset=2624 */ "uncore_sys_ccn_pmu\000"
|
|
/* offset=2643 */ "sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000\000\000\000"
|
|
/* offset=2720 */ "uncore_sys_cmn_pmu\000"
|
|
/* offset=2739 */ "sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000\000\000\000"
|
|
/* offset=2882 */ "CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000"
|
|
/* offset=2904 */ "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000"
|
|
/* offset=2967 */ "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000"
|
|
/* offset=3133 */ "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000"
|
|
/* offset=3197 */ "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000"
|
|
/* offset=3264 */ "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000"
|
|
/* offset=3335 */ "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000"
|
|
/* offset=3429 */ "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000"
|
|
/* offset=3563 */ "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000"
|
|
/* offset=3627 */ "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000"
|
|
/* offset=3695 */ "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000"
|
|
/* offset=3765 */ "M1\000\000ipc + M2\000\000\000\000\000\000\000\00000"
|
|
/* offset=3787 */ "M2\000\000ipc + M1\000\000\000\000\000\000\000\00000"
|
|
/* offset=3809 */ "M3\000\0001 / M3\000\000\000\000\000\000\000\00000"
|
|
/* offset=3829 */ "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000"
|
|
;
|
|
|
|
static const struct compact_pmu_event pmu_events__common_tool[] = {
|
|
{ 5 }, /* duration_time\000tool\000Wall clock interval time in nanoseconds\000config=1\000\00000\000\000\000\000\000 */
|
|
{ 219 }, /* has_pmem\000tool\0001 if persistent memory installed otherwise 0\000config=4\000\00000\000\000\000\000\000 */
|
|
{ 295 }, /* num_cores\000tool\000Number of cores. A core consists of 1 or more thread, with each thread being associated with a logical Linux CPU\000config=5\000\00000\000\000\000\000\000 */
|
|
{ 440 }, /* num_cpus\000tool\000Number of logical Linux CPUs. There may be multiple such CPUs on a core\000config=6\000\00000\000\000\000\000\000 */
|
|
{ 543 }, /* num_cpus_online\000tool\000Number of online logical Linux CPUs. There may be multiple such CPUs on a core\000config=7\000\00000\000\000\000\000\000 */
|
|
{ 660 }, /* num_dies\000tool\000Number of dies. Each die has 1 or more cores\000config=8\000\00000\000\000\000\000\000 */
|
|
{ 736 }, /* num_packages\000tool\000Number of packages. Each package has 1 or more die\000config=9\000\00000\000\000\000\000\000 */
|
|
{ 822 }, /* slots\000tool\000Number of functional units that in parallel can execute parts of an instruction\000config=0xa\000\00000\000\000\000\000\000 */
|
|
{ 932 }, /* smt_on\000tool\0001 if simultaneous multithreading (aka hyperthreading) is enable otherwise 0\000config=0xb\000\00000\000\000\000\000\000 */
|
|
{ 151 }, /* system_time\000tool\000System/kernel time in nanoseconds\000config=3\000\00000\000\000\000\000\000 */
|
|
{ 1039 }, /* system_tsc_freq\000tool\000The amount a Time Stamp Counter (TSC) increases per second\000config=0xc\000\00000\000\000\000\000\000 */
|
|
{ 81 }, /* user_time\000tool\000User (non-kernel) time in nanoseconds\000config=2\000\00000\000\000\000\000\000 */
|
|
|
|
};
|
|
|
|
const struct pmu_table_entry pmu_events__common[] = {
|
|
{
|
|
.entries = pmu_events__common_tool,
|
|
.num_entries = ARRAY_SIZE(pmu_events__common_tool),
|
|
.pmu_name = { 0 /* tool\000 */ },
|
|
},
|
|
};
|
|
|
|
static const struct compact_pmu_event pmu_events__test_soc_cpu_default_core[] = {
|
|
{ 1151 }, /* bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000\000\000\000 */
|
|
{ 1213 }, /* bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000\000\000\000 */
|
|
{ 1475 }, /* dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000\000\000\000 */
|
|
{ 1608 }, /* eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000\000\000\000 */
|
|
{ 1275 }, /* l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000\000\000\000Attributable Level 3 cache access, read\000 */
|
|
{ 1373 }, /* segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000\000\000\000 */
|
|
};
|
|
static const struct compact_pmu_event pmu_events__test_soc_cpu_hisi_sccl_ddrc[] = {
|
|
{ 1741 }, /* uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000\000\000\000DDRC write commands\000 */
|
|
};
|
|
static const struct compact_pmu_event pmu_events__test_soc_cpu_hisi_sccl_l3c[] = {
|
|
{ 2232 }, /* uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000\000\000\000Total read hits\000 */
|
|
};
|
|
static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_cbox[] = {
|
|
{ 2076 }, /* event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000\000\000\000UNC_CBO_HYPHEN\000 */
|
|
{ 2144 }, /* event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000\000\000\000UNC_CBO_TWO_HYPH\000 */
|
|
{ 1842 }, /* unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000\000\000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000 */
|
|
};
|
|
static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_imc[] = {
|
|
{ 2448 }, /* uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000\000\000\000Total cache hits\000 */
|
|
};
|
|
static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_imc_free_running[] = {
|
|
{ 2339 }, /* uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000\000\000\000Total cache misses\000 */
|
|
|
|
};
|
|
|
|
const struct pmu_table_entry pmu_events__test_soc_cpu[] = {
|
|
{
|
|
.entries = pmu_events__test_soc_cpu_default_core,
|
|
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_default_core),
|
|
.pmu_name = { 1138 /* default_core\000 */ },
|
|
},
|
|
{
|
|
.entries = pmu_events__test_soc_cpu_hisi_sccl_ddrc,
|
|
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_hisi_sccl_ddrc),
|
|
.pmu_name = { 1726 /* hisi_sccl,ddrc\000 */ },
|
|
},
|
|
{
|
|
.entries = pmu_events__test_soc_cpu_hisi_sccl_l3c,
|
|
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_hisi_sccl_l3c),
|
|
.pmu_name = { 2218 /* hisi_sccl,l3c\000 */ },
|
|
},
|
|
{
|
|
.entries = pmu_events__test_soc_cpu_uncore_cbox,
|
|
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_cbox),
|
|
.pmu_name = { 1830 /* uncore_cbox\000 */ },
|
|
},
|
|
{
|
|
.entries = pmu_events__test_soc_cpu_uncore_imc,
|
|
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_imc),
|
|
.pmu_name = { 2437 /* uncore_imc\000 */ },
|
|
},
|
|
{
|
|
.entries = pmu_events__test_soc_cpu_uncore_imc_free_running,
|
|
.num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_imc_free_running),
|
|
.pmu_name = { 2315 /* uncore_imc_free_running\000 */ },
|
|
},
|
|
};
|
|
|
|
static const struct compact_pmu_event pmu_metrics__test_soc_cpu_default_core[] = {
|
|
{ 2882 }, /* CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000 */
|
|
{ 3563 }, /* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000 */
|
|
{ 3335 }, /* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000 */
|
|
{ 3429 }, /* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000 */
|
|
{ 3627 }, /* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000 */
|
|
{ 3695 }, /* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000 */
|
|
{ 2967 }, /* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000 */
|
|
{ 2904 }, /* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000 */
|
|
{ 3829 }, /* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000 */
|
|
{ 3765 }, /* M1\000\000ipc + M2\000\000\000\000\000\000\000\00000 */
|
|
{ 3787 }, /* M2\000\000ipc + M1\000\000\000\000\000\000\000\00000 */
|
|
{ 3809 }, /* M3\000\0001 / M3\000\000\000\000\000\000\000\00000 */
|
|
{ 3264 }, /* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000 */
|
|
{ 3133 }, /* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */
|
|
{ 3197 }, /* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */
|
|
|
|
};
|
|
|
|
const struct pmu_table_entry pmu_metrics__test_soc_cpu[] = {
|
|
{
|
|
.entries = pmu_metrics__test_soc_cpu_default_core,
|
|
.num_entries = ARRAY_SIZE(pmu_metrics__test_soc_cpu_default_core),
|
|
.pmu_name = { 1138 /* default_core\000 */ },
|
|
},
|
|
};
|
|
|
|
static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_ccn_pmu[] = {
|
|
{ 2643 }, /* sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000\000\000\000 */
|
|
};
|
|
static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_cmn_pmu[] = {
|
|
{ 2739 }, /* sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000\000\000\000 */
|
|
};
|
|
static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_ddr_pmu[] = {
|
|
{ 2548 }, /* sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000\000\000\000 */
|
|
|
|
};
|
|
|
|
const struct pmu_table_entry pmu_events__test_soc_sys[] = {
|
|
{
|
|
.entries = pmu_events__test_soc_sys_uncore_sys_ccn_pmu,
|
|
.num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_ccn_pmu),
|
|
.pmu_name = { 2624 /* uncore_sys_ccn_pmu\000 */ },
|
|
},
|
|
{
|
|
.entries = pmu_events__test_soc_sys_uncore_sys_cmn_pmu,
|
|
.num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_cmn_pmu),
|
|
.pmu_name = { 2720 /* uncore_sys_cmn_pmu\000 */ },
|
|
},
|
|
{
|
|
.entries = pmu_events__test_soc_sys_uncore_sys_ddr_pmu,
|
|
.num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_ddr_pmu),
|
|
.pmu_name = { 2529 /* uncore_sys_ddr_pmu\000 */ },
|
|
},
|
|
};
|
|
|
|
|
|
/* Struct used to make the PMU event table implementation opaque to callers. */
|
|
struct pmu_events_table {
|
|
const struct pmu_table_entry *pmus;
|
|
uint32_t num_pmus;
|
|
};
|
|
|
|
/* Struct used to make the PMU metric table implementation opaque to callers. */
|
|
struct pmu_metrics_table {
|
|
const struct pmu_table_entry *pmus;
|
|
uint32_t num_pmus;
|
|
};
|
|
|
|
/*
|
|
* Map a CPU to its table of PMU events. The CPU is identified by the
|
|
* cpuid field, which is an arch-specific identifier for the CPU.
|
|
* The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
|
|
* must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
|
|
*
|
|
* The cpuid can contain any character other than the comma.
|
|
*/
|
|
struct pmu_events_map {
|
|
const char *arch;
|
|
const char *cpuid;
|
|
struct pmu_events_table event_table;
|
|
struct pmu_metrics_table metric_table;
|
|
};
|
|
|
|
/*
|
|
* Global table mapping each known CPU for the architecture to its
|
|
* table of PMU events.
|
|
*/
|
|
const struct pmu_events_map pmu_events_map[] = {
|
|
{
|
|
.arch = "common",
|
|
.cpuid = "common",
|
|
.event_table = {
|
|
.pmus = pmu_events__common,
|
|
.num_pmus = ARRAY_SIZE(pmu_events__common),
|
|
},
|
|
.metric_table = {},
|
|
},
|
|
{
|
|
.arch = "testarch",
|
|
.cpuid = "testcpu",
|
|
.event_table = {
|
|
.pmus = pmu_events__test_soc_cpu,
|
|
.num_pmus = ARRAY_SIZE(pmu_events__test_soc_cpu),
|
|
},
|
|
.metric_table = {
|
|
.pmus = pmu_metrics__test_soc_cpu,
|
|
.num_pmus = ARRAY_SIZE(pmu_metrics__test_soc_cpu),
|
|
}
|
|
},
|
|
{
|
|
.arch = 0,
|
|
.cpuid = 0,
|
|
.event_table = { 0, 0 },
|
|
.metric_table = { 0, 0 },
|
|
}
|
|
};
|
|
|
|
struct pmu_sys_events {
|
|
const char *name;
|
|
struct pmu_events_table event_table;
|
|
struct pmu_metrics_table metric_table;
|
|
};
|
|
|
|
static const struct pmu_sys_events pmu_sys_event_tables[] = {
|
|
{
|
|
.event_table = {
|
|
.pmus = pmu_events__test_soc_sys,
|
|
.num_pmus = ARRAY_SIZE(pmu_events__test_soc_sys)
|
|
},
|
|
.name = "pmu_events__test_soc_sys",
|
|
},
|
|
{
|
|
.event_table = { 0, 0 },
|
|
.metric_table = { 0, 0 },
|
|
},
|
|
};
|
|
|
|
static void decompress_event(int offset, struct pmu_event *pe)
|
|
{
|
|
const char *p = &big_c_string[offset];
|
|
|
|
pe->name = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pe->topic = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pe->desc = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pe->event = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pe->compat = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pe->deprecated = *p - '0';
|
|
p++;
|
|
pe->perpkg = *p - '0';
|
|
p++;
|
|
pe->unit = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pe->retirement_latency_mean = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pe->retirement_latency_min = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pe->retirement_latency_max = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pe->long_desc = (*p == '\0' ? NULL : p);
|
|
}
|
|
|
|
static void decompress_metric(int offset, struct pmu_metric *pm)
|
|
{
|
|
const char *p = &big_c_string[offset];
|
|
|
|
pm->metric_name = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->metric_group = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->metric_expr = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->metric_threshold = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->desc = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->long_desc = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->unit = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->compat = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->metricgroup_no_group = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->default_metricgroup_name = (*p == '\0' ? NULL : p);
|
|
while (*p++);
|
|
pm->aggr_mode = *p - '0';
|
|
p++;
|
|
pm->event_grouping = *p - '0';
|
|
}
|
|
|
|
static int pmu_events_table__for_each_event_pmu(const struct pmu_events_table *table,
|
|
const struct pmu_table_entry *pmu,
|
|
pmu_event_iter_fn fn,
|
|
void *data)
|
|
{
|
|
int ret;
|
|
struct pmu_event pe = {
|
|
.pmu = &big_c_string[pmu->pmu_name.offset],
|
|
};
|
|
|
|
for (uint32_t i = 0; i < pmu->num_entries; i++) {
|
|
decompress_event(pmu->entries[i].offset, &pe);
|
|
if (!pe.name)
|
|
continue;
|
|
ret = fn(&pe, table, data);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int pmu_events_table__find_event_pmu(const struct pmu_events_table *table,
|
|
const struct pmu_table_entry *pmu,
|
|
const char *name,
|
|
pmu_event_iter_fn fn,
|
|
void *data)
|
|
{
|
|
struct pmu_event pe = {
|
|
.pmu = &big_c_string[pmu->pmu_name.offset],
|
|
};
|
|
int low = 0, high = pmu->num_entries - 1;
|
|
|
|
while (low <= high) {
|
|
int cmp, mid = (low + high) / 2;
|
|
|
|
decompress_event(pmu->entries[mid].offset, &pe);
|
|
|
|
if (!pe.name && !name)
|
|
goto do_call;
|
|
|
|
if (!pe.name && name) {
|
|
low = mid + 1;
|
|
continue;
|
|
}
|
|
if (pe.name && !name) {
|
|
high = mid - 1;
|
|
continue;
|
|
}
|
|
|
|
cmp = strcasecmp(pe.name, name);
|
|
if (cmp < 0) {
|
|
low = mid + 1;
|
|
continue;
|
|
}
|
|
if (cmp > 0) {
|
|
high = mid - 1;
|
|
continue;
|
|
}
|
|
do_call:
|
|
return fn ? fn(&pe, table, data) : 0;
|
|
}
|
|
return PMU_EVENTS__NOT_FOUND;
|
|
}
|
|
|
|
int pmu_events_table__for_each_event(const struct pmu_events_table *table,
|
|
struct perf_pmu *pmu,
|
|
pmu_event_iter_fn fn,
|
|
void *data)
|
|
{
|
|
for (size_t i = 0; i < table->num_pmus; i++) {
|
|
const struct pmu_table_entry *table_pmu = &table->pmus[i];
|
|
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
|
|
int ret;
|
|
|
|
if (pmu && !perf_pmu__name_wildcard_match(pmu, pmu_name))
|
|
continue;
|
|
|
|
ret = pmu_events_table__for_each_event_pmu(table, table_pmu, fn, data);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int pmu_events_table__find_event(const struct pmu_events_table *table,
|
|
struct perf_pmu *pmu,
|
|
const char *name,
|
|
pmu_event_iter_fn fn,
|
|
void *data)
|
|
{
|
|
for (size_t i = 0; i < table->num_pmus; i++) {
|
|
const struct pmu_table_entry *table_pmu = &table->pmus[i];
|
|
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
|
|
int ret;
|
|
|
|
if (pmu && !perf_pmu__name_wildcard_match(pmu, pmu_name))
|
|
continue;
|
|
|
|
ret = pmu_events_table__find_event_pmu(table, table_pmu, name, fn, data);
|
|
if (ret != PMU_EVENTS__NOT_FOUND)
|
|
return ret;
|
|
}
|
|
return PMU_EVENTS__NOT_FOUND;
|
|
}
|
|
|
|
size_t pmu_events_table__num_events(const struct pmu_events_table *table,
|
|
struct perf_pmu *pmu)
|
|
{
|
|
size_t count = 0;
|
|
|
|
for (size_t i = 0; i < table->num_pmus; i++) {
|
|
const struct pmu_table_entry *table_pmu = &table->pmus[i];
|
|
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
|
|
|
|
if (perf_pmu__name_wildcard_match(pmu, pmu_name))
|
|
count += table_pmu->num_entries;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static int pmu_metrics_table__for_each_metric_pmu(const struct pmu_metrics_table *table,
|
|
const struct pmu_table_entry *pmu,
|
|
pmu_metric_iter_fn fn,
|
|
void *data)
|
|
{
|
|
int ret;
|
|
struct pmu_metric pm = {
|
|
.pmu = &big_c_string[pmu->pmu_name.offset],
|
|
};
|
|
|
|
for (uint32_t i = 0; i < pmu->num_entries; i++) {
|
|
decompress_metric(pmu->entries[i].offset, &pm);
|
|
if (!pm.metric_expr)
|
|
continue;
|
|
ret = fn(&pm, table, data);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int pmu_metrics_table__find_metric_pmu(const struct pmu_metrics_table *table,
|
|
const struct pmu_table_entry *pmu,
|
|
const char *metric,
|
|
pmu_metric_iter_fn fn,
|
|
void *data)
|
|
{
|
|
struct pmu_metric pm = {
|
|
.pmu = &big_c_string[pmu->pmu_name.offset],
|
|
};
|
|
int low = 0, high = pmu->num_entries - 1;
|
|
|
|
while (low <= high) {
|
|
int cmp, mid = (low + high) / 2;
|
|
|
|
decompress_metric(pmu->entries[mid].offset, &pm);
|
|
|
|
if (!pm.metric_name && !metric)
|
|
goto do_call;
|
|
|
|
if (!pm.metric_name && metric) {
|
|
low = mid + 1;
|
|
continue;
|
|
}
|
|
if (pm.metric_name && !metric) {
|
|
high = mid - 1;
|
|
continue;
|
|
}
|
|
|
|
cmp = strcmp(pm.metric_name, metric);
|
|
if (cmp < 0) {
|
|
low = mid + 1;
|
|
continue;
|
|
}
|
|
if (cmp > 0) {
|
|
high = mid - 1;
|
|
continue;
|
|
}
|
|
do_call:
|
|
return fn ? fn(&pm, table, data) : 0;
|
|
}
|
|
return PMU_METRICS__NOT_FOUND;
|
|
}
|
|
|
|
int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table,
|
|
pmu_metric_iter_fn fn,
|
|
void *data)
|
|
{
|
|
for (size_t i = 0; i < table->num_pmus; i++) {
|
|
int ret = pmu_metrics_table__for_each_metric_pmu(table, &table->pmus[i],
|
|
fn, data);
|
|
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int pmu_metrics_table__find_metric(const struct pmu_metrics_table *table,
|
|
struct perf_pmu *pmu,
|
|
const char *metric,
|
|
pmu_metric_iter_fn fn,
|
|
void *data)
|
|
{
|
|
for (size_t i = 0; i < table->num_pmus; i++) {
|
|
const struct pmu_table_entry *table_pmu = &table->pmus[i];
|
|
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
|
|
int ret;
|
|
|
|
if (pmu && !perf_pmu__name_wildcard_match(pmu, pmu_name))
|
|
continue;
|
|
|
|
ret = pmu_metrics_table__find_metric_pmu(table, table_pmu, metric, fn, data);
|
|
if (ret != PMU_METRICS__NOT_FOUND)
|
|
return ret;
|
|
}
|
|
return PMU_METRICS__NOT_FOUND;
|
|
}
|
|
|
|
static const struct pmu_events_map *map_for_cpu(struct perf_cpu cpu)
|
|
{
|
|
static struct {
|
|
const struct pmu_events_map *map;
|
|
struct perf_cpu cpu;
|
|
} last_result;
|
|
static struct {
|
|
const struct pmu_events_map *map;
|
|
char *cpuid;
|
|
} last_map_search;
|
|
static bool has_last_result, has_last_map_search;
|
|
const struct pmu_events_map *map = NULL;
|
|
char *cpuid = NULL;
|
|
size_t i;
|
|
|
|
if (has_last_result && last_result.cpu.cpu == cpu.cpu)
|
|
return last_result.map;
|
|
|
|
cpuid = get_cpuid_allow_env_override(cpu);
|
|
|
|
/*
|
|
* On some platforms which uses cpus map, cpuid can be NULL for
|
|
* PMUs other than CORE PMUs.
|
|
*/
|
|
if (!cpuid)
|
|
goto out_update_last_result;
|
|
|
|
if (has_last_map_search && !strcmp(last_map_search.cpuid, cpuid)) {
|
|
map = last_map_search.map;
|
|
free(cpuid);
|
|
} else {
|
|
i = 0;
|
|
for (;;) {
|
|
map = &pmu_events_map[i++];
|
|
|
|
if (!map->arch) {
|
|
map = NULL;
|
|
break;
|
|
}
|
|
|
|
if (!strcmp_cpuid_str(map->cpuid, cpuid))
|
|
break;
|
|
}
|
|
free(last_map_search.cpuid);
|
|
last_map_search.cpuid = cpuid;
|
|
last_map_search.map = map;
|
|
has_last_map_search = true;
|
|
}
|
|
out_update_last_result:
|
|
last_result.cpu = cpu;
|
|
last_result.map = map;
|
|
has_last_result = true;
|
|
return map;
|
|
}
|
|
|
|
static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu)
|
|
{
|
|
struct perf_cpu cpu = {-1};
|
|
|
|
if (pmu)
|
|
cpu = perf_cpu_map__min(pmu->cpus);
|
|
return map_for_cpu(cpu);
|
|
}
|
|
|
|
const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
|
|
{
|
|
const struct pmu_events_map *map = map_for_pmu(pmu);
|
|
|
|
if (!map)
|
|
return NULL;
|
|
|
|
if (!pmu)
|
|
return &map->event_table;
|
|
|
|
for (size_t i = 0; i < map->event_table.num_pmus; i++) {
|
|
const struct pmu_table_entry *table_pmu = &map->event_table.pmus[i];
|
|
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
|
|
|
|
if (perf_pmu__name_wildcard_match(pmu, pmu_name))
|
|
return &map->event_table;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const struct pmu_metrics_table *pmu_metrics_table__find(void)
|
|
{
|
|
struct perf_cpu cpu = {-1};
|
|
const struct pmu_events_map *map = map_for_cpu(cpu);
|
|
|
|
return map ? &map->metric_table : NULL;
|
|
}
|
|
|
|
const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
|
|
{
|
|
for (const struct pmu_events_map *tables = &pmu_events_map[0];
|
|
tables->arch;
|
|
tables++) {
|
|
if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
|
|
return &tables->event_table;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid)
|
|
{
|
|
for (const struct pmu_events_map *tables = &pmu_events_map[0];
|
|
tables->arch;
|
|
tables++) {
|
|
if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
|
|
return &tables->metric_table;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
|
|
{
|
|
for (const struct pmu_events_map *tables = &pmu_events_map[0];
|
|
tables->arch;
|
|
tables++) {
|
|
int ret = pmu_events_table__for_each_event(&tables->event_table,
|
|
/*pmu=*/ NULL, fn, data);
|
|
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
|
|
{
|
|
for (const struct pmu_events_map *tables = &pmu_events_map[0];
|
|
tables->arch;
|
|
tables++) {
|
|
int ret = pmu_metrics_table__for_each_metric(&tables->metric_table, fn, data);
|
|
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const struct pmu_events_table *find_sys_events_table(const char *name)
|
|
{
|
|
for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
|
|
tables->name;
|
|
tables++) {
|
|
if (!strcmp(tables->name, name))
|
|
return &tables->event_table;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
|
|
{
|
|
for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
|
|
tables->name;
|
|
tables++) {
|
|
int ret = pmu_events_table__for_each_event(&tables->event_table,
|
|
/*pmu=*/ NULL, fn, data);
|
|
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data)
|
|
{
|
|
for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
|
|
tables->name;
|
|
tables++) {
|
|
int ret = pmu_metrics_table__for_each_metric(&tables->metric_table, fn, data);
|
|
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const int metricgroups[][2] = {
|
|
|
|
};
|
|
|
|
const char *describe_metricgroup(const char *group)
|
|
{
|
|
int low = 0, high = (int)ARRAY_SIZE(metricgroups) - 1;
|
|
|
|
while (low <= high) {
|
|
int mid = (low + high) / 2;
|
|
const char *mgroup = &big_c_string[metricgroups[mid][0]];
|
|
int cmp = strcmp(mgroup, group);
|
|
|
|
if (cmp == 0) {
|
|
return &big_c_string[metricgroups[mid][1]];
|
|
} else if (cmp < 0) {
|
|
low = mid + 1;
|
|
} else {
|
|
high = mid - 1;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|