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

perf probe: Allow wildcard for cached events

Allo glob wildcard for reusing cached/SDT events. E.g.

# perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\*

This example adds probes for all SDT in libc.
Note that the SDTs must have been scanned by perf buildid-cache.

Committer note:

Using it to check what of those SDT probes would take place when doing
a cargo run (rust):

# trace --no-sys --event sdt_libc:* cargo run
0.000 sdt_libc:setjmp:(7f326b69c4d1))
28.423 sdt_libc:setjmp:(7f4b0a5364d1))
29.000 sdt_libc:setjmp:(7f4b0a5364d1))
88.597 sdt_libc:setjmp:(7fc01fd414d1))
89.220 sdt_libc:setjmp:(7fc01fd414d1))
95.501 sdt_libc:setjmp:(7f326b69c4d1))
Running `target/debug/hello_world`
97.110 sdt_libc:setjmp:(7f95e09234d1))
Hello, world!
#

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/146831791813.17065.17846564230840594888.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Masami Hiramatsu and committed by
Arnaldo Carvalho de Melo
42bba263 05bf2c8a

+138 -10
+103 -4
tools/perf/util/probe-event.c
··· 1204 1204 ptr = strchr(*arg, ':'); 1205 1205 if (ptr) { 1206 1206 *ptr = '\0'; 1207 - if (!is_c_func_name(*arg)) 1207 + if (!pev->sdt && !is_c_func_name(*arg)) 1208 1208 goto ng_name; 1209 1209 pev->group = strdup(*arg); 1210 1210 if (!pev->group) ··· 1212 1212 *arg = ptr + 1; 1213 1213 } else 1214 1214 pev->group = NULL; 1215 - if (!is_c_func_name(*arg)) { 1215 + if (!pev->sdt && !is_c_func_name(*arg)) { 1216 1216 ng_name: 1217 1217 semantic_error("%s is bad for event name -it must " 1218 1218 "follow C symbol-naming rule.\n", *arg); ··· 1644 1644 ret = -ENOMEM; 1645 1645 goto out; 1646 1646 } 1647 + tev->uprobes = (tp->module[0] == '/'); 1647 1648 p++; 1648 1649 } else 1649 1650 p = argv[1]; ··· 2519 2518 int ret; 2520 2519 2521 2520 /* If probe_event or trace_event already have the name, reuse it */ 2522 - if (pev->event) 2521 + if (pev->event && !pev->sdt) 2523 2522 event = pev->event; 2524 2523 else if (tev->event) 2525 2524 event = tev->event; ··· 2532 2531 else 2533 2532 event = tev->point.realname; 2534 2533 } 2535 - if (pev->group) 2534 + if (pev->group && !pev->sdt) 2536 2535 group = pev->group; 2537 2536 else if (tev->group) 2538 2537 group = tev->group; ··· 2895 2894 2896 2895 bool __weak arch__prefers_symtab(void) { return false; } 2897 2896 2897 + /* Concatinate two arrays */ 2898 + static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b) 2899 + { 2900 + void *ret; 2901 + 2902 + ret = malloc(sz_a + sz_b); 2903 + if (ret) { 2904 + memcpy(ret, a, sz_a); 2905 + memcpy(ret + sz_a, b, sz_b); 2906 + } 2907 + return ret; 2908 + } 2909 + 2910 + static int 2911 + concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs, 2912 + struct probe_trace_event **tevs2, int ntevs2) 2913 + { 2914 + struct probe_trace_event *new_tevs; 2915 + int ret = 0; 2916 + 2917 + if (ntevs == 0) { 2918 + *tevs = *tevs2; 2919 + *ntevs = ntevs2; 2920 + *tevs2 = NULL; 2921 + return 0; 2922 + } 2923 + 2924 + if (*ntevs + ntevs2 > probe_conf.max_probes) 2925 + ret = -E2BIG; 2926 + else { 2927 + /* Concatinate the array of probe_trace_event */ 2928 + new_tevs = memcat(*tevs, (*ntevs) * sizeof(**tevs), 2929 + *tevs2, ntevs2 * sizeof(**tevs2)); 2930 + if (!new_tevs) 2931 + ret = -ENOMEM; 2932 + else { 2933 + free(*tevs); 2934 + *tevs = new_tevs; 2935 + *ntevs += ntevs2; 2936 + } 2937 + } 2938 + if (ret < 0) 2939 + clear_probe_trace_events(*tevs2, ntevs2); 2940 + zfree(tevs2); 2941 + 2942 + return ret; 2943 + } 2944 + 2945 + /* 2946 + * Try to find probe_trace_event from given probe caches. Return the number 2947 + * of cached events found, if an error occurs return the error. 2948 + */ 2949 + static int find_cached_events(struct perf_probe_event *pev, 2950 + struct probe_trace_event **tevs, 2951 + const char *target) 2952 + { 2953 + struct probe_cache *cache; 2954 + struct probe_cache_entry *entry; 2955 + struct probe_trace_event *tmp_tevs = NULL; 2956 + int ntevs = 0; 2957 + int ret = 0; 2958 + 2959 + cache = probe_cache__new(target); 2960 + /* Return 0 ("not found") if the target has no probe cache. */ 2961 + if (!cache) 2962 + return 0; 2963 + 2964 + for_each_probe_cache_entry(entry, cache) { 2965 + /* Skip the cache entry which has no name */ 2966 + if (!entry->pev.event || !entry->pev.group) 2967 + continue; 2968 + if ((!pev->group || strglobmatch(entry->pev.group, pev->group)) && 2969 + strglobmatch(entry->pev.event, pev->event)) { 2970 + ret = probe_cache_entry__get_event(entry, &tmp_tevs); 2971 + if (ret > 0) 2972 + ret = concat_probe_trace_events(tevs, &ntevs, 2973 + &tmp_tevs, ret); 2974 + if (ret < 0) 2975 + break; 2976 + } 2977 + } 2978 + probe_cache__delete(cache); 2979 + if (ret < 0) { 2980 + clear_probe_trace_events(*tevs, ntevs); 2981 + zfree(tevs); 2982 + } else { 2983 + ret = ntevs; 2984 + if (ntevs > 0 && target && target[0] == '/') 2985 + pev->uprobes = true; 2986 + } 2987 + 2988 + return ret; 2989 + } 2990 + 2898 2991 static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, 2899 2992 struct probe_trace_event **tevs) 2900 2993 { ··· 2997 2902 struct probe_trace_event *tev; 2998 2903 struct str_node *node; 2999 2904 int ret, i; 2905 + 2906 + if (pev->sdt) 2907 + /* For SDT/cached events, we use special search functions */ 2908 + return find_cached_events(pev, tevs, pev->target); 3000 2909 3001 2910 cache = probe_cache__new(pev->target); 3002 2911 if (!cache)
+32 -6
tools/perf/util/probe-file.c
··· 362 362 return entry; 363 363 } 364 364 365 - /* For the kernel probe caches, pass target = NULL */ 365 + int probe_cache_entry__get_event(struct probe_cache_entry *entry, 366 + struct probe_trace_event **tevs) 367 + { 368 + struct probe_trace_event *tev; 369 + struct str_node *node; 370 + int ret, i; 371 + 372 + ret = strlist__nr_entries(entry->tevlist); 373 + if (ret > probe_conf.max_probes) 374 + return -E2BIG; 375 + 376 + *tevs = zalloc(ret * sizeof(*tev)); 377 + if (!*tevs) 378 + return -ENOMEM; 379 + 380 + i = 0; 381 + strlist__for_each_entry(node, entry->tevlist) { 382 + tev = &(*tevs)[i++]; 383 + ret = parse_probe_trace_command(node->s, tev); 384 + if (ret < 0) 385 + break; 386 + } 387 + return i; 388 + } 389 + 390 + /* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */ 366 391 static int probe_cache__open(struct probe_cache *pcache, const char *target) 367 392 { 368 393 char cpath[PATH_MAX]; 369 394 char sbuildid[SBUILD_ID_SIZE]; 370 395 char *dir_name = NULL; 371 - bool is_kallsyms = !target; 396 + bool is_kallsyms = false; 372 397 int ret, fd; 373 398 374 399 if (target && build_id_cache__cached(target)) { ··· 403 378 goto found; 404 379 } 405 380 406 - if (target) 407 - ret = filename__sprintf_build_id(target, sbuildid); 408 - else { 381 + if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) { 409 382 target = DSO__NAME_KALLSYMS; 383 + is_kallsyms = true; 410 384 ret = sysfs__sprintf_build_id("/", sbuildid); 411 - } 385 + } else 386 + ret = filename__sprintf_build_id(target, sbuildid); 387 + 412 388 if (ret < 0) { 413 389 pr_debug("Failed to get build-id from %s.\n", target); 414 390 return ret;
+3
tools/perf/util/probe-file.h
··· 34 34 struct strlist *plist); 35 35 int probe_file__del_strlist(int fd, struct strlist *namelist); 36 36 37 + int probe_cache_entry__get_event(struct probe_cache_entry *entry, 38 + struct probe_trace_event **tevs); 39 + 37 40 struct probe_cache *probe_cache__new(const char *target); 38 41 int probe_cache__add_entry(struct probe_cache *pcache, 39 42 struct perf_probe_event *pev,