[PATCH 08/12] perf arm_spe: Separate setting of memory levels for loads and stores

James Clark james.clark at linaro.org
Fri Jun 20 03:30:19 PDT 2025



On 13/06/2025 4:53 pm, Leo Yan wrote:
> For a load hit, the lowest-level cache reflects the latency of fetching
> a data. Otherwise, the highest-level cache involved in refilling
> indicates the overhead caused by a load.
> 
> Store operations remain unchanged to keep the descending order when
> iterating through cache levels.
> 
> Split into two functions: one is for setting memory levels for loads and
> another for stores.
> 
> Signed-off-by: Leo Yan <leo.yan at arm.com>

Reviewed-by: James Clark <james.clark at linaro.org>

> ---
>   tools/perf/util/arm-spe.c | 45 +++++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 43 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
> index b2296cd025382ea36820641164ec71b13a4e7a0e..8f18af7336db53b00b450eb4299feee350d0ecb9 100644
> --- a/tools/perf/util/arm-spe.c
> +++ b/tools/perf/util/arm-spe.c
> @@ -45,6 +45,9 @@
>   #define arm_spe_is_cache_level(type, lvl) \
>   	((type) & ARM_SPE_CACHE_EVENT(lvl))
>   
> +#define arm_spe_is_cache_hit(type, lvl) \
> +	(((type) & ARM_SPE_CACHE_EVENT(lvl)) == ARM_SPE_##lvl##_ACCESS)
> +
>   #define arm_spe_is_cache_miss(type, lvl) \
>   	((type) & ARM_SPE_##lvl##_MISS)
>   
> @@ -828,9 +831,38 @@ static const struct data_source_handle data_source_handles[] = {
>   	DS(hisi_hip_ds_encoding_cpus, data_source_hisi_hip),
>   };
>   
> -static void arm_spe__synth_memory_level(const struct arm_spe_record *record,
> -					union perf_mem_data_src *data_src)
> +static void arm_spe__synth_ld_memory_level(const struct arm_spe_record *record,
> +					   union perf_mem_data_src *data_src)
> +{
> +	/*
> +	 * To find a cache hit, search in ascending order from the lower level
> +	 * caches to the higher level caches. This reflects the best scenario
> +	 * for a cache hit.
> +	 */
> +	if (arm_spe_is_cache_hit(record->type, L1D)) {
> +		data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT;
> +		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1;
> +	} else if (arm_spe_is_cache_hit(record->type, LLC)) {
> +		data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT;
> +		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
> +	/*
> +	 * To find a cache miss, search in descending order from the higher
> +	 * level cache to the lower level cache. This represents the worst
> +	 * scenario for a cache miss.
> +	 */
> +	} else if (arm_spe_is_cache_miss(record->type, LLC)) {
> +		data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_MISS;
> +		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
> +	} else if (arm_spe_is_cache_miss(record->type, L1D)) {
> +		data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS;
> +		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1;
> +	}
> +}
> +
> +static void arm_spe__synth_st_memory_level(const struct arm_spe_record *record,
> +					   union perf_mem_data_src *data_src)
>   {
> +	/* Record the greatest level info for a store operation. */
>   	if (arm_spe_is_cache_level(record->type, LLC)) {
>   		data_src->mem_lvl = PERF_MEM_LVL_L3;
>   		data_src->mem_lvl |= arm_spe_is_cache_miss(record->type, LLC) ?
> @@ -842,6 +874,15 @@ static void arm_spe__synth_memory_level(const struct arm_spe_record *record,
>   				     PERF_MEM_LVL_MISS : PERF_MEM_LVL_HIT;
>   		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1;
>   	}
> +}
> +
> +static void arm_spe__synth_memory_level(const struct arm_spe_record *record,
> +					union perf_mem_data_src *data_src)
> +{
> +	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;
> 




More information about the linux-arm-kernel mailing list