aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/arch/arm64/include/asm/barrier.h133
-rw-r--r--tools/perf/Documentation/perf-list.txt1
-rw-r--r--tools/perf/Makefile.perf2
-rw-r--r--tools/perf/builtin-record.c7
-rw-r--r--tools/perf/builtin-stat.c28
-rw-r--r--tools/perf/builtin-top.c3
-rw-r--r--tools/perf/builtin-trace.c34
-rw-r--r--tools/perf/examples/bpf/augmented_raw_syscalls.c131
-rw-r--r--tools/perf/jvmti/jvmti_agent.c49
-rwxr-xr-xtools/perf/scripts/python/exported-sql-viewer.py493
-rw-r--r--tools/perf/tests/attr/test-record-group-sampling1
-rw-r--r--tools/perf/util/evlist.c27
-rw-r--r--tools/perf/util/evlist.h3
-rw-r--r--tools/perf/util/evsel.c1
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.c4
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-log.c5
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-log.h1
-rw-r--r--tools/perf/util/intel-pt.c16
-rw-r--r--tools/perf/util/pmu.c2
-rw-r--r--tools/testing/nvdimm/test/nfit.c8
-rw-r--r--tools/testing/selftests/powerpc/mm/wild_bctr.c21
21 files changed, 842 insertions, 128 deletions
diff --git a/tools/arch/arm64/include/asm/barrier.h b/tools/arch/arm64/include/asm/barrier.h
index 12835ea0e417..378c051fa177 100644
--- a/tools/arch/arm64/include/asm/barrier.h
+++ b/tools/arch/arm64/include/asm/barrier.h
@@ -14,74 +14,75 @@
14#define wmb() asm volatile("dmb ishst" ::: "memory") 14#define wmb() asm volatile("dmb ishst" ::: "memory")
15#define rmb() asm volatile("dmb ishld" ::: "memory") 15#define rmb() asm volatile("dmb ishld" ::: "memory")
16 16
17#define smp_store_release(p, v) \ 17#define smp_store_release(p, v) \
18do { \ 18do { \
19 union { typeof(*p) __val; char __c[1]; } __u = \ 19 union { typeof(*p) __val; char __c[1]; } __u = \
20 { .__val = (__force typeof(*p)) (v) }; \ 20 { .__val = (v) }; \
21 \ 21 \
22 switch (sizeof(*p)) { \ 22 switch (sizeof(*p)) { \
23 case 1: \ 23 case 1: \
24 asm volatile ("stlrb %w1, %0" \ 24 asm volatile ("stlrb %w1, %0" \
25 : "=Q" (*p) \ 25 : "=Q" (*p) \
26 : "r" (*(__u8 *)__u.__c) \ 26 : "r" (*(__u8_alias_t *)__u.__c) \
27 : "memory"); \ 27 : "memory"); \
28 break; \ 28 break; \
29 case 2: \ 29 case 2: \
30 asm volatile ("stlrh %w1, %0" \ 30 asm volatile ("stlrh %w1, %0" \
31 : "=Q" (*p) \ 31 : "=Q" (*p) \
32 : "r" (*(__u16 *)__u.__c) \ 32 : "r" (*(__u16_alias_t *)__u.__c) \
33 : "memory"); \ 33 : "memory"); \
34 break; \ 34 break; \
35 case 4: \ 35 case 4: \
36 asm volatile ("stlr %w1, %0" \ 36 asm volatile ("stlr %w1, %0" \
37 : "=Q" (*p) \ 37 : "=Q" (*p) \
38 : "r" (*(__u32 *)__u.__c) \ 38 : "r" (*(__u32_alias_t *)__u.__c) \
39 : "memory"); \ 39 : "memory"); \
40 break; \ 40 break; \
41 case 8: \ 41 case 8: \
42 asm volatile ("stlr %1, %0" \ 42 asm volatile ("stlr %1, %0" \
43 : "=Q" (*p) \ 43 : "=Q" (*p) \
44 : "r" (*(__u64 *)__u.__c) \ 44 : "r" (*(__u64_alias_t *)__u.__c) \
45 : "memory"); \ 45 : "memory"); \
46 break; \ 46 break; \
47 default: \ 47 default: \
48 /* Only to shut up gcc ... */ \ 48 /* Only to shut up gcc ... */ \
49 mb(); \ 49 mb(); \
50 break; \ 50 break; \
51 } \ 51 } \
52} while (0) 52} while (0)
53 53
54#define smp_load_acquire(p) \ 54#define smp_load_acquire(p) \
55({ \ 55({ \
56 union { typeof(*p) __val; char __c[1]; } __u; \ 56 union { typeof(*p) __val; char __c[1]; } __u = \
57 \ 57 { .__c = { 0 } }; \
58 switch (sizeof(*p)) { \ 58 \
59 case 1: \ 59 switch (sizeof(*p)) { \
60 asm volatile ("ldarb %w0, %1" \ 60 case 1: \
61 : "=r" (*(__u8 *)__u.__c) \ 61 asm volatile ("ldarb %w0, %1" \
62 : "Q" (*p) : "memory"); \ 62 : "=r" (*(__u8_alias_t *)__u.__c) \
63 break; \ 63 : "Q" (*p) : "memory"); \
64 case 2: \ 64 break; \
65 asm volatile ("ldarh %w0, %1" \ 65 case 2: \
66 : "=r" (*(__u16 *)__u.__c) \ 66 asm volatile ("ldarh %w0, %1" \
67 : "Q" (*p) : "memory"); \ 67 : "=r" (*(__u16_alias_t *)__u.__c) \
68 break; \ 68 : "Q" (*p) : "memory"); \
69 case 4: \ 69 break; \
70 asm volatile ("ldar %w0, %1" \ 70 case 4: \
71 : "=r" (*(__u32 *)__u.__c) \ 71 asm volatile ("ldar %w0, %1" \
72 : "Q" (*p) : "memory"); \ 72 : "=r" (*(__u32_alias_t *)__u.__c) \
73 break; \ 73 : "Q" (*p) : "memory"); \
74 case 8: \ 74 break; \
75 asm volatile ("ldar %0, %1" \ 75 case 8: \
76 : "=r" (*(__u64 *)__u.__c) \ 76 asm volatile ("ldar %0, %1" \
77 : "Q" (*p) : "memory"); \ 77 : "=r" (*(__u64_alias_t *)__u.__c) \
78 break; \ 78 : "Q" (*p) : "memory"); \
79 default: \ 79 break; \
80 /* Only to shut up gcc ... */ \ 80 default: \
81 mb(); \ 81 /* Only to shut up gcc ... */ \
82 break; \ 82 mb(); \
83 } \ 83 break; \
84 __u.__val; \ 84 } \
85 __u.__val; \
85}) 86})
86 87
87#endif /* _TOOLS_LINUX_ASM_AARCH64_BARRIER_H */ 88#endif /* _TOOLS_LINUX_ASM_AARCH64_BARRIER_H */
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 236b9b97dfdb..667c14e56031 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -55,7 +55,6 @@ counted. The following modifiers exist:
55 S - read sample value (PERF_SAMPLE_READ) 55 S - read sample value (PERF_SAMPLE_READ)
56 D - pin the event to the PMU 56 D - pin the event to the PMU
57 W - group is weak and will fallback to non-group if not schedulable, 57 W - group is weak and will fallback to non-group if not schedulable,
58 only supported in 'perf stat' for now.
59 58
60The 'p' modifier can be used for specifying how precise the instruction 59The 'p' modifier can be used for specifying how precise the instruction
61address should be. The 'p' modifier can be specified multiple times: 60address should be. The 'p' modifier can be specified multiple times:
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 3ccb4f0bf088..d95655489f7e 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -387,7 +387,7 @@ SHELL = $(SHELL_PATH)
387 387
388linux_uapi_dir := $(srctree)/tools/include/uapi/linux 388linux_uapi_dir := $(srctree)/tools/include/uapi/linux
389asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic 389asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic
390arch_asm_uapi_dir := $(srctree)/tools/arch/$(ARCH)/include/uapi/asm/ 390arch_asm_uapi_dir := $(srctree)/tools/arch/$(SRCARCH)/include/uapi/asm/
391 391
392beauty_outdir := $(OUTPUT)trace/beauty/generated 392beauty_outdir := $(OUTPUT)trace/beauty/generated
393beauty_ioctl_outdir := $(beauty_outdir)/ioctl 393beauty_ioctl_outdir := $(beauty_outdir)/ioctl
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 10cf889c6d75..488779bc4c8d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -391,7 +391,12 @@ try_again:
391 ui__warning("%s\n", msg); 391 ui__warning("%s\n", msg);
392 goto try_again; 392 goto try_again;
393 } 393 }
394 394 if ((errno == EINVAL || errno == EBADF) &&
395 pos->leader != pos &&
396 pos->weak_group) {
397 pos = perf_evlist__reset_weak_group(evlist, pos);
398 goto try_again;
399 }
395 rc = -errno; 400 rc = -errno;
396 perf_evsel__open_strerror(pos, &opts->target, 401 perf_evsel__open_strerror(pos, &opts->target,
397 errno, msg, sizeof(msg)); 402 errno, msg, sizeof(msg));
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index d1028d7755bb..a635abfa77b6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -383,32 +383,6 @@ static bool perf_evsel__should_store_id(struct perf_evsel *counter)
383 return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID; 383 return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID;
384} 384}
385 385
386static struct perf_evsel *perf_evsel__reset_weak_group(struct perf_evsel *evsel)
387{
388 struct perf_evsel *c2, *leader;
389 bool is_open = true;
390
391 leader = evsel->leader;
392 pr_debug("Weak group for %s/%d failed\n",
393 leader->name, leader->nr_members);
394
395 /*
396 * for_each_group_member doesn't work here because it doesn't
397 * include the first entry.
398 */
399 evlist__for_each_entry(evsel_list, c2) {
400 if (c2 == evsel)
401 is_open = false;
402 if (c2->leader == leader) {
403 if (is_open)
404 perf_evsel__close(c2);
405 c2->leader = c2;
406 c2->nr_members = 0;
407 }
408 }
409 return leader;
410}
411
412static bool is_target_alive(struct target *_target, 386static bool is_target_alive(struct target *_target,
413 struct thread_map *threads) 387 struct thread_map *threads)
414{ 388{
@@ -477,7 +451,7 @@ try_again:
477 if ((errno == EINVAL || errno == EBADF) && 451 if ((errno == EINVAL || errno == EBADF) &&
478 counter->leader != counter && 452 counter->leader != counter &&
479 counter->weak_group) { 453 counter->weak_group) {
480 counter = perf_evsel__reset_weak_group(counter); 454 counter = perf_evlist__reset_weak_group(evsel_list, counter);
481 goto try_again; 455 goto try_again;
482 } 456 }
483 457
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index b2838de13de0..aa0c73e57924 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1429,6 +1429,9 @@ int cmd_top(int argc, const char **argv)
1429 } 1429 }
1430 } 1430 }
1431 1431
1432 if (opts->branch_stack && callchain_param.enabled)
1433 symbol_conf.show_branchflag_count = true;
1434
1432 sort__mode = SORT_MODE__TOP; 1435 sort__mode = SORT_MODE__TOP;
1433 /* display thread wants entries to be collapsed in a different tree */ 1436 /* display thread wants entries to be collapsed in a different tree */
1434 perf_hpp_list.need_collapse = 1; 1437 perf_hpp_list.need_collapse = 1;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index dc8a6c4986ce..835619476370 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -108,6 +108,7 @@ struct trace {
108 } stats; 108 } stats;
109 unsigned int max_stack; 109 unsigned int max_stack;
110 unsigned int min_stack; 110 unsigned int min_stack;
111 bool raw_augmented_syscalls;
111 bool not_ev_qualifier; 112 bool not_ev_qualifier;
112 bool live; 113 bool live;
113 bool full_time; 114 bool full_time;
@@ -1724,13 +1725,28 @@ static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1724 return printed; 1725 return printed;
1725} 1726}
1726 1727
1727static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size) 1728static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, bool raw_augmented)
1728{ 1729{
1729 void *augmented_args = NULL; 1730 void *augmented_args = NULL;
1731 /*
1732 * For now with BPF raw_augmented we hook into raw_syscalls:sys_enter
1733 * and there we get all 6 syscall args plus the tracepoint common
1734 * fields (sizeof(long)) and the syscall_nr (another long). So we check
1735 * if that is the case and if so don't look after the sc->args_size,
1736 * but always after the full raw_syscalls:sys_enter payload, which is
1737 * fixed.
1738 *
1739 * We'll revisit this later to pass s->args_size to the BPF augmenter
1740 * (now tools/perf/examples/bpf/augmented_raw_syscalls.c, so that it
1741 * copies only what we need for each syscall, like what happens when we
1742 * use syscalls:sys_enter_NAME, so that we reduce the kernel/userspace
1743 * traffic to just what is needed for each syscall.
1744 */
1745 int args_size = raw_augmented ? (8 * (int)sizeof(long)) : sc->args_size;
1730 1746
1731 *augmented_args_size = sample->raw_size - sc->args_size; 1747 *augmented_args_size = sample->raw_size - args_size;
1732 if (*augmented_args_size > 0) 1748 if (*augmented_args_size > 0)
1733 augmented_args = sample->raw_data + sc->args_size; 1749 augmented_args = sample->raw_data + args_size;
1734 1750
1735 return augmented_args; 1751 return augmented_args;
1736} 1752}
@@ -1780,7 +1796,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1780 * here and avoid using augmented syscalls when the evsel is the raw_syscalls one. 1796 * here and avoid using augmented syscalls when the evsel is the raw_syscalls one.
1781 */ 1797 */
1782 if (evsel != trace->syscalls.events.sys_enter) 1798 if (evsel != trace->syscalls.events.sys_enter)
1783 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size); 1799 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls);
1784 ttrace->entry_time = sample->time; 1800 ttrace->entry_time = sample->time;
1785 msg = ttrace->entry_str; 1801 msg = ttrace->entry_str;
1786 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name); 1802 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
@@ -1833,7 +1849,7 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evse
1833 goto out_put; 1849 goto out_put;
1834 1850
1835 args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1851 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
1836 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size); 1852 augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls);
1837 syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread); 1853 syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
1838 fprintf(trace->output, "%s", msg); 1854 fprintf(trace->output, "%s", msg);
1839 err = 0; 1855 err = 0;
@@ -3501,7 +3517,15 @@ int cmd_trace(int argc, const char **argv)
3501 evsel->handler = trace__sys_enter; 3517 evsel->handler = trace__sys_enter;
3502 3518
3503 evlist__for_each_entry(trace.evlist, evsel) { 3519 evlist__for_each_entry(trace.evlist, evsel) {
3520 bool raw_syscalls_sys_exit = strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_exit") == 0;
3521
3522 if (raw_syscalls_sys_exit) {
3523 trace.raw_augmented_syscalls = true;
3524 goto init_augmented_syscall_tp;
3525 }
3526
3504 if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) { 3527 if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) {
3528init_augmented_syscall_tp:
3505 perf_evsel__init_augmented_syscall_tp(evsel); 3529 perf_evsel__init_augmented_syscall_tp(evsel);
3506 perf_evsel__init_augmented_syscall_tp_ret(evsel); 3530 perf_evsel__init_augmented_syscall_tp_ret(evsel);
3507 evsel->handler = trace__sys_exit; 3531 evsel->handler = trace__sys_exit;
diff --git a/tools/perf/examples/bpf/augmented_raw_syscalls.c b/tools/perf/examples/bpf/augmented_raw_syscalls.c
new file mode 100644
index 000000000000..90a19336310b
--- /dev/null
+++ b/tools/perf/examples/bpf/augmented_raw_syscalls.c
@@ -0,0 +1,131 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Augment the raw_syscalls tracepoints with the contents of the pointer arguments.
4 *
5 * Test it with:
6 *
7 * perf trace -e tools/perf/examples/bpf/augmented_raw_syscalls.c cat /etc/passwd > /dev/null
8 *
9 * This exactly matches what is marshalled into the raw_syscall:sys_enter
10 * payload expected by the 'perf trace' beautifiers.
11 *
12 * For now it just uses the existing tracepoint augmentation code in 'perf
13 * trace', in the next csets we'll hook up these with the sys_enter/sys_exit
14 * code that will combine entry/exit in a strace like way.
15 */
16
17#include <stdio.h>
18#include <linux/socket.h>
19
20/* bpf-output associated map */
21struct bpf_map SEC("maps") __augmented_syscalls__ = {
22 .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
23 .key_size = sizeof(int),
24 .value_size = sizeof(u32),
25 .max_entries = __NR_CPUS__,
26};
27
28struct syscall_enter_args {
29 unsigned long long common_tp_fields;
30 long syscall_nr;
31 unsigned long args[6];
32};
33
34struct syscall_exit_args {
35 unsigned long long common_tp_fields;
36 long syscall_nr;
37 long ret;
38};
39
40struct augmented_filename {
41 unsigned int size;
42 int reserved;
43 char value[256];
44};
45
46#define SYS_OPEN 2
47#define SYS_OPENAT 257
48
49SEC("raw_syscalls:sys_enter")
50int sys_enter(struct syscall_enter_args *args)
51{
52 struct {
53 struct syscall_enter_args args;
54 struct augmented_filename filename;
55 } augmented_args;
56 unsigned int len = sizeof(augmented_args);
57 const void *filename_arg = NULL;
58
59 probe_read(&augmented_args.args, sizeof(augmented_args.args), args);
60 /*
61 * Yonghong and Edward Cree sayz:
62 *
63 * https://www.spinics.net/lists/netdev/msg531645.html
64 *
65 * >> R0=inv(id=0) R1=inv2 R6=ctx(id=0,off=0,imm=0) R7=inv64 R10=fp0,call_-1
66 * >> 10: (bf) r1 = r6
67 * >> 11: (07) r1 += 16
68 * >> 12: (05) goto pc+2
69 * >> 15: (79) r3 = *(u64 *)(r1 +0)
70 * >> dereference of modified ctx ptr R1 off=16 disallowed
71 * > Aha, we at least got a different error message this time.
72 * > And indeed llvm has done that optimisation, rather than the more obvious
73 * > 11: r3 = *(u64 *)(r1 +16)
74 * > because it wants to have lots of reads share a single insn. You may be able
75 * > to defeat that optimisation by adding compiler barriers, idk. Maybe someone
76 * > with llvm knowledge can figure out how to stop it (ideally, llvm would know
77 * > when it's generating for bpf backend and not do that). -O0? ¯\_(ツ)_/¯
78 *
79 * The optimization mostly likes below:
80 *
81 * br1:
82 * ...
83 * r1 += 16
84 * goto merge
85 * br2:
86 * ...
87 * r1 += 20
88 * goto merge
89 * merge:
90 * *(u64 *)(r1 + 0)
91 *
92 * The compiler tries to merge common loads. There is no easy way to
93 * stop this compiler optimization without turning off a lot of other
94 * optimizations. The easiest way is to add barriers:
95 *
96 * __asm__ __volatile__("": : :"memory")
97 *
98 * after the ctx memory access to prevent their down stream merging.
99 */
100 switch (augmented_args.args.syscall_nr) {
101 case SYS_OPEN: filename_arg = (const void *)args->args[0];
102 __asm__ __volatile__("": : :"memory");
103 break;
104 case SYS_OPENAT: filename_arg = (const void *)args->args[1];
105 break;
106 }
107
108 if (filename_arg != NULL) {
109 augmented_args.filename.reserved = 0;
110 augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
111 sizeof(augmented_args.filename.value),
112 filename_arg);
113 if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) {
114 len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size;
115 len &= sizeof(augmented_args.filename.value) - 1;
116 }
117 } else {
118 len = sizeof(augmented_args.args);
119 }
120
121 perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len);
122 return 0;
123}
124
125SEC("raw_syscalls:sys_exit")
126int sys_exit(struct syscall_exit_args *args)
127{
128 return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */
129}
130
131license(GPL);
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
index ac1bcdc17dae..f7eb63cbbc65 100644
--- a/tools/perf/jvmti/jvmti_agent.c
+++ b/tools/perf/jvmti/jvmti_agent.c
@@ -125,7 +125,7 @@ perf_get_timestamp(void)
125} 125}
126 126
127static int 127static int
128debug_cache_init(void) 128create_jit_cache_dir(void)
129{ 129{
130 char str[32]; 130 char str[32];
131 char *base, *p; 131 char *base, *p;
@@ -144,8 +144,13 @@ debug_cache_init(void)
144 144
145 strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm); 145 strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm);
146 146
147 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base); 147 ret = snprintf(jit_path, PATH_MAX, "%s/.debug/", base);
148 148 if (ret >= PATH_MAX) {
149 warnx("jvmti: cannot generate jit cache dir because %s/.debug/"
150 " is too long, please check the cwd, JITDUMPDIR, and"
151 " HOME variables", base);
152 return -1;
153 }
149 ret = mkdir(jit_path, 0755); 154 ret = mkdir(jit_path, 0755);
150 if (ret == -1) { 155 if (ret == -1) {
151 if (errno != EEXIST) { 156 if (errno != EEXIST) {
@@ -154,20 +159,32 @@ debug_cache_init(void)
154 } 159 }
155 } 160 }
156 161
157 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base); 162 ret = snprintf(jit_path, PATH_MAX, "%s/.debug/jit", base);
163 if (ret >= PATH_MAX) {
164 warnx("jvmti: cannot generate jit cache dir because"
165 " %s/.debug/jit is too long, please check the cwd,"
166 " JITDUMPDIR, and HOME variables", base);
167 return -1;
168 }
158 ret = mkdir(jit_path, 0755); 169 ret = mkdir(jit_path, 0755);
159 if (ret == -1) { 170 if (ret == -1) {
160 if (errno != EEXIST) { 171 if (errno != EEXIST) {
161 warn("cannot create jit cache dir %s", jit_path); 172 warn("jvmti: cannot create jit cache dir %s", jit_path);
162 return -1; 173 return -1;
163 } 174 }
164 } 175 }
165 176
166 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str); 177 ret = snprintf(jit_path, PATH_MAX, "%s/.debug/jit/%s.XXXXXXXX", base, str);
167 178 if (ret >= PATH_MAX) {
179 warnx("jvmti: cannot generate jit cache dir because"
180 " %s/.debug/jit/%s.XXXXXXXX is too long, please check"
181 " the cwd, JITDUMPDIR, and HOME variables",
182 base, str);
183 return -1;
184 }
168 p = mkdtemp(jit_path); 185 p = mkdtemp(jit_path);
169 if (p != jit_path) { 186 if (p != jit_path) {
170 warn("cannot create jit cache dir %s", jit_path); 187 warn("jvmti: cannot create jit cache dir %s", jit_path);
171 return -1; 188 return -1;
172 } 189 }
173 190
@@ -228,7 +245,7 @@ void *jvmti_open(void)
228{ 245{
229 char dump_path[PATH_MAX]; 246 char dump_path[PATH_MAX];
230 struct jitheader header; 247 struct jitheader header;
231 int fd; 248 int fd, ret;
232 FILE *fp; 249 FILE *fp;
233 250
234 init_arch_timestamp(); 251 init_arch_timestamp();
@@ -245,12 +262,22 @@ void *jvmti_open(void)
245 262
246 memset(&header, 0, sizeof(header)); 263 memset(&header, 0, sizeof(header));
247 264
248 debug_cache_init(); 265 /*
266 * jitdump file dir
267 */
268 if (create_jit_cache_dir() < 0)
269 return NULL;
249 270
250 /* 271 /*
251 * jitdump file name 272 * jitdump file name
252 */ 273 */
253 scnprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid()); 274 ret = snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
275 if (ret >= PATH_MAX) {
276 warnx("jvmti: cannot generate jitdump file full path because"
277 " %s/jit-%i.dump is too long, please check the cwd,"
278 " JITDUMPDIR, and HOME variables", jit_path, getpid());
279 return NULL;
280 }
254 281
255 fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666); 282 fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
256 if (fd == -1) 283 if (fd == -1)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index 24cb0bd56afa..f278ce5ebab7 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -119,6 +119,14 @@ def dsoname(name):
119 return "[kernel]" 119 return "[kernel]"
120 return name 120 return name
121 121
122def findnth(s, sub, n, offs=0):
123 pos = s.find(sub)
124 if pos < 0:
125 return pos
126 if n <= 1:
127 return offs + pos
128 return findnth(s[pos + 1:], sub, n - 1, offs + pos + 1)
129
122# Percent to one decimal place 130# Percent to one decimal place
123 131
124def PercentToOneDP(n, d): 132def PercentToOneDP(n, d):
@@ -1464,6 +1472,317 @@ class BranchWindow(QMdiSubWindow):
1464 else: 1472 else:
1465 self.find_bar.NotFound() 1473 self.find_bar.NotFound()
1466 1474
1475# Dialog data item converted and validated using a SQL table
1476
1477class SQLTableDialogDataItem():
1478
1479 def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent):
1480 self.glb = glb
1481 self.label = label
1482 self.placeholder_text = placeholder_text
1483 self.table_name = table_name
1484 self.match_column = match_column
1485 self.column_name1 = column_name1
1486 self.column_name2 = column_name2
1487 self.parent = parent
1488
1489 self.value = ""
1490
1491 self.widget = QLineEdit()
1492 self.widget.editingFinished.connect(self.Validate)
1493 self.widget.textChanged.connect(self.Invalidate)
1494 self.red = False
1495 self.error = ""
1496 self.validated = True
1497
1498 self.last_id = 0
1499 self.first_time = 0
1500 self.last_time = 2 ** 64
1501 if self.table_name == "<timeranges>":
1502 query = QSqlQuery(self.glb.db)
1503 QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1")
1504 if query.next():
1505 self.last_id = int(query.value(0))
1506 self.last_time = int(query.value(1))
1507 QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1")
1508 if query.next():
1509 self.first_time = int(query.value(0))
1510 if placeholder_text:
1511 placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time)
1512
1513 if placeholder_text:
1514 self.widget.setPlaceholderText(placeholder_text)
1515
1516 def ValueToIds(self, value):
1517 ids = []
1518 query = QSqlQuery(self.glb.db)
1519 stmt = "SELECT id FROM " + self.table_name + " WHERE " + self.match_column + " = '" + value + "'"
1520 ret = query.exec_(stmt)
1521 if ret:
1522 while query.next():
1523 ids.append(str(query.value(0)))
1524 return ids
1525
1526 def IdBetween(self, query, lower_id, higher_id, order):
1527 QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1")
1528 if query.next():
1529 return True, int(query.value(0))
1530 else:
1531 return False, 0
1532
1533 def BinarySearchTime(self, lower_id, higher_id, target_time, get_floor):
1534 query = QSqlQuery(self.glb.db)
1535 while True:
1536 next_id = int((lower_id + higher_id) / 2)
1537 QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id))
1538 if not query.next():
1539 ok, dbid = self.IdBetween(query, lower_id, next_id, "DESC")
1540 if not ok:
1541 ok, dbid = self.IdBetween(query, next_id, higher_id, "")
1542 if not ok:
1543 return str(higher_id)
1544 next_id = dbid
1545 QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id))
1546 next_time = int(query.value(0))
1547 if get_floor:
1548 if target_time > next_time:
1549 lower_id = next_id
1550 else:
1551 higher_id = next_id
1552 if higher_id <= lower_id + 1:
1553 return str(higher_id)
1554 else:
1555 if target_time >= next_time:
1556 lower_id = next_id
1557 else:
1558 higher_id = next_id
1559 if higher_id <= lower_id + 1:
1560 return str(lower_id)
1561
1562 def ConvertRelativeTime(self, val):
1563 print "val ", val
1564 mult = 1
1565 suffix = val[-2:]
1566 if suffix == "ms":
1567 mult = 1000000
1568 elif suffix == "us":
1569 mult = 1000
1570 elif suffix == "ns":
1571 mult = 1
1572 else:
1573 return val
1574 val = val[:-2].strip()
1575 if not self.IsNumber(val):
1576 return val
1577 val = int(val) * mult
1578 if val >= 0:
1579 val += self.first_time
1580 else:
1581 val += self.last_time
1582 return str(val)
1583
1584 def ConvertTimeRange(self, vrange):
1585 print "vrange ", vrange
1586 if vrange[0] == "":
1587 vrange[0] = str(self.first_time)
1588 if vrange[1] == "":
1589 vrange[1] = str(self.last_time)
1590 vrange[0] = self.ConvertRelativeTime(vrange[0])
1591 vrange[1] = self.ConvertRelativeTime(vrange[1])
1592 print "vrange2 ", vrange
1593 if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):
1594 return False
1595 print "ok1"
1596 beg_range = max(int(vrange[0]), self.first_time)
1597 end_range = min(int(vrange[1]), self.last_time)
1598 if beg_range > self.last_time or end_range < self.first_time:
1599 return False
1600 print "ok2"
1601 vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True)
1602 vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False)
1603 print "vrange3 ", vrange
1604 return True
1605
1606 def AddTimeRange(self, value, ranges):
1607 print "value ", value
1608 n = value.count("-")
1609 if n == 1:
1610 pass
1611 elif n == 2:
1612 if value.split("-")[1].strip() == "":
1613 n = 1
1614 elif n == 3:
1615 n = 2
1616 else:
1617 return False
1618 pos = findnth(value, "-", n)
1619 vrange = [value[:pos].strip() ,value[pos+1:].strip()]
1620 if self.ConvertTimeRange(vrange):
1621 ranges.append(vrange)
1622 return True
1623 return False
1624
1625 def InvalidValue(self, value):
1626 self.value = ""
1627 palette = QPalette()
1628 palette.setColor(QPalette.Text,Qt.red)
1629 self.widget.setPalette(palette)
1630 self.red = True
1631 self.error = self.label + " invalid value '" + value + "'"
1632 self.parent.ShowMessage(self.error)
1633
1634 def IsNumber(self, value):
1635 try:
1636 x = int(value)
1637 except:
1638 x = 0
1639 return str(x) == value
1640
1641 def Invalidate(self):
1642 self.validated = False
1643
1644 def Validate(self):
1645 input_string = self.widget.text()
1646 self.validated = True
1647 if self.red:
1648 palette = QPalette()
1649 self.widget.setPalette(palette)
1650 self.red = False
1651 if not len(input_string.strip()):
1652 self.error = ""
1653 self.value = ""
1654 return
1655 if self.table_name == "<timeranges>":
1656 ranges = []
1657 for value in [x.strip() for x in input_string.split(",")]:
1658 if not self.AddTimeRange(value, ranges):
1659 return self.InvalidValue(value)
1660 ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges]
1661 self.value = " OR ".join(ranges)
1662 elif self.table_name == "<ranges>":
1663 singles = []
1664 ranges = []
1665 for value in [x.strip() for x in input_string.split(",")]:
1666 if "-" in value:
1667 vrange = value.split("-")
1668 if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):
1669 return self.InvalidValue(value)
1670 ranges.append(vrange)
1671 else:
1672 if not self.IsNumber(value):
1673 return self.InvalidValue(value)
1674 singles.append(value)
1675 ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges]
1676 if len(singles):
1677 ranges.append(self.column_name1 + " IN (" + ",".join(singles) + ")")
1678 self.value = " OR ".join(ranges)
1679 elif self.table_name:
1680 all_ids = []
1681 for value in [x.strip() for x in input_string.split(",")]:
1682 ids = self.ValueToIds(value)
1683 if len(ids):
1684 all_ids.extend(ids)
1685 else:
1686 return self.InvalidValue(value)
1687 self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")"
1688 if self.column_name2:
1689 self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )"
1690 else:
1691 self.value = input_string.strip()
1692 self.error = ""
1693 self.parent.ClearMessage()
1694
1695 def IsValid(self):
1696 if not self.validated:
1697 self.Validate()
1698 if len(self.error):
1699 self.parent.ShowMessage(self.error)
1700 return False
1701 return True
1702
1703# Selected branch report creation dialog
1704
1705class SelectedBranchDialog(QDialog):
1706
1707 def __init__(self, glb, parent=None):
1708 super(SelectedBranchDialog, self).__init__(parent)
1709
1710 self.glb = glb
1711
1712 self.name = ""
1713 self.where_clause = ""
1714
1715 self.setWindowTitle("Selected Branches")
1716 self.setMinimumWidth(600)
1717
1718 items = (
1719 ("Report name:", "Enter a name to appear in the window title bar", "", "", "", ""),
1720 ("Time ranges:", "Enter time ranges", "<timeranges>", "", "samples.id", ""),
1721 ("CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "<ranges>", "", "cpu", ""),
1722 ("Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", ""),
1723 ("PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", ""),
1724 ("TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", ""),
1725 ("DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id"),
1726 ("Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id"),
1727 ("Raw SQL clause: ", "Enter a raw SQL WHERE clause", "", "", "", ""),
1728 )
1729 self.data_items = [SQLTableDialogDataItem(glb, *x, parent=self) for x in items]
1730
1731 self.grid = QGridLayout()
1732
1733 for row in xrange(len(self.data_items)):
1734 self.grid.addWidget(QLabel(self.data_items[row].label), row, 0)
1735 self.grid.addWidget(self.data_items[row].widget, row, 1)
1736
1737 self.status = QLabel()
1738
1739 self.ok_button = QPushButton("Ok", self)
1740 self.ok_button.setDefault(True)
1741 self.ok_button.released.connect(self.Ok)
1742 self.ok_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
1743
1744 self.cancel_button = QPushButton("Cancel", self)
1745 self.cancel_button.released.connect(self.reject)
1746 self.cancel_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
1747
1748 self.hbox = QHBoxLayout()
1749 #self.hbox.addStretch()
1750 self.hbox.addWidget(self.status)
1751 self.hbox.addWidget(self.ok_button)
1752 self.hbox.addWidget(self.cancel_button)
1753
1754 self.vbox = QVBoxLayout()
1755 self.vbox.addLayout(self.grid)
1756 self.vbox.addLayout(self.hbox)
1757
1758 self.setLayout(self.vbox);
1759
1760 def Ok(self):
1761 self.name = self.data_items[0].value
1762 if not self.name:
1763 self.ShowMessage("Report name is required")
1764 return
1765 for d in self.data_items:
1766 if not d.IsValid():
1767 return
1768 for d in self.data_items[1:]:
1769 if len(d.value):
1770 if len(self.where_clause):
1771 self.where_clause += " AND "
1772 self.where_clause += d.value
1773 if len(self.where_clause):
1774 self.where_clause = " AND ( " + self.where_clause + " ) "
1775 else:
1776 self.ShowMessage("No selection")
1777 return
1778 self.accept()
1779
1780 def ShowMessage(self, msg):
1781 self.status.setText("<font color=#FF0000>" + msg)
1782
1783 def ClearMessage(self):
1784 self.status.setText("")
1785
1467# Event list 1786# Event list
1468 1787
1469def GetEventList(db): 1788def GetEventList(db):
@@ -1656,7 +1975,7 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
1656 def FindDone(self, row): 1975 def FindDone(self, row):
1657 self.find_bar.Idle() 1976 self.find_bar.Idle()
1658 if row >= 0: 1977 if row >= 0:
1659 self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) 1978 self.view.setCurrentIndex(self.model.mapFromSource(self.data_model.index(row, 0, QModelIndex())))
1660 else: 1979 else:
1661 self.find_bar.NotFound() 1980 self.find_bar.NotFound()
1662 1981
@@ -1765,6 +2084,149 @@ class WindowMenu():
1765 def setActiveSubWindow(self, nr): 2084 def setActiveSubWindow(self, nr):
1766 self.mdi_area.setActiveSubWindow(self.mdi_area.subWindowList()[nr - 1]) 2085 self.mdi_area.setActiveSubWindow(self.mdi_area.subWindowList()[nr - 1])
1767 2086
2087# Help text
2088
2089glb_help_text = """
2090<h1>Contents</h1>
2091<style>
2092p.c1 {
2093 text-indent: 40px;
2094}
2095p.c2 {
2096 text-indent: 80px;
2097}
2098}
2099</style>
2100<p class=c1><a href=#reports>1. Reports</a></p>
2101<p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p>
2102<p class=c2><a href=#allbranches>1.2 All branches</a></p>
2103<p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p>
2104<p class=c1><a href=#tables>2. Tables</a></p>
2105<h1 id=reports>1. Reports</h1>
2106<h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2>
2107The result is a GUI window with a tree representing a context-sensitive
2108call-graph. Expanding a couple of levels of the tree and adjusting column
2109widths to suit will display something like:
2110<pre>
2111 Call Graph: pt_example
2112Call Path Object Count Time(ns) Time(%) Branch Count Branch Count(%)
2113v- ls
2114 v- 2638:2638
2115 v- _start ld-2.19.so 1 10074071 100.0 211135 100.0
2116 |- unknown unknown 1 13198 0.1 1 0.0
2117 >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3
2118 >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3
2119 v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4
2120 >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1
2121 >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0
2122 >- __libc_csu_init ls 1 10354 0.1 10 0.0
2123 |- _setjmp libc-2.19.so 1 0 0.0 4 0.0
2124 v- main ls 1 8182043 99.6 180254 99.9
2125</pre>
2126<h3>Points to note:</h3>
2127<ul>
2128<li>The top level is a command name (comm)</li>
2129<li>The next level is a thread (pid:tid)</li>
2130<li>Subsequent levels are functions</li>
2131<li>'Count' is the number of calls</li>
2132<li>'Time' is the elapsed time until the function returns</li>
2133<li>Percentages are relative to the level above</li>
2134<li>'Branch Count' is the total number of branches for that function and all functions that it calls
2135</ul>
2136<h3>Find</h3>
2137Ctrl-F displays a Find bar which finds function names by either an exact match or a pattern match.
2138The pattern matching symbols are ? for any character and * for zero or more characters.
2139<h2 id=allbranches>1.2 All branches</h2>
2140The All branches report displays all branches in chronological order.
2141Not all data is fetched immediately. More records can be fetched using the Fetch bar provided.
2142<h3>Disassembly</h3>
2143Open a branch to display disassembly. This only works if:
2144<ol>
2145<li>The disassembler is available. Currently, only Intel XED is supported - see <a href=#xed>Intel XED Setup</a></li>
2146<li>The object code is available. Currently, only the perf build ID cache is searched for object code.
2147The default directory ~/.debug can be overridden by setting environment variable PERF_BUILDID_DIR.
2148One exception is kcore where the DSO long name is used (refer dsos_view on the Tables menu),
2149or alternatively, set environment variable PERF_KCORE to the kcore file name.</li>
2150</ol>
2151<h4 id=xed>Intel XED Setup</h4>
2152To use Intel XED, libxed.so must be present. To build and install libxed.so:
2153<pre>
2154git clone https://github.com/intelxed/mbuild.git mbuild
2155git clone https://github.com/intelxed/xed
2156cd xed
2157./mfile.py --share
2158sudo ./mfile.py --prefix=/usr/local install
2159sudo ldconfig
2160</pre>
2161<h3>Find</h3>
2162Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match.
2163Refer to Python documentation for the regular expression syntax.
2164All columns are searched, but only currently fetched rows are searched.
2165<h2 id=selectedbranches>1.3 Selected branches</h2>
2166This is the same as the <a href=#allbranches>All branches</a> report but with the data reduced
2167by various selection criteria. A dialog box displays available criteria which are AND'ed together.
2168<h3>1.3.1 Time ranges</h3>
2169The time ranges hint text shows the total time range. Relative time ranges can also be entered in
2170ms, us or ns. Also, negative values are relative to the end of trace. Examples:
2171<pre>
2172 81073085947329-81073085958238 From 81073085947329 to 81073085958238
2173 100us-200us From 100us to 200us
2174 10ms- From 10ms to the end
2175 -100ns The first 100ns
2176 -10ms- The last 10ms
2177</pre>
2178N.B. Due to the granularity of timestamps, there could be no branches in any given time range.
2179<h1 id=tables>2. Tables</h1>
2180The Tables menu shows all tables and views in the database. Most tables have an associated view
2181which displays the information in a more friendly way. Not all data for large tables is fetched
2182immediately. More records can be fetched using the Fetch bar provided. Columns can be sorted,
2183but that can be slow for large tables.
2184<p>There are also tables of database meta-information.
2185For SQLite3 databases, the sqlite_master table is included.
2186For PostgreSQL databases, information_schema.tables/views/columns are included.
2187<h3>Find</h3>
2188Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match.
2189Refer to Python documentation for the regular expression syntax.
2190All columns are searched, but only currently fetched rows are searched.
2191<p>N.B. Results are found in id order, so if the table is re-ordered, find-next and find-previous
2192will go to the next/previous result in id order, instead of display order.
2193"""
2194
2195# Help window
2196
2197class HelpWindow(QMdiSubWindow):
2198
2199 def __init__(self, glb, parent=None):
2200 super(HelpWindow, self).__init__(parent)
2201
2202 self.text = QTextBrowser()
2203 self.text.setHtml(glb_help_text)
2204 self.text.setReadOnly(True)
2205 self.text.setOpenExternalLinks(True)
2206
2207 self.setWidget(self.text)
2208
2209 AddSubWindow(glb.mainwindow.mdi_area, self, "Exported SQL Viewer Help")
2210
2211# Main window that only displays the help text
2212
2213class HelpOnlyWindow(QMainWindow):
2214
2215 def __init__(self, parent=None):
2216 super(HelpOnlyWindow, self).__init__(parent)
2217
2218 self.setMinimumSize(200, 100)
2219 self.resize(800, 600)
2220 self.setWindowTitle("Exported SQL Viewer Help")
2221 self.setWindowIcon(self.style().standardIcon(QStyle.SP_MessageBoxInformation))
2222
2223 self.text = QTextBrowser()
2224 self.text.setHtml(glb_help_text)
2225 self.text.setReadOnly(True)
2226 self.text.setOpenExternalLinks(True)
2227
2228 self.setCentralWidget(self.text)
2229
1768# Font resize 2230# Font resize
1769 2231
1770def ResizeFont(widget, diff): 2232def ResizeFont(widget, diff):
@@ -1851,6 +2313,9 @@ class MainWindow(QMainWindow):
1851 2313
1852 self.window_menu = WindowMenu(self.mdi_area, menu) 2314 self.window_menu = WindowMenu(self.mdi_area, menu)
1853 2315
2316 help_menu = menu.addMenu("&Help")
2317 help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents))
2318
1854 def Find(self): 2319 def Find(self):
1855 win = self.mdi_area.activeSubWindow() 2320 win = self.mdi_area.activeSubWindow()
1856 if win: 2321 if win:
@@ -1888,6 +2353,8 @@ class MainWindow(QMainWindow):
1888 if event == "branches": 2353 if event == "branches":
1889 label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")" 2354 label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")"
1890 reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self)) 2355 reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self))
2356 label = "Selected branches" if branches_events == 1 else "Selected branches " + "(id=" + dbid + ")"
2357 reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewSelectedBranchView(x), self))
1891 2358
1892 def TableMenu(self, tables, menu): 2359 def TableMenu(self, tables, menu):
1893 table_menu = menu.addMenu("&Tables") 2360 table_menu = menu.addMenu("&Tables")
@@ -1900,9 +2367,18 @@ class MainWindow(QMainWindow):
1900 def NewBranchView(self, event_id): 2367 def NewBranchView(self, event_id):
1901 BranchWindow(self.glb, event_id, "", "", self) 2368 BranchWindow(self.glb, event_id, "", "", self)
1902 2369
2370 def NewSelectedBranchView(self, event_id):
2371 dialog = SelectedBranchDialog(self.glb, self)
2372 ret = dialog.exec_()
2373 if ret:
2374 BranchWindow(self.glb, event_id, dialog.name, dialog.where_clause, self)
2375
1903 def NewTableView(self, table_name): 2376 def NewTableView(self, table_name):
1904 TableWindow(self.glb, table_name, self) 2377 TableWindow(self.glb, table_name, self)
1905 2378
2379 def Help(self):
2380 HelpWindow(self.glb, self)
2381
1906# XED Disassembler 2382# XED Disassembler
1907 2383
1908class xed_state_t(Structure): 2384class xed_state_t(Structure):
@@ -1929,7 +2405,12 @@ class XEDInstruction():
1929class LibXED(): 2405class LibXED():
1930 2406
1931 def __init__(self): 2407 def __init__(self):
1932 self.libxed = CDLL("libxed.so") 2408 try:
2409 self.libxed = CDLL("libxed.so")
2410 except:
2411 self.libxed = None
2412 if not self.libxed:
2413 self.libxed = CDLL("/usr/local/lib/libxed.so")
1933 2414
1934 self.xed_tables_init = self.libxed.xed_tables_init 2415 self.xed_tables_init = self.libxed.xed_tables_init
1935 self.xed_tables_init.restype = None 2416 self.xed_tables_init.restype = None
@@ -2097,10 +2578,16 @@ class DBRef():
2097 2578
2098def Main(): 2579def Main():
2099 if (len(sys.argv) < 2): 2580 if (len(sys.argv) < 2):
2100 print >> sys.stderr, "Usage is: exported-sql-viewer.py <database name>" 2581 print >> sys.stderr, "Usage is: exported-sql-viewer.py {<database name> | --help-only}"
2101 raise Exception("Too few arguments") 2582 raise Exception("Too few arguments")
2102 2583
2103 dbname = sys.argv[1] 2584 dbname = sys.argv[1]
2585 if dbname == "--help-only":
2586 app = QApplication(sys.argv)
2587 mainwindow = HelpOnlyWindow()
2588 mainwindow.show()
2589 err = app.exec_()
2590 sys.exit(err)
2104 2591
2105 is_sqlite3 = False 2592 is_sqlite3 = False
2106 try: 2593 try:
diff --git a/tools/perf/tests/attr/test-record-group-sampling b/tools/perf/tests/attr/test-record-group-sampling
index 8a33ca4f9e1f..f0729c454f16 100644
--- a/tools/perf/tests/attr/test-record-group-sampling
+++ b/tools/perf/tests/attr/test-record-group-sampling
@@ -37,4 +37,3 @@ sample_freq=0
37sample_period=0 37sample_period=0
38freq=0 38freq=0
39write_backward=0 39write_backward=0
40sample_id_all=0
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index e88e6f9b1463..668d2a9ef0f4 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1810,3 +1810,30 @@ void perf_evlist__force_leader(struct perf_evlist *evlist)
1810 leader->forced_leader = true; 1810 leader->forced_leader = true;
1811 } 1811 }
1812} 1812}
1813
1814struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
1815 struct perf_evsel *evsel)
1816{
1817 struct perf_evsel *c2, *leader;
1818 bool is_open = true;
1819
1820 leader = evsel->leader;
1821 pr_debug("Weak group for %s/%d failed\n",
1822 leader->name, leader->nr_members);
1823
1824 /*
1825 * for_each_group_member doesn't work here because it doesn't
1826 * include the first entry.
1827 */
1828 evlist__for_each_entry(evsel_list, c2) {
1829 if (c2 == evsel)
1830 is_open = false;
1831 if (c2->leader == leader) {
1832 if (is_open)
1833 perf_evsel__close(c2);
1834 c2->leader = c2;
1835 c2->nr_members = 0;
1836 }
1837 }
1838 return leader;
1839}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index dc66436add98..9919eed6d15b 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -312,4 +312,7 @@ bool perf_evlist__exclude_kernel(struct perf_evlist *evlist);
312 312
313void perf_evlist__force_leader(struct perf_evlist *evlist); 313void perf_evlist__force_leader(struct perf_evlist *evlist);
314 314
315struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist,
316 struct perf_evsel *evsel);
317
315#endif /* __PERF_EVLIST_H */ 318#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 6d187059a373..d37bb1566cd9 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -956,7 +956,6 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
956 attr->sample_freq = 0; 956 attr->sample_freq = 0;
957 attr->sample_period = 0; 957 attr->sample_period = 0;
958 attr->write_backward = 0; 958 attr->write_backward = 0;
959 attr->sample_id_all = 0;
960 } 959 }
961 960
962 if (opts->no_samples) 961 if (opts->no_samples)
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 58f6a9ceb590..4503f3ca45ab 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -1474,6 +1474,8 @@ static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder)
1474 decoder->have_calc_cyc_to_tsc = false; 1474 decoder->have_calc_cyc_to_tsc = false;
1475 intel_pt_calc_cyc_to_tsc(decoder, true); 1475 intel_pt_calc_cyc_to_tsc(decoder, true);
1476 } 1476 }
1477
1478 intel_pt_log_to("Setting timestamp", decoder->timestamp);
1477} 1479}
1478 1480
1479static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder) 1481static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder)
@@ -1514,6 +1516,8 @@ static void intel_pt_calc_cyc_timestamp(struct intel_pt_decoder *decoder)
1514 decoder->timestamp = timestamp; 1516 decoder->timestamp = timestamp;
1515 1517
1516 decoder->timestamp_insn_cnt = 0; 1518 decoder->timestamp_insn_cnt = 0;
1519
1520 intel_pt_log_to("Setting timestamp", decoder->timestamp);
1517} 1521}
1518 1522
1519/* Walk PSB+ packets when already in sync. */ 1523/* Walk PSB+ packets when already in sync. */
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.c b/tools/perf/util/intel-pt-decoder/intel-pt-log.c
index e02bc7b166a0..5e64da270f97 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-log.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.c
@@ -31,6 +31,11 @@ static FILE *f;
31static char log_name[MAX_LOG_NAME]; 31static char log_name[MAX_LOG_NAME];
32bool intel_pt_enable_logging; 32bool intel_pt_enable_logging;
33 33
34void *intel_pt_log_fp(void)
35{
36 return f;
37}
38
34void intel_pt_log_enable(void) 39void intel_pt_log_enable(void)
35{ 40{
36 intel_pt_enable_logging = true; 41 intel_pt_enable_logging = true;
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.h b/tools/perf/util/intel-pt-decoder/intel-pt-log.h
index 45b64f93f358..cc084937f701 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-log.h
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.h
@@ -22,6 +22,7 @@
22 22
23struct intel_pt_pkt; 23struct intel_pt_pkt;
24 24
25void *intel_pt_log_fp(void);
25void intel_pt_log_enable(void); 26void intel_pt_log_enable(void);
26void intel_pt_log_disable(void); 27void intel_pt_log_disable(void);
27void intel_pt_log_set_name(const char *name); 28void intel_pt_log_set_name(const char *name);
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index 86cc9a64e982..149ff361ca78 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -206,6 +206,16 @@ static void intel_pt_dump_event(struct intel_pt *pt, unsigned char *buf,
206 intel_pt_dump(pt, buf, len); 206 intel_pt_dump(pt, buf, len);
207} 207}
208 208
209static void intel_pt_log_event(union perf_event *event)
210{
211 FILE *f = intel_pt_log_fp();
212
213 if (!intel_pt_enable_logging || !f)
214 return;
215
216 perf_event__fprintf(event, f);
217}
218
209static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a, 219static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a,
210 struct auxtrace_buffer *b) 220 struct auxtrace_buffer *b)
211{ 221{
@@ -2010,9 +2020,9 @@ static int intel_pt_process_event(struct perf_session *session,
2010 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) 2020 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
2011 err = intel_pt_context_switch(pt, event, sample); 2021 err = intel_pt_context_switch(pt, event, sample);
2012 2022
2013 intel_pt_log("event %s (%u): cpu %d time %"PRIu64" tsc %#"PRIx64"\n", 2023 intel_pt_log("event %u: cpu %d time %"PRIu64" tsc %#"PRIx64" ",
2014 perf_event__name(event->header.type), event->header.type, 2024 event->header.type, sample->cpu, sample->time, timestamp);
2015 sample->cpu, sample->time, timestamp); 2025 intel_pt_log_event(event);
2016 2026
2017 return err; 2027 return err;
2018} 2028}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7799788f662f..7e49baad304d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -773,7 +773,7 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
773 773
774 if (!is_arm_pmu_core(name)) { 774 if (!is_arm_pmu_core(name)) {
775 pname = pe->pmu ? pe->pmu : "cpu"; 775 pname = pe->pmu ? pe->pmu : "cpu";
776 if (strncmp(pname, name, strlen(pname))) 776 if (strcmp(pname, name))
777 continue; 777 continue;
778 } 778 }
779 779
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 9527d47a1070..01ec04bf91b5 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -140,8 +140,8 @@ static u32 handle[] = {
140 [6] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 1), 140 [6] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 1),
141}; 141};
142 142
143static unsigned long dimm_fail_cmd_flags[NUM_DCR]; 143static unsigned long dimm_fail_cmd_flags[ARRAY_SIZE(handle)];
144static int dimm_fail_cmd_code[NUM_DCR]; 144static int dimm_fail_cmd_code[ARRAY_SIZE(handle)];
145 145
146static const struct nd_intel_smart smart_def = { 146static const struct nd_intel_smart smart_def = {
147 .flags = ND_INTEL_SMART_HEALTH_VALID 147 .flags = ND_INTEL_SMART_HEALTH_VALID
@@ -205,7 +205,7 @@ struct nfit_test {
205 unsigned long deadline; 205 unsigned long deadline;
206 spinlock_t lock; 206 spinlock_t lock;
207 } ars_state; 207 } ars_state;
208 struct device *dimm_dev[NUM_DCR]; 208 struct device *dimm_dev[ARRAY_SIZE(handle)];
209 struct nd_intel_smart *smart; 209 struct nd_intel_smart *smart;
210 struct nd_intel_smart_threshold *smart_threshold; 210 struct nd_intel_smart_threshold *smart_threshold;
211 struct badrange badrange; 211 struct badrange badrange;
@@ -2680,7 +2680,7 @@ static int nfit_test_probe(struct platform_device *pdev)
2680 u32 nfit_handle = __to_nfit_memdev(nfit_mem)->device_handle; 2680 u32 nfit_handle = __to_nfit_memdev(nfit_mem)->device_handle;
2681 int i; 2681 int i;
2682 2682
2683 for (i = 0; i < NUM_DCR; i++) 2683 for (i = 0; i < ARRAY_SIZE(handle); i++)
2684 if (nfit_handle == handle[i]) 2684 if (nfit_handle == handle[i])
2685 dev_set_drvdata(nfit_test->dimm_dev[i], 2685 dev_set_drvdata(nfit_test->dimm_dev[i],
2686 nfit_mem); 2686 nfit_mem);
diff --git a/tools/testing/selftests/powerpc/mm/wild_bctr.c b/tools/testing/selftests/powerpc/mm/wild_bctr.c
index 1b0e9e9a2ddc..f2fa101c5a6a 100644
--- a/tools/testing/selftests/powerpc/mm/wild_bctr.c
+++ b/tools/testing/selftests/powerpc/mm/wild_bctr.c
@@ -47,8 +47,9 @@ static int ok(void)
47 return 0; 47 return 0;
48} 48}
49 49
50#define REG_POISON 0x5a5aUL 50#define REG_POISON 0x5a5a
51#define POISONED_REG(n) ((REG_POISON << 48) | ((n) << 32) | (REG_POISON << 16) | (n)) 51#define POISONED_REG(n) ((((unsigned long)REG_POISON) << 48) | ((n) << 32) | \
52 (((unsigned long)REG_POISON) << 16) | (n))
52 53
53static inline void poison_regs(void) 54static inline void poison_regs(void)
54{ 55{
@@ -105,6 +106,20 @@ static void dump_regs(void)
105 } 106 }
106} 107}
107 108
109#ifdef _CALL_AIXDESC
110struct opd {
111 unsigned long ip;
112 unsigned long toc;
113 unsigned long env;
114};
115static struct opd bad_opd = {
116 .ip = BAD_NIP,
117};
118#define BAD_FUNC (&bad_opd)
119#else
120#define BAD_FUNC BAD_NIP
121#endif
122
108int test_wild_bctr(void) 123int test_wild_bctr(void)
109{ 124{
110 int (*func_ptr)(void); 125 int (*func_ptr)(void);
@@ -133,7 +148,7 @@ int test_wild_bctr(void)
133 148
134 poison_regs(); 149 poison_regs();
135 150
136 func_ptr = (int (*)(void))BAD_NIP; 151 func_ptr = (int (*)(void))BAD_FUNC;
137 func_ptr(); 152 func_ptr();
138 153
139 FAIL_IF(1); /* we didn't segv? */ 154 FAIL_IF(1); /* we didn't segv? */