Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

perf cs-etm: Create decoders after both AUX and HW_ID search passes

Both of these passes gather information about how to create the
decoders. AUX records determine formatted/unformatted, and the HW_IDs
determine the traceID/metadata mappings.

Therefore it makes sense to cache the information and wait until both
passes are over until creating the decoders, rather than creating them
at the first HW_ID found.

This will allow a simplification of the creation process where
cs_etm_queue->traceid_list will exclusively used to create the decoders,
rather than the current two methods depending on whether the trace is
formatted or not.

Previously the sample CPU from the AUX record was used to initialize
the decoder CPU, but actually sample CPU == AUX queue index in per-CPU
mode, so saving the sample CPU isn't required.

Similarly formatted/unformatted was used upfront to create the decoders,
but now it's cached until later.

Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Reviewed-by: Mike Leach <mike.leach@linaro.org>
Signed-off-by: James Clark <james.clark@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
Tested-by: Ganapatrao Kulkarni <gankulkarni@os.amperecomputing.com>
Tested-by: Leo Yan <leo.yan@arm.com>
Acked-by: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linux.dev>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20240722101202.26915-2-james.clark@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

James Clark and committed by
Arnaldo Carvalho de Melo
b6aa0de9 0fd77ae4

+113 -69
+113 -69
tools/perf/util/cs-etm.c
··· 97 97 struct cs_etm_packet_queue packet_queue; 98 98 }; 99 99 100 + enum cs_etm_format { 101 + UNSET, 102 + FORMATTED, 103 + UNFORMATTED 104 + }; 105 + 100 106 struct cs_etm_queue { 101 107 struct cs_etm_auxtrace *etm; 102 108 struct cs_etm_decoder *decoder; 103 109 struct auxtrace_buffer *buffer; 104 110 unsigned int queue_nr; 105 111 u8 pending_timestamp_chan_id; 112 + enum cs_etm_format format; 106 113 u64 offset; 107 114 const unsigned char *buf; 108 115 size_t buf_len, buf_used; ··· 703 696 704 697 static int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params, 705 698 struct cs_etm_auxtrace *etm, 706 - bool formatted, 699 + enum cs_etm_format format, 707 700 int sample_cpu, 708 701 int decoders) 709 702 { ··· 712 705 u64 architecture; 713 706 714 707 for (t_idx = 0; t_idx < decoders; t_idx++) { 715 - if (formatted) 708 + if (format == FORMATTED) 716 709 m_idx = t_idx; 717 710 else { 718 711 m_idx = get_cpu_data_idx(etm, sample_cpu); ··· 745 738 746 739 static int cs_etm__init_decoder_params(struct cs_etm_decoder_params *d_params, 747 740 struct cs_etm_queue *etmq, 748 - enum cs_etm_decoder_operation mode, 749 - bool formatted) 741 + enum cs_etm_decoder_operation mode) 750 742 { 751 743 int ret = -EINVAL; 752 744 ··· 755 749 d_params->packet_printer = cs_etm__packet_dump; 756 750 d_params->operation = mode; 757 751 d_params->data = etmq; 758 - d_params->formatted = formatted; 752 + d_params->formatted = etmq->format == FORMATTED; 759 753 d_params->fsyncs = false; 760 754 d_params->hsyncs = false; 761 755 d_params->frame_aligned = true; ··· 1047 1041 return ret; 1048 1042 } 1049 1043 1050 - static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm, 1051 - bool formatted, int sample_cpu) 1044 + static struct cs_etm_queue *cs_etm__alloc_queue(void) 1052 1045 { 1053 - struct cs_etm_decoder_params d_params; 1054 - struct cs_etm_trace_params *t_params = NULL; 1055 - struct cs_etm_queue *etmq; 1056 - /* 1057 - * Each queue can only contain data from one CPU when unformatted, so only one decoder is 1058 - * needed. 1059 - */ 1060 - int decoders = formatted ? etm->num_cpu : 1; 1061 - 1062 - etmq = zalloc(sizeof(*etmq)); 1046 + struct cs_etm_queue *etmq = zalloc(sizeof(*etmq)); 1063 1047 if (!etmq) 1064 1048 return NULL; 1065 1049 1066 1050 etmq->traceid_queues_list = intlist__new(NULL); 1067 1051 if (!etmq->traceid_queues_list) 1068 - goto out_free; 1052 + free(etmq); 1069 1053 1070 - /* Use metadata to fill in trace parameters for trace decoder */ 1071 - t_params = zalloc(sizeof(*t_params) * decoders); 1072 - 1073 - if (!t_params) 1074 - goto out_free; 1075 - 1076 - if (cs_etm__init_trace_params(t_params, etm, formatted, sample_cpu, decoders)) 1077 - goto out_free; 1078 - 1079 - /* Set decoder parameters to decode trace packets */ 1080 - if (cs_etm__init_decoder_params(&d_params, etmq, 1081 - dump_trace ? CS_ETM_OPERATION_PRINT : 1082 - CS_ETM_OPERATION_DECODE, 1083 - formatted)) 1084 - goto out_free; 1085 - 1086 - etmq->decoder = cs_etm_decoder__new(decoders, &d_params, 1087 - t_params); 1088 - 1089 - if (!etmq->decoder) 1090 - goto out_free; 1091 - 1092 - /* 1093 - * Register a function to handle all memory accesses required by 1094 - * the trace decoder library. 1095 - */ 1096 - if (cs_etm_decoder__add_mem_access_cb(etmq->decoder, 1097 - 0x0L, ((u64) -1L), 1098 - cs_etm__mem_access)) 1099 - goto out_free_decoder; 1100 - 1101 - zfree(&t_params); 1102 1054 return etmq; 1103 - 1104 - out_free_decoder: 1105 - cs_etm_decoder__free(etmq->decoder); 1106 - out_free: 1107 - intlist__delete(etmq->traceid_queues_list); 1108 - free(etmq); 1109 - 1110 - return NULL; 1111 1055 } 1112 1056 1113 1057 static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm, 1114 1058 struct auxtrace_queue *queue, 1115 - unsigned int queue_nr, 1116 - bool formatted, 1117 - int sample_cpu) 1059 + unsigned int queue_nr, enum cs_etm_format format) 1118 1060 { 1119 1061 struct cs_etm_queue *etmq = queue->priv; 1062 + 1063 + if (etmq && format != etmq->format) { 1064 + pr_err("CS_ETM: mixed formatted and unformatted trace not supported\n"); 1065 + return -EINVAL; 1066 + } 1120 1067 1121 1068 if (list_empty(&queue->head) || etmq) 1122 1069 return 0; 1123 1070 1124 - etmq = cs_etm__alloc_queue(etm, formatted, sample_cpu); 1071 + etmq = cs_etm__alloc_queue(); 1125 1072 1126 1073 if (!etmq) 1127 1074 return -ENOMEM; ··· 1082 1123 queue->priv = etmq; 1083 1124 etmq->etm = etm; 1084 1125 etmq->queue_nr = queue_nr; 1126 + queue->cpu = queue_nr; /* Placeholder, may be reset to -1 in per-thread mode */ 1085 1127 etmq->offset = 0; 1128 + etmq->format = format; 1086 1129 1087 1130 return 0; 1088 1131 } ··· 2779 2818 * formatted in piped mode (true). 2780 2819 */ 2781 2820 err = cs_etm__setup_queue(etm, &etm->queues.queue_array[idx], 2782 - idx, true, -1); 2821 + idx, FORMATTED); 2783 2822 if (err) 2784 2823 return err; 2785 2824 ··· 2900 2939 union perf_event auxtrace_fragment; 2901 2940 __u64 aux_offset, aux_size; 2902 2941 __u32 idx; 2903 - bool formatted; 2942 + enum cs_etm_format format; 2904 2943 2905 2944 struct cs_etm_auxtrace *etm = container_of(session->auxtrace, 2906 2945 struct cs_etm_auxtrace, ··· 2983 3022 return err; 2984 3023 2985 3024 idx = auxtrace_event->idx; 2986 - formatted = !(aux_event->flags & PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW); 2987 - return cs_etm__setup_queue(etm, &etm->queues.queue_array[idx], 2988 - idx, formatted, sample->cpu); 3025 + format = (aux_event->flags & PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW) ? 3026 + UNFORMATTED : FORMATTED; 3027 + 3028 + return cs_etm__setup_queue(etm, &etm->queues.queue_array[idx], idx, format); 2989 3029 } 2990 3030 2991 3031 /* Wasn't inside this buffer, but there were no parse errors. 1 == 'not found' */ ··· 3170 3208 return 0; 3171 3209 } 3172 3210 3211 + /* 3212 + * Use the data gathered by the peeks for HW_ID (trace ID mappings) and AUX 3213 + * (formatted or not) packets to create the decoders. 3214 + */ 3215 + static int cs_etm__create_queue_decoders(struct cs_etm_queue *etmq) 3216 + { 3217 + struct cs_etm_decoder_params d_params; 3218 + 3219 + /* 3220 + * Each queue can only contain data from one CPU when unformatted, so only one decoder is 3221 + * needed. 3222 + */ 3223 + int decoders = etmq->format == FORMATTED ? etmq->etm->num_cpu : 1; 3224 + 3225 + /* Use metadata to fill in trace parameters for trace decoder */ 3226 + struct cs_etm_trace_params *t_params = zalloc(sizeof(*t_params) * decoders); 3227 + 3228 + if (!t_params) 3229 + goto out_free; 3230 + 3231 + if (cs_etm__init_trace_params(t_params, etmq->etm, etmq->format, 3232 + etmq->queue_nr, decoders)) 3233 + goto out_free; 3234 + 3235 + /* Set decoder parameters to decode trace packets */ 3236 + if (cs_etm__init_decoder_params(&d_params, etmq, 3237 + dump_trace ? CS_ETM_OPERATION_PRINT : 3238 + CS_ETM_OPERATION_DECODE)) 3239 + goto out_free; 3240 + 3241 + etmq->decoder = cs_etm_decoder__new(decoders, &d_params, 3242 + t_params); 3243 + 3244 + if (!etmq->decoder) 3245 + goto out_free; 3246 + 3247 + /* 3248 + * Register a function to handle all memory accesses required by 3249 + * the trace decoder library. 3250 + */ 3251 + if (cs_etm_decoder__add_mem_access_cb(etmq->decoder, 3252 + 0x0L, ((u64) -1L), 3253 + cs_etm__mem_access)) 3254 + goto out_free_decoder; 3255 + 3256 + zfree(&t_params); 3257 + return 0; 3258 + 3259 + out_free_decoder: 3260 + cs_etm_decoder__free(etmq->decoder); 3261 + out_free: 3262 + zfree(&t_params); 3263 + return -EINVAL; 3264 + } 3265 + 3266 + static int cs_etm__create_decoders(struct cs_etm_auxtrace *etm) 3267 + { 3268 + struct auxtrace_queues *queues = &etm->queues; 3269 + 3270 + for (unsigned int i = 0; i < queues->nr_queues; i++) { 3271 + bool empty = list_empty(&queues->queue_array[i].head); 3272 + struct cs_etm_queue *etmq = queues->queue_array[i].priv; 3273 + int ret; 3274 + 3275 + /* 3276 + * Don't create decoders for empty queues, mainly because 3277 + * etmq->format is unknown for empty queues. 3278 + */ 3279 + if (empty) 3280 + continue; 3281 + 3282 + ret = cs_etm__create_queue_decoders(etmq); 3283 + if (ret) 3284 + return ret; 3285 + } 3286 + return 0; 3287 + } 3288 + 3173 3289 int cs_etm__process_auxtrace_info_full(union perf_event *event, 3174 3290 struct perf_session *session) 3175 3291 { ··· 3411 3371 if (err) 3412 3372 goto err_free_queues; 3413 3373 3374 + err = cs_etm__queue_aux_records(session); 3375 + if (err) 3376 + goto err_free_queues; 3377 + 3414 3378 /* 3415 3379 * Map Trace ID values to CPU metadata. 3416 3380 * ··· 3437 3393 * flags if present. 3438 3394 */ 3439 3395 3440 - /* first scan for AUX_OUTPUT_HW_ID records to map trace ID values to CPU metadata */ 3396 + /* Scan for AUX_OUTPUT_HW_ID records to map trace ID values to CPU metadata */ 3441 3397 aux_hw_id_found = 0; 3442 3398 err = perf_session__peek_events(session, session->header.data_offset, 3443 3399 session->header.data_size, ··· 3455 3411 if (err) 3456 3412 goto err_free_queues; 3457 3413 3458 - err = cs_etm__queue_aux_records(session); 3414 + err = cs_etm__create_decoders(etm); 3459 3415 if (err) 3460 3416 goto err_free_queues; 3461 3417