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

perf: cs-etm: Move traceid_list to each queue

The global list won't work for per-sink trace ID allocations, so put a
list in each queue where the IDs will be unique to that queue.

To keep the same behavior as before, for version 0 of the HW_ID packets,
copy all the HW_ID mappings into all queues.

This change doesn't effect the decoders, only trace ID lookups on the
Perf side. The decoders are still created with global mappings which
will be fixed in a later commit.

Reviewed-by: Mike Leach <mike.leach@linaro.org>
Signed-off-by: James Clark <james.clark@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: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Ganapatrao Kulkarni <gankulkarni@os.amperecomputing.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: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20240722101202.26915-4-james.clark@linaro.org
Signed-off-by: James Clark <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
77c123f5 57880a79

+148 -99
+16 -12
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
··· 388 388 } 389 389 390 390 static ocsd_datapath_resp_t 391 - cs_etm_decoder__buffer_packet(struct cs_etm_packet_queue *packet_queue, 391 + cs_etm_decoder__buffer_packet(struct cs_etm_queue *etmq, 392 + struct cs_etm_packet_queue *packet_queue, 392 393 const u8 trace_chan_id, 393 394 enum cs_etm_sample_type sample_type) 394 395 { ··· 399 398 if (packet_queue->packet_count >= CS_ETM_PACKET_MAX_BUFFER - 1) 400 399 return OCSD_RESP_FATAL_SYS_ERR; 401 400 402 - if (cs_etm__get_cpu(trace_chan_id, &cpu) < 0) 401 + if (cs_etm__get_cpu(etmq, trace_chan_id, &cpu) < 0) 403 402 return OCSD_RESP_FATAL_SYS_ERR; 404 403 405 404 et = packet_queue->tail; ··· 437 436 int ret = 0; 438 437 struct cs_etm_packet *packet; 439 438 440 - ret = cs_etm_decoder__buffer_packet(packet_queue, trace_chan_id, 439 + ret = cs_etm_decoder__buffer_packet(etmq, packet_queue, trace_chan_id, 441 440 CS_ETM_RANGE); 442 441 if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT) 443 442 return ret; ··· 497 496 } 498 497 499 498 static ocsd_datapath_resp_t 500 - cs_etm_decoder__buffer_discontinuity(struct cs_etm_packet_queue *queue, 499 + cs_etm_decoder__buffer_discontinuity(struct cs_etm_queue *etmq, 500 + struct cs_etm_packet_queue *queue, 501 501 const uint8_t trace_chan_id) 502 502 { 503 503 /* ··· 506 504 * reset time statistics. 507 505 */ 508 506 cs_etm_decoder__reset_timestamp(queue); 509 - return cs_etm_decoder__buffer_packet(queue, trace_chan_id, 507 + return cs_etm_decoder__buffer_packet(etmq, queue, trace_chan_id, 510 508 CS_ETM_DISCONTINUITY); 511 509 } 512 510 513 511 static ocsd_datapath_resp_t 514 - cs_etm_decoder__buffer_exception(struct cs_etm_packet_queue *queue, 512 + cs_etm_decoder__buffer_exception(struct cs_etm_queue *etmq, 513 + struct cs_etm_packet_queue *queue, 515 514 const ocsd_generic_trace_elem *elem, 516 515 const uint8_t trace_chan_id) 517 516 { int ret = 0; 518 517 struct cs_etm_packet *packet; 519 518 520 - ret = cs_etm_decoder__buffer_packet(queue, trace_chan_id, 519 + ret = cs_etm_decoder__buffer_packet(etmq, queue, trace_chan_id, 521 520 CS_ETM_EXCEPTION); 522 521 if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT) 523 522 return ret; ··· 530 527 } 531 528 532 529 static ocsd_datapath_resp_t 533 - cs_etm_decoder__buffer_exception_ret(struct cs_etm_packet_queue *queue, 530 + cs_etm_decoder__buffer_exception_ret(struct cs_etm_queue *etmq, 531 + struct cs_etm_packet_queue *queue, 534 532 const uint8_t trace_chan_id) 535 533 { 536 - return cs_etm_decoder__buffer_packet(queue, trace_chan_id, 534 + return cs_etm_decoder__buffer_packet(etmq, queue, trace_chan_id, 537 535 CS_ETM_EXCEPTION_RET); 538 536 } 539 537 ··· 603 599 case OCSD_GEN_TRC_ELEM_EO_TRACE: 604 600 case OCSD_GEN_TRC_ELEM_NO_SYNC: 605 601 case OCSD_GEN_TRC_ELEM_TRACE_ON: 606 - resp = cs_etm_decoder__buffer_discontinuity(packet_queue, 602 + resp = cs_etm_decoder__buffer_discontinuity(etmq, packet_queue, 607 603 trace_chan_id); 608 604 break; 609 605 case OCSD_GEN_TRC_ELEM_INSTR_RANGE: ··· 611 607 trace_chan_id); 612 608 break; 613 609 case OCSD_GEN_TRC_ELEM_EXCEPTION: 614 - resp = cs_etm_decoder__buffer_exception(packet_queue, elem, 610 + resp = cs_etm_decoder__buffer_exception(etmq, packet_queue, elem, 615 611 trace_chan_id); 616 612 break; 617 613 case OCSD_GEN_TRC_ELEM_EXCEPTION_RET: 618 - resp = cs_etm_decoder__buffer_exception_ret(packet_queue, 614 + resp = cs_etm_decoder__buffer_exception_ret(etmq, packet_queue, 619 615 trace_chan_id); 620 616 break; 621 617 case OCSD_GEN_TRC_ELEM_TIMESTAMP:
+131 -86
tools/perf/util/cs-etm.c
··· 116 116 /* Conversion between traceID and index in traceid_queues array */ 117 117 struct intlist *traceid_queues_list; 118 118 struct cs_etm_traceid_queue **traceid_queues; 119 + /* Conversion between traceID and metadata pointers */ 120 + struct intlist *traceid_list; 119 121 }; 120 - 121 - /* RB tree for quick conversion between traceID and metadata pointers */ 122 - static struct intlist *traceid_list; 123 122 124 123 static int cs_etm__process_timestamped_queues(struct cs_etm_auxtrace *etm); 125 124 static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm, 126 125 pid_t tid); 127 126 static int cs_etm__get_data_block(struct cs_etm_queue *etmq); 128 127 static int cs_etm__decode_data_block(struct cs_etm_queue *etmq); 128 + static int cs_etm__metadata_get_trace_id(u8 *trace_chan_id, u64 *cpu_metadata); 129 + static u64 *get_cpu_data(struct cs_etm_auxtrace *etm, int cpu); 130 + static int cs_etm__metadata_set_trace_id(u8 trace_chan_id, u64 *cpu_metadata); 129 131 130 132 /* PTMs ETMIDR [11:8] set to b0011 */ 131 133 #define ETMIDR_PTM_VERSION 0x00000300 ··· 153 151 return CS_ETM_PROTO_ETMV3; 154 152 } 155 153 156 - static int cs_etm__get_magic(u8 trace_chan_id, u64 *magic) 154 + static int cs_etm__get_magic(struct cs_etm_queue *etmq, u8 trace_chan_id, u64 *magic) 157 155 { 158 156 struct int_node *inode; 159 157 u64 *metadata; 160 158 161 - inode = intlist__find(traceid_list, trace_chan_id); 159 + inode = intlist__find(etmq->traceid_list, trace_chan_id); 162 160 if (!inode) 163 161 return -EINVAL; 164 162 ··· 167 165 return 0; 168 166 } 169 167 170 - int cs_etm__get_cpu(u8 trace_chan_id, int *cpu) 168 + int cs_etm__get_cpu(struct cs_etm_queue *etmq, u8 trace_chan_id, int *cpu) 171 169 { 172 170 struct int_node *inode; 173 171 u64 *metadata; 174 172 175 - inode = intlist__find(traceid_list, trace_chan_id); 173 + inode = intlist__find(etmq->traceid_list, trace_chan_id); 176 174 if (!inode) 177 175 return -EINVAL; 178 176 ··· 224 222 return etmq->etm->pid_fmt; 225 223 } 226 224 227 - static int cs_etm__map_trace_id(u8 trace_chan_id, u64 *cpu_metadata) 225 + static int cs_etm__insert_trace_id_node(struct cs_etm_queue *etmq, 226 + u8 trace_chan_id, u64 *cpu_metadata) 228 227 { 229 - struct int_node *inode; 230 - 231 228 /* Get an RB node for this CPU */ 232 - inode = intlist__findnew(traceid_list, trace_chan_id); 229 + struct int_node *inode = intlist__findnew(etmq->traceid_list, trace_chan_id); 233 230 234 231 /* Something went wrong, no need to continue */ 235 232 if (!inode) 236 233 return -ENOMEM; 237 234 238 - /* 239 - * The node for that CPU should not be taken. 240 - * Back out if that's the case. 241 - */ 242 - if (inode->priv) 243 - return -EINVAL; 235 + /* Disallow re-mapping a different traceID to metadata pair. */ 236 + if (inode->priv) { 237 + u64 *curr_cpu_data = inode->priv; 238 + u8 curr_chan_id; 239 + int err; 244 240 245 - /* All good, associate the traceID with the metadata pointer */ 241 + if (curr_cpu_data[CS_ETM_CPU] != cpu_metadata[CS_ETM_CPU]) { 242 + pr_err("CS_ETM: map mismatch between HW_ID packet CPU and Trace ID\n"); 243 + return -EINVAL; 244 + } 245 + 246 + /* check that the mapped ID matches */ 247 + err = cs_etm__metadata_get_trace_id(&curr_chan_id, curr_cpu_data); 248 + if (err) 249 + return err; 250 + 251 + if (curr_chan_id != trace_chan_id) { 252 + pr_err("CS_ETM: mismatch between CPU trace ID and HW_ID packet ID\n"); 253 + return -EINVAL; 254 + } 255 + 256 + /* Skip re-adding the same mappings if everything matched */ 257 + return 0; 258 + } 259 + 260 + /* Not one we've seen before, associate the traceID with the metadata pointer */ 246 261 inode->priv = cpu_metadata; 247 262 248 263 return 0; 264 + } 265 + 266 + static struct cs_etm_queue *cs_etm__get_queue(struct cs_etm_auxtrace *etm, int cpu) 267 + { 268 + if (etm->per_thread_decoding) 269 + return etm->queues.queue_array[0].priv; 270 + else 271 + return etm->queues.queue_array[cpu].priv; 272 + } 273 + 274 + static int cs_etm__map_trace_id_v0(struct cs_etm_auxtrace *etm, u8 trace_chan_id, 275 + u64 *cpu_metadata) 276 + { 277 + struct cs_etm_queue *etmq; 278 + 279 + /* 280 + * If the queue is unformatted then only save one mapping in the 281 + * queue associated with that CPU so only one decoder is made. 282 + */ 283 + etmq = cs_etm__get_queue(etm, cpu_metadata[CS_ETM_CPU]); 284 + if (etmq->format == UNFORMATTED) 285 + return cs_etm__insert_trace_id_node(etmq, trace_chan_id, 286 + cpu_metadata); 287 + 288 + /* 289 + * Otherwise, version 0 trace IDs are global so save them into every 290 + * queue. 291 + */ 292 + for (unsigned int i = 0; i < etm->queues.nr_queues; ++i) { 293 + int ret; 294 + 295 + etmq = etm->queues.queue_array[i].priv; 296 + ret = cs_etm__insert_trace_id_node(etmq, trace_chan_id, 297 + cpu_metadata); 298 + if (ret) 299 + return ret; 300 + } 301 + 302 + return 0; 303 + } 304 + 305 + static int cs_etm__process_trace_id_v0(struct cs_etm_auxtrace *etm, int cpu, 306 + u64 hw_id) 307 + { 308 + int err; 309 + u64 *cpu_data; 310 + u8 trace_chan_id = FIELD_GET(CS_AUX_HW_ID_TRACE_ID_MASK, hw_id); 311 + 312 + cpu_data = get_cpu_data(etm, cpu); 313 + if (cpu_data == NULL) 314 + return -EINVAL; 315 + 316 + err = cs_etm__map_trace_id_v0(etm, trace_chan_id, cpu_data); 317 + if (err) 318 + return err; 319 + 320 + /* 321 + * if we are picking up the association from the packet, need to plug 322 + * the correct trace ID into the metadata for setting up decoders later. 323 + */ 324 + return cs_etm__metadata_set_trace_id(trace_chan_id, cpu_data); 249 325 } 250 326 251 327 static int cs_etm__metadata_get_trace_id(u8 *trace_chan_id, u64 *cpu_metadata) ··· 409 329 { 410 330 struct cs_etm_auxtrace *etm; 411 331 struct perf_sample sample; 412 - struct int_node *inode; 413 332 struct evsel *evsel; 414 - u64 *cpu_data; 415 333 u64 hw_id; 416 334 int cpu, version, err; 417 - u8 trace_chan_id, curr_chan_id; 418 335 419 336 /* extract and parse the HW ID */ 420 337 hw_id = event->aux_output_hw_id.hw_id; 421 338 version = FIELD_GET(CS_AUX_HW_ID_VERSION_MASK, hw_id); 422 - trace_chan_id = FIELD_GET(CS_AUX_HW_ID_TRACE_ID_MASK, hw_id); 423 339 424 340 /* check that we can handle this version */ 425 341 if (version > CS_AUX_HW_ID_CURR_VERSION) { ··· 443 367 return -EINVAL; 444 368 } 445 369 446 - /* See if the ID is mapped to a CPU, and it matches the current CPU */ 447 - inode = intlist__find(traceid_list, trace_chan_id); 448 - if (inode) { 449 - cpu_data = inode->priv; 450 - if ((int)cpu_data[CS_ETM_CPU] != cpu) { 451 - pr_err("CS_ETM: map mismatch between HW_ID packet CPU and Trace ID\n"); 452 - return -EINVAL; 453 - } 454 - 455 - /* check that the mapped ID matches */ 456 - err = cs_etm__metadata_get_trace_id(&curr_chan_id, cpu_data); 457 - if (err) 458 - return err; 459 - if (curr_chan_id != trace_chan_id) { 460 - pr_err("CS_ETM: mismatch between CPU trace ID and HW_ID packet ID\n"); 461 - return -EINVAL; 462 - } 463 - 464 - /* mapped and matched - return OK */ 465 - return 0; 466 - } 467 - 468 - cpu_data = get_cpu_data(etm, cpu); 469 - if (cpu_data == NULL) 470 - return err; 471 - 472 - /* not one we've seen before - lets map it */ 473 - err = cs_etm__map_trace_id(trace_chan_id, cpu_data); 474 - if (err) 475 - return err; 476 - 477 - /* 478 - * if we are picking up the association from the packet, need to plug 479 - * the correct trace ID into the metadata for setting up decoders later. 480 - */ 481 - err = cs_etm__metadata_set_trace_id(trace_chan_id, cpu_data); 482 - return err; 370 + return cs_etm__process_trace_id_v0(etm, cpu, hw_id); 483 371 } 484 372 485 373 void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq, ··· 896 856 897 857 static void cs_etm__free_queue(void *priv) 898 858 { 859 + struct int_node *inode, *tmp; 899 860 struct cs_etm_queue *etmq = priv; 900 861 901 862 if (!etmq) ··· 904 863 905 864 cs_etm_decoder__free(etmq->decoder); 906 865 cs_etm__free_traceid_queues(etmq); 866 + 867 + /* First remove all traceID/metadata nodes for the RB tree */ 868 + intlist__for_each_entry_safe(inode, tmp, etmq->traceid_list) 869 + intlist__remove(etmq->traceid_list, inode); 870 + 871 + /* Then the RB tree itself */ 872 + intlist__delete(etmq->traceid_list); 873 + 907 874 free(etmq); 908 875 } 909 876 ··· 934 885 static void cs_etm__free(struct perf_session *session) 935 886 { 936 887 int i; 937 - struct int_node *inode, *tmp; 938 888 struct cs_etm_auxtrace *aux = container_of(session->auxtrace, 939 889 struct cs_etm_auxtrace, 940 890 auxtrace); 941 891 cs_etm__free_events(session); 942 892 session->auxtrace = NULL; 943 - 944 - /* First remove all traceID/metadata nodes for the RB tree */ 945 - intlist__for_each_entry_safe(inode, tmp, traceid_list) 946 - intlist__remove(traceid_list, inode); 947 - /* Then the RB tree itself */ 948 - intlist__delete(traceid_list); 949 893 950 894 for (i = 0; i < aux->num_cpu; i++) 951 895 zfree(&aux->metadata[i]); ··· 1097 1055 1098 1056 etmq->traceid_queues_list = intlist__new(NULL); 1099 1057 if (!etmq->traceid_queues_list) 1100 - free(etmq); 1058 + goto out_free; 1059 + 1060 + /* 1061 + * Create an RB tree for traceID-metadata tuple. Since the conversion 1062 + * has to be made for each packet that gets decoded, optimizing access 1063 + * in anything other than a sequential array is worth doing. 1064 + */ 1065 + etmq->traceid_list = intlist__new(NULL); 1066 + if (!etmq->traceid_list) 1067 + goto out_free; 1101 1068 1102 1069 return etmq; 1070 + 1071 + out_free: 1072 + intlist__delete(etmq->traceid_queues_list); 1073 + free(etmq); 1074 + 1075 + return NULL; 1103 1076 } 1104 1077 1105 1078 static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm, ··· 2239 2182 PERF_IP_FLAG_TRACE_END; 2240 2183 break; 2241 2184 case CS_ETM_EXCEPTION: 2242 - ret = cs_etm__get_magic(packet->trace_chan_id, &magic); 2185 + ret = cs_etm__get_magic(etmq, packet->trace_chan_id, &magic); 2243 2186 if (ret) 2244 2187 return ret; 2245 2188 ··· 3156 3099 } 3157 3100 3158 3101 /* map trace ids to correct metadata block, from information in metadata */ 3159 - static int cs_etm__map_trace_ids_metadata(int num_cpu, u64 **metadata) 3102 + static int cs_etm__map_trace_ids_metadata(struct cs_etm_auxtrace *etm, int num_cpu, 3103 + u64 **metadata) 3160 3104 { 3161 3105 u64 cs_etm_magic; 3162 3106 u8 trace_chan_id; ··· 3179 3121 /* unknown magic number */ 3180 3122 return -EINVAL; 3181 3123 } 3182 - err = cs_etm__map_trace_id(trace_chan_id, metadata[i]); 3124 + err = cs_etm__map_trace_id_v0(etm, trace_chan_id, metadata[i]); 3183 3125 if (err) 3184 3126 return err; 3185 3127 } ··· 3310 3252 u64 *ptr = NULL; 3311 3253 u64 **metadata = NULL; 3312 3254 3313 - /* 3314 - * Create an RB tree for traceID-metadata tuple. Since the conversion 3315 - * has to be made for each packet that gets decoded, optimizing access 3316 - * in anything other than a sequential array is worth doing. 3317 - */ 3318 - traceid_list = intlist__new(NULL); 3319 - if (!traceid_list) 3320 - return -ENOMEM; 3321 - 3322 3255 /* First the global part */ 3323 3256 ptr = (u64 *) auxtrace_info->priv; 3324 3257 num_cpu = ptr[CS_PMU_TYPE_CPUS] & 0xffffffff; 3325 3258 metadata = zalloc(sizeof(*metadata) * num_cpu); 3326 - if (!metadata) { 3327 - err = -ENOMEM; 3328 - goto err_free_traceid_list; 3329 - } 3259 + if (!metadata) 3260 + return -ENOMEM; 3330 3261 3331 3262 /* Start parsing after the common part of the header */ 3332 3263 i = CS_HEADER_VERSION_MAX; ··· 3494 3447 err = cs_etm__clear_unused_trace_ids_metadata(num_cpu, metadata); 3495 3448 /* otherwise, this is a file with metadata values only, map from metadata */ 3496 3449 else 3497 - err = cs_etm__map_trace_ids_metadata(num_cpu, metadata); 3450 + err = cs_etm__map_trace_ids_metadata(etm, num_cpu, metadata); 3498 3451 3499 3452 if (err) 3500 3453 goto err_free_queues; ··· 3516 3469 for (int j = 0; j < num_cpu; j++) 3517 3470 zfree(&metadata[j]); 3518 3471 zfree(&metadata); 3519 - err_free_traceid_list: 3520 - intlist__delete(traceid_list); 3521 3472 return err; 3522 3473 }
+1 -1
tools/perf/util/cs-etm.h
··· 252 252 253 253 #ifdef HAVE_CSTRACE_SUPPORT 254 254 #include <opencsd/ocsd_if_types.h> 255 - int cs_etm__get_cpu(u8 trace_chan_id, int *cpu); 255 + int cs_etm__get_cpu(struct cs_etm_queue *etmq, u8 trace_chan_id, int *cpu); 256 256 enum cs_etm_pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq); 257 257 int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid, 258 258 u8 trace_chan_id, ocsd_ex_level el);