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

perf arm-spe: Support hardware-based PID tracing

If ARM SPE traces contains CONTEXT packets with TID info, use these
values for tracking the TID of samples. Otherwise fall back to using
context switch events and display a message warning to the user of
possible timing inaccuracies [1].

[1] https://lore.kernel.org/lkml/f877cfa6-9b25-6445-3806-ca44a4042eaf@arm.com/

Signed-off-by: German Gomez <german.gomez@arm.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Will Deacon <will@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20211111133625.193568-5-german.gomez@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

German Gomez and committed by
Arnaldo Carvalho de Melo
27d113cf 169de64f

+70 -29
+70 -29
tools/perf/util/arm-spe.c
··· 71 71 u64 kernel_start; 72 72 73 73 unsigned long num_events; 74 + u8 use_ctx_pkt_for_pid; 74 75 }; 75 76 76 77 struct arm_spe_queue { ··· 225 224 return ip >= spe->kernel_start ? 226 225 PERF_RECORD_MISC_KERNEL : 227 226 PERF_RECORD_MISC_USER; 227 + } 228 + 229 + static void arm_spe_set_pid_tid_cpu(struct arm_spe *spe, 230 + struct auxtrace_queue *queue) 231 + { 232 + struct arm_spe_queue *speq = queue->priv; 233 + pid_t tid; 234 + 235 + tid = machine__get_current_tid(spe->machine, speq->cpu); 236 + if (tid != -1) { 237 + speq->tid = tid; 238 + thread__zput(speq->thread); 239 + } else 240 + speq->tid = queue->tid; 241 + 242 + if ((!speq->thread) && (speq->tid != -1)) { 243 + speq->thread = machine__find_thread(spe->machine, -1, 244 + speq->tid); 245 + } 246 + 247 + if (speq->thread) { 248 + speq->pid = speq->thread->pid_; 249 + if (queue->cpu == -1) 250 + speq->cpu = speq->thread->cpu; 251 + } 252 + } 253 + 254 + static int arm_spe_set_tid(struct arm_spe_queue *speq, pid_t tid) 255 + { 256 + struct arm_spe *spe = speq->spe; 257 + int err = machine__set_current_tid(spe->machine, speq->cpu, -1, tid); 258 + 259 + if (err) 260 + return err; 261 + 262 + arm_spe_set_pid_tid_cpu(spe, &spe->queues.queue_array[speq->queue_nr]); 263 + 264 + return 0; 228 265 } 229 266 230 267 static void arm_spe_prep_sample(struct arm_spe *spe, ··· 499 460 * can correlate samples between Arm SPE trace data and other 500 461 * perf events with correct time ordering. 501 462 */ 463 + 464 + /* 465 + * Update pid/tid info. 466 + */ 467 + record = &speq->decoder->record; 468 + if (!spe->timeless_decoding && record->context_id != (u64)-1) { 469 + ret = arm_spe_set_tid(speq, record->context_id); 470 + if (ret) 471 + return ret; 472 + 473 + spe->use_ctx_pkt_for_pid = true; 474 + } 475 + 502 476 ret = arm_spe_sample(speq); 503 477 if (ret) 504 478 return ret; ··· 638 586 return timeless_decoding; 639 587 } 640 588 641 - static void arm_spe_set_pid_tid_cpu(struct arm_spe *spe, 642 - struct auxtrace_queue *queue) 643 - { 644 - struct arm_spe_queue *speq = queue->priv; 645 - pid_t tid; 646 - 647 - tid = machine__get_current_tid(spe->machine, speq->cpu); 648 - if (tid != -1) { 649 - speq->tid = tid; 650 - thread__zput(speq->thread); 651 - } else 652 - speq->tid = queue->tid; 653 - 654 - if ((!speq->thread) && (speq->tid != -1)) { 655 - speq->thread = machine__find_thread(spe->machine, -1, 656 - speq->tid); 657 - } 658 - 659 - if (speq->thread) { 660 - speq->pid = speq->thread->pid_; 661 - if (queue->cpu == -1) 662 - speq->cpu = speq->thread->cpu; 663 - } 664 - } 665 - 666 589 static int arm_spe_process_queues(struct arm_spe *spe, u64 timestamp) 667 590 { 668 591 unsigned int queue_nr; ··· 668 641 ts = timestamp; 669 642 } 670 643 671 - arm_spe_set_pid_tid_cpu(spe, queue); 644 + /* 645 + * A previous context-switch event has set pid/tid in the machine's context, so 646 + * here we need to update the pid/tid in the thread and SPE queue. 647 + */ 648 + if (!spe->use_ctx_pkt_for_pid) 649 + arm_spe_set_pid_tid_cpu(spe, queue); 672 650 673 651 ret = arm_spe_run_decoder(speq, &ts); 674 652 if (ret < 0) { ··· 772 740 if (err) 773 741 return err; 774 742 775 - if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE || 776 - event->header.type == PERF_RECORD_SWITCH) 743 + if (!spe->use_ctx_pkt_for_pid && 744 + (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE || 745 + event->header.type == PERF_RECORD_SWITCH)) 777 746 err = arm_spe_context_switch(spe, event, sample); 778 747 } 779 748 ··· 841 808 return arm_spe_process_timeless_queues(spe, -1, 842 809 MAX_TIMESTAMP - 1); 843 810 844 - return arm_spe_process_queues(spe, MAX_TIMESTAMP); 811 + ret = arm_spe_process_queues(spe, MAX_TIMESTAMP); 812 + if (ret) 813 + return ret; 814 + 815 + if (!spe->use_ctx_pkt_for_pid) 816 + ui__warning("Arm SPE CONTEXT packets not found in the traces.\n" 817 + "Matching of TIDs to SPE events could be inaccurate.\n"); 818 + 819 + return 0; 845 820 } 846 821 847 822 static void arm_spe_free_queue(void *priv)