2626#include "../../../util/arm-spe.h"
2727#include <tools/libc_compat.h> // reallocarray
2828
29+ #define ARM_SPE_CPU_MAGIC 0x1010101010101010ULL
30+
2931#define KiB (x ) ((x) * 1024)
3032#define MiB (x ) ((x) * 1024 * 1024)
3133
@@ -37,32 +39,142 @@ struct arm_spe_recording {
3739 bool * wrapped ;
3840};
3941
42+ /*
43+ * arm_spe_find_cpus() returns a new cpu map, and the caller should invoke
44+ * perf_cpu_map__put() to release the map after use.
45+ */
46+ static struct perf_cpu_map * arm_spe_find_cpus (struct evlist * evlist )
47+ {
48+ struct perf_cpu_map * event_cpus = evlist -> core .user_requested_cpus ;
49+ struct perf_cpu_map * online_cpus = perf_cpu_map__new_online_cpus ();
50+ struct perf_cpu_map * intersect_cpus ;
51+
52+ /* cpu map is not "any" CPU , we have specific CPUs to work with */
53+ if (!perf_cpu_map__has_any_cpu (event_cpus )) {
54+ intersect_cpus = perf_cpu_map__intersect (event_cpus , online_cpus );
55+ perf_cpu_map__put (online_cpus );
56+ /* Event can be "any" CPU so count all CPUs. */
57+ } else {
58+ intersect_cpus = online_cpus ;
59+ }
60+
61+ return intersect_cpus ;
62+ }
63+
4064static size_t
4165arm_spe_info_priv_size (struct auxtrace_record * itr __maybe_unused ,
42- struct evlist * evlist __maybe_unused )
66+ struct evlist * evlist )
4367{
44- return ARM_SPE_AUXTRACE_PRIV_SIZE ;
68+ struct perf_cpu_map * cpu_map = arm_spe_find_cpus (evlist );
69+ size_t size ;
70+
71+ if (!cpu_map )
72+ return 0 ;
73+
74+ size = ARM_SPE_AUXTRACE_PRIV_MAX +
75+ ARM_SPE_CPU_PRIV_MAX * perf_cpu_map__nr (cpu_map );
76+ size *= sizeof (u64 );
77+
78+ perf_cpu_map__put (cpu_map );
79+ return size ;
80+ }
81+
82+ static int arm_spe_save_cpu_header (struct auxtrace_record * itr ,
83+ struct perf_cpu cpu , __u64 data [])
84+ {
85+ struct arm_spe_recording * sper =
86+ container_of (itr , struct arm_spe_recording , itr );
87+ struct perf_pmu * pmu = NULL ;
88+ struct perf_pmu tmp_pmu ;
89+ char cpu_id_str [16 ];
90+ char * cpuid = NULL ;
91+ u64 val ;
92+
93+ snprintf (cpu_id_str , sizeof (cpu_id_str ), "%d" , cpu .cpu );
94+ tmp_pmu .cpus = perf_cpu_map__new (cpu_id_str );
95+ if (!tmp_pmu .cpus )
96+ return - ENOMEM ;
97+
98+ /* Read CPU MIDR */
99+ cpuid = perf_pmu__getcpuid (& tmp_pmu );
100+
101+ /* The CPU map will not be used anymore, release it */
102+ perf_cpu_map__put (tmp_pmu .cpus );
103+
104+ if (!cpuid )
105+ return - ENOMEM ;
106+ val = strtol (cpuid , NULL , 16 );
107+
108+ data [ARM_SPE_MAGIC ] = ARM_SPE_CPU_MAGIC ;
109+ data [ARM_SPE_CPU ] = cpu .cpu ;
110+ data [ARM_SPE_CPU_NR_PARAMS ] = ARM_SPE_CPU_PRIV_MAX - ARM_SPE_CPU_MIDR ;
111+ data [ARM_SPE_CPU_MIDR ] = val ;
112+
113+ /* Find the associate Arm SPE PMU for the CPU */
114+ if (perf_cpu_map__has (sper -> arm_spe_pmu -> cpus , cpu ))
115+ pmu = sper -> arm_spe_pmu ;
116+
117+ if (!pmu ) {
118+ /* No Arm SPE PMU is found */
119+ data [ARM_SPE_CPU_PMU_TYPE ] = ULLONG_MAX ;
120+ data [ARM_SPE_CAP_MIN_IVAL ] = 0 ;
121+ } else {
122+ data [ARM_SPE_CPU_PMU_TYPE ] = pmu -> type ;
123+
124+ if (perf_pmu__scan_file (pmu , "caps/min_interval" , "%lu" , & val ) != 1 )
125+ val = 0 ;
126+ data [ARM_SPE_CAP_MIN_IVAL ] = val ;
127+ }
128+
129+ free (cpuid );
130+ return ARM_SPE_CPU_PRIV_MAX ;
45131}
46132
47133static int arm_spe_info_fill (struct auxtrace_record * itr ,
48134 struct perf_session * session ,
49135 struct perf_record_auxtrace_info * auxtrace_info ,
50136 size_t priv_size )
51137{
138+ int i , ret ;
139+ size_t offset ;
52140 struct arm_spe_recording * sper =
53141 container_of (itr , struct arm_spe_recording , itr );
54142 struct perf_pmu * arm_spe_pmu = sper -> arm_spe_pmu ;
143+ struct perf_cpu_map * cpu_map ;
144+ struct perf_cpu cpu ;
145+ __u64 * data ;
55146
56- if (priv_size != ARM_SPE_AUXTRACE_PRIV_SIZE )
147+ if (priv_size != arm_spe_info_priv_size ( itr , session -> evlist ) )
57148 return - EINVAL ;
58149
59150 if (!session -> evlist -> core .nr_mmaps )
60151 return - EINVAL ;
61152
153+ cpu_map = arm_spe_find_cpus (session -> evlist );
154+ if (!cpu_map )
155+ return - EINVAL ;
156+
62157 auxtrace_info -> type = PERF_AUXTRACE_ARM_SPE ;
63- auxtrace_info -> priv [ARM_SPE_PMU_TYPE ] = arm_spe_pmu -> type ;
158+ auxtrace_info -> priv [ARM_SPE_HEADER_VERSION ] = ARM_SPE_HEADER_CURRENT_VERSION ;
159+ auxtrace_info -> priv [ARM_SPE_HEADER_SIZE ] =
160+ ARM_SPE_AUXTRACE_PRIV_MAX - ARM_SPE_HEADER_VERSION ;
161+ auxtrace_info -> priv [ARM_SPE_PMU_TYPE_V2 ] = arm_spe_pmu -> type ;
162+ auxtrace_info -> priv [ARM_SPE_CPUS_NUM ] = perf_cpu_map__nr (cpu_map );
163+
164+ offset = ARM_SPE_AUXTRACE_PRIV_MAX ;
165+ perf_cpu_map__for_each_cpu (cpu , i , cpu_map ) {
166+ assert (offset < priv_size );
167+ data = & auxtrace_info -> priv [offset ];
168+ ret = arm_spe_save_cpu_header (itr , cpu , data );
169+ if (ret < 0 )
170+ goto out ;
171+ offset += ret ;
172+ }
64173
65- return 0 ;
174+ ret = 0 ;
175+ out :
176+ perf_cpu_map__put (cpu_map );
177+ return ret ;
66178}
67179
68180static void
0 commit comments