[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