[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