[PATCH 12/12] perf arm_spe: Allow parsing both data source and events
James Clark
james.clark at linaro.org
Fri Jun 20 03:55:04 PDT 2025
On 13/06/2025 4:53 pm, Leo Yan wrote:
> Current code skips to parse events after generating data source. The
> reason is the data source packets have cache and snooping related info,
> the afterwards event packets might contain duplicate info.
>
> This commit changes to continue parsing the events after data source
> analysis. If data source does not give out memory level and snooping
> types, then the event info is used to synthesize the related fields.
>
> As a result, both the peer snoop option ('-d peer') and hitm options
> ('-d tot/lcl/rmt') are supported by Arm SPE in the perf c2c.
>
Reviewed-by: James Clark <james.clark at linaro.org>
> Signed-off-by: Leo Yan <leo.yan at arm.com>
> ---
> tools/perf/util/arm-spe.c | 69 ++++++++++++++++++++++++++++-------------------
> 1 file changed, 41 insertions(+), 28 deletions(-)
>
> diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
> index 8a889f727f9cd5351b4ca027935112eddd16ea6c..8fde6f6cbce92aabf20d25b01ee2ade4aae7ea61 100644
> --- a/tools/perf/util/arm-spe.c
> +++ b/tools/perf/util/arm-spe.c
> @@ -909,40 +909,54 @@ static void arm_spe__synth_memory_level(struct arm_spe_queue *speq,
> {
> struct arm_spe *spe = speq->spe;
>
> - if (data_src->mem_op == PERF_MEM_OP_LOAD)
> - arm_spe__synth_ld_memory_level(record, data_src);
> - if (data_src->mem_op == PERF_MEM_OP_STORE)
> - arm_spe__synth_st_memory_level(record, data_src);
> + /*
> + * The data source packet contains more info for cache levels for
> + * peer snooping. So respect the memory level if has been set by
> + * data source parsing.
> + */
> + if (!data_src->mem_lvl) {
> + if (data_src->mem_op == PERF_MEM_OP_LOAD)
> + arm_spe__synth_ld_memory_level(record, data_src);
> + if (data_src->mem_op == PERF_MEM_OP_STORE)
> + arm_spe__synth_st_memory_level(record, data_src);
> + }
>
> if (!data_src->mem_lvl) {
> data_src->mem_lvl = PERF_MEM_LVL_NA;
> data_src->mem_lvl_num = PERF_MEM_LVLNUM_NA;
> }
>
> - if (record->type & ARM_SPE_DATA_SNOOPED) {
> - if (record->type & ARM_SPE_HITM)
> - data_src->mem_snoop = PERF_MEM_SNOOP_HITM;
> - else
> - data_src->mem_snoop = PERF_MEM_SNOOP_HIT;
> - } else {
> - u64 *metadata = arm_spe__get_metadata_by_cpu(spe, speq->cpu);
> -
> - /*
> - * Set NA ("Not available") mode if no meta data or the
> - * SNOOPED event is not supported.
> - */
> - if (!metadata ||
> - !(metadata[ARM_SPE_CAP_EVENTS] & ARM_SPE_DATA_SNOOPED))
> - data_src->mem_snoop = PERF_MEM_SNOOP_NA;
> - else
> - data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
> + /*
> + * If 'mem_snoop' has been set by data source packet, skip to set
> + * it at here.
> + */
> + if (!data_src->mem_snoop) {
> + if (record->type & ARM_SPE_DATA_SNOOPED) {
> + if (record->type & ARM_SPE_HITM)
> + data_src->mem_snoop = PERF_MEM_SNOOP_HITM;
> + else
> + data_src->mem_snoop = PERF_MEM_SNOOP_HIT;
> + } else {
> + u64 *metadata =
> + arm_spe__get_metadata_by_cpu(spe, speq->cpu);
> +
> + /*
> + * Set NA ("Not available") mode if no meta data or the
> + * SNOOPED event is not supported.
> + */
> + if (!metadata ||
> + !(metadata[ARM_SPE_CAP_EVENTS] & ARM_SPE_DATA_SNOOPED))
> + data_src->mem_snoop = PERF_MEM_SNOOP_NA;
> + else
> + data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
> + }
> }
>
> if (record->type & ARM_SPE_REMOTE_ACCESS)
> data_src->mem_remote = PERF_MEM_REMOTE_REMOTE;
> }
>
> -static bool arm_spe__synth_ds(struct arm_spe_queue *speq,
> +static void arm_spe__synth_ds(struct arm_spe_queue *speq,
> const struct arm_spe_record *record,
> union perf_mem_data_src *data_src)
> {
> @@ -961,19 +975,18 @@ static bool arm_spe__synth_ds(struct arm_spe_queue *speq,
> } else {
> metadata = arm_spe__get_metadata_by_cpu(spe, speq->cpu);
> if (!metadata)
> - return false;
> + return;
>
> midr = metadata[ARM_SPE_CPU_MIDR];
> }
>
> for (i = 0; i < ARRAY_SIZE(data_source_handles); i++) {
> if (is_midr_in_range_list(midr, data_source_handles[i].midr_ranges)) {
> - data_source_handles[i].ds_synth(record, data_src);
> - return true;
> + return data_source_handles[i].ds_synth(record, data_src);
> }
> }
>
> - return false;
> + return;
> }
>
> static u64 arm_spe__synth_data_source(struct arm_spe_queue *speq,
> @@ -992,8 +1005,8 @@ static u64 arm_spe__synth_data_source(struct arm_spe_queue *speq,
> else
> return 0;
>
> - if (!arm_spe__synth_ds(speq, record, &data_src))
> - arm_spe__synth_memory_level(speq, record, &data_src);
> + arm_spe__synth_ds(speq, record, &data_src);
> + arm_spe__synth_memory_level(speq, record, &data_src);
>
> if (record->type & (ARM_SPE_TLB_ACCESS | ARM_SPE_TLB_MISS)) {
> data_src.mem_dtlb = PERF_MEM_TLB_WK;
>
More information about the linux-arm-kernel
mailing list