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

perf probe: Support SDT markers having reference counter (semaphore)

With this, perf buildid-cache will save SDT markers with reference
counter in probe cache. Perf probe will be able to probe markers
having reference counter. Ex,

# readelf -n /tmp/tick | grep -A1 loop2
Name: loop2
... Semaphore: 0x0000000010020036

# ./perf buildid-cache --add /tmp/tick
# ./perf probe sdt_tick:loop2
# ./perf stat -e sdt_tick:loop2 /tmp/tick
hi: 0
hi: 1
hi: 2
^C
Performance counter stats for '/tmp/tick':
3 sdt_tick:loop2
2.561851452 seconds time elapsed

Link: http://lkml.kernel.org/r/20180820044250.11659-5-ravi.bangoria@linux.ibm.com

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Reviewed-by: Song Liu <songliubraving@fb.com>
Tested-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>

authored by

Ravi Bangoria and committed by
Steven Rostedt (VMware)
5a5e3d3c ccea8727

+106 -22
+35 -4
tools/perf/util/probe-event.c
··· 1819 1819 tp->offset = strtoul(fmt2_str, NULL, 10); 1820 1820 } 1821 1821 1822 + if (tev->uprobes) { 1823 + fmt2_str = strchr(p, '('); 1824 + if (fmt2_str) 1825 + tp->ref_ctr_offset = strtoul(fmt2_str + 1, NULL, 0); 1826 + } 1827 + 1822 1828 tev->nargs = argc - 2; 1823 1829 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1824 1830 if (tev->args == NULL) { ··· 2018 2012 return err; 2019 2013 } 2020 2014 2015 + static int 2016 + synthesize_uprobe_trace_def(struct probe_trace_event *tev, struct strbuf *buf) 2017 + { 2018 + struct probe_trace_point *tp = &tev->point; 2019 + int err; 2020 + 2021 + err = strbuf_addf(buf, "%s:0x%lx", tp->module, tp->address); 2022 + 2023 + if (err >= 0 && tp->ref_ctr_offset) { 2024 + if (!uprobe_ref_ctr_is_supported()) 2025 + return -1; 2026 + err = strbuf_addf(buf, "(0x%lx)", tp->ref_ctr_offset); 2027 + } 2028 + return err >= 0 ? 0 : -1; 2029 + } 2030 + 2021 2031 char *synthesize_probe_trace_command(struct probe_trace_event *tev) 2022 2032 { 2023 2033 struct probe_trace_point *tp = &tev->point; ··· 2063 2041 } 2064 2042 2065 2043 /* Use the tp->address for uprobes */ 2066 - if (tev->uprobes) 2067 - err = strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address); 2068 - else if (!strncmp(tp->symbol, "0x", 2)) 2044 + if (tev->uprobes) { 2045 + err = synthesize_uprobe_trace_def(tev, &buf); 2046 + } else if (!strncmp(tp->symbol, "0x", 2)) { 2069 2047 /* Absolute address. See try_to_find_absolute_address() */ 2070 2048 err = strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "", 2071 2049 tp->module ? ":" : "", tp->address); 2072 - else 2050 + } else { 2073 2051 err = strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "", 2074 2052 tp->module ? ":" : "", tp->symbol, tp->offset); 2053 + } 2054 + 2075 2055 if (err) 2076 2056 goto error; 2077 2057 ··· 2657 2633 { 2658 2634 int i; 2659 2635 char *buf = synthesize_probe_trace_command(tev); 2636 + struct probe_trace_point *tp = &tev->point; 2637 + 2638 + if (tp->ref_ctr_offset && !uprobe_ref_ctr_is_supported()) { 2639 + pr_warning("A semaphore is associated with %s:%s and " 2640 + "seems your kernel doesn't support it.\n", 2641 + tev->group, tev->event); 2642 + } 2660 2643 2661 2644 /* Old uprobe event doesn't support memory dereference */ 2662 2645 if (!tev->uprobes || tev->nargs == 0 || !buf)
+1
tools/perf/util/probe-event.h
··· 27 27 char *symbol; /* Base symbol */ 28 28 char *module; /* Module name */ 29 29 unsigned long offset; /* Offset from symbol */ 30 + unsigned long ref_ctr_offset; /* SDT reference counter offset */ 30 31 unsigned long address; /* Actual address of the trace point */ 31 32 bool retprobe; /* Return probe flag */ 32 33 };
+28 -6
tools/perf/util/probe-file.c
··· 696 696 #ifdef HAVE_GELF_GETNOTE_SUPPORT 697 697 static unsigned long long sdt_note__get_addr(struct sdt_note *note) 698 698 { 699 - return note->bit32 ? (unsigned long long)note->addr.a32[0] 700 - : (unsigned long long)note->addr.a64[0]; 699 + return note->bit32 ? 700 + (unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] : 701 + (unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC]; 702 + } 703 + 704 + static unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note) 705 + { 706 + return note->bit32 ? 707 + (unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] : 708 + (unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR]; 701 709 } 702 710 703 711 static const char * const type_to_suffix[] = { ··· 783 775 { 784 776 struct strbuf buf; 785 777 char *ret = NULL, **args; 786 - int i, args_count; 778 + int i, args_count, err; 779 + unsigned long long ref_ctr_offset; 787 780 788 781 if (strbuf_init(&buf, 32) < 0) 789 782 return NULL; 790 783 791 - if (strbuf_addf(&buf, "p:%s/%s %s:0x%llx", 792 - sdtgrp, note->name, pathname, 793 - sdt_note__get_addr(note)) < 0) 784 + err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx", 785 + sdtgrp, note->name, pathname, 786 + sdt_note__get_addr(note)); 787 + 788 + ref_ctr_offset = sdt_note__get_ref_ctr_offset(note); 789 + if (ref_ctr_offset && err >= 0) 790 + err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset); 791 + 792 + if (err < 0) 794 793 goto error; 795 794 796 795 if (!note->args) ··· 1013 998 enum ftrace_readme { 1014 999 FTRACE_README_PROBE_TYPE_X = 0, 1015 1000 FTRACE_README_KRETPROBE_OFFSET, 1001 + FTRACE_README_UPROBE_REF_CTR, 1016 1002 FTRACE_README_END, 1017 1003 }; 1018 1004 ··· 1025 1009 [idx] = {.pattern = pat, .avail = false} 1026 1010 DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"), 1027 1011 DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"), 1012 + DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"), 1028 1013 }; 1029 1014 1030 1015 static bool scan_ftrace_readme(enum ftrace_readme type) ··· 1080 1063 bool kretprobe_offset_is_supported(void) 1081 1064 { 1082 1065 return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET); 1066 + } 1067 + 1068 + bool uprobe_ref_ctr_is_supported(void) 1069 + { 1070 + return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR); 1083 1071 }
+1
tools/perf/util/probe-file.h
··· 69 69 int probe_cache__show_all_caches(struct strfilter *filter); 70 70 bool probe_type_is_available(enum probe_type type); 71 71 bool kretprobe_offset_is_supported(void); 72 + bool uprobe_ref_ctr_is_supported(void); 72 73 #else /* ! HAVE_LIBELF_SUPPORT */ 73 74 static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused, struct nsinfo *nsi __maybe_unused) 74 75 {
+34 -12
tools/perf/util/symbol-elf.c
··· 1947 1947 } 1948 1948 1949 1949 #ifdef HAVE_GELF_GETNOTE_SUPPORT 1950 + 1951 + static void sdt_adjust_loc(struct sdt_note *tmp, GElf_Addr base_off) 1952 + { 1953 + if (!base_off) 1954 + return; 1955 + 1956 + if (tmp->bit32) 1957 + tmp->addr.a32[SDT_NOTE_IDX_LOC] = 1958 + tmp->addr.a32[SDT_NOTE_IDX_LOC] + base_off - 1959 + tmp->addr.a32[SDT_NOTE_IDX_BASE]; 1960 + else 1961 + tmp->addr.a64[SDT_NOTE_IDX_LOC] = 1962 + tmp->addr.a64[SDT_NOTE_IDX_LOC] + base_off - 1963 + tmp->addr.a64[SDT_NOTE_IDX_BASE]; 1964 + } 1965 + 1966 + static void sdt_adjust_refctr(struct sdt_note *tmp, GElf_Addr base_addr, 1967 + GElf_Addr base_off) 1968 + { 1969 + if (!base_off) 1970 + return; 1971 + 1972 + if (tmp->bit32 && tmp->addr.a32[SDT_NOTE_IDX_REFCTR]) 1973 + tmp->addr.a32[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off); 1974 + else if (tmp->addr.a64[SDT_NOTE_IDX_REFCTR]) 1975 + tmp->addr.a64[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off); 1976 + } 1977 + 1950 1978 /** 1951 1979 * populate_sdt_note : Parse raw data and identify SDT note 1952 1980 * @elf: elf of the opened file ··· 1992 1964 const char *provider, *name, *args; 1993 1965 struct sdt_note *tmp = NULL; 1994 1966 GElf_Ehdr ehdr; 1995 - GElf_Addr base_off = 0; 1996 1967 GElf_Shdr shdr; 1997 1968 int ret = -EINVAL; 1998 1969 ··· 2087 2060 * base address in the description of the SDT note. If its different, 2088 2061 * then accordingly, adjust the note location. 2089 2062 */ 2090 - if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) { 2091 - base_off = shdr.sh_offset; 2092 - if (base_off) { 2093 - if (tmp->bit32) 2094 - tmp->addr.a32[0] = tmp->addr.a32[0] + base_off - 2095 - tmp->addr.a32[1]; 2096 - else 2097 - tmp->addr.a64[0] = tmp->addr.a64[0] + base_off - 2098 - tmp->addr.a64[1]; 2099 - } 2100 - } 2063 + if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) 2064 + sdt_adjust_loc(tmp, shdr.sh_offset); 2065 + 2066 + /* Adjust reference counter offset */ 2067 + if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_PROBES_SCN, NULL)) 2068 + sdt_adjust_refctr(tmp, shdr.sh_addr, shdr.sh_offset); 2101 2069 2102 2070 list_add_tail(&tmp->note_list, sdt_notes); 2103 2071 return 0;
+7
tools/perf/util/symbol.h
··· 379 379 int cleanup_sdt_note_list(struct list_head *sdt_notes); 380 380 int sdt_notes__get_count(struct list_head *start); 381 381 382 + #define SDT_PROBES_SCN ".probes" 382 383 #define SDT_BASE_SCN ".stapsdt.base" 383 384 #define SDT_NOTE_SCN ".note.stapsdt" 384 385 #define SDT_NOTE_TYPE 3 385 386 #define SDT_NOTE_NAME "stapsdt" 386 387 #define NR_ADDR 3 388 + 389 + enum { 390 + SDT_NOTE_IDX_LOC = 0, 391 + SDT_NOTE_IDX_BASE, 392 + SDT_NOTE_IDX_REFCTR, 393 + }; 387 394 388 395 struct mem_info *mem_info__new(void); 389 396 struct mem_info *mem_info__get(struct mem_info *mi);