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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf fixes from Thomas Gleixner:
"A bunch of perf tooling fixes:

- Make the Intel PT SQL viewer more robust

- Make the Intel PT debug log more useful

- Support weak groups in perf record so it's behaving the same way as
perf stat

- Display the LBR stats in callchain entries properly in perf top

- Handle different PMu names with common prefix properlin in pert
stat

- Start syscall augmenting in perf trace. Preparation for
architecture independent eBPF instrumentation of syscalls.

- Fix build breakage in JVMTI perf lib

- Fix arm64 tools build failure wrt smp_load_{acquire,release}"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
perf tools: Do not zero sample_id_all for group members
perf tools: Fix undefined symbol scnprintf in libperf-jvmti.so
perf beauty: Use SRCARCH, ARCH=x86_64 must map to "x86" to find the headers
perf intel-pt: Add MTC and CYC timestamps to debug log
perf intel-pt: Add more event information to debug log
perf scripts python: exported-sql-viewer.py: Fix table find when table re-ordered
perf scripts python: exported-sql-viewer.py: Add help window
perf scripts python: exported-sql-viewer.py: Add Selected branches report
perf scripts python: exported-sql-viewer.py: Fall back to /usr/local/lib/libxed.so
perf top: Display the LBR stats in callchain entry
perf stat: Handle different PMU names with common prefix
perf record: Support weak groups
perf evlist: Move perf_evsel__reset_weak_group into evlist
perf augmented_syscalls: Start collecting pathnames in the BPF program
perf trace: Fix setting of augmented payload when using eBPF + raw_syscalls
perf trace: When augmenting raw_syscalls plug raw_syscalls:sys_exit too
perf examples bpf: Start augmenting raw_syscalls:sys_{start,exit}
tools headers barrier: Fix arm64 tools build failure wrt smp_load_{acquire,release}

+820 -121
+67 -66
tools/arch/arm64/include/asm/barrier.h
··· 14 14 #define wmb() asm volatile("dmb ishst" ::: "memory") 15 15 #define rmb() asm volatile("dmb ishld" ::: "memory") 16 16 17 - #define smp_store_release(p, v) \ 18 - do { \ 19 - union { typeof(*p) __val; char __c[1]; } __u = \ 20 - { .__val = (__force typeof(*p)) (v) }; \ 21 - \ 22 - switch (sizeof(*p)) { \ 23 - case 1: \ 24 - asm volatile ("stlrb %w1, %0" \ 25 - : "=Q" (*p) \ 26 - : "r" (*(__u8 *)__u.__c) \ 27 - : "memory"); \ 28 - break; \ 29 - case 2: \ 30 - asm volatile ("stlrh %w1, %0" \ 31 - : "=Q" (*p) \ 32 - : "r" (*(__u16 *)__u.__c) \ 33 - : "memory"); \ 34 - break; \ 35 - case 4: \ 36 - asm volatile ("stlr %w1, %0" \ 37 - : "=Q" (*p) \ 38 - : "r" (*(__u32 *)__u.__c) \ 39 - : "memory"); \ 40 - break; \ 41 - case 8: \ 42 - asm volatile ("stlr %1, %0" \ 43 - : "=Q" (*p) \ 44 - : "r" (*(__u64 *)__u.__c) \ 45 - : "memory"); \ 46 - break; \ 47 - default: \ 48 - /* Only to shut up gcc ... */ \ 49 - mb(); \ 50 - break; \ 51 - } \ 17 + #define smp_store_release(p, v) \ 18 + do { \ 19 + union { typeof(*p) __val; char __c[1]; } __u = \ 20 + { .__val = (v) }; \ 21 + \ 22 + switch (sizeof(*p)) { \ 23 + case 1: \ 24 + asm volatile ("stlrb %w1, %0" \ 25 + : "=Q" (*p) \ 26 + : "r" (*(__u8_alias_t *)__u.__c) \ 27 + : "memory"); \ 28 + break; \ 29 + case 2: \ 30 + asm volatile ("stlrh %w1, %0" \ 31 + : "=Q" (*p) \ 32 + : "r" (*(__u16_alias_t *)__u.__c) \ 33 + : "memory"); \ 34 + break; \ 35 + case 4: \ 36 + asm volatile ("stlr %w1, %0" \ 37 + : "=Q" (*p) \ 38 + : "r" (*(__u32_alias_t *)__u.__c) \ 39 + : "memory"); \ 40 + break; \ 41 + case 8: \ 42 + asm volatile ("stlr %1, %0" \ 43 + : "=Q" (*p) \ 44 + : "r" (*(__u64_alias_t *)__u.__c) \ 45 + : "memory"); \ 46 + break; \ 47 + default: \ 48 + /* Only to shut up gcc ... */ \ 49 + mb(); \ 50 + break; \ 51 + } \ 52 52 } while (0) 53 53 54 - #define smp_load_acquire(p) \ 55 - ({ \ 56 - union { typeof(*p) __val; char __c[1]; } __u; \ 57 - \ 58 - switch (sizeof(*p)) { \ 59 - case 1: \ 60 - asm volatile ("ldarb %w0, %1" \ 61 - : "=r" (*(__u8 *)__u.__c) \ 62 - : "Q" (*p) : "memory"); \ 63 - break; \ 64 - case 2: \ 65 - asm volatile ("ldarh %w0, %1" \ 66 - : "=r" (*(__u16 *)__u.__c) \ 67 - : "Q" (*p) : "memory"); \ 68 - break; \ 69 - case 4: \ 70 - asm volatile ("ldar %w0, %1" \ 71 - : "=r" (*(__u32 *)__u.__c) \ 72 - : "Q" (*p) : "memory"); \ 73 - break; \ 74 - case 8: \ 75 - asm volatile ("ldar %0, %1" \ 76 - : "=r" (*(__u64 *)__u.__c) \ 77 - : "Q" (*p) : "memory"); \ 78 - break; \ 79 - default: \ 80 - /* Only to shut up gcc ... */ \ 81 - mb(); \ 82 - break; \ 83 - } \ 84 - __u.__val; \ 54 + #define smp_load_acquire(p) \ 55 + ({ \ 56 + union { typeof(*p) __val; char __c[1]; } __u = \ 57 + { .__c = { 0 } }; \ 58 + \ 59 + switch (sizeof(*p)) { \ 60 + case 1: \ 61 + asm volatile ("ldarb %w0, %1" \ 62 + : "=r" (*(__u8_alias_t *)__u.__c) \ 63 + : "Q" (*p) : "memory"); \ 64 + break; \ 65 + case 2: \ 66 + asm volatile ("ldarh %w0, %1" \ 67 + : "=r" (*(__u16_alias_t *)__u.__c) \ 68 + : "Q" (*p) : "memory"); \ 69 + break; \ 70 + case 4: \ 71 + asm volatile ("ldar %w0, %1" \ 72 + : "=r" (*(__u32_alias_t *)__u.__c) \ 73 + : "Q" (*p) : "memory"); \ 74 + break; \ 75 + case 8: \ 76 + asm volatile ("ldar %0, %1" \ 77 + : "=r" (*(__u64_alias_t *)__u.__c) \ 78 + : "Q" (*p) : "memory"); \ 79 + break; \ 80 + default: \ 81 + /* Only to shut up gcc ... */ \ 82 + mb(); \ 83 + break; \ 84 + } \ 85 + __u.__val; \ 85 86 }) 86 87 87 88 #endif /* _TOOLS_LINUX_ASM_AARCH64_BARRIER_H */
-1
tools/perf/Documentation/perf-list.txt
··· 55 55 S - read sample value (PERF_SAMPLE_READ) 56 56 D - pin the event to the PMU 57 57 W - group is weak and will fallback to non-group if not schedulable, 58 - only supported in 'perf stat' for now. 59 58 60 59 The 'p' modifier can be used for specifying how precise the instruction 61 60 address should be. The 'p' modifier can be specified multiple times:
+1 -1
tools/perf/Makefile.perf
··· 387 387 388 388 linux_uapi_dir := $(srctree)/tools/include/uapi/linux 389 389 asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic 390 - arch_asm_uapi_dir := $(srctree)/tools/arch/$(ARCH)/include/uapi/asm/ 390 + arch_asm_uapi_dir := $(srctree)/tools/arch/$(SRCARCH)/include/uapi/asm/ 391 391 392 392 beauty_outdir := $(OUTPUT)trace/beauty/generated 393 393 beauty_ioctl_outdir := $(beauty_outdir)/ioctl
+6 -1
tools/perf/builtin-record.c
··· 391 391 ui__warning("%s\n", msg); 392 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 400 rc = -errno; 396 401 perf_evsel__open_strerror(pos, &opts->target, 397 402 errno, msg, sizeof(msg));
+1 -27
tools/perf/builtin-stat.c
··· 383 383 return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID; 384 384 } 385 385 386 - static 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 - 412 386 static bool is_target_alive(struct target *_target, 413 387 struct thread_map *threads) 414 388 { ··· 451 477 if ((errno == EINVAL || errno == EBADF) && 452 478 counter->leader != counter && 453 479 counter->weak_group) { 454 - counter = perf_evsel__reset_weak_group(counter); 480 + counter = perf_evlist__reset_weak_group(evsel_list, counter); 455 481 goto try_again; 456 482 } 457 483
+3
tools/perf/builtin-top.c
··· 1429 1429 } 1430 1430 } 1431 1431 1432 + if (opts->branch_stack && callchain_param.enabled) 1433 + symbol_conf.show_branchflag_count = true; 1434 + 1432 1435 sort__mode = SORT_MODE__TOP; 1433 1436 /* display thread wants entries to be collapsed in a different tree */ 1434 1437 perf_hpp_list.need_collapse = 1;
+29 -5
tools/perf/builtin-trace.c
··· 108 108 } stats; 109 109 unsigned int max_stack; 110 110 unsigned int min_stack; 111 + bool raw_augmented_syscalls; 111 112 bool not_ev_qualifier; 112 113 bool live; 113 114 bool full_time; ··· 1725 1724 return printed; 1726 1725 } 1727 1726 1728 - static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size) 1727 + static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, bool raw_augmented) 1729 1728 { 1730 1729 void *augmented_args = NULL; 1730 + /* 1731 + * For now with BPF raw_augmented we hook into raw_syscalls:sys_enter 1732 + * and there we get all 6 syscall args plus the tracepoint common 1733 + * fields (sizeof(long)) and the syscall_nr (another long). So we check 1734 + * if that is the case and if so don't look after the sc->args_size, 1735 + * but always after the full raw_syscalls:sys_enter payload, which is 1736 + * fixed. 1737 + * 1738 + * We'll revisit this later to pass s->args_size to the BPF augmenter 1739 + * (now tools/perf/examples/bpf/augmented_raw_syscalls.c, so that it 1740 + * copies only what we need for each syscall, like what happens when we 1741 + * use syscalls:sys_enter_NAME, so that we reduce the kernel/userspace 1742 + * traffic to just what is needed for each syscall. 1743 + */ 1744 + int args_size = raw_augmented ? (8 * (int)sizeof(long)) : sc->args_size; 1731 1745 1732 - *augmented_args_size = sample->raw_size - sc->args_size; 1746 + *augmented_args_size = sample->raw_size - args_size; 1733 1747 if (*augmented_args_size > 0) 1734 - augmented_args = sample->raw_data + sc->args_size; 1748 + augmented_args = sample->raw_data + args_size; 1735 1749 1736 1750 return augmented_args; 1737 1751 } ··· 1796 1780 * here and avoid using augmented syscalls when the evsel is the raw_syscalls one. 1797 1781 */ 1798 1782 if (evsel != trace->syscalls.events.sys_enter) 1799 - augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size); 1783 + augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls); 1800 1784 ttrace->entry_time = sample->time; 1801 1785 msg = ttrace->entry_str; 1802 1786 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name); ··· 1849 1833 goto out_put; 1850 1834 1851 1835 args = perf_evsel__sc_tp_ptr(evsel, args, sample); 1852 - augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size); 1836 + augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls); 1853 1837 syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread); 1854 1838 fprintf(trace->output, "%s", msg); 1855 1839 err = 0; ··· 3517 3501 evsel->handler = trace__sys_enter; 3518 3502 3519 3503 evlist__for_each_entry(trace.evlist, evsel) { 3504 + bool raw_syscalls_sys_exit = strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_exit") == 0; 3505 + 3506 + if (raw_syscalls_sys_exit) { 3507 + trace.raw_augmented_syscalls = true; 3508 + goto init_augmented_syscall_tp; 3509 + } 3510 + 3520 3511 if (strstarts(perf_evsel__name(evsel), "syscalls:sys_exit_")) { 3512 + init_augmented_syscall_tp: 3521 3513 perf_evsel__init_augmented_syscall_tp(evsel); 3522 3514 perf_evsel__init_augmented_syscall_tp_ret(evsel); 3523 3515 evsel->handler = trace__sys_exit;
+131
tools/perf/examples/bpf/augmented_raw_syscalls.c
··· 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 */ 21 + struct 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 + 28 + struct syscall_enter_args { 29 + unsigned long long common_tp_fields; 30 + long syscall_nr; 31 + unsigned long args[6]; 32 + }; 33 + 34 + struct syscall_exit_args { 35 + unsigned long long common_tp_fields; 36 + long syscall_nr; 37 + long ret; 38 + }; 39 + 40 + struct 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 + 49 + SEC("raw_syscalls:sys_enter") 50 + int 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 + 125 + SEC("raw_syscalls:sys_exit") 126 + int 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 + 131 + license(GPL);
+38 -11
tools/perf/jvmti/jvmti_agent.c
··· 125 125 } 126 126 127 127 static int 128 - debug_cache_init(void) 128 + create_jit_cache_dir(void) 129 129 { 130 130 char str[32]; 131 131 char *base, *p; ··· 144 144 145 145 strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm); 146 146 147 - snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base); 148 - 147 + ret = snprintf(jit_path, PATH_MAX, "%s/.debug/", base); 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 154 ret = mkdir(jit_path, 0755); 150 155 if (ret == -1) { 151 156 if (errno != EEXIST) { ··· 159 154 } 160 155 } 161 156 162 - snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base); 157 + ret = snprintf(jit_path, PATH_MAX, "%s/.debug/jit", base); 158 + if (ret >= PATH_MAX) { 159 + warnx("jvmti: cannot generate jit cache dir because" 160 + " %s/.debug/jit is too long, please check the cwd," 161 + " JITDUMPDIR, and HOME variables", base); 162 + return -1; 163 + } 163 164 ret = mkdir(jit_path, 0755); 164 165 if (ret == -1) { 165 166 if (errno != EEXIST) { 166 - warn("cannot create jit cache dir %s", jit_path); 167 + warn("jvmti: cannot create jit cache dir %s", jit_path); 167 168 return -1; 168 169 } 169 170 } 170 171 171 - snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str); 172 - 172 + ret = snprintf(jit_path, PATH_MAX, "%s/.debug/jit/%s.XXXXXXXX", base, str); 173 + if (ret >= PATH_MAX) { 174 + warnx("jvmti: cannot generate jit cache dir because" 175 + " %s/.debug/jit/%s.XXXXXXXX is too long, please check" 176 + " the cwd, JITDUMPDIR, and HOME variables", 177 + base, str); 178 + return -1; 179 + } 173 180 p = mkdtemp(jit_path); 174 181 if (p != jit_path) { 175 - warn("cannot create jit cache dir %s", jit_path); 182 + warn("jvmti: cannot create jit cache dir %s", jit_path); 176 183 return -1; 177 184 } 178 185 ··· 245 228 { 246 229 char dump_path[PATH_MAX]; 247 230 struct jitheader header; 248 - int fd; 231 + int fd, ret; 249 232 FILE *fp; 250 233 251 234 init_arch_timestamp(); ··· 262 245 263 246 memset(&header, 0, sizeof(header)); 264 247 265 - debug_cache_init(); 248 + /* 249 + * jitdump file dir 250 + */ 251 + if (create_jit_cache_dir() < 0) 252 + return NULL; 266 253 267 254 /* 268 255 * jitdump file name 269 256 */ 270 - scnprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid()); 257 + ret = snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid()); 258 + if (ret >= PATH_MAX) { 259 + warnx("jvmti: cannot generate jitdump file full path because" 260 + " %s/jit-%i.dump is too long, please check the cwd," 261 + " JITDUMPDIR, and HOME variables", jit_path, getpid()); 262 + return NULL; 263 + } 271 264 272 265 fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666); 273 266 if (fd == -1)
+490 -3
tools/perf/scripts/python/exported-sql-viewer.py
··· 119 119 return "[kernel]" 120 120 return name 121 121 122 + def 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 130 # Percent to one decimal place 123 131 124 132 def PercentToOneDP(n, d): ··· 1472 1464 else: 1473 1465 self.find_bar.NotFound() 1474 1466 1467 + # Dialog data item converted and validated using a SQL table 1468 + 1469 + class SQLTableDialogDataItem(): 1470 + 1471 + def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent): 1472 + self.glb = glb 1473 + self.label = label 1474 + self.placeholder_text = placeholder_text 1475 + self.table_name = table_name 1476 + self.match_column = match_column 1477 + self.column_name1 = column_name1 1478 + self.column_name2 = column_name2 1479 + self.parent = parent 1480 + 1481 + self.value = "" 1482 + 1483 + self.widget = QLineEdit() 1484 + self.widget.editingFinished.connect(self.Validate) 1485 + self.widget.textChanged.connect(self.Invalidate) 1486 + self.red = False 1487 + self.error = "" 1488 + self.validated = True 1489 + 1490 + self.last_id = 0 1491 + self.first_time = 0 1492 + self.last_time = 2 ** 64 1493 + if self.table_name == "<timeranges>": 1494 + query = QSqlQuery(self.glb.db) 1495 + QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1") 1496 + if query.next(): 1497 + self.last_id = int(query.value(0)) 1498 + self.last_time = int(query.value(1)) 1499 + QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1") 1500 + if query.next(): 1501 + self.first_time = int(query.value(0)) 1502 + if placeholder_text: 1503 + placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time) 1504 + 1505 + if placeholder_text: 1506 + self.widget.setPlaceholderText(placeholder_text) 1507 + 1508 + def ValueToIds(self, value): 1509 + ids = [] 1510 + query = QSqlQuery(self.glb.db) 1511 + stmt = "SELECT id FROM " + self.table_name + " WHERE " + self.match_column + " = '" + value + "'" 1512 + ret = query.exec_(stmt) 1513 + if ret: 1514 + while query.next(): 1515 + ids.append(str(query.value(0))) 1516 + return ids 1517 + 1518 + def IdBetween(self, query, lower_id, higher_id, order): 1519 + QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1") 1520 + if query.next(): 1521 + return True, int(query.value(0)) 1522 + else: 1523 + return False, 0 1524 + 1525 + def BinarySearchTime(self, lower_id, higher_id, target_time, get_floor): 1526 + query = QSqlQuery(self.glb.db) 1527 + while True: 1528 + next_id = int((lower_id + higher_id) / 2) 1529 + QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) 1530 + if not query.next(): 1531 + ok, dbid = self.IdBetween(query, lower_id, next_id, "DESC") 1532 + if not ok: 1533 + ok, dbid = self.IdBetween(query, next_id, higher_id, "") 1534 + if not ok: 1535 + return str(higher_id) 1536 + next_id = dbid 1537 + QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) 1538 + next_time = int(query.value(0)) 1539 + if get_floor: 1540 + if target_time > next_time: 1541 + lower_id = next_id 1542 + else: 1543 + higher_id = next_id 1544 + if higher_id <= lower_id + 1: 1545 + return str(higher_id) 1546 + else: 1547 + if target_time >= next_time: 1548 + lower_id = next_id 1549 + else: 1550 + higher_id = next_id 1551 + if higher_id <= lower_id + 1: 1552 + return str(lower_id) 1553 + 1554 + def ConvertRelativeTime(self, val): 1555 + print "val ", val 1556 + mult = 1 1557 + suffix = val[-2:] 1558 + if suffix == "ms": 1559 + mult = 1000000 1560 + elif suffix == "us": 1561 + mult = 1000 1562 + elif suffix == "ns": 1563 + mult = 1 1564 + else: 1565 + return val 1566 + val = val[:-2].strip() 1567 + if not self.IsNumber(val): 1568 + return val 1569 + val = int(val) * mult 1570 + if val >= 0: 1571 + val += self.first_time 1572 + else: 1573 + val += self.last_time 1574 + return str(val) 1575 + 1576 + def ConvertTimeRange(self, vrange): 1577 + print "vrange ", vrange 1578 + if vrange[0] == "": 1579 + vrange[0] = str(self.first_time) 1580 + if vrange[1] == "": 1581 + vrange[1] = str(self.last_time) 1582 + vrange[0] = self.ConvertRelativeTime(vrange[0]) 1583 + vrange[1] = self.ConvertRelativeTime(vrange[1]) 1584 + print "vrange2 ", vrange 1585 + if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): 1586 + return False 1587 + print "ok1" 1588 + beg_range = max(int(vrange[0]), self.first_time) 1589 + end_range = min(int(vrange[1]), self.last_time) 1590 + if beg_range > self.last_time or end_range < self.first_time: 1591 + return False 1592 + print "ok2" 1593 + vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True) 1594 + vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False) 1595 + print "vrange3 ", vrange 1596 + return True 1597 + 1598 + def AddTimeRange(self, value, ranges): 1599 + print "value ", value 1600 + n = value.count("-") 1601 + if n == 1: 1602 + pass 1603 + elif n == 2: 1604 + if value.split("-")[1].strip() == "": 1605 + n = 1 1606 + elif n == 3: 1607 + n = 2 1608 + else: 1609 + return False 1610 + pos = findnth(value, "-", n) 1611 + vrange = [value[:pos].strip() ,value[pos+1:].strip()] 1612 + if self.ConvertTimeRange(vrange): 1613 + ranges.append(vrange) 1614 + return True 1615 + return False 1616 + 1617 + def InvalidValue(self, value): 1618 + self.value = "" 1619 + palette = QPalette() 1620 + palette.setColor(QPalette.Text,Qt.red) 1621 + self.widget.setPalette(palette) 1622 + self.red = True 1623 + self.error = self.label + " invalid value '" + value + "'" 1624 + self.parent.ShowMessage(self.error) 1625 + 1626 + def IsNumber(self, value): 1627 + try: 1628 + x = int(value) 1629 + except: 1630 + x = 0 1631 + return str(x) == value 1632 + 1633 + def Invalidate(self): 1634 + self.validated = False 1635 + 1636 + def Validate(self): 1637 + input_string = self.widget.text() 1638 + self.validated = True 1639 + if self.red: 1640 + palette = QPalette() 1641 + self.widget.setPalette(palette) 1642 + self.red = False 1643 + if not len(input_string.strip()): 1644 + self.error = "" 1645 + self.value = "" 1646 + return 1647 + if self.table_name == "<timeranges>": 1648 + ranges = [] 1649 + for value in [x.strip() for x in input_string.split(",")]: 1650 + if not self.AddTimeRange(value, ranges): 1651 + return self.InvalidValue(value) 1652 + ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges] 1653 + self.value = " OR ".join(ranges) 1654 + elif self.table_name == "<ranges>": 1655 + singles = [] 1656 + ranges = [] 1657 + for value in [x.strip() for x in input_string.split(",")]: 1658 + if "-" in value: 1659 + vrange = value.split("-") 1660 + if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): 1661 + return self.InvalidValue(value) 1662 + ranges.append(vrange) 1663 + else: 1664 + if not self.IsNumber(value): 1665 + return self.InvalidValue(value) 1666 + singles.append(value) 1667 + ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges] 1668 + if len(singles): 1669 + ranges.append(self.column_name1 + " IN (" + ",".join(singles) + ")") 1670 + self.value = " OR ".join(ranges) 1671 + elif self.table_name: 1672 + all_ids = [] 1673 + for value in [x.strip() for x in input_string.split(",")]: 1674 + ids = self.ValueToIds(value) 1675 + if len(ids): 1676 + all_ids.extend(ids) 1677 + else: 1678 + return self.InvalidValue(value) 1679 + self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")" 1680 + if self.column_name2: 1681 + self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )" 1682 + else: 1683 + self.value = input_string.strip() 1684 + self.error = "" 1685 + self.parent.ClearMessage() 1686 + 1687 + def IsValid(self): 1688 + if not self.validated: 1689 + self.Validate() 1690 + if len(self.error): 1691 + self.parent.ShowMessage(self.error) 1692 + return False 1693 + return True 1694 + 1695 + # Selected branch report creation dialog 1696 + 1697 + class SelectedBranchDialog(QDialog): 1698 + 1699 + def __init__(self, glb, parent=None): 1700 + super(SelectedBranchDialog, self).__init__(parent) 1701 + 1702 + self.glb = glb 1703 + 1704 + self.name = "" 1705 + self.where_clause = "" 1706 + 1707 + self.setWindowTitle("Selected Branches") 1708 + self.setMinimumWidth(600) 1709 + 1710 + items = ( 1711 + ("Report name:", "Enter a name to appear in the window title bar", "", "", "", ""), 1712 + ("Time ranges:", "Enter time ranges", "<timeranges>", "", "samples.id", ""), 1713 + ("CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "<ranges>", "", "cpu", ""), 1714 + ("Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", ""), 1715 + ("PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", ""), 1716 + ("TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", ""), 1717 + ("DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id"), 1718 + ("Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id"), 1719 + ("Raw SQL clause: ", "Enter a raw SQL WHERE clause", "", "", "", ""), 1720 + ) 1721 + self.data_items = [SQLTableDialogDataItem(glb, *x, parent=self) for x in items] 1722 + 1723 + self.grid = QGridLayout() 1724 + 1725 + for row in xrange(len(self.data_items)): 1726 + self.grid.addWidget(QLabel(self.data_items[row].label), row, 0) 1727 + self.grid.addWidget(self.data_items[row].widget, row, 1) 1728 + 1729 + self.status = QLabel() 1730 + 1731 + self.ok_button = QPushButton("Ok", self) 1732 + self.ok_button.setDefault(True) 1733 + self.ok_button.released.connect(self.Ok) 1734 + self.ok_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 1735 + 1736 + self.cancel_button = QPushButton("Cancel", self) 1737 + self.cancel_button.released.connect(self.reject) 1738 + self.cancel_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 1739 + 1740 + self.hbox = QHBoxLayout() 1741 + #self.hbox.addStretch() 1742 + self.hbox.addWidget(self.status) 1743 + self.hbox.addWidget(self.ok_button) 1744 + self.hbox.addWidget(self.cancel_button) 1745 + 1746 + self.vbox = QVBoxLayout() 1747 + self.vbox.addLayout(self.grid) 1748 + self.vbox.addLayout(self.hbox) 1749 + 1750 + self.setLayout(self.vbox); 1751 + 1752 + def Ok(self): 1753 + self.name = self.data_items[0].value 1754 + if not self.name: 1755 + self.ShowMessage("Report name is required") 1756 + return 1757 + for d in self.data_items: 1758 + if not d.IsValid(): 1759 + return 1760 + for d in self.data_items[1:]: 1761 + if len(d.value): 1762 + if len(self.where_clause): 1763 + self.where_clause += " AND " 1764 + self.where_clause += d.value 1765 + if len(self.where_clause): 1766 + self.where_clause = " AND ( " + self.where_clause + " ) " 1767 + else: 1768 + self.ShowMessage("No selection") 1769 + return 1770 + self.accept() 1771 + 1772 + def ShowMessage(self, msg): 1773 + self.status.setText("<font color=#FF0000>" + msg) 1774 + 1775 + def ClearMessage(self): 1776 + self.status.setText("") 1777 + 1475 1778 # Event list 1476 1779 1477 1780 def GetEventList(db): ··· 1975 1656 def FindDone(self, row): 1976 1657 self.find_bar.Idle() 1977 1658 if row >= 0: 1978 - self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) 1659 + self.view.setCurrentIndex(self.model.mapFromSource(self.data_model.index(row, 0, QModelIndex()))) 1979 1660 else: 1980 1661 self.find_bar.NotFound() 1981 1662 ··· 2084 1765 def setActiveSubWindow(self, nr): 2085 1766 self.mdi_area.setActiveSubWindow(self.mdi_area.subWindowList()[nr - 1]) 2086 1767 1768 + # Help text 1769 + 1770 + glb_help_text = """ 1771 + <h1>Contents</h1> 1772 + <style> 1773 + p.c1 { 1774 + text-indent: 40px; 1775 + } 1776 + p.c2 { 1777 + text-indent: 80px; 1778 + } 1779 + } 1780 + </style> 1781 + <p class=c1><a href=#reports>1. Reports</a></p> 1782 + <p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p> 1783 + <p class=c2><a href=#allbranches>1.2 All branches</a></p> 1784 + <p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p> 1785 + <p class=c1><a href=#tables>2. Tables</a></p> 1786 + <h1 id=reports>1. Reports</h1> 1787 + <h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2> 1788 + The result is a GUI window with a tree representing a context-sensitive 1789 + call-graph. Expanding a couple of levels of the tree and adjusting column 1790 + widths to suit will display something like: 1791 + <pre> 1792 + Call Graph: pt_example 1793 + Call Path Object Count Time(ns) Time(%) Branch Count Branch Count(%) 1794 + v- ls 1795 + v- 2638:2638 1796 + v- _start ld-2.19.so 1 10074071 100.0 211135 100.0 1797 + |- unknown unknown 1 13198 0.1 1 0.0 1798 + >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3 1799 + >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3 1800 + v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4 1801 + >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1 1802 + >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0 1803 + >- __libc_csu_init ls 1 10354 0.1 10 0.0 1804 + |- _setjmp libc-2.19.so 1 0 0.0 4 0.0 1805 + v- main ls 1 8182043 99.6 180254 99.9 1806 + </pre> 1807 + <h3>Points to note:</h3> 1808 + <ul> 1809 + <li>The top level is a command name (comm)</li> 1810 + <li>The next level is a thread (pid:tid)</li> 1811 + <li>Subsequent levels are functions</li> 1812 + <li>'Count' is the number of calls</li> 1813 + <li>'Time' is the elapsed time until the function returns</li> 1814 + <li>Percentages are relative to the level above</li> 1815 + <li>'Branch Count' is the total number of branches for that function and all functions that it calls 1816 + </ul> 1817 + <h3>Find</h3> 1818 + Ctrl-F displays a Find bar which finds function names by either an exact match or a pattern match. 1819 + The pattern matching symbols are ? for any character and * for zero or more characters. 1820 + <h2 id=allbranches>1.2 All branches</h2> 1821 + The All branches report displays all branches in chronological order. 1822 + Not all data is fetched immediately. More records can be fetched using the Fetch bar provided. 1823 + <h3>Disassembly</h3> 1824 + Open a branch to display disassembly. This only works if: 1825 + <ol> 1826 + <li>The disassembler is available. Currently, only Intel XED is supported - see <a href=#xed>Intel XED Setup</a></li> 1827 + <li>The object code is available. Currently, only the perf build ID cache is searched for object code. 1828 + The default directory ~/.debug can be overridden by setting environment variable PERF_BUILDID_DIR. 1829 + One exception is kcore where the DSO long name is used (refer dsos_view on the Tables menu), 1830 + or alternatively, set environment variable PERF_KCORE to the kcore file name.</li> 1831 + </ol> 1832 + <h4 id=xed>Intel XED Setup</h4> 1833 + To use Intel XED, libxed.so must be present. To build and install libxed.so: 1834 + <pre> 1835 + git clone https://github.com/intelxed/mbuild.git mbuild 1836 + git clone https://github.com/intelxed/xed 1837 + cd xed 1838 + ./mfile.py --share 1839 + sudo ./mfile.py --prefix=/usr/local install 1840 + sudo ldconfig 1841 + </pre> 1842 + <h3>Find</h3> 1843 + Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. 1844 + Refer to Python documentation for the regular expression syntax. 1845 + All columns are searched, but only currently fetched rows are searched. 1846 + <h2 id=selectedbranches>1.3 Selected branches</h2> 1847 + This is the same as the <a href=#allbranches>All branches</a> report but with the data reduced 1848 + by various selection criteria. A dialog box displays available criteria which are AND'ed together. 1849 + <h3>1.3.1 Time ranges</h3> 1850 + The time ranges hint text shows the total time range. Relative time ranges can also be entered in 1851 + ms, us or ns. Also, negative values are relative to the end of trace. Examples: 1852 + <pre> 1853 + 81073085947329-81073085958238 From 81073085947329 to 81073085958238 1854 + 100us-200us From 100us to 200us 1855 + 10ms- From 10ms to the end 1856 + -100ns The first 100ns 1857 + -10ms- The last 10ms 1858 + </pre> 1859 + N.B. Due to the granularity of timestamps, there could be no branches in any given time range. 1860 + <h1 id=tables>2. Tables</h1> 1861 + The Tables menu shows all tables and views in the database. Most tables have an associated view 1862 + which displays the information in a more friendly way. Not all data for large tables is fetched 1863 + immediately. More records can be fetched using the Fetch bar provided. Columns can be sorted, 1864 + but that can be slow for large tables. 1865 + <p>There are also tables of database meta-information. 1866 + For SQLite3 databases, the sqlite_master table is included. 1867 + For PostgreSQL databases, information_schema.tables/views/columns are included. 1868 + <h3>Find</h3> 1869 + Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. 1870 + Refer to Python documentation for the regular expression syntax. 1871 + All columns are searched, but only currently fetched rows are searched. 1872 + <p>N.B. Results are found in id order, so if the table is re-ordered, find-next and find-previous 1873 + will go to the next/previous result in id order, instead of display order. 1874 + """ 1875 + 1876 + # Help window 1877 + 1878 + class HelpWindow(QMdiSubWindow): 1879 + 1880 + def __init__(self, glb, parent=None): 1881 + super(HelpWindow, self).__init__(parent) 1882 + 1883 + self.text = QTextBrowser() 1884 + self.text.setHtml(glb_help_text) 1885 + self.text.setReadOnly(True) 1886 + self.text.setOpenExternalLinks(True) 1887 + 1888 + self.setWidget(self.text) 1889 + 1890 + AddSubWindow(glb.mainwindow.mdi_area, self, "Exported SQL Viewer Help") 1891 + 1892 + # Main window that only displays the help text 1893 + 1894 + class HelpOnlyWindow(QMainWindow): 1895 + 1896 + def __init__(self, parent=None): 1897 + super(HelpOnlyWindow, self).__init__(parent) 1898 + 1899 + self.setMinimumSize(200, 100) 1900 + self.resize(800, 600) 1901 + self.setWindowTitle("Exported SQL Viewer Help") 1902 + self.setWindowIcon(self.style().standardIcon(QStyle.SP_MessageBoxInformation)) 1903 + 1904 + self.text = QTextBrowser() 1905 + self.text.setHtml(glb_help_text) 1906 + self.text.setReadOnly(True) 1907 + self.text.setOpenExternalLinks(True) 1908 + 1909 + self.setCentralWidget(self.text) 1910 + 2087 1911 # Font resize 2088 1912 2089 1913 def ResizeFont(widget, diff): ··· 2313 1851 2314 1852 self.window_menu = WindowMenu(self.mdi_area, menu) 2315 1853 1854 + help_menu = menu.addMenu("&Help") 1855 + help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents)) 1856 + 2316 1857 def Find(self): 2317 1858 win = self.mdi_area.activeSubWindow() 2318 1859 if win: ··· 2353 1888 if event == "branches": 2354 1889 label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")" 2355 1890 reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self)) 1891 + label = "Selected branches" if branches_events == 1 else "Selected branches " + "(id=" + dbid + ")" 1892 + reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewSelectedBranchView(x), self)) 2356 1893 2357 1894 def TableMenu(self, tables, menu): 2358 1895 table_menu = menu.addMenu("&Tables") ··· 2367 1900 def NewBranchView(self, event_id): 2368 1901 BranchWindow(self.glb, event_id, "", "", self) 2369 1902 1903 + def NewSelectedBranchView(self, event_id): 1904 + dialog = SelectedBranchDialog(self.glb, self) 1905 + ret = dialog.exec_() 1906 + if ret: 1907 + BranchWindow(self.glb, event_id, dialog.name, dialog.where_clause, self) 1908 + 2370 1909 def NewTableView(self, table_name): 2371 1910 TableWindow(self.glb, table_name, self) 1911 + 1912 + def Help(self): 1913 + HelpWindow(self.glb, self) 2372 1914 2373 1915 # XED Disassembler 2374 1916 ··· 2405 1929 class LibXED(): 2406 1930 2407 1931 def __init__(self): 2408 - self.libxed = CDLL("libxed.so") 1932 + try: 1933 + self.libxed = CDLL("libxed.so") 1934 + except: 1935 + self.libxed = None 1936 + if not self.libxed: 1937 + self.libxed = CDLL("/usr/local/lib/libxed.so") 2409 1938 2410 1939 self.xed_tables_init = self.libxed.xed_tables_init 2411 1940 self.xed_tables_init.restype = None ··· 2578 2097 2579 2098 def Main(): 2580 2099 if (len(sys.argv) < 2): 2581 - print >> sys.stderr, "Usage is: exported-sql-viewer.py <database name>" 2100 + print >> sys.stderr, "Usage is: exported-sql-viewer.py {<database name> | --help-only}" 2582 2101 raise Exception("Too few arguments") 2583 2102 2584 2103 dbname = sys.argv[1] 2104 + if dbname == "--help-only": 2105 + app = QApplication(sys.argv) 2106 + mainwindow = HelpOnlyWindow() 2107 + mainwindow.show() 2108 + err = app.exec_() 2109 + sys.exit(err) 2585 2110 2586 2111 is_sqlite3 = False 2587 2112 try:
-1
tools/perf/tests/attr/test-record-group-sampling
··· 37 37 sample_period=0 38 38 freq=0 39 39 write_backward=0 40 - sample_id_all=0
+27
tools/perf/util/evlist.c
··· 1810 1810 leader->forced_leader = true; 1811 1811 } 1812 1812 } 1813 + 1814 + struct 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 + }
+3
tools/perf/util/evlist.h
··· 312 312 313 313 void perf_evlist__force_leader(struct perf_evlist *evlist); 314 314 315 + struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist, 316 + struct perf_evsel *evsel); 317 + 315 318 #endif /* __PERF_EVLIST_H */
-1
tools/perf/util/evsel.c
··· 956 956 attr->sample_freq = 0; 957 957 attr->sample_period = 0; 958 958 attr->write_backward = 0; 959 - attr->sample_id_all = 0; 960 959 } 961 960 962 961 if (opts->no_samples)
+4
tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
··· 1474 1474 decoder->have_calc_cyc_to_tsc = false; 1475 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 1479 1481 static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder) ··· 1516 1514 decoder->timestamp = timestamp; 1517 1515 1518 1516 decoder->timestamp_insn_cnt = 0; 1517 + 1518 + intel_pt_log_to("Setting timestamp", decoder->timestamp); 1519 1519 } 1520 1520 1521 1521 /* Walk PSB+ packets when already in sync. */
+5
tools/perf/util/intel-pt-decoder/intel-pt-log.c
··· 31 31 static char log_name[MAX_LOG_NAME]; 32 32 bool intel_pt_enable_logging; 33 33 34 + void *intel_pt_log_fp(void) 35 + { 36 + return f; 37 + } 38 + 34 39 void intel_pt_log_enable(void) 35 40 { 36 41 intel_pt_enable_logging = true;
+1
tools/perf/util/intel-pt-decoder/intel-pt-log.h
··· 22 22 23 23 struct intel_pt_pkt; 24 24 25 + void *intel_pt_log_fp(void); 25 26 void intel_pt_log_enable(void); 26 27 void intel_pt_log_disable(void); 27 28 void intel_pt_log_set_name(const char *name);
+13 -3
tools/perf/util/intel-pt.c
··· 206 206 intel_pt_dump(pt, buf, len); 207 207 } 208 208 209 + static 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 + 209 219 static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a, 210 220 struct auxtrace_buffer *b) 211 221 { ··· 2020 2010 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) 2021 2011 err = intel_pt_context_switch(pt, event, sample); 2022 2012 2023 - intel_pt_log("event %s (%u): cpu %d time %"PRIu64" tsc %#"PRIx64"\n", 2024 - perf_event__name(event->header.type), event->header.type, 2025 - sample->cpu, sample->time, timestamp); 2013 + intel_pt_log("event %u: cpu %d time %"PRIu64" tsc %#"PRIx64" ", 2014 + event->header.type, sample->cpu, sample->time, timestamp); 2015 + intel_pt_log_event(event); 2026 2016 2027 2017 return err; 2028 2018 }
+1 -1
tools/perf/util/pmu.c
··· 773 773 774 774 if (!is_arm_pmu_core(name)) { 775 775 pname = pe->pmu ? pe->pmu : "cpu"; 776 - if (strncmp(pname, name, strlen(pname))) 776 + if (strcmp(pname, name)) 777 777 continue; 778 778 } 779 779