diff options
31 files changed, 231 insertions, 132 deletions
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 6a1146ea4d4d..4e3d5a9621fe 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c | |||
@@ -223,27 +223,48 @@ static unsigned long | |||
223 | __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr) | 223 | __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr) |
224 | { | 224 | { |
225 | struct kprobe *kp; | 225 | struct kprobe *kp; |
226 | unsigned long faddr; | ||
226 | 227 | ||
227 | kp = get_kprobe((void *)addr); | 228 | kp = get_kprobe((void *)addr); |
228 | /* There is no probe, return original address */ | 229 | faddr = ftrace_location(addr); |
229 | if (!kp) | 230 | /* |
231 | * Addresses inside the ftrace location are refused by | ||
232 | * arch_check_ftrace_location(). Something went terribly wrong | ||
233 | * if such an address is checked here. | ||
234 | */ | ||
235 | if (WARN_ON(faddr && faddr != addr)) | ||
236 | return 0UL; | ||
237 | /* | ||
238 | * Use the current code if it is not modified by Kprobe | ||
239 | * and it cannot be modified by ftrace. | ||
240 | */ | ||
241 | if (!kp && !faddr) | ||
230 | return addr; | 242 | return addr; |
231 | 243 | ||
232 | /* | 244 | /* |
233 | * Basically, kp->ainsn.insn has an original instruction. | 245 | * Basically, kp->ainsn.insn has an original instruction. |
234 | * However, RIP-relative instruction can not do single-stepping | 246 | * However, RIP-relative instruction can not do single-stepping |
235 | * at different place, __copy_instruction() tweaks the displacement of | 247 | * at different place, __copy_instruction() tweaks the displacement of |
236 | * that instruction. In that case, we can't recover the instruction | 248 | * that instruction. In that case, we can't recover the instruction |
237 | * from the kp->ainsn.insn. | 249 | * from the kp->ainsn.insn. |
238 | * | 250 | * |
239 | * On the other hand, kp->opcode has a copy of the first byte of | 251 | * On the other hand, in case on normal Kprobe, kp->opcode has a copy |
240 | * the probed instruction, which is overwritten by int3. And | 252 | * of the first byte of the probed instruction, which is overwritten |
241 | * the instruction at kp->addr is not modified by kprobes except | 253 | * by int3. And the instruction at kp->addr is not modified by kprobes |
242 | * for the first byte, we can recover the original instruction | 254 | * except for the first byte, we can recover the original instruction |
243 | * from it and kp->opcode. | 255 | * from it and kp->opcode. |
256 | * | ||
257 | * In case of Kprobes using ftrace, we do not have a copy of | ||
258 | * the original instruction. In fact, the ftrace location might | ||
259 | * be modified at anytime and even could be in an inconsistent state. | ||
260 | * Fortunately, we know that the original code is the ideal 5-byte | ||
261 | * long NOP. | ||
244 | */ | 262 | */ |
245 | memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); | 263 | memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); |
246 | buf[0] = kp->opcode; | 264 | if (faddr) |
265 | memcpy(buf, ideal_nops[NOP_ATOMIC5], 5); | ||
266 | else | ||
267 | buf[0] = kp->opcode; | ||
247 | return (unsigned long)buf; | 268 | return (unsigned long)buf; |
248 | } | 269 | } |
249 | 270 | ||
@@ -251,6 +272,7 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr) | |||
251 | * Recover the probed instruction at addr for further analysis. | 272 | * Recover the probed instruction at addr for further analysis. |
252 | * Caller must lock kprobes by kprobe_mutex, or disable preemption | 273 | * Caller must lock kprobes by kprobe_mutex, or disable preemption |
253 | * for preventing to release referencing kprobes. | 274 | * for preventing to release referencing kprobes. |
275 | * Returns zero if the instruction can not get recovered. | ||
254 | */ | 276 | */ |
255 | unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr) | 277 | unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr) |
256 | { | 278 | { |
@@ -285,6 +307,8 @@ static int can_probe(unsigned long paddr) | |||
285 | * normally used, we just go through if there is no kprobe. | 307 | * normally used, we just go through if there is no kprobe. |
286 | */ | 308 | */ |
287 | __addr = recover_probed_instruction(buf, addr); | 309 | __addr = recover_probed_instruction(buf, addr); |
310 | if (!__addr) | ||
311 | return 0; | ||
288 | kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE); | 312 | kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE); |
289 | insn_get_length(&insn); | 313 | insn_get_length(&insn); |
290 | 314 | ||
@@ -333,6 +357,8 @@ int __copy_instruction(u8 *dest, u8 *src) | |||
333 | unsigned long recovered_insn = | 357 | unsigned long recovered_insn = |
334 | recover_probed_instruction(buf, (unsigned long)src); | 358 | recover_probed_instruction(buf, (unsigned long)src); |
335 | 359 | ||
360 | if (!recovered_insn) | ||
361 | return 0; | ||
336 | kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE); | 362 | kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE); |
337 | insn_get_length(&insn); | 363 | insn_get_length(&insn); |
338 | /* Another subsystem puts a breakpoint, failed to recover */ | 364 | /* Another subsystem puts a breakpoint, failed to recover */ |
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 0dd8d089c315..7b3b9d15c47a 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c | |||
@@ -259,6 +259,8 @@ static int can_optimize(unsigned long paddr) | |||
259 | */ | 259 | */ |
260 | return 0; | 260 | return 0; |
261 | recovered_insn = recover_probed_instruction(buf, addr); | 261 | recovered_insn = recover_probed_instruction(buf, addr); |
262 | if (!recovered_insn) | ||
263 | return 0; | ||
262 | kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE); | 264 | kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE); |
263 | insn_get_length(&insn); | 265 | insn_get_length(&insn); |
264 | /* Another subsystem puts a breakpoint */ | 266 | /* Another subsystem puts a breakpoint */ |
diff --git a/kernel/events/core.c b/kernel/events/core.c index af924bc38121..8bb20cc39a92 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -4446,7 +4446,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) | |||
4446 | * If we have rb pages ensure they're a power-of-two number, so we | 4446 | * If we have rb pages ensure they're a power-of-two number, so we |
4447 | * can do bitmasks instead of modulo. | 4447 | * can do bitmasks instead of modulo. |
4448 | */ | 4448 | */ |
4449 | if (!is_power_of_2(nr_pages)) | 4449 | if (nr_pages != 0 && !is_power_of_2(nr_pages)) |
4450 | return -EINVAL; | 4450 | return -EINVAL; |
4451 | 4451 | ||
4452 | if (vma_size != PAGE_SIZE * (1 + nr_pages)) | 4452 | if (vma_size != PAGE_SIZE * (1 + nr_pages)) |
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 40399c3d97d6..68328f517a2e 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore | |||
@@ -1,6 +1,7 @@ | |||
1 | PERF-CFLAGS | 1 | PERF-CFLAGS |
2 | PERF-GUI-VARS | 2 | PERF-GUI-VARS |
3 | PERF-VERSION-FILE | 3 | PERF-VERSION-FILE |
4 | PERF-FEATURES | ||
4 | perf | 5 | perf |
5 | perf-read-vdso32 | 6 | perf-read-vdso32 |
6 | perf-read-vdsox32 | 7 | perf-read-vdsox32 |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index cae75c11120f..355c4f5569b5 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -55,6 +55,11 @@ OPTIONS | |||
55 | If you want to profile write accesses in [0x1000~1008), just set | 55 | If you want to profile write accesses in [0x1000~1008), just set |
56 | 'mem:0x1000/8:w'. | 56 | 'mem:0x1000/8:w'. |
57 | 57 | ||
58 | - a group of events surrounded by a pair of brace ("{event1,event2,...}"). | ||
59 | Each event is separated by commas and the group should be quoted to | ||
60 | prevent the shell interpretation. You also need to use --group on | ||
61 | "perf report" to view group events together. | ||
62 | |||
58 | --filter=<filter>:: | 63 | --filter=<filter>:: |
59 | Event filter. | 64 | Event filter. |
60 | 65 | ||
@@ -62,9 +67,6 @@ OPTIONS | |||
62 | --all-cpus:: | 67 | --all-cpus:: |
63 | System-wide collection from all CPUs. | 68 | System-wide collection from all CPUs. |
64 | 69 | ||
65 | -l:: | ||
66 | Scale counter values. | ||
67 | |||
68 | -p:: | 70 | -p:: |
69 | --pid=:: | 71 | --pid=:: |
70 | Record events on existing process ID (comma separated list). | 72 | Record events on existing process ID (comma separated list). |
@@ -107,6 +109,10 @@ OPTIONS | |||
107 | specification with appended unit character - B/K/M/G. The | 109 | specification with appended unit character - B/K/M/G. The |
108 | size is rounded up to have nearest pages power of two value. | 110 | size is rounded up to have nearest pages power of two value. |
109 | 111 | ||
112 | --group:: | ||
113 | Put all events in a single event group. This precedes the --event | ||
114 | option and remains only for backward compatibility. See --event. | ||
115 | |||
110 | -g:: | 116 | -g:: |
111 | Enables call-graph (stack chain/backtrace) recording. | 117 | Enables call-graph (stack chain/backtrace) recording. |
112 | 118 | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index cb2e5868c8e8..d5020aeb5626 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -25,7 +25,7 @@ unexport MAKEFLAGS | |||
25 | # | 25 | # |
26 | ifeq ($(JOBS),) | 26 | ifeq ($(JOBS),) |
27 | JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null) | 27 | JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null) |
28 | ifeq ($(JOBS),) | 28 | ifeq ($(JOBS),0) |
29 | JOBS := 1 | 29 | JOBS := 1 |
30 | endif | 30 | endif |
31 | endif | 31 | endif |
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c index 6c14afe8c1b1..db1d3a29d97f 100644 --- a/tools/perf/bench/mem-memcpy.c +++ b/tools/perf/bench/mem-memcpy.c | |||
@@ -289,7 +289,7 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault) | |||
289 | memcpy_t fn = r->fn.memcpy; | 289 | memcpy_t fn = r->fn.memcpy; |
290 | int i; | 290 | int i; |
291 | 291 | ||
292 | memcpy_alloc_mem(&src, &dst, len); | 292 | memcpy_alloc_mem(&dst, &src, len); |
293 | 293 | ||
294 | if (prefault) | 294 | if (prefault) |
295 | fn(dst, src, len); | 295 | fn(dst, src, len); |
@@ -312,7 +312,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len, | |||
312 | void *src = NULL, *dst = NULL; | 312 | void *src = NULL, *dst = NULL; |
313 | int i; | 313 | int i; |
314 | 314 | ||
315 | memcpy_alloc_mem(&src, &dst, len); | 315 | memcpy_alloc_mem(&dst, &src, len); |
316 | 316 | ||
317 | if (prefault) | 317 | if (prefault) |
318 | fn(dst, src, len); | 318 | fn(dst, src, len); |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 7ce296618717..a3ebf1d3c29d 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -831,7 +831,7 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread) | |||
831 | return -1; | 831 | return -1; |
832 | } | 832 | } |
833 | 833 | ||
834 | atoms->thread = thread; | 834 | atoms->thread = thread__get(thread); |
835 | INIT_LIST_HEAD(&atoms->work_list); | 835 | INIT_LIST_HEAD(&atoms->work_list); |
836 | __thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid); | 836 | __thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid); |
837 | return 0; | 837 | return 0; |
@@ -1439,8 +1439,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ | |||
1439 | return err; | 1439 | return err; |
1440 | } | 1440 | } |
1441 | 1441 | ||
1442 | static int perf_sched__read_events(struct perf_sched *sched, | 1442 | static int perf_sched__read_events(struct perf_sched *sched) |
1443 | struct perf_session **psession) | ||
1444 | { | 1443 | { |
1445 | const struct perf_evsel_str_handler handlers[] = { | 1444 | const struct perf_evsel_str_handler handlers[] = { |
1446 | { "sched:sched_switch", process_sched_switch_event, }, | 1445 | { "sched:sched_switch", process_sched_switch_event, }, |
@@ -1454,6 +1453,7 @@ static int perf_sched__read_events(struct perf_sched *sched, | |||
1454 | .path = input_name, | 1453 | .path = input_name, |
1455 | .mode = PERF_DATA_MODE_READ, | 1454 | .mode = PERF_DATA_MODE_READ, |
1456 | }; | 1455 | }; |
1456 | int rc = -1; | ||
1457 | 1457 | ||
1458 | session = perf_session__new(&file, false, &sched->tool); | 1458 | session = perf_session__new(&file, false, &sched->tool); |
1459 | if (session == NULL) { | 1459 | if (session == NULL) { |
@@ -1478,16 +1478,10 @@ static int perf_sched__read_events(struct perf_sched *sched, | |||
1478 | sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST]; | 1478 | sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST]; |
1479 | } | 1479 | } |
1480 | 1480 | ||
1481 | if (psession) | 1481 | rc = 0; |
1482 | *psession = session; | ||
1483 | else | ||
1484 | perf_session__delete(session); | ||
1485 | |||
1486 | return 0; | ||
1487 | |||
1488 | out_delete: | 1482 | out_delete: |
1489 | perf_session__delete(session); | 1483 | perf_session__delete(session); |
1490 | return -1; | 1484 | return rc; |
1491 | } | 1485 | } |
1492 | 1486 | ||
1493 | static void print_bad_events(struct perf_sched *sched) | 1487 | static void print_bad_events(struct perf_sched *sched) |
@@ -1515,12 +1509,10 @@ static void print_bad_events(struct perf_sched *sched) | |||
1515 | static int perf_sched__lat(struct perf_sched *sched) | 1509 | static int perf_sched__lat(struct perf_sched *sched) |
1516 | { | 1510 | { |
1517 | struct rb_node *next; | 1511 | struct rb_node *next; |
1518 | struct perf_session *session; | ||
1519 | 1512 | ||
1520 | setup_pager(); | 1513 | setup_pager(); |
1521 | 1514 | ||
1522 | /* save session -- references to threads are held in work_list */ | 1515 | if (perf_sched__read_events(sched)) |
1523 | if (perf_sched__read_events(sched, &session)) | ||
1524 | return -1; | 1516 | return -1; |
1525 | 1517 | ||
1526 | perf_sched__sort_lat(sched); | 1518 | perf_sched__sort_lat(sched); |
@@ -1537,6 +1529,7 @@ static int perf_sched__lat(struct perf_sched *sched) | |||
1537 | work_list = rb_entry(next, struct work_atoms, node); | 1529 | work_list = rb_entry(next, struct work_atoms, node); |
1538 | output_lat_thread(sched, work_list); | 1530 | output_lat_thread(sched, work_list); |
1539 | next = rb_next(next); | 1531 | next = rb_next(next); |
1532 | thread__zput(work_list->thread); | ||
1540 | } | 1533 | } |
1541 | 1534 | ||
1542 | printf(" -----------------------------------------------------------------------------------------------------------------\n"); | 1535 | printf(" -----------------------------------------------------------------------------------------------------------------\n"); |
@@ -1548,7 +1541,6 @@ static int perf_sched__lat(struct perf_sched *sched) | |||
1548 | print_bad_events(sched); | 1541 | print_bad_events(sched); |
1549 | printf("\n"); | 1542 | printf("\n"); |
1550 | 1543 | ||
1551 | perf_session__delete(session); | ||
1552 | return 0; | 1544 | return 0; |
1553 | } | 1545 | } |
1554 | 1546 | ||
@@ -1557,7 +1549,7 @@ static int perf_sched__map(struct perf_sched *sched) | |||
1557 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); | 1549 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); |
1558 | 1550 | ||
1559 | setup_pager(); | 1551 | setup_pager(); |
1560 | if (perf_sched__read_events(sched, NULL)) | 1552 | if (perf_sched__read_events(sched)) |
1561 | return -1; | 1553 | return -1; |
1562 | print_bad_events(sched); | 1554 | print_bad_events(sched); |
1563 | return 0; | 1555 | return 0; |
@@ -1572,7 +1564,7 @@ static int perf_sched__replay(struct perf_sched *sched) | |||
1572 | 1564 | ||
1573 | test_calibrations(sched); | 1565 | test_calibrations(sched); |
1574 | 1566 | ||
1575 | if (perf_sched__read_events(sched, NULL)) | 1567 | if (perf_sched__read_events(sched)) |
1576 | return -1; | 1568 | return -1; |
1577 | 1569 | ||
1578 | printf("nr_run_events: %ld\n", sched->nr_run_events); | 1570 | printf("nr_run_events: %ld\n", sched->nr_run_events); |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e598e4e98170..d28949d210cc 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -510,6 +510,9 @@ static int read_counter(struct perf_evsel *counter) | |||
510 | int ncpus = perf_evsel__nr_cpus(counter); | 510 | int ncpus = perf_evsel__nr_cpus(counter); |
511 | int cpu, thread; | 511 | int cpu, thread; |
512 | 512 | ||
513 | if (!counter->supported) | ||
514 | return -ENOENT; | ||
515 | |||
513 | if (counter->system_wide) | 516 | if (counter->system_wide) |
514 | nthreads = 1; | 517 | nthreads = 1; |
515 | 518 | ||
@@ -1285,7 +1288,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) | |||
1285 | if (prefix) | 1288 | if (prefix) |
1286 | fprintf(output, "%s", prefix); | 1289 | fprintf(output, "%s", prefix); |
1287 | 1290 | ||
1288 | if (scaled == -1) { | 1291 | if (scaled == -1 || !counter->supported) { |
1289 | fprintf(output, "%*s%s", | 1292 | fprintf(output, "%*s%s", |
1290 | csv_output ? 0 : 18, | 1293 | csv_output ? 0 : 18, |
1291 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 1294 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d95a8f4d988c..211614fba217 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -1741,7 +1741,10 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | |||
1741 | } else | 1741 | } else |
1742 | ttrace->entry_pending = true; | 1742 | ttrace->entry_pending = true; |
1743 | 1743 | ||
1744 | trace->current = thread; | 1744 | if (trace->current != thread) { |
1745 | thread__put(trace->current); | ||
1746 | trace->current = thread__get(thread); | ||
1747 | } | ||
1745 | 1748 | ||
1746 | return 0; | 1749 | return 0; |
1747 | } | 1750 | } |
@@ -2274,6 +2277,8 @@ next_event: | |||
2274 | } | 2277 | } |
2275 | 2278 | ||
2276 | out_disable: | 2279 | out_disable: |
2280 | thread__zput(trace->current); | ||
2281 | |||
2277 | perf_evlist__disable(evlist); | 2282 | perf_evlist__disable(evlist); |
2278 | 2283 | ||
2279 | if (!err) { | 2284 | if (!err) { |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index c3570b5f3bf3..d44c64d64465 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -531,7 +531,7 @@ else | |||
531 | ifneq ($(feature-libperl), 1) | 531 | ifneq ($(feature-libperl), 1) |
532 | CFLAGS += -DNO_LIBPERL | 532 | CFLAGS += -DNO_LIBPERL |
533 | NO_LIBPERL := 1 | 533 | NO_LIBPERL := 1 |
534 | msg := $(warning Missing perl devel files. Disabling perl scripting support, consider installing perl-ExtUtils-Embed); | 534 | msg := $(warning Missing perl devel files. Disabling perl scripting support, please install perl-ExtUtils-Embed/libperl-dev); |
535 | else | 535 | else |
536 | LDFLAGS += $(PERL_EMBED_LDFLAGS) | 536 | LDFLAGS += $(PERL_EMBED_LDFLAGS) |
537 | EXTLIBS += $(PERL_EMBED_LIBADD) | 537 | EXTLIBS += $(PERL_EMBED_LIBADD) |
@@ -548,22 +548,21 @@ endif | |||
548 | disable-python = $(eval $(disable-python_code)) | 548 | disable-python = $(eval $(disable-python_code)) |
549 | define disable-python_code | 549 | define disable-python_code |
550 | CFLAGS += -DNO_LIBPYTHON | 550 | CFLAGS += -DNO_LIBPYTHON |
551 | $(if $(1),$(warning No $(1) was found)) | 551 | $(warning $1) |
552 | $(warning Python support will not be built) | ||
553 | NO_LIBPYTHON := 1 | 552 | NO_LIBPYTHON := 1 |
554 | endef | 553 | endef |
555 | 554 | ||
556 | ifdef NO_LIBPYTHON | 555 | ifdef NO_LIBPYTHON |
557 | $(call disable-python) | 556 | $(call disable-python,Python support disabled by user) |
558 | else | 557 | else |
559 | 558 | ||
560 | ifndef PYTHON | 559 | ifndef PYTHON |
561 | $(call disable-python,python interpreter) | 560 | $(call disable-python,No python interpreter was found: disables Python support - please install python-devel/python-dev) |
562 | else | 561 | else |
563 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | 562 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) |
564 | 563 | ||
565 | ifndef PYTHON_CONFIG | 564 | ifndef PYTHON_CONFIG |
566 | $(call disable-python,python-config tool) | 565 | $(call disable-python,No 'python-config' tool was found: disables Python support - please install python-devel/python-dev) |
567 | else | 566 | else |
568 | 567 | ||
569 | PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) | 568 | PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) |
@@ -575,7 +574,7 @@ else | |||
575 | FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) | 574 | FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) |
576 | 575 | ||
577 | ifneq ($(feature-libpython), 1) | 576 | ifneq ($(feature-libpython), 1) |
578 | $(call disable-python,Python.h (for Python 2.x)) | 577 | $(call disable-python,No 'Python.h' (for Python 2.x support) was found: disables Python support - please install python-devel/python-dev) |
579 | else | 578 | else |
580 | 579 | ||
581 | ifneq ($(feature-libpython-version), 1) | 580 | ifneq ($(feature-libpython-version), 1) |
@@ -636,7 +635,7 @@ else | |||
636 | EXTLIBS += -liberty | 635 | EXTLIBS += -liberty |
637 | CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT | 636 | CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT |
638 | else | 637 | else |
639 | msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) | 638 | msg := $(warning No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling) |
640 | CFLAGS += -DNO_DEMANGLE | 639 | CFLAGS += -DNO_DEMANGLE |
641 | endif | 640 | endif |
642 | endif | 641 | endif |
@@ -707,7 +706,7 @@ endif | |||
707 | 706 | ||
708 | ifndef NO_LIBBABELTRACE | 707 | ifndef NO_LIBBABELTRACE |
709 | ifeq ($(feature-libbabeltrace), 0) | 708 | ifeq ($(feature-libbabeltrace), 0) |
710 | msg := $(warning No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-devel/libbabeltrace-ctf-dev); | 709 | msg := $(warning No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev); |
711 | NO_LIBBABELTRACE := 1 | 710 | NO_LIBBABELTRACE := 1 |
712 | else | 711 | else |
713 | CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS) | 712 | CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS) |
diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch index ff95a68741d1..e9720571341d 100644 --- a/tools/perf/config/Makefile.arch +++ b/tools/perf/config/Makefile.arch | |||
@@ -1,28 +1,15 @@ | |||
1 | ifndef ARCH | ||
2 | ARCH := $(shell uname -m 2>/dev/null || echo not) | ||
3 | endif | ||
1 | 4 | ||
2 | uname_M := $(shell uname -m 2>/dev/null || echo not) | 5 | ARCH := $(shell echo $(ARCH) | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ |
3 | 6 | -e s/sun4u/sparc/ -e s/sparc64/sparc/ \ | |
4 | RAW_ARCH := $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | ||
5 | -e s/arm.*/arm/ -e s/sa110/arm/ \ | 7 | -e s/arm.*/arm/ -e s/sa110/arm/ \ |
6 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ | 8 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ |
7 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ | 9 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ |
8 | -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ | 10 | -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ |
9 | -e s/tile.*/tile/ ) | 11 | -e s/tile.*/tile/ ) |
10 | 12 | ||
11 | # Additional ARCH settings for x86 | ||
12 | ifeq ($(RAW_ARCH),i386) | ||
13 | ARCH ?= x86 | ||
14 | endif | ||
15 | |||
16 | ifeq ($(RAW_ARCH),x86_64) | ||
17 | ARCH ?= x86 | ||
18 | |||
19 | ifneq (, $(findstring m32,$(CFLAGS))) | ||
20 | RAW_ARCH := x86_32 | ||
21 | endif | ||
22 | endif | ||
23 | |||
24 | ARCH ?= $(RAW_ARCH) | ||
25 | |||
26 | LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) | 13 | LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) |
27 | ifeq ($(LP64), 1) | 14 | ifeq ($(LP64), 1) |
28 | IS_64_BIT := 1 | 15 | IS_64_BIT := 1 |
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 70c9aebe9da3..8fe067864957 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile | |||
@@ -39,24 +39,24 @@ PKG_CONFIG := $(CROSS_COMPILE)pkg-config | |||
39 | 39 | ||
40 | all: $(FILES) | 40 | all: $(FILES) |
41 | 41 | ||
42 | BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) | 42 | BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) |
43 | 43 | ||
44 | ############################### | 44 | ############################### |
45 | 45 | ||
46 | test-all.bin: | 46 | test-all.bin: |
47 | $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -lbabeltrace | 47 | $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -lbabeltrace |
48 | 48 | ||
49 | test-hello.bin: | 49 | test-hello.bin: |
50 | $(BUILD) | 50 | $(BUILD) |
51 | 51 | ||
52 | test-pthread-attr-setaffinity-np.bin: | 52 | test-pthread-attr-setaffinity-np.bin: |
53 | $(BUILD) -D_GNU_SOURCE -Werror -lpthread | 53 | $(BUILD) -D_GNU_SOURCE -lpthread |
54 | 54 | ||
55 | test-stackprotector-all.bin: | 55 | test-stackprotector-all.bin: |
56 | $(BUILD) -Werror -fstack-protector-all | 56 | $(BUILD) -fstack-protector-all |
57 | 57 | ||
58 | test-fortify-source.bin: | 58 | test-fortify-source.bin: |
59 | $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 | 59 | $(BUILD) -O2 -D_FORTIFY_SOURCE=2 |
60 | 60 | ||
61 | test-bionic.bin: | 61 | test-bionic.bin: |
62 | $(BUILD) | 62 | $(BUILD) |
@@ -119,10 +119,10 @@ test-libbfd.bin: | |||
119 | $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl | 119 | $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl |
120 | 120 | ||
121 | test-liberty.bin: | 121 | test-liberty.bin: |
122 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty | 122 | $(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty |
123 | 123 | ||
124 | test-liberty-z.bin: | 124 | test-liberty-z.bin: |
125 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz | 125 | $(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz |
126 | 126 | ||
127 | test-cplus-demangle.bin: | 127 | test-cplus-demangle.bin: |
128 | $(BUILD) -liberty | 128 | $(BUILD) -liberty |
@@ -140,7 +140,7 @@ test-libbabeltrace.bin: | |||
140 | $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace) | 140 | $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace) |
141 | 141 | ||
142 | test-sync-compare-and-swap.bin: | 142 | test-sync-compare-and-swap.bin: |
143 | $(BUILD) -Werror | 143 | $(BUILD) |
144 | 144 | ||
145 | test-compile-32.bin: | 145 | test-compile-32.bin: |
146 | $(CC) -m32 -o $(OUTPUT)$@ test-compile.c | 146 | $(CC) -m32 -o $(OUTPUT)$@ test-compile.c |
diff --git a/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c b/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c index 0a0d3ecb4e8a..fdada5e8d454 100644 --- a/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c +++ b/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c | |||
@@ -1,14 +1,17 @@ | |||
1 | #include <stdint.h> | 1 | #include <stdint.h> |
2 | #include <pthread.h> | 2 | #include <pthread.h> |
3 | #include <sched.h> | ||
3 | 4 | ||
4 | int main(void) | 5 | int main(void) |
5 | { | 6 | { |
6 | int ret = 0; | 7 | int ret = 0; |
7 | pthread_attr_t thread_attr; | 8 | pthread_attr_t thread_attr; |
9 | cpu_set_t cs; | ||
8 | 10 | ||
9 | pthread_attr_init(&thread_attr); | 11 | pthread_attr_init(&thread_attr); |
10 | /* don't care abt exact args, just the API itself in libpthread */ | 12 | CPU_ZERO(&cs); |
11 | ret = pthread_attr_setaffinity_np(&thread_attr, 0, NULL); | 13 | |
14 | ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cs), &cs); | ||
12 | 15 | ||
13 | return ret; | 16 | return ret; |
14 | } | 17 | } |
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak index 7076a62d0ff7..c16ce833079c 100644 --- a/tools/perf/config/utilities.mak +++ b/tools/perf/config/utilities.mak | |||
@@ -175,6 +175,5 @@ _ge-abspath = $(if $(is-executable),$(1)) | |||
175 | define get-executable-or-default | 175 | define get-executable-or-default |
176 | $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) | 176 | $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) |
177 | endef | 177 | endef |
178 | _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) | 178 | _ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2))) |
179 | _gea_warn = $(warning The path '$(1)' is not executable.) | ||
180 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) | 179 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 788506eef567..ad312d91caed 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1467,7 +1467,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1467 | perf_hpp__set_user_width(symbol_conf.col_width_list_str); | 1467 | perf_hpp__set_user_width(symbol_conf.col_width_list_str); |
1468 | 1468 | ||
1469 | while (1) { | 1469 | while (1) { |
1470 | const struct thread *thread = NULL; | 1470 | struct thread *thread = NULL; |
1471 | const struct dso *dso = NULL; | 1471 | const struct dso *dso = NULL; |
1472 | int choice = 0, | 1472 | int choice = 0, |
1473 | annotate = -2, zoom_dso = -2, zoom_thread = -2, | 1473 | annotate = -2, zoom_dso = -2, zoom_thread = -2, |
@@ -1754,13 +1754,13 @@ zoom_thread: | |||
1754 | pstack__remove(fstack, &browser->hists->thread_filter); | 1754 | pstack__remove(fstack, &browser->hists->thread_filter); |
1755 | zoom_out_thread: | 1755 | zoom_out_thread: |
1756 | ui_helpline__pop(); | 1756 | ui_helpline__pop(); |
1757 | browser->hists->thread_filter = NULL; | 1757 | thread__zput(browser->hists->thread_filter); |
1758 | perf_hpp__set_elide(HISTC_THREAD, false); | 1758 | perf_hpp__set_elide(HISTC_THREAD, false); |
1759 | } else { | 1759 | } else { |
1760 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", | 1760 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", |
1761 | thread->comm_set ? thread__comm_str(thread) : "", | 1761 | thread->comm_set ? thread__comm_str(thread) : "", |
1762 | thread->tid); | 1762 | thread->tid); |
1763 | browser->hists->thread_filter = thread; | 1763 | browser->hists->thread_filter = thread__get(thread); |
1764 | perf_hpp__set_elide(HISTC_THREAD, false); | 1764 | perf_hpp__set_elide(HISTC_THREAD, false); |
1765 | pstack__push(fstack, &browser->hists->thread_filter); | 1765 | pstack__push(fstack, &browser->hists->thread_filter); |
1766 | } | 1766 | } |
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index a2c8047d25f7..972a6e0da7ad 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -71,7 +71,7 @@ libperf-y += stat.o | |||
71 | libperf-y += record.o | 71 | libperf-y += record.o |
72 | libperf-y += srcline.o | 72 | libperf-y += srcline.o |
73 | libperf-y += data.o | 73 | libperf-y += data.o |
74 | libperf-y += tsc.o | 74 | libperf-$(CONFIG_X86) += tsc.o |
75 | libperf-y += cloexec.o | 75 | libperf-y += cloexec.o |
76 | libperf-y += thread-stack.o | 76 | libperf-y += thread-stack.o |
77 | 77 | ||
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index ffdc338df925..a19674666b4e 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -61,8 +61,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, | |||
61 | 61 | ||
62 | if (thread) { | 62 | if (thread) { |
63 | rb_erase(&thread->rb_node, &machine->threads); | 63 | rb_erase(&thread->rb_node, &machine->threads); |
64 | machine->last_match = NULL; | 64 | if (machine->last_match == thread) |
65 | thread__delete(thread); | 65 | thread__zput(machine->last_match); |
66 | thread__put(thread); | ||
66 | } | 67 | } |
67 | 68 | ||
68 | return 0; | 69 | return 0; |
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index 47b78b3f0325..6da965bdbc2c 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c | |||
@@ -25,6 +25,10 @@ static int perf_flag_probe(void) | |||
25 | if (cpu < 0) | 25 | if (cpu < 0) |
26 | cpu = 0; | 26 | cpu = 0; |
27 | 27 | ||
28 | /* | ||
29 | * Using -1 for the pid is a workaround to avoid gratuitous jump label | ||
30 | * changes. | ||
31 | */ | ||
28 | while (1) { | 32 | while (1) { |
29 | /* check cloexec flag */ | 33 | /* check cloexec flag */ |
30 | fd = sys_perf_event_open(&attr, pid, cpu, -1, | 34 | fd = sys_perf_event_open(&attr, pid, cpu, -1, |
@@ -47,16 +51,24 @@ static int perf_flag_probe(void) | |||
47 | err, strerror_r(err, sbuf, sizeof(sbuf))); | 51 | err, strerror_r(err, sbuf, sizeof(sbuf))); |
48 | 52 | ||
49 | /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ | 53 | /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ |
50 | fd = sys_perf_event_open(&attr, pid, cpu, -1, 0); | 54 | while (1) { |
55 | fd = sys_perf_event_open(&attr, pid, cpu, -1, 0); | ||
56 | if (fd < 0 && pid == -1 && errno == EACCES) { | ||
57 | pid = 0; | ||
58 | continue; | ||
59 | } | ||
60 | break; | ||
61 | } | ||
51 | err = errno; | 62 | err = errno; |
52 | 63 | ||
64 | if (fd >= 0) | ||
65 | close(fd); | ||
66 | |||
53 | if (WARN_ONCE(fd < 0 && err != EBUSY, | 67 | if (WARN_ONCE(fd < 0 && err != EBUSY, |
54 | "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", | 68 | "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", |
55 | err, strerror_r(err, sbuf, sizeof(sbuf)))) | 69 | err, strerror_r(err, sbuf, sizeof(sbuf)))) |
56 | return -1; | 70 | return -1; |
57 | 71 | ||
58 | close(fd); | ||
59 | |||
60 | return 0; | 72 | return 0; |
61 | } | 73 | } |
62 | 74 | ||
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 9e806d855b04..d5efa5092ce6 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -95,9 +95,7 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len) | |||
95 | return tgid; | 95 | return tgid; |
96 | } | 96 | } |
97 | 97 | ||
98 | static pid_t perf_event__synthesize_comm(struct perf_tool *tool, | 98 | static pid_t perf_event__prepare_comm(union perf_event *event, pid_t pid, |
99 | union perf_event *event, pid_t pid, | ||
100 | perf_event__handler_t process, | ||
101 | struct machine *machine) | 99 | struct machine *machine) |
102 | { | 100 | { |
103 | size_t size; | 101 | size_t size; |
@@ -124,6 +122,19 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, | |||
124 | (sizeof(event->comm.comm) - size) + | 122 | (sizeof(event->comm.comm) - size) + |
125 | machine->id_hdr_size); | 123 | machine->id_hdr_size); |
126 | event->comm.tid = pid; | 124 | event->comm.tid = pid; |
125 | out: | ||
126 | return tgid; | ||
127 | } | ||
128 | |||
129 | static pid_t perf_event__synthesize_comm(struct perf_tool *tool, | ||
130 | union perf_event *event, pid_t pid, | ||
131 | perf_event__handler_t process, | ||
132 | struct machine *machine) | ||
133 | { | ||
134 | pid_t tgid = perf_event__prepare_comm(event, pid, machine); | ||
135 | |||
136 | if (tgid == -1) | ||
137 | goto out; | ||
127 | 138 | ||
128 | if (process(tool, event, &synth_sample, machine) != 0) | 139 | if (process(tool, event, &synth_sample, machine) != 0) |
129 | return -1; | 140 | return -1; |
@@ -139,7 +150,6 @@ static int perf_event__synthesize_fork(struct perf_tool *tool, | |||
139 | { | 150 | { |
140 | memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); | 151 | memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); |
141 | 152 | ||
142 | /* this is really a clone event but we use fork to synthesize it */ | ||
143 | event->fork.ppid = tgid; | 153 | event->fork.ppid = tgid; |
144 | event->fork.ptid = tgid; | 154 | event->fork.ptid = tgid; |
145 | event->fork.pid = tgid; | 155 | event->fork.pid = tgid; |
@@ -368,19 +378,23 @@ static int __event__synthesize_thread(union perf_event *comm_event, | |||
368 | if (*end) | 378 | if (*end) |
369 | continue; | 379 | continue; |
370 | 380 | ||
371 | tgid = perf_event__synthesize_comm(tool, comm_event, _pid, | 381 | tgid = perf_event__prepare_comm(comm_event, _pid, machine); |
372 | process, machine); | ||
373 | if (tgid == -1) | 382 | if (tgid == -1) |
374 | return -1; | 383 | return -1; |
375 | 384 | ||
385 | if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, | ||
386 | process, machine) < 0) | ||
387 | return -1; | ||
388 | /* | ||
389 | * Send the prepared comm event | ||
390 | */ | ||
391 | if (process(tool, comm_event, &synth_sample, machine) != 0) | ||
392 | return -1; | ||
393 | |||
376 | if (_pid == pid) { | 394 | if (_pid == pid) { |
377 | /* process the parent's maps too */ | 395 | /* process the parent's maps too */ |
378 | rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, | 396 | rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, |
379 | process, machine, mmap_data); | 397 | process, machine, mmap_data); |
380 | } else { | ||
381 | /* only fork the tid's map, to save time */ | ||
382 | rc = perf_event__synthesize_fork(tool, fork_event, _pid, tgid, | ||
383 | process, machine); | ||
384 | } | 398 | } |
385 | 399 | ||
386 | if (rc) | 400 | if (rc) |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index d4768a30f884..f07c984465f0 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -28,7 +28,7 @@ struct perf_mmap { | |||
28 | int mask; | 28 | int mask; |
29 | int refcnt; | 29 | int refcnt; |
30 | unsigned int prev; | 30 | unsigned int prev; |
31 | char event_copy[PERF_SAMPLE_MAX_SIZE]; | 31 | char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); |
32 | }; | 32 | }; |
33 | 33 | ||
34 | struct perf_evlist { | 34 | struct perf_evlist { |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 70b48a65064c..95f5ab707b74 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -355,6 +355,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, | |||
355 | callchain_init(he->callchain); | 355 | callchain_init(he->callchain); |
356 | 356 | ||
357 | INIT_LIST_HEAD(&he->pairs.node); | 357 | INIT_LIST_HEAD(&he->pairs.node); |
358 | thread__get(he->thread); | ||
358 | } | 359 | } |
359 | 360 | ||
360 | return he; | 361 | return he; |
@@ -941,6 +942,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
941 | 942 | ||
942 | void hist_entry__delete(struct hist_entry *he) | 943 | void hist_entry__delete(struct hist_entry *he) |
943 | { | 944 | { |
945 | thread__zput(he->thread); | ||
944 | zfree(&he->branch_info); | 946 | zfree(&he->branch_info); |
945 | zfree(&he->mem_info); | 947 | zfree(&he->mem_info); |
946 | zfree(&he->stat_acc); | 948 | zfree(&he->stat_acc); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 2b690d028907..e988c9fcd1bc 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -60,7 +60,7 @@ struct hists { | |||
60 | struct rb_root entries_collapsed; | 60 | struct rb_root entries_collapsed; |
61 | u64 nr_entries; | 61 | u64 nr_entries; |
62 | u64 nr_non_filtered_entries; | 62 | u64 nr_non_filtered_entries; |
63 | const struct thread *thread_filter; | 63 | struct thread *thread_filter; |
64 | const struct dso *dso_filter; | 64 | const struct dso *dso_filter; |
65 | const char *uid_filter_str; | 65 | const char *uid_filter_str; |
66 | const char *symbol_filter_str; | 66 | const char *symbol_filter_str; |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 9e0f60a7e7b3..24f8c978cfd4 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include "unwind.h" | 14 | #include "unwind.h" |
15 | #include "linux/hash.h" | 15 | #include "linux/hash.h" |
16 | 16 | ||
17 | static void machine__remove_thread(struct machine *machine, struct thread *th); | ||
18 | |||
17 | static void dsos__init(struct dsos *dsos) | 19 | static void dsos__init(struct dsos *dsos) |
18 | { | 20 | { |
19 | INIT_LIST_HEAD(&dsos->head); | 21 | INIT_LIST_HEAD(&dsos->head); |
@@ -89,16 +91,6 @@ static void dsos__delete(struct dsos *dsos) | |||
89 | } | 91 | } |
90 | } | 92 | } |
91 | 93 | ||
92 | void machine__delete_dead_threads(struct machine *machine) | ||
93 | { | ||
94 | struct thread *n, *t; | ||
95 | |||
96 | list_for_each_entry_safe(t, n, &machine->dead_threads, node) { | ||
97 | list_del(&t->node); | ||
98 | thread__delete(t); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | void machine__delete_threads(struct machine *machine) | 94 | void machine__delete_threads(struct machine *machine) |
103 | { | 95 | { |
104 | struct rb_node *nd = rb_first(&machine->threads); | 96 | struct rb_node *nd = rb_first(&machine->threads); |
@@ -106,9 +98,8 @@ void machine__delete_threads(struct machine *machine) | |||
106 | while (nd) { | 98 | while (nd) { |
107 | struct thread *t = rb_entry(nd, struct thread, rb_node); | 99 | struct thread *t = rb_entry(nd, struct thread, rb_node); |
108 | 100 | ||
109 | rb_erase(&t->rb_node, &machine->threads); | ||
110 | nd = rb_next(nd); | 101 | nd = rb_next(nd); |
111 | thread__delete(t); | 102 | machine__remove_thread(machine, t); |
112 | } | 103 | } |
113 | } | 104 | } |
114 | 105 | ||
@@ -361,9 +352,13 @@ static struct thread *__machine__findnew_thread(struct machine *machine, | |||
361 | * the full rbtree: | 352 | * the full rbtree: |
362 | */ | 353 | */ |
363 | th = machine->last_match; | 354 | th = machine->last_match; |
364 | if (th && th->tid == tid) { | 355 | if (th != NULL) { |
365 | machine__update_thread_pid(machine, th, pid); | 356 | if (th->tid == tid) { |
366 | return th; | 357 | machine__update_thread_pid(machine, th, pid); |
358 | return th; | ||
359 | } | ||
360 | |||
361 | thread__zput(machine->last_match); | ||
367 | } | 362 | } |
368 | 363 | ||
369 | while (*p != NULL) { | 364 | while (*p != NULL) { |
@@ -371,7 +366,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, | |||
371 | th = rb_entry(parent, struct thread, rb_node); | 366 | th = rb_entry(parent, struct thread, rb_node); |
372 | 367 | ||
373 | if (th->tid == tid) { | 368 | if (th->tid == tid) { |
374 | machine->last_match = th; | 369 | machine->last_match = thread__get(th); |
375 | machine__update_thread_pid(machine, th, pid); | 370 | machine__update_thread_pid(machine, th, pid); |
376 | return th; | 371 | return th; |
377 | } | 372 | } |
@@ -403,8 +398,11 @@ static struct thread *__machine__findnew_thread(struct machine *machine, | |||
403 | thread__delete(th); | 398 | thread__delete(th); |
404 | return NULL; | 399 | return NULL; |
405 | } | 400 | } |
406 | 401 | /* | |
407 | machine->last_match = th; | 402 | * It is now in the rbtree, get a ref |
403 | */ | ||
404 | thread__get(th); | ||
405 | machine->last_match = thread__get(th); | ||
408 | } | 406 | } |
409 | 407 | ||
410 | return th; | 408 | return th; |
@@ -1238,13 +1236,17 @@ out_problem: | |||
1238 | 1236 | ||
1239 | static void machine__remove_thread(struct machine *machine, struct thread *th) | 1237 | static void machine__remove_thread(struct machine *machine, struct thread *th) |
1240 | { | 1238 | { |
1241 | machine->last_match = NULL; | 1239 | if (machine->last_match == th) |
1240 | thread__zput(machine->last_match); | ||
1241 | |||
1242 | rb_erase(&th->rb_node, &machine->threads); | 1242 | rb_erase(&th->rb_node, &machine->threads); |
1243 | /* | 1243 | /* |
1244 | * We may have references to this thread, for instance in some hist_entry | 1244 | * Move it first to the dead_threads list, then drop the reference, |
1245 | * instances, so just move them to a separate list. | 1245 | * if this is the last reference, then the thread__delete destructor |
1246 | * will be called and we will remove it from the dead_threads list. | ||
1246 | */ | 1247 | */ |
1247 | list_add_tail(&th->node, &machine->dead_threads); | 1248 | list_add_tail(&th->node, &machine->dead_threads); |
1249 | thread__put(th); | ||
1248 | } | 1250 | } |
1249 | 1251 | ||
1250 | int machine__process_fork_event(struct machine *machine, union perf_event *event, | 1252 | int machine__process_fork_event(struct machine *machine, union perf_event *event, |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index e8b7779a0a3f..e2faf3b47e7b 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -118,7 +118,6 @@ void machines__set_comm_exec(struct machines *machines, bool comm_exec); | |||
118 | struct machine *machine__new_host(void); | 118 | struct machine *machine__new_host(void); |
119 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); | 119 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); |
120 | void machine__exit(struct machine *machine); | 120 | void machine__exit(struct machine *machine); |
121 | void machine__delete_dead_threads(struct machine *machine); | ||
122 | void machine__delete_threads(struct machine *machine); | 121 | void machine__delete_threads(struct machine *machine); |
123 | void machine__delete(struct machine *machine); | 122 | void machine__delete(struct machine *machine); |
124 | 123 | ||
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 7c0e765fa2e3..1c570c2fa7cc 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -2199,6 +2199,27 @@ static int get_new_event_name(char *buf, size_t len, const char *base, | |||
2199 | return ret; | 2199 | return ret; |
2200 | } | 2200 | } |
2201 | 2201 | ||
2202 | /* Warn if the current kernel's uprobe implementation is old */ | ||
2203 | static void warn_uprobe_event_compat(struct probe_trace_event *tev) | ||
2204 | { | ||
2205 | int i; | ||
2206 | char *buf = synthesize_probe_trace_command(tev); | ||
2207 | |||
2208 | /* Old uprobe event doesn't support memory dereference */ | ||
2209 | if (!tev->uprobes || tev->nargs == 0 || !buf) | ||
2210 | goto out; | ||
2211 | |||
2212 | for (i = 0; i < tev->nargs; i++) | ||
2213 | if (strglobmatch(tev->args[i].value, "[$@+-]*")) { | ||
2214 | pr_warning("Please upgrade your kernel to at least " | ||
2215 | "3.14 to have access to feature %s\n", | ||
2216 | tev->args[i].value); | ||
2217 | break; | ||
2218 | } | ||
2219 | out: | ||
2220 | free(buf); | ||
2221 | } | ||
2222 | |||
2202 | static int __add_probe_trace_events(struct perf_probe_event *pev, | 2223 | static int __add_probe_trace_events(struct perf_probe_event *pev, |
2203 | struct probe_trace_event *tevs, | 2224 | struct probe_trace_event *tevs, |
2204 | int ntevs, bool allow_suffix) | 2225 | int ntevs, bool allow_suffix) |
@@ -2295,6 +2316,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2295 | */ | 2316 | */ |
2296 | allow_suffix = true; | 2317 | allow_suffix = true; |
2297 | } | 2318 | } |
2319 | if (ret == -EINVAL && pev->uprobes) | ||
2320 | warn_uprobe_event_compat(tev); | ||
2298 | 2321 | ||
2299 | /* Note that it is possible to skip all events because of blacklist */ | 2322 | /* Note that it is possible to skip all events because of blacklist */ |
2300 | if (ret >= 0 && tev->event) { | 2323 | if (ret >= 0 && tev->event) { |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index d14193518e4d..46f009aa486c 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -1345,11 +1345,8 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, | |||
1345 | const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; | 1345 | const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; |
1346 | int baseline = 0, lineno = 0, ret = 0; | 1346 | int baseline = 0, lineno = 0, ret = 0; |
1347 | 1347 | ||
1348 | /* Adjust address with bias */ | ||
1349 | addr += dbg->bias; | ||
1350 | |||
1351 | /* Find cu die */ | 1348 | /* Find cu die */ |
1352 | if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr - dbg->bias, &cudie)) { | 1349 | if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { |
1353 | pr_warning("Failed to find debug information for address %lx\n", | 1350 | pr_warning("Failed to find debug information for address %lx\n", |
1354 | addr); | 1351 | addr); |
1355 | ret = -EINVAL; | 1352 | ret = -EINVAL; |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e4f166981ff0..ed4e5cf2bd9d 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -138,11 +138,6 @@ struct perf_session *perf_session__new(struct perf_data_file *file, | |||
138 | return NULL; | 138 | return NULL; |
139 | } | 139 | } |
140 | 140 | ||
141 | static void perf_session__delete_dead_threads(struct perf_session *session) | ||
142 | { | ||
143 | machine__delete_dead_threads(&session->machines.host); | ||
144 | } | ||
145 | |||
146 | static void perf_session__delete_threads(struct perf_session *session) | 141 | static void perf_session__delete_threads(struct perf_session *session) |
147 | { | 142 | { |
148 | machine__delete_threads(&session->machines.host); | 143 | machine__delete_threads(&session->machines.host); |
@@ -167,7 +162,6 @@ static void perf_session_env__delete(struct perf_session_env *env) | |||
167 | void perf_session__delete(struct perf_session *session) | 162 | void perf_session__delete(struct perf_session *session) |
168 | { | 163 | { |
169 | perf_session__destroy_kernel_maps(session); | 164 | perf_session__destroy_kernel_maps(session); |
170 | perf_session__delete_dead_threads(session); | ||
171 | perf_session__delete_threads(session); | 165 | perf_session__delete_threads(session); |
172 | perf_session_env__delete(&session->header.env); | 166 | perf_session_env__delete(&session->header.env); |
173 | machines__exit(&session->machines); | 167 | machines__exit(&session->machines); |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index b02731a19d1f..ada16762fac2 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -11,6 +11,11 @@ | |||
11 | #include <symbol/kallsyms.h> | 11 | #include <symbol/kallsyms.h> |
12 | #include "debug.h" | 12 | #include "debug.h" |
13 | 13 | ||
14 | #ifndef EM_AARCH64 | ||
15 | #define EM_AARCH64 183 /* ARM 64 bit */ | ||
16 | #endif | ||
17 | |||
18 | |||
14 | #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT | 19 | #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT |
15 | extern char *cplus_demangle(const char *, int); | 20 | extern char *cplus_demangle(const char *, int); |
16 | 21 | ||
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 9ebc8b1f9be5..a5dbba95107f 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -82,6 +82,20 @@ void thread__delete(struct thread *thread) | |||
82 | free(thread); | 82 | free(thread); |
83 | } | 83 | } |
84 | 84 | ||
85 | struct thread *thread__get(struct thread *thread) | ||
86 | { | ||
87 | ++thread->refcnt; | ||
88 | return thread; | ||
89 | } | ||
90 | |||
91 | void thread__put(struct thread *thread) | ||
92 | { | ||
93 | if (thread && --thread->refcnt == 0) { | ||
94 | list_del_init(&thread->node); | ||
95 | thread__delete(thread); | ||
96 | } | ||
97 | } | ||
98 | |||
85 | struct comm *thread__comm(const struct thread *thread) | 99 | struct comm *thread__comm(const struct thread *thread) |
86 | { | 100 | { |
87 | if (list_empty(&thread->comm_list)) | 101 | if (list_empty(&thread->comm_list)) |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 160fd066a7d1..783b6688d2f7 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -20,6 +20,7 @@ struct thread { | |||
20 | pid_t tid; | 20 | pid_t tid; |
21 | pid_t ppid; | 21 | pid_t ppid; |
22 | int cpu; | 22 | int cpu; |
23 | int refcnt; | ||
23 | char shortname[3]; | 24 | char shortname[3]; |
24 | bool comm_set; | 25 | bool comm_set; |
25 | bool dead; /* if set thread has exited */ | 26 | bool dead; /* if set thread has exited */ |
@@ -37,6 +38,18 @@ struct comm; | |||
37 | struct thread *thread__new(pid_t pid, pid_t tid); | 38 | struct thread *thread__new(pid_t pid, pid_t tid); |
38 | int thread__init_map_groups(struct thread *thread, struct machine *machine); | 39 | int thread__init_map_groups(struct thread *thread, struct machine *machine); |
39 | void thread__delete(struct thread *thread); | 40 | void thread__delete(struct thread *thread); |
41 | |||
42 | struct thread *thread__get(struct thread *thread); | ||
43 | void thread__put(struct thread *thread); | ||
44 | |||
45 | static inline void __thread__zput(struct thread **thread) | ||
46 | { | ||
47 | thread__put(*thread); | ||
48 | *thread = NULL; | ||
49 | } | ||
50 | |||
51 | #define thread__zput(thread) __thread__zput(&thread) | ||
52 | |||
40 | static inline void thread__exited(struct thread *thread) | 53 | static inline void thread__exited(struct thread *thread) |
41 | { | 54 | { |
42 | thread->dead = true; | 55 | thread->dead = true; |