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

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

- Take tracefs into account when reporting errors about accessing
tracepoint information in tools like 'perf trace' (Arnaldo Carvalho de Melo)

- Let user have timestamps with per-thread recording in 'perf record' (Adrian Hunter)

Infrastructure changes:

- Introduce series of functions to build event filters so that we
can set them in just one ioctl call, useful to set up common_pid,
raw_syscalls:sys_{enter,exit}'s "id" filters to use with
'perf trace' (Arnaldo Carvalho de Melo)

- Delete an unnecessary check before calling strfilter__delete() (Markus Elfring)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>

+224 -81
+13 -2
tools/lib/api/fs/debugfs.c
··· 12 12 #include <linux/kernel.h> 13 13 14 14 #include "debugfs.h" 15 + #include "tracefs.h" 15 16 16 17 #ifndef DEBUGFS_DEFAULT_PATH 17 18 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug" ··· 95 94 "Hint:\tIs the debugfs filesystem mounted?\n" 96 95 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); 97 96 break; 98 - case EACCES: 97 + case EACCES: { 98 + const char *mountpoint = debugfs_mountpoint; 99 + 100 + if (!access(debugfs_mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { 101 + const char *tracefs_mntpoint = tracefs_find_mountpoint(); 102 + 103 + if (tracefs_mntpoint) 104 + mountpoint = tracefs_mntpoint; 105 + } 106 + 99 107 snprintf(buf, size, 100 108 "Error:\tNo permissions to read %s/%s\n" 101 109 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", 102 - debugfs_mountpoint, filename, debugfs_mountpoint); 110 + debugfs_mountpoint, filename, mountpoint); 111 + } 103 112 break; 104 113 default: 105 114 snprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf)));
+1 -2
tools/perf/builtin-probe.c
··· 297 297 clear_perf_probe_event(params.events + i); 298 298 line_range__clear(&params.line_range); 299 299 free(params.target); 300 - if (params.filter) 301 - strfilter__delete(params.filter); 300 + strfilter__delete(params.filter); 302 301 memset(&params, 0, sizeof(params)); 303 302 } 304 303
+3 -1
tools/perf/builtin-record.c
··· 1030 1030 OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, 1031 1031 "per thread counts"), 1032 1032 OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"), 1033 - OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Record the sample timestamps"), 1033 + OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time, 1034 + &record.opts.sample_time_set, 1035 + "Record the sample timestamps"), 1034 1036 OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"), 1035 1037 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, 1036 1038 "don't sample"),
+113 -65
tools/perf/builtin-trace.c
··· 247 247 ({ struct syscall_tp *fields = evsel->priv; \ 248 248 fields->name.pointer(&fields->name, sample); }) 249 249 250 - static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist, 251 - void *sys_enter_handler, 252 - void *sys_exit_handler) 253 - { 254 - int ret = -1; 255 - struct perf_evsel *sys_enter, *sys_exit; 256 - 257 - sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler); 258 - if (sys_enter == NULL) 259 - goto out; 260 - 261 - if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args)) 262 - goto out_delete_sys_enter; 263 - 264 - sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler); 265 - if (sys_exit == NULL) 266 - goto out_delete_sys_enter; 267 - 268 - if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret)) 269 - goto out_delete_sys_exit; 270 - 271 - perf_evlist__add(evlist, sys_enter); 272 - perf_evlist__add(evlist, sys_exit); 273 - 274 - ret = 0; 275 - out: 276 - return ret; 277 - 278 - out_delete_sys_exit: 279 - perf_evsel__delete_priv(sys_exit); 280 - out_delete_sys_enter: 281 - perf_evsel__delete_priv(sys_enter); 282 - goto out; 283 - } 284 - 285 - 286 250 struct syscall_arg { 287 251 unsigned long val; 288 252 struct thread *thread; ··· 1187 1223 int nr_args; 1188 1224 struct format_field *args; 1189 1225 const char *name; 1190 - bool filtered; 1191 1226 bool is_exit; 1192 1227 struct syscall_fmt *fmt; 1193 1228 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg); ··· 1270 1307 struct { 1271 1308 int max; 1272 1309 struct syscall *table; 1310 + struct { 1311 + struct perf_evsel *sys_enter, 1312 + *sys_exit; 1313 + } events; 1273 1314 } syscalls; 1274 1315 struct record_opts opts; 1275 1316 struct perf_evlist *evlist; ··· 1283 1316 FILE *output; 1284 1317 unsigned long nr_events; 1285 1318 struct strlist *ev_qualifier; 1319 + struct { 1320 + size_t nr; 1321 + int *entries; 1322 + } ev_qualifier_ids; 1286 1323 const char *last_vfs_getname; 1287 1324 struct intlist *tid_list; 1288 1325 struct intlist *pid_list; ··· 1549 1578 sc = trace->syscalls.table + id; 1550 1579 sc->name = name; 1551 1580 1552 - if (trace->ev_qualifier) { 1553 - bool in = strlist__find(trace->ev_qualifier, name) != NULL; 1554 - 1555 - if (!(in ^ trace->not_ev_qualifier)) { 1556 - sc->filtered = true; 1557 - /* 1558 - * No need to do read tracepoint information since this will be 1559 - * filtered out. 1560 - */ 1561 - return 0; 1562 - } 1563 - } 1564 - 1565 1581 sc->fmt = syscall_fmt__find(sc->name); 1566 1582 1567 1583 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); ··· 1577 1619 1578 1620 static int trace__validate_ev_qualifier(struct trace *trace) 1579 1621 { 1580 - int err = 0; 1622 + int err = 0, i; 1581 1623 struct str_node *pos; 1624 + 1625 + trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier); 1626 + trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr * 1627 + sizeof(trace->ev_qualifier_ids.entries[0])); 1628 + 1629 + if (trace->ev_qualifier_ids.entries == NULL) { 1630 + fputs("Error:\tNot enough memory for allocating events qualifier ids\n", 1631 + trace->output); 1632 + err = -EINVAL; 1633 + goto out; 1634 + } 1635 + 1636 + i = 0; 1582 1637 1583 1638 strlist__for_each(pos, trace->ev_qualifier) { 1584 1639 const char *sc = pos->s; 1640 + int id = audit_name_to_syscall(sc, trace->audit.machine); 1585 1641 1586 - if (audit_name_to_syscall(sc, trace->audit.machine) < 0) { 1642 + if (id < 0) { 1587 1643 if (err == 0) { 1588 1644 fputs("Error:\tInvalid syscall ", trace->output); 1589 1645 err = -EINVAL; ··· 1607 1635 1608 1636 fputs(sc, trace->output); 1609 1637 } 1638 + 1639 + trace->ev_qualifier_ids.entries[i++] = id; 1610 1640 } 1611 1641 1612 1642 if (err < 0) { 1613 1643 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'" 1614 1644 "\nHint:\tand: 'man syscalls'\n", trace->output); 1645 + zfree(&trace->ev_qualifier_ids.entries); 1646 + trace->ev_qualifier_ids.nr = 0; 1615 1647 } 1616 - 1648 + out: 1617 1649 return err; 1618 1650 } 1619 1651 ··· 1809 1833 if (sc == NULL) 1810 1834 return -1; 1811 1835 1812 - if (sc->filtered) 1813 - return 0; 1814 - 1815 1836 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 1816 1837 ttrace = thread__trace(thread, trace->output); 1817 1838 if (ttrace == NULL) ··· 1863 1890 1864 1891 if (sc == NULL) 1865 1892 return -1; 1866 - 1867 - if (sc->filtered) 1868 - return 0; 1869 1893 1870 1894 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 1871 1895 ttrace = thread__trace(thread, trace->output); ··· 2253 2283 } 2254 2284 } 2255 2285 2286 + static int trace__add_syscall_newtp(struct trace *trace) 2287 + { 2288 + int ret = -1; 2289 + struct perf_evlist *evlist = trace->evlist; 2290 + struct perf_evsel *sys_enter, *sys_exit; 2291 + 2292 + sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter); 2293 + if (sys_enter == NULL) 2294 + goto out; 2295 + 2296 + if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args)) 2297 + goto out_delete_sys_enter; 2298 + 2299 + sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit); 2300 + if (sys_exit == NULL) 2301 + goto out_delete_sys_enter; 2302 + 2303 + if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret)) 2304 + goto out_delete_sys_exit; 2305 + 2306 + perf_evlist__add(evlist, sys_enter); 2307 + perf_evlist__add(evlist, sys_exit); 2308 + 2309 + trace->syscalls.events.sys_enter = sys_enter; 2310 + trace->syscalls.events.sys_exit = sys_exit; 2311 + 2312 + ret = 0; 2313 + out: 2314 + return ret; 2315 + 2316 + out_delete_sys_exit: 2317 + perf_evsel__delete_priv(sys_exit); 2318 + out_delete_sys_enter: 2319 + perf_evsel__delete_priv(sys_enter); 2320 + goto out; 2321 + } 2322 + 2323 + static int trace__set_ev_qualifier_filter(struct trace *trace) 2324 + { 2325 + int err = -1; 2326 + char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier, 2327 + trace->ev_qualifier_ids.nr, 2328 + trace->ev_qualifier_ids.entries); 2329 + 2330 + if (filter == NULL) 2331 + goto out_enomem; 2332 + 2333 + if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter)) 2334 + err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter); 2335 + 2336 + free(filter); 2337 + out: 2338 + return err; 2339 + out_enomem: 2340 + errno = ENOMEM; 2341 + goto out; 2342 + } 2343 + 2256 2344 static int trace__run(struct trace *trace, int argc, const char **argv) 2257 2345 { 2258 2346 struct perf_evlist *evlist = trace->evlist; 2347 + struct perf_evsel *evsel; 2259 2348 int err = -1, i; 2260 2349 unsigned long before; 2261 2350 const bool forks = argc > 0; ··· 2322 2293 2323 2294 trace->live = true; 2324 2295 2325 - if (trace->trace_syscalls && 2326 - perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, 2327 - trace__sys_exit)) 2296 + if (trace->trace_syscalls && trace__add_syscall_newtp(trace)) 2328 2297 goto out_error_raw_syscalls; 2329 2298 2330 2299 if (trace->trace_syscalls) ··· 2383 2356 else if (thread_map__pid(evlist->threads, 0) == -1) 2384 2357 err = perf_evlist__set_filter_pid(evlist, getpid()); 2385 2358 2386 - if (err < 0) { 2387 - printf("err=%d,%s\n", -err, strerror(-err)); 2388 - exit(1); 2359 + if (err < 0) 2360 + goto out_error_mem; 2361 + 2362 + if (trace->ev_qualifier_ids.nr > 0) { 2363 + err = trace__set_ev_qualifier_filter(trace); 2364 + if (err < 0) 2365 + goto out_errno; 2389 2366 } 2367 + 2368 + pr_debug("%s\n", trace->syscalls.events.sys_exit->filter); 2369 + 2370 + err = perf_evlist__apply_filters(evlist, &evsel); 2371 + if (err < 0) 2372 + goto out_error_apply_filters; 2390 2373 2391 2374 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); 2392 2375 if (err < 0) ··· 2499 2462 out_error: 2500 2463 fprintf(trace->output, "%s\n", errbuf); 2501 2464 goto out_delete_evlist; 2465 + 2466 + out_error_apply_filters: 2467 + fprintf(trace->output, 2468 + "Failed to set filter \"%s\" on event %s with %d (%s)\n", 2469 + evsel->filter, perf_evsel__name(evsel), errno, 2470 + strerror_r(errno, errbuf, sizeof(errbuf))); 2471 + goto out_delete_evlist; 2502 2472 } 2503 2473 out_error_mem: 2504 2474 fprintf(trace->output, "Not enough memory to run!\n"); 2475 + goto out_delete_evlist; 2476 + 2477 + out_errno: 2478 + fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno)); 2505 2479 goto out_delete_evlist; 2506 2480 } 2507 2481
+1
tools/perf/perf.h
··· 51 51 bool sample_address; 52 52 bool sample_weight; 53 53 bool sample_time; 54 + bool sample_time_set; 54 55 bool period; 55 56 bool sample_intr_regs; 56 57 bool running_time;
+2 -4
tools/perf/util/evlist.c
··· 1161 1161 if (evsel->filter == NULL) 1162 1162 continue; 1163 1163 1164 - err = perf_evsel__set_filter(evsel, ncpus, nthreads, evsel->filter); 1164 + err = perf_evsel__apply_filter(evsel, ncpus, nthreads, evsel->filter); 1165 1165 if (err) { 1166 1166 *err_evsel = evsel; 1167 1167 break; ··· 1175 1175 { 1176 1176 struct perf_evsel *evsel; 1177 1177 int err = 0; 1178 - const int ncpus = cpu_map__nr(evlist->cpus), 1179 - nthreads = thread_map__nr(evlist->threads); 1180 1178 1181 1179 evlist__for_each(evlist, evsel) { 1182 - err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); 1180 + err = perf_evsel__set_filter(evsel, filter); 1183 1181 if (err) 1184 1182 break; 1185 1183 }
+34 -3
tools/perf/util/evsel.c
··· 707 707 */ 708 708 if (opts->sample_time && 709 709 (!perf_missing_features.sample_id_all && 710 - (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu))) 710 + (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu || 711 + opts->sample_time_set))) 711 712 perf_evsel__set_sample_bit(evsel, TIME); 712 713 713 714 if (opts->raw_samples && !evsel->no_aux_samples) { ··· 816 815 return 0; 817 816 } 818 817 819 - int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 820 - const char *filter) 818 + int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 819 + const char *filter) 821 820 { 822 821 return perf_evsel__run_ioctl(evsel, ncpus, nthreads, 823 822 PERF_EVENT_IOC_SET_FILTER, 824 823 (void *)filter); 824 + } 825 + 826 + int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter) 827 + { 828 + char *new_filter = strdup(filter); 829 + 830 + if (new_filter != NULL) { 831 + free(evsel->filter); 832 + evsel->filter = new_filter; 833 + return 0; 834 + } 835 + 836 + return -1; 837 + } 838 + 839 + int perf_evsel__append_filter(struct perf_evsel *evsel, 840 + const char *op, const char *filter) 841 + { 842 + char *new_filter; 843 + 844 + if (evsel->filter == NULL) 845 + return perf_evsel__set_filter(evsel, filter); 846 + 847 + if (asprintf(&new_filter,"(%s) %s (%s)", evsel->filter, op, filter) > 0) { 848 + free(evsel->filter); 849 + evsel->filter = new_filter; 850 + return 0; 851 + } 852 + 853 + return -1; 825 854 } 826 855 827 856 int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
+5 -2
tools/perf/util/evsel.h
··· 182 182 void perf_evsel__set_sample_id(struct perf_evsel *evsel, 183 183 bool use_sample_identifier); 184 184 185 - int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 186 - const char *filter); 185 + int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter); 186 + int perf_evsel__append_filter(struct perf_evsel *evsel, 187 + const char *op, const char *filter); 188 + int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 189 + const char *filter); 187 190 int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads); 188 191 189 192 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
+1 -2
tools/perf/util/parse-events.c
··· 1177 1177 return -1; 1178 1178 } 1179 1179 1180 - last->filter = strdup(str); 1181 - if (last->filter == NULL) { 1180 + if (perf_evsel__set_filter(last, str) < 0) { 1182 1181 fprintf(stderr, "not enough memory to hold filter string\n"); 1183 1182 return -1; 1184 1183 }
+39
tools/perf/util/string.c
··· 357 357 358 358 return p; 359 359 } 360 + 361 + char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints) 362 + { 363 + /* 364 + * FIXME: replace this with an expression using log10() when we 365 + * find a suitable implementation, maybe the one in the dvb drivers... 366 + * 367 + * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators 368 + */ 369 + size_t size = nints * 28 + 1; /* \0 */ 370 + size_t i, printed = 0; 371 + char *expr = malloc(size); 372 + 373 + if (expr) { 374 + const char *or_and = "||", *eq_neq = "=="; 375 + char *e = expr; 376 + 377 + if (!in) { 378 + or_and = "&&"; 379 + eq_neq = "!="; 380 + } 381 + 382 + for (i = 0; i < nints; ++i) { 383 + if (printed == size) 384 + goto out_err_overflow; 385 + 386 + if (i > 0) 387 + printed += snprintf(e + printed, size - printed, " %s ", or_and); 388 + printed += scnprintf(e + printed, size - printed, 389 + "%s %s %d", var, eq_neq, ints[i]); 390 + } 391 + } 392 + 393 + return expr; 394 + 395 + out_err_overflow: 396 + free(expr); 397 + return NULL; 398 + }
+12
tools/perf/util/util.h
··· 339 339 int lzma_decompress_to_file(const char *input, int output_fd); 340 340 #endif 341 341 342 + char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints); 343 + 344 + static inline char *asprintf_expr_in_ints(const char *var, size_t nints, int *ints) 345 + { 346 + return asprintf_expr_inout_ints(var, true, nints, ints); 347 + } 348 + 349 + static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int *ints) 350 + { 351 + return asprintf_expr_inout_ints(var, false, nints, ints); 352 + } 353 + 342 354 #endif /* GIT_COMPAT_UTIL_H */