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 thread: Add support for reading the e_machine type for a thread

First try to read the e_machine from the dsos associated with the
thread's maps. If live use the executable from /proc/pid/exe and read
the e_machine from the ELF header. On failure use EM_HOST. Change
builtin-trace syscall functions to pass e_machine from the thread
rather than EM_HOST, so that in later patches when syscalltbl can use
the e_machine the system calls are specific to the architecture.

Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Link: https://lore.kernel.org/r/20250319050741.269828-8-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
70351029 afffec6f

+115 -22
+22 -21
tools/perf/builtin-trace.c
··· 2731 2731 int printed = 0; 2732 2732 struct thread *thread; 2733 2733 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; 2734 - int augmented_args_size = 0; 2734 + int augmented_args_size = 0, e_machine; 2735 2735 void *augmented_args = NULL; 2736 - /* TODO: get e_machine from thread. */ 2737 - struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); 2736 + struct syscall *sc; 2738 2737 struct thread_trace *ttrace; 2739 2738 2740 - if (sc == NULL) 2741 - return -1; 2742 - 2743 2739 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 2740 + e_machine = thread__e_machine(thread, trace->host); 2741 + sc = trace__syscall_info(trace, evsel, e_machine, id); 2742 + if (sc == NULL) 2743 + goto out_put; 2744 2744 ttrace = thread__trace(thread, trace); 2745 2745 if (ttrace == NULL) 2746 2746 goto out_put; ··· 2808 2808 struct thread_trace *ttrace; 2809 2809 struct thread *thread; 2810 2810 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; 2811 - /* TODO: get e_machine from thread. */ 2812 - struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); 2811 + struct syscall *sc; 2813 2812 char msg[1024]; 2814 2813 void *args, *augmented_args = NULL; 2815 - int augmented_args_size; 2814 + int augmented_args_size, e_machine; 2816 2815 size_t printed = 0; 2817 2816 2818 - if (sc == NULL) 2819 - return -1; 2820 2817 2821 2818 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 2819 + e_machine = thread__e_machine(thread, trace->host); 2820 + sc = trace__syscall_info(trace, evsel, e_machine, id); 2821 + if (sc == NULL) 2822 + return -1; 2822 2823 ttrace = thread__trace(thread, trace); 2823 2824 /* 2824 2825 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args() ··· 2884 2883 bool duration_calculated = false; 2885 2884 struct thread *thread; 2886 2885 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0, printed = 0; 2887 - int alignment = trace->args_alignment; 2888 - /* TODO: get e_machine from thread. */ 2889 - struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); 2886 + int alignment = trace->args_alignment, e_machine; 2887 + struct syscall *sc; 2890 2888 struct thread_trace *ttrace; 2891 2889 2892 - if (sc == NULL) 2893 - return -1; 2894 - 2895 2890 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 2891 + e_machine = thread__e_machine(thread, trace->host); 2892 + sc = trace__syscall_info(trace, evsel, e_machine, id); 2893 + if (sc == NULL) 2894 + goto out_put; 2896 2895 ttrace = thread__trace(thread, trace); 2897 2896 if (ttrace == NULL) 2898 2897 goto out_put; ··· 3239 3238 3240 3239 if (evsel == trace->syscalls.events.bpf_output) { 3241 3240 int id = perf_evsel__sc_tp_uint(evsel, id, sample); 3242 - /* TODO: get e_machine from thread. */ 3243 - struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id); 3241 + int e_machine = thread ? thread__e_machine(thread, trace->host) : EM_HOST; 3242 + struct syscall *sc = trace__syscall_info(trace, evsel, e_machine, id); 3244 3243 3245 3244 if (sc) { 3246 3245 fprintf(trace->output, "%s(", sc->name); ··· 4890 4889 { 4891 4890 size_t printed = 0; 4892 4891 struct thread_trace *ttrace = thread__priv(thread); 4892 + int e_machine = thread__e_machine(thread, trace->host); 4893 4893 double ratio; 4894 4894 4895 4895 if (ttrace == NULL) ··· 4910 4908 else if (fputc('\n', fp) != EOF) 4911 4909 ++printed; 4912 4910 4913 - /* TODO: get e_machine from thread. */ 4914 - printed += thread__dump_stats(ttrace, trace, EM_HOST, fp); 4911 + printed += thread__dump_stats(ttrace, trace, e_machine, fp); 4915 4912 4916 4913 return printed; 4917 4914 }
+80
tools/perf/util/thread.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 + #include <elf.h> 2 3 #include <errno.h> 4 + #include <fcntl.h> 3 5 #include <stdlib.h> 4 6 #include <stdio.h> 5 7 #include <string.h> ··· 18 16 #include "symbol.h" 19 17 #include "unwind.h" 20 18 #include "callchain.h" 19 + #include "dwarf-regs.h" 21 20 22 21 #include <api/fs/fs.h> 23 22 ··· 54 51 thread__set_ppid(thread, -1); 55 52 thread__set_cpu(thread, -1); 56 53 thread__set_guest_cpu(thread, -1); 54 + thread__set_e_machine(thread, EM_NONE); 57 55 thread__set_lbr_stitch_enable(thread, false); 58 56 INIT_LIST_HEAD(thread__namespaces_list(thread)); 59 57 INIT_LIST_HEAD(thread__comm_list(thread)); ··· 425 421 if (al->map) 426 422 break; 427 423 } 424 + } 425 + 426 + static uint16_t read_proc_e_machine_for_pid(pid_t pid) 427 + { 428 + char path[6 /* "/proc/" */ + 11 /* max length of pid */ + 5 /* "/exe\0" */]; 429 + int fd; 430 + uint16_t e_machine = EM_NONE; 431 + 432 + snprintf(path, sizeof(path), "/proc/%d/exe", pid); 433 + fd = open(path, O_RDONLY); 434 + if (fd >= 0) { 435 + _Static_assert(offsetof(Elf32_Ehdr, e_machine) == 18, "Unexpected offset"); 436 + _Static_assert(offsetof(Elf64_Ehdr, e_machine) == 18, "Unexpected offset"); 437 + if (pread(fd, &e_machine, sizeof(e_machine), 18) != sizeof(e_machine)) 438 + e_machine = EM_NONE; 439 + close(fd); 440 + } 441 + return e_machine; 442 + } 443 + 444 + static int thread__e_machine_callback(struct map *map, void *machine) 445 + { 446 + struct dso *dso = map__dso(map); 447 + 448 + _Static_assert(0 == EM_NONE, "Unexpected EM_NONE"); 449 + if (!dso) 450 + return EM_NONE; 451 + 452 + return dso__e_machine(dso, machine); 453 + } 454 + 455 + uint16_t thread__e_machine(struct thread *thread, struct machine *machine) 456 + { 457 + pid_t tid, pid; 458 + uint16_t e_machine = RC_CHK_ACCESS(thread)->e_machine; 459 + 460 + if (e_machine != EM_NONE) 461 + return e_machine; 462 + 463 + tid = thread__tid(thread); 464 + pid = thread__pid(thread); 465 + if (pid != tid) { 466 + struct thread *parent = machine__findnew_thread(machine, pid, pid); 467 + 468 + if (parent) { 469 + e_machine = thread__e_machine(parent, machine); 470 + thread__set_e_machine(thread, e_machine); 471 + return e_machine; 472 + } 473 + /* Something went wrong, fallback. */ 474 + } 475 + /* Reading on the PID thread. First try to find from the maps. */ 476 + e_machine = maps__for_each_map(thread__maps(thread), 477 + thread__e_machine_callback, 478 + machine); 479 + if (e_machine == EM_NONE) { 480 + /* Maps failed, perhaps we're live with map events disabled. */ 481 + bool is_live = machine->machines == NULL; 482 + 483 + if (!is_live) { 484 + /* Check if the session has a data file. */ 485 + struct perf_session *session = container_of(machine->machines, 486 + struct perf_session, 487 + machines); 488 + 489 + is_live = !!session->data; 490 + } 491 + /* Read from /proc/pid/exe if live. */ 492 + if (is_live) 493 + e_machine = read_proc_e_machine_for_pid(pid); 494 + } 495 + if (e_machine != EM_NONE) 496 + thread__set_e_machine(thread, e_machine); 497 + else 498 + e_machine = EM_HOST; 499 + return e_machine; 428 500 } 429 501 430 502 struct thread *thread__main_thread(struct machine *machine, struct thread *thread)
+13 -1
tools/perf/util/thread.h
··· 60 60 struct srccode_state srccode_state; 61 61 bool filter; 62 62 int filter_entry_depth; 63 - 63 + /** 64 + * @e_machine: The ELF EM_* associated with the thread. EM_NONE if not 65 + * computed. 66 + */ 67 + uint16_t e_machine; 64 68 /* LBR call stack stitch */ 65 69 bool lbr_stitch_enable; 66 70 struct lbr_stitch *lbr_stitch; ··· 305 301 { 306 302 RC_CHK_ACCESS(thread)->filter_entry_depth = depth; 307 303 } 304 + 305 + uint16_t thread__e_machine(struct thread *thread, struct machine *machine); 306 + 307 + static inline void thread__set_e_machine(struct thread *thread, uint16_t e_machine) 308 + { 309 + RC_CHK_ACCESS(thread)->e_machine = e_machine; 310 + } 311 + 308 312 309 313 static inline bool thread__lbr_stitch_enable(const struct thread *thread) 310 314 {