Pull more perf updates from Thomas Gleixner: "A rather large set of perf updates: Kernel: - Fix various initialization issues - Prevent creating [ku]probes for not CAP_SYS_ADMIN users Tooling: - Show only failing syscalls with 'perf trace --failure' (Arnaldo Carvalho de Melo) e.g: See what 'openat' syscalls are failing: # perf trace --failure -e openat 762.323 ( 0.007 ms): VideoCapture/4566 openat(dfd: CWD, filename: /dev/video2) = -1 ENOENT No such file or directory <SNIP N /dev/videoN open attempts... sigh, where is that improvised camera lid?!? > 790.228 ( 0.008 ms): VideoCapture/4566 openat(dfd: CWD, filename: /dev/video63) = -1 ENOENT No such file or directory ^C# - Show information about the event (freq, nr_samples, total period/nr_events) in the annotate --tui and --stdio2 'perf annotate' output, similar to the first line in the 'perf report --tui', but just for the samples for a the annotated symbol (Arnaldo Carvalho de Melo) - Introduce 'perf version --build-options' to show what features were linked, aliased as well as a shorter 'perf -vv' (Jin Yao) - Add a "dso_size" sort order (Kim Phillips) - Remove redundant ')' in the tracepoint output in 'perf trace' (Changbin Du) - Synchronize x86's cpufeatures.h, no effect on toolss (Arnaldo Carvalho de Melo) - Show group details on the title line in the annotate browser and 'perf annotate --stdio2' output, so that the per-event columns can have headers (Arnaldo Carvalho de Melo) - Fixup vertical line separating metrics from instructions and cleaning unused lines at the bottom, both in the annotate TUI browser (Arnaldo Carvalho de Melo) - Remove duplicated 'samples' in lost samples warning in 'perf report' (Arnaldo Carvalho de Melo) - Synchronize i915_drm.h, silencing the perf build process, automagically adding support for the new DRM_I915_QUERY ioctl (Arnaldo Carvalho de Melo) - Make auxtrace_queues__add_buffer() allocate struct buffer, from a patchkit already applied (Adrian Hunter) - Fix the --stdio2/TUI annotate output to include group details, be it for a recorded '{a,b,f}' explicit event group or when forcing group display using 'perf report --group' for a set of events not recorded as a group (Arnaldo Carvalho de Melo) - Fix display artifacts in the ui browser (base class for the annotate and main report/top TUI browser) related to the extra title lines work (Arnaldo Carvalho de Melo) - perf auxtrace refactorings, leftovers from a previously partially processed patchset (Adrian Hunter) - Fix the builtin clang build (Sandipan Das, Arnaldo Carvalho de Melo) - Synchronize i915_drm.h, silencing a perf build warning and in the process automagically adding support for a new ioctl command (Arnaldo Carvalho de Melo) - Fix a strncpy issue in uprobe tracing" * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (36 commits) perf/core: Need CAP_SYS_ADMIN to create k/uprobe with perf_event_open() tracing/uprobe_event: Fix strncpy corner case perf/core: Fix perf_uprobe_init() perf/core: Fix perf_kprobe_init() perf/core: Fix use-after-free in uprobe_perf_close() perf tests clang: Fix function name for clang IR test perf clang: Add support for recent clang versions perf tools: Fix perf builds with clang support perf tools: No need to include namespaces.h in util.h perf hists browser: Remove leftover from row returned from refresh perf hists browser: Show extra_title_lines in the 'D' debug hotkey perf auxtrace: Make auxtrace_queues__add_buffer() do CPU filtering tools headers uapi: Synchronize i915_drm.h perf report: Remove duplicated 'samples' in lost samples warning perf ui browser: Fixup cleaning unused lines at the bottom perf annotate browser: Fixup vertical line separating metrics from instructions perf annotate: Show group details on the title line perf auxtrace: Make auxtrace_queues__add_buffer() allocate struct buffer perf/x86/intel: Move regs->flags EXACT bit init perf trace: Remove redundant ')' ...
Unified · Split
| @@ -1153,7 +1153,6 @@ static void setup_pebs_sample_data(struct perf_event *event, · 1152 unmodified lines | ||
| 1153 | 1153 | if (pebs == NULL) |
| 1154 | 1154 | return; |
| 1155 | 1155 | |
| 1156 | − regs->flags &= ~PERF_EFLAGS_EXACT; | |
| 1157 | 1156 | sample_type = event->attr.sample_type; |
| 1158 | 1157 | dsrc = sample_type & PERF_SAMPLE_DATA_SRC; |
| 1159 | 1158 | |
| @@ -1197,7 +1196,13 @@ static void setup_pebs_sample_data(struct perf_event *event, · 37 unmodified lines | ||
| 1197 | 1196 | * and PMI. |
| 1198 | 1197 | */ |
| 1199 | 1198 | *regs = *iregs; |
| 1200 | − regs->flags = pebs->flags; | |
| 1199 | + | |
| 1200 | + /* | |
| 1201 | + * Initialize regs_>flags from PEBS, | |
| 1202 | + * Clear exact bit (which uses x86 EFLAGS Reserved bit 3), | |
| 1203 | + * i.e., do not rely on it being zero: | |
| 1204 | + */ | |
| 1205 | + regs->flags = pebs->flags & ~PERF_EFLAGS_EXACT; | |
| 1201 | 1206 | |
| 1202 | 1207 | if (sample_type & PERF_SAMPLE_REGS_INTR) { |
| 1203 | 1208 | regs->ax = pebs->ax; |
| @@ -1217,10 +1222,6 @@ static void setup_pebs_sample_data(struct perf_event *event, · 13 unmodified lines | ||
| 1217 | 1222 | regs->sp = pebs->sp; |
| 1218 | 1223 | } |
| 1219 | 1224 | |
| 1220 | − /* | |
| 1221 | − * Preserve PERF_EFLAGS_VM from set_linear_ip(). | |
| 1222 | − */ | |
| 1223 | − regs->flags = pebs->flags | (regs->flags & PERF_EFLAGS_VM); | |
| 1224 | 1225 | #ifndef CONFIG_X86_32 |
| 1225 | 1226 | regs->r8 = pebs->r8; |
| 1226 | 1227 | regs->r9 = pebs->r9; |
| @@ -1234,20 +1235,33 @@ static void setup_pebs_sample_data(struct perf_event *event, · 7 unmodified lines | ||
| 1234 | 1235 | } |
| 1235 | 1236 | |
| 1236 | 1237 | if (event->attr.precise_ip > 1) { |
| 1237 | − /* Haswell and later have the eventing IP, so use it: */ | |
| 1238 | + /* | |
| 1239 | + * Haswell and later processors have an 'eventing IP' | |
| 1240 | + * (real IP) which fixes the off-by-1 skid in hardware. | |
| 1241 | + * Use it when precise_ip >= 2 : | |
| 1242 | + */ | |
| 1238 | 1243 | if (x86_pmu.intel_cap.pebs_format >= 2) { |
| 1239 | 1244 | set_linear_ip(regs, pebs->real_ip); |
| 1240 | 1245 | regs->flags |= PERF_EFLAGS_EXACT; |
| 1241 | 1246 | } else { |
| 1242 | − /* Otherwise use PEBS off-by-1 IP: */ | |
| 1247 | + /* Otherwise, use PEBS off-by-1 IP: */ | |
| 1243 | 1248 | set_linear_ip(regs, pebs->ip); |
| 1244 | 1249 | |
| 1245 | − /* ... and try to fix it up using the LBR entries: */ | |
| 1250 | + /* | |
| 1251 | + * With precise_ip >= 2, try to fix up the off-by-1 IP | |
| 1252 | + * using the LBR. If successful, the fixup function | |
| 1253 | + * corrects regs->ip and calls set_linear_ip() on regs: | |
| 1254 | + */ | |
| 1246 | 1255 | if (intel_pmu_pebs_fixup_ip(regs)) |
| 1247 | 1256 | regs->flags |= PERF_EFLAGS_EXACT; |
| 1248 | 1257 | } |
| 1249 | − } else | |
| 1258 | + } else { | |
| 1259 | + /* | |
| 1260 | + * When precise_ip == 1, return the PEBS off-by-1 IP, | |
| 1261 | + * no fixup attempted: | |
| 1262 | + */ | |
| 1250 | 1263 | set_linear_ip(regs, pebs->ip); |
| 1264 | + } | |
| 1251 | 1265 | |
| 1252 | 1266 | |
| 1253 | 1267 | if ((sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR)) && |
| @@ -4447,6 +4447,9 @@ static void _free_event(struct perf_event *event) · 4446 unmodified lines | ||
| 4447 | 4447 | if (event->ctx) |
| 4448 | 4448 | put_ctx(event->ctx); |
| 4449 | 4449 | |
| 4450 | + if (event->hw.target) | |
| 4451 | + put_task_struct(event->hw.target); | |
| 4452 | + | |
| 4450 | 4453 | exclusive_event_destroy(event); |
| 4451 | 4454 | module_put(event->pmu->module); |
| 4452 | 4455 | |
| @@ -8397,6 +8400,10 @@ static int perf_kprobe_event_init(struct perf_event *event) · 3944 unmodified lines | ||
| 8397 | 8400 | |
| 8398 | 8401 | if (event->attr.type != perf_kprobe.type) |
| 8399 | 8402 | return -ENOENT; |
| 8403 | + | |
| 8404 | + if (!capable(CAP_SYS_ADMIN)) | |
| 8405 | + return -EACCES; | |
| 8406 | + | |
| 8400 | 8407 | /* |
| 8401 | 8408 | * no branch sampling for probe events |
| 8402 | 8409 | */ |
| @@ -8434,6 +8441,10 @@ static int perf_uprobe_event_init(struct perf_event *event) · 31 unmodified lines | ||
| 8434 | 8441 | |
| 8435 | 8442 | if (event->attr.type != perf_uprobe.type) |
| 8436 | 8443 | return -ENOENT; |
| 8444 | + | |
| 8445 | + if (!capable(CAP_SYS_ADMIN)) | |
| 8446 | + return -EACCES; | |
| 8447 | + | |
| 8437 | 8448 | /* |
| 8438 | 8449 | * no branch sampling for probe events |
| 8439 | 8450 | */ |
| @@ -9955,6 +9966,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, · 1515 unmodified lines | ||
| 9955 | 9966 | * and we cannot use the ctx information because we need the |
| 9956 | 9967 | * pmu before we get a ctx. |
| 9957 | 9968 | */ |
| 9969 | + get_task_struct(task); | |
| 9958 | 9970 | event->hw.target = task; |
| 9959 | 9971 | } |
| 9960 | 9972 | |
| @@ -10070,6 +10082,8 @@ err_ns: · 109 unmodified lines | ||
| 10070 | 10082 | perf_detach_cgroup(event); |
| 10071 | 10083 | if (event->ns) |
| 10072 | 10084 | put_pid_ns(event->ns); |
| 10085 | + if (event->hw.target) | |
| 10086 | + put_task_struct(event->hw.target); | |
| 10073 | 10087 | kfree(event); |
| 10074 | 10088 | |
| 10075 | 10089 | return ERR_PTR(err); |
| @@ -252,6 +252,8 @@ int perf_kprobe_init(struct perf_event *p_event, bool is_retprobe) · 251 unmodified lines | ||
| 252 | 252 | ret = strncpy_from_user( |
| 253 | 253 | func, u64_to_user_ptr(p_event->attr.kprobe_func), |
| 254 | 254 | KSYM_NAME_LEN); |
| 255 | + if (ret == KSYM_NAME_LEN) | |
| 256 | + ret = -E2BIG; | |
| 255 | 257 | if (ret < 0) |
| 256 | 258 | goto out; |
| 257 | 259 | |
| @@ -300,6 +302,8 @@ int perf_uprobe_init(struct perf_event *p_event, bool is_retprobe) · 42 unmodified lines | ||
| 300 | 302 | return -ENOMEM; |
| 301 | 303 | ret = strncpy_from_user( |
| 302 | 304 | path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX); |
| 305 | + if (ret == PATH_MAX) | |
| 306 | + return -E2BIG; | |
| 303 | 307 | if (ret < 0) |
| 304 | 308 | goto out; |
| 305 | 309 | if (path[0] == '\0') { |
| @@ -151,6 +151,8 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, · 150 unmodified lines | ||
| 151 | 151 | return; |
| 152 | 152 | |
| 153 | 153 | ret = strncpy_from_user(dst, src, maxlen); |
| 154 | + if (ret == maxlen) | |
| 155 | + dst[--ret] = '\0'; | |
| 154 | 156 | |
| 155 | 157 | if (ret < 0) { /* Failed to fetch string */ |
| 156 | 158 | ((u8 *)get_rloc_data(dest))[0] = '\0'; |
| @@ -316,6 +316,7 @@ · 315 unmodified lines | ||
| 316 | 316 | #define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ |
| 317 | 317 | #define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ |
| 318 | 318 | #define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ |
| 319 | +#define X86_FEATURE_TME (16*32+13) /* Intel Total Memory Encryption */ | |
| 319 | 320 | #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ |
| 320 | 321 | #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ |
| 321 | 322 | #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ |
| @@ -328,6 +329,7 @@ · 6 unmodified lines | ||
| 328 | 329 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ |
| 329 | 330 | #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ |
| 330 | 331 | #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ |
| 332 | +#define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ | |
| 331 | 333 | #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ |
| 332 | 334 | #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ |
| 333 | 335 | #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ |
| @@ -0,0 +1,34 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +#ifndef _TOOLS_CONFIG_H | |
| 3 | +#define _TOOLS_CONFIG_H | |
| 4 | + | |
| 5 | +/* Subset of include/linux/kconfig.h */ | |
| 6 | + | |
| 7 | +#define __ARG_PLACEHOLDER_1 0, | |
| 8 | +#define __take_second_arg(__ignored, val, ...) val | |
| 9 | + | |
| 10 | +/* | |
| 11 | + * Helper macros to use CONFIG_ options in C/CPP expressions. Note that | |
| 12 | + * these only work with boolean and tristate options. | |
| 13 | + */ | |
| 14 | + | |
| 15 | +/* | |
| 16 | + * Getting something that works in C and CPP for an arg that may or may | |
| 17 | + * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1" | |
| 18 | + * we match on the placeholder define, insert the "0," for arg1 and generate | |
| 19 | + * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one). | |
| 20 | + * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when | |
| 21 | + * the last step cherry picks the 2nd arg, we get a zero. | |
| 22 | + */ | |
| 23 | +#define __is_defined(x) ___is_defined(x) | |
| 24 | +#define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val) | |
| 25 | +#define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0) | |
| 26 | + | |
| 27 | +/* | |
| 28 | + * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0 | |
| 29 | + * otherwise. For boolean options, this is equivalent to | |
| 30 | + * IS_ENABLED(CONFIG_FOO). | |
| 31 | + */ | |
| 32 | +#define IS_BUILTIN(option) __is_defined(option) | |
| 33 | + | |
| 34 | +#endif /* _TOOLS_CONFIG_H */ | |
| @@ -318,6 +318,7 @@ typedef struct _drm_i915_sarea { · 317 unmodified lines | ||
| 318 | 318 | #define DRM_I915_PERF_OPEN 0x36 |
| 319 | 319 | #define DRM_I915_PERF_ADD_CONFIG 0x37 |
| 320 | 320 | #define DRM_I915_PERF_REMOVE_CONFIG 0x38 |
| 321 | +#define DRM_I915_QUERY 0x39 | |
| 321 | 322 | |
| 322 | 323 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) |
| 323 | 324 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) |
| @@ -375,6 +376,7 @@ typedef struct _drm_i915_sarea { · 51 unmodified lines | ||
| 375 | 376 | #define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) |
| 376 | 377 | #define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) |
| 377 | 378 | #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) |
| 379 | +#define DRM_IOCTL_I915_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query) | |
| 378 | 380 | |
| 379 | 381 | /* Allow drivers to submit batchbuffers directly to hardware, relying |
| 380 | 382 | * on the security mechanisms provided by hardware. |
| @@ -1358,7 +1360,9 @@ struct drm_intel_overlay_attrs { · 977 unmodified lines | ||
| 1358 | 1360 | * active on a given plane. |
| 1359 | 1361 | */ |
| 1360 | 1362 | |
| 1361 | −#define I915_SET_COLORKEY_NONE (1<<0) /* disable color key matching */ | |
| 1363 | +#define I915_SET_COLORKEY_NONE (1<<0) /* Deprecated. Instead set | |
| 1364 | + * flags==0 to disable colorkeying. | |
| 1365 | + */ | |
| 1362 | 1366 | #define I915_SET_COLORKEY_DESTINATION (1<<1) |
| 1363 | 1367 | #define I915_SET_COLORKEY_SOURCE (1<<2) |
| 1364 | 1368 | struct drm_intel_sprite_colorkey { |
| @@ -1604,15 +1608,115 @@ struct drm_i915_perf_oa_config { · 239 unmodified lines | ||
| 1604 | 1608 | __u32 n_flex_regs; |
| 1605 | 1609 | |
| 1606 | 1610 | /* |
| 1607 | − * These fields are pointers to tuples of u32 values (register | |
| 1608 | − * address, value). For example the expected length of the buffer | |
| 1609 | − * pointed by mux_regs_ptr is (2 * sizeof(u32) * n_mux_regs). | |
| 1611 | + * These fields are pointers to tuples of u32 values (register address, | |
| 1612 | + * value). For example the expected length of the buffer pointed by | |
| 1613 | + * mux_regs_ptr is (2 * sizeof(u32) * n_mux_regs). | |
| 1610 | 1614 | */ |
| 1611 | 1615 | __u64 mux_regs_ptr; |
| 1612 | 1616 | __u64 boolean_regs_ptr; |
| 1613 | 1617 | __u64 flex_regs_ptr; |
| 1614 | 1618 | }; |
| 1615 | 1619 | |
| 1620 | +struct drm_i915_query_item { | |
| 1621 | + __u64 query_id; | |
| 1622 | +#define DRM_I915_QUERY_TOPOLOGY_INFO 1 | |
| 1623 | + | |
| 1624 | + /* | |
| 1625 | + * When set to zero by userspace, this is filled with the size of the | |
| 1626 | + * data to be written at the data_ptr pointer. The kernel sets this | |
| 1627 | + * value to a negative value to signal an error on a particular query | |
| 1628 | + * item. | |
| 1629 | + */ | |
| 1630 | + __s32 length; | |
| 1631 | + | |
| 1632 | + /* | |
| 1633 | + * Unused for now. Must be cleared to zero. | |
| 1634 | + */ | |
| 1635 | + __u32 flags; | |
| 1636 | + | |
| 1637 | + /* | |
| 1638 | + * Data will be written at the location pointed by data_ptr when the | |
| 1639 | + * value of length matches the length of the data to be written by the | |
| 1640 | + * kernel. | |
| 1641 | + */ | |
| 1642 | + __u64 data_ptr; | |
| 1643 | +}; | |
| 1644 | + | |
| 1645 | +struct drm_i915_query { | |
| 1646 | + __u32 num_items; | |
| 1647 | + | |
| 1648 | + /* | |
| 1649 | + * Unused for now. Must be cleared to zero. | |
| 1650 | + */ | |
| 1651 | + __u32 flags; | |
| 1652 | + | |
| 1653 | + /* | |
| 1654 | + * This points to an array of num_items drm_i915_query_item structures. | |
| 1655 | + */ | |
| 1656 | + __u64 items_ptr; | |
| 1657 | +}; | |
| 1658 | + | |
| 1659 | +/* | |
| 1660 | + * Data written by the kernel with query DRM_I915_QUERY_TOPOLOGY_INFO : | |
| 1661 | + * | |
| 1662 | + * data: contains the 3 pieces of information : | |
| 1663 | + * | |
| 1664 | + * - the slice mask with one bit per slice telling whether a slice is | |
| 1665 | + * available. The availability of slice X can be queried with the following | |
| 1666 | + * formula : | |
| 1667 | + * | |
| 1668 | + * (data[X / 8] >> (X % 8)) & 1 | |
| 1669 | + * | |
| 1670 | + * - the subslice mask for each slice with one bit per subslice telling | |
| 1671 | + * whether a subslice is available. The availability of subslice Y in slice | |
| 1672 | + * X can be queried with the following formula : | |
| 1673 | + * | |
| 1674 | + * (data[subslice_offset + | |
| 1675 | + * X * subslice_stride + | |
| 1676 | + * Y / 8] >> (Y % 8)) & 1 | |
| 1677 | + * | |
| 1678 | + * - the EU mask for each subslice in each slice with one bit per EU telling | |
| 1679 | + * whether an EU is available. The availability of EU Z in subslice Y in | |
| 1680 | + * slice X can be queried with the following formula : | |
| 1681 | + * | |
| 1682 | + * (data[eu_offset + | |
| 1683 | + * (X * max_subslices + Y) * eu_stride + | |
| 1684 | + * Z / 8] >> (Z % 8)) & 1 | |
| 1685 | + */ | |
| 1686 | +struct drm_i915_query_topology_info { | |
| 1687 | + /* | |
| 1688 | + * Unused for now. Must be cleared to zero. | |
| 1689 | + */ | |
| 1690 | + __u16 flags; | |
| 1691 | + | |
| 1692 | + __u16 max_slices; | |
| 1693 | + __u16 max_subslices; | |
| 1694 | + __u16 max_eus_per_subslice; | |
| 1695 | + | |
| 1696 | + /* | |
| 1697 | + * Offset in data[] at which the subslice masks are stored. | |
| 1698 | + */ | |
| 1699 | + __u16 subslice_offset; | |
| 1700 | + | |
| 1701 | + /* | |
| 1702 | + * Stride at which each of the subslice masks for each slice are | |
| 1703 | + * stored. | |
| 1704 | + */ | |
| 1705 | + __u16 subslice_stride; | |
| 1706 | + | |
| 1707 | + /* | |
| 1708 | + * Offset in data[] at which the EU masks are stored. | |
| 1709 | + */ | |
| 1710 | + __u16 eu_offset; | |
| 1711 | + | |
| 1712 | + /* | |
| 1713 | + * Stride at which each of the EU masks for each subslice are stored. | |
| 1714 | + */ | |
| 1715 | + __u16 eu_stride; | |
| 1716 | + | |
| 1717 | + __u8 data[]; | |
| 1718 | +}; | |
| 1719 | + | |
| 1616 | 1720 | #if defined(__cplusplus) |
| 1617 | 1721 | } |
| 1618 | 1722 | #endif |
| @@ -80,6 +80,7 @@ OPTIONS · 79 unmodified lines | ||
| 80 | 80 | - comm: command (name) of the task which can be read via /proc/<pid>/comm |
| 81 | 81 | - pid: command and tid of the task |
| 82 | 82 | - dso: name of library or module executed at the time of sample |
| 83 | + - dso_size: size of library or module executed at the time of sample | |
| 83 | 84 | - symbol: name of function executed at the time of sample |
| 84 | 85 | - symbol_size: size of function executed at the time of sample |
| 85 | 86 | - parent: name of function matched to the parent regex filter. Unmatched |
| @@ -117,6 +117,9 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. · 116 unmodified lines | ||
| 117 | 117 | --sched:: |
| 118 | 118 | Accrue thread runtime and provide a summary at the end of the session. |
| 119 | 119 | |
| 120 | +--failure:: | |
| 121 | + Show only syscalls that failed, i.e. that returned < 0. | |
| 122 | + | |
| 120 | 123 | -i:: |
| 121 | 124 | --input:: |
| 122 | 125 | Process events from a given perf data file. |
| @@ -0,0 +1,24 @@ | ||
| 1 | +perf-version(1) | |
| 2 | +=============== | |
| 3 | + | |
| 4 | +NAME | |
| 5 | +---- | |
| 6 | +perf-version - display the version of perf binary | |
| 7 | + | |
| 8 | +SYNOPSIS | |
| 9 | +-------- | |
| 10 | +'perf version' [--build-options] | |
| 11 | + | |
| 12 | +DESCRIPTION | |
| 13 | +----------- | |
| 14 | +With no options given, the 'perf version' prints the perf version | |
| 15 | +on the standard output. | |
| 16 | + | |
| 17 | +If the option '--build-options' is given, then the status of | |
| 18 | +compiled-in libraries are printed on the standard output. | |
| 19 | + | |
| 20 | +OPTIONS | |
| 21 | +------- | |
| 22 | +--build-options:: | |
| 23 | + Prints the status of compiled-in libraries on the | |
| 24 | + standard output. | |
| @@ -346,12 +346,16 @@ else · 345 unmodified lines | ||
| 346 | 346 | ifneq ($(feature-dwarf_getlocations), 1) |
| 347 | 347 | msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157); |
| 348 | 348 | else |
| 349 | − CFLAGS += -DHAVE_DWARF_GETLOCATIONS | |
| 349 | + CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT | |
| 350 | 350 | endif # dwarf_getlocations |
| 351 | 351 | endif # Dwarf support |
| 352 | 352 | endif # libelf support |
| 353 | 353 | endif # NO_LIBELF |
| 354 | 354 | |
| 355 | +ifeq ($(feature-glibc), 1) | |
| 356 | + CFLAGS += -DHAVE_GLIBC_SUPPORT | |
| 357 | +endif | |
| 358 | + | |
| 355 | 359 | ifdef NO_DWARF |
| 356 | 360 | NO_LIBDW_DWARF_UNWIND := 1 |
| 357 | 361 | endif |
| @@ -635,6 +639,7 @@ else · 277 unmodified lines | ||
| 635 | 639 | else |
| 636 | 640 | LDFLAGS += $(PERL_EMBED_LDFLAGS) |
| 637 | 641 | EXTLIBS += $(PERL_EMBED_LIBADD) |
| 642 | + CFLAGS += -DHAVE_LIBPERL_SUPPORT | |
| 638 | 643 | $(call detected,CONFIG_LIBPERL) |
| 639 | 644 | endif |
| 640 | 645 | endif |
| @@ -671,6 +676,7 @@ else · 30 unmodified lines | ||
| 671 | 676 | LDFLAGS += $(PYTHON_EMBED_LDFLAGS) |
| 672 | 677 | EXTLIBS += $(PYTHON_EMBED_LIBADD) |
| 673 | 678 | LANG_BINDINGS += $(obj-perf)python/perf.so |
| 679 | + CFLAGS += -DHAVE_LIBPYTHON_SUPPORT | |
| 674 | 680 | $(call detected,CONFIG_LIBPYTHON) |
| 675 | 681 | endif |
| 676 | 682 | endif |
| @@ -364,7 +364,8 @@ LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive · 363 unmodified lines | ||
| 364 | 364 | |
| 365 | 365 | ifeq ($(USE_CLANG), 1) |
| 366 | 366 | CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization |
| 367 | − LIBCLANG = $(foreach l,$(CLANGLIBS_LIST),$(wildcard $(shell $(LLVM_CONFIG) --libdir)/libclang$(l).a)) | |
| 367 | + CLANGLIBS_NOEXT_LIST = $(foreach l,$(CLANGLIBS_LIST),$(shell $(LLVM_CONFIG) --libdir)/libclang$(l)) | |
| 368 | + LIBCLANG = $(foreach l,$(CLANGLIBS_NOEXT_LIST),$(wildcard $(l).a $(l).so)) | |
| 368 | 369 | LIBS += -Wl,--start-group $(LIBCLANG) -Wl,--end-group |
| 369 | 370 | endif |
| 370 | 371 | |
| @@ -112,6 +112,7 @@ struct trace { · 111 unmodified lines | ||
| 112 | 112 | bool multiple_threads; |
| 113 | 113 | bool summary; |
| 114 | 114 | bool summary_only; |
| 115 | + bool failure_only; | |
| 115 | 116 | bool show_comm; |
| 116 | 117 | bool print_sample; |
| 117 | 118 | bool show_tool_stats; |
| @@ -1565,7 +1566,7 @@ static int trace__printf_interrupted_entry(struct trace *trace) · 1447 unmodified lines | ||
| 1565 | 1566 | struct thread_trace *ttrace; |
| 1566 | 1567 | size_t printed; |
| 1567 | 1568 | |
| 1568 | − if (trace->current == NULL) | |
| 1569 | + if (trace->failure_only || trace->current == NULL) | |
| 1569 | 1570 | return 0; |
| 1570 | 1571 | |
| 1571 | 1572 | ttrace = thread__priv(trace->current); |
| @@ -1638,7 +1639,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, · 66 unmodified lines | ||
| 1638 | 1639 | args, trace, thread); |
| 1639 | 1640 | |
| 1640 | 1641 | if (sc->is_exit) { |
| 1641 | − if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { | |
| 1642 | + if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) { | |
| 1642 | 1643 | trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output); |
| 1643 | 1644 | fprintf(trace->output, "%-70s)\n", ttrace->entry_str); |
| 1644 | 1645 | } |
| @@ -1742,7 +1743,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, · 97 unmodified lines | ||
| 1742 | 1743 | } |
| 1743 | 1744 | } |
| 1744 | 1745 | |
| 1745 | − if (trace->summary_only) | |
| 1746 | + if (trace->summary_only || (ret >= 0 && trace->failure_only)) | |
| 1746 | 1747 | goto out; |
| 1747 | 1748 | |
| 1748 | 1749 | trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output); |
| @@ -1961,7 +1962,7 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, · 212 unmodified lines | ||
| 1961 | 1962 | trace->output); |
| 1962 | 1963 | } |
| 1963 | 1964 | |
| 1964 | − fprintf(trace->output, ")\n"); | |
| 1965 | + fprintf(trace->output, "\n"); | |
| 1965 | 1966 | |
| 1966 | 1967 | if (callchain_ret > 0) |
| 1967 | 1968 | trace__fprintf_callchain(trace, sample); |
| @@ -3087,6 +3088,8 @@ int cmd_trace(int argc, const char **argv) · 1119 unmodified lines | ||
| 3087 | 3088 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), |
| 3088 | 3089 | OPT_BOOLEAN('T', "time", &trace.full_time, |
| 3089 | 3090 | "Show full timestamp, not time relative to first start"), |
| 3091 | + OPT_BOOLEAN(0, "failure", &trace.failure_only, | |
| 3092 | + "Show only syscalls that failed"), | |
| 3090 | 3093 | OPT_BOOLEAN('s', "summary", &trace.summary_only, |
| 3091 | 3094 | "Show only syscall summary with statistics"), |
| 3092 | 3095 | OPT_BOOLEAN('S', "with-summary", &trace.summary, |
| @@ -1,11 +1,91 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | #include "builtin.h" |
| 3 | 3 | #include "perf.h" |
| 4 | +#include "color.h" | |
| 4 | 5 | #include <linux/compiler.h> |
| 6 | +#include <tools/config.h> | |
| 5 | 7 | #include <stdio.h> |
| 8 | +#include <string.h> | |
| 9 | +#include <subcmd/parse-options.h> | |
| 6 | 10 | |
| 7 | −int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused) | |
| 11 | +int version_verbose; | |
| 12 | + | |
| 13 | +struct version { | |
| 14 | + bool build_options; | |
| 15 | +}; | |
| 16 | + | |
| 17 | +static struct version version; | |
| 18 | + | |
| 19 | +static struct option version_options[] = { | |
| 20 | + OPT_BOOLEAN(0, "build-options", &version.build_options, | |
| 21 | + "display the build options"), | |
| 22 | +}; | |
| 23 | + | |
| 24 | +static const char * const version_usage[] = { | |
| 25 | + "perf version [<options>]", | |
| 26 | + NULL | |
| 27 | +}; | |
| 28 | + | |
| 29 | +static void on_off_print(const char *status) | |
| 30 | +{ | |
| 31 | + printf("[ "); | |
| 32 | + | |
| 33 | + if (!strcmp(status, "OFF")) | |
| 34 | + color_fprintf(stdout, PERF_COLOR_RED, "%-3s", status); | |
| 35 | + else | |
| 36 | + color_fprintf(stdout, PERF_COLOR_GREEN, "%-3s", status); | |
| 37 | + | |
| 38 | + printf(" ]"); | |
| 39 | +} | |
| 40 | + | |
| 41 | +static void status_print(const char *name, const char *macro, | |
| 42 | + const char *status) | |
| 8 | 43 | { |
| 44 | + printf("%22s: ", name); | |
| 45 | + on_off_print(status); | |
| 46 | + printf(" # %s\n", macro); | |
| 47 | +} | |
| 48 | + | |
| 49 | +#define STATUS(__d, __m) \ | |
| 50 | +do { \ | |
| 51 | + if (IS_BUILTIN(__d)) \ | |
| 52 | + status_print(#__m, #__d, "on"); \ | |
| 53 | + else \ | |
| 54 | + status_print(#__m, #__d, "OFF"); \ | |
| 55 | +} while (0) | |
| 56 | + | |
| 57 | +static void library_status(void) | |
| 58 | +{ | |
| 59 | + STATUS(HAVE_DWARF_SUPPORT, dwarf); | |
| 60 | + STATUS(HAVE_DWARF_GETLOCATIONS_SUPPORT, dwarf_getlocations); | |
| 61 | + STATUS(HAVE_GLIBC_SUPPORT, glibc); | |
| 62 | + STATUS(HAVE_GTK2_SUPPORT, gtk2); | |
| 63 | + STATUS(HAVE_LIBAUDIT_SUPPORT, libaudit); | |
| 64 | + STATUS(HAVE_LIBBFD_SUPPORT, libbfd); | |
| 65 | + STATUS(HAVE_LIBELF_SUPPORT, libelf); | |
| 66 | + STATUS(HAVE_LIBNUMA_SUPPORT, libnuma); | |
| 67 | + STATUS(HAVE_LIBNUMA_SUPPORT, numa_num_possible_cpus); | |
| 68 | + STATUS(HAVE_LIBPERL_SUPPORT, libperl); | |
| 69 | + STATUS(HAVE_LIBPYTHON_SUPPORT, libpython); | |
| 70 | + STATUS(HAVE_SLANG_SUPPORT, libslang); | |
| 71 | + STATUS(HAVE_LIBCRYPTO_SUPPORT, libcrypto); | |
| 72 | + STATUS(HAVE_LIBUNWIND_SUPPORT, libunwind); | |
| 73 | + STATUS(HAVE_DWARF_SUPPORT, libdw-dwarf-unwind); | |
| 74 | + STATUS(HAVE_ZLIB_SUPPORT, zlib); | |
| 75 | + STATUS(HAVE_LZMA_SUPPORT, lzma); | |
| 76 | + STATUS(HAVE_AUXTRACE_SUPPORT, get_cpuid); | |
| 77 | + STATUS(HAVE_LIBBPF_SUPPORT, bpf); | |
| 78 | +} | |
| 79 | + | |
| 80 | +int cmd_version(int argc, const char **argv) | |
| 81 | +{ | |
| 82 | + argc = parse_options(argc, argv, version_options, version_usage, | |
| 83 | + PARSE_OPT_STOP_AT_NON_OPTION); | |
| 84 | + | |
| 9 | 85 | printf("perf version %s\n", perf_version_string); |
| 86 | + | |
| 87 | + if (version.build_options || version_verbose == 1) | |
| 88 | + library_status(); | |
| 89 | + | |
| 10 | 90 | return 0; |
| 11 | 91 | } |
| @@ -190,6 +190,12 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) · 189 unmodified lines | ||
| 190 | 190 | break; |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | + if (!strcmp(cmd, "-vv")) { | |
| 194 | + (*argv)[0] = "version"; | |
| 195 | + version_verbose = 1; | |
| 196 | + break; | |
| 197 | + } | |
| 198 | + | |
| 193 | 199 | /* |
| 194 | 200 | * Check remaining flags. |
| 195 | 201 | */ |
| @@ -84,6 +84,7 @@ struct record_opts { · 83 unmodified lines | ||
| 84 | 84 | struct option; |
| 85 | 85 | extern const char * const *record_usage; |
| 86 | 86 | extern struct option *record_options; |
| 87 | +extern int version_verbose; | |
| 87 | 88 | |
| 88 | 89 | int record__parse_freq(const struct option *opt, const char *str, int unset); |
| 89 | 90 | #endif |
| @@ -45,11 +45,16 @@ void ui_browser__set_percent_color(struct ui_browser *browser, · 44 unmodified lines | ||
| 45 | 45 | ui_browser__set_color(browser, color); |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | −void ui_browser__gotorc(struct ui_browser *browser, int y, int x) | |
| 48 | +void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x) | |
| 49 | 49 | { |
| 50 | 50 | SLsmg_gotorc(browser->y + y, browser->x + x); |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | +void ui_browser__gotorc(struct ui_browser *browser, int y, int x) | |
| 54 | +{ | |
| 55 | + SLsmg_gotorc(browser->y + y + browser->extra_title_lines, browser->x + x); | |
| 56 | +} | |
| 57 | + | |
| 53 | 58 | void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg, |
| 54 | 59 | unsigned int width) |
| 55 | 60 | { |
| @@ -191,6 +196,7 @@ void ui_browser__refresh_dimensions(struct ui_browser *browser) · 135 unmodified lines | ||
| 191 | 196 | { |
| 192 | 197 | browser->width = SLtt_Screen_Cols - 1; |
| 193 | 198 | browser->height = browser->rows = SLtt_Screen_Rows - 2; |
| 199 | + browser->rows -= browser->extra_title_lines; | |
| 194 | 200 | browser->y = 1; |
| 195 | 201 | browser->x = 0; |
| 196 | 202 | } |
| @@ -337,8 +343,8 @@ static int __ui_browser__refresh(struct ui_browser *browser) · 140 unmodified lines | ||
| 337 | 343 | else |
| 338 | 344 | width += 1; |
| 339 | 345 | |
| 340 | − SLsmg_fill_region(browser->y + row, browser->x, | |
| 341 | − browser->height - row, width, ' '); | |
| 346 | + SLsmg_fill_region(browser->y + row + browser->extra_title_lines, browser->x, | |
| 347 | + browser->rows - row, width, ' '); | |
| 342 | 348 | |
| 343 | 349 | return 0; |
| 344 | 350 | } |
| @@ -17,6 +17,7 @@ struct ui_browser { · 16 unmodified lines | ||
| 17 | 17 | u64 index, top_idx; |
| 18 | 18 | void *top, *entries; |
| 19 | 19 | u16 y, x, width, height, rows, columns, horiz_scroll; |
| 20 | + u8 extra_title_lines; | |
| 20 | 21 | int current_color; |
| 21 | 22 | void *priv; |
| 22 | 23 | const char *title; |
| @@ -38,6 +39,7 @@ bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row); · 15 unmodified lines | ||
| 38 | 39 | void ui_browser__refresh_dimensions(struct ui_browser *browser); |
| 39 | 40 | void ui_browser__reset_index(struct ui_browser *browser); |
| 40 | 41 | |
| 42 | +void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x); | |
| 41 | 43 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x); |
| 42 | 44 | void ui_browser__write_nstring(struct ui_browser *browser, const char *msg, |
| 43 | 45 | unsigned int width); |
| @@ -218,7 +218,7 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser) · 217 unmodified lines | ||
| 218 | 218 | annotate_browser__draw_current_jump(browser); |
| 219 | 219 | |
| 220 | 220 | ui_browser__set_color(browser, HE_COLORSET_NORMAL); |
| 221 | − __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1); | |
| 221 | + __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1); | |
| 222 | 222 | return ret; |
| 223 | 223 | } |
| 224 | 224 | |
| @@ -592,21 +592,40 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, · 367 unmodified lines | ||
| 592 | 592 | return __annotate_browser__search_reverse(browser); |
| 593 | 593 | } |
| 594 | 594 | |
| 595 | +static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) | |
| 596 | +{ | |
| 597 | + struct map_symbol *ms = browser->priv; | |
| 598 | + struct symbol *sym = ms->sym; | |
| 599 | + char symbol_dso[SYM_TITLE_MAX_SIZE]; | |
| 600 | + | |
| 601 | + if (ui_browser__show(browser, title, help) < 0) | |
| 602 | + return -1; | |
| 603 | + | |
| 604 | + sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso)); | |
| 605 | + | |
| 606 | + ui_browser__gotorc_title(browser, 0, 0); | |
| 607 | + ui_browser__set_color(browser, HE_COLORSET_ROOT); | |
| 608 | + ui_browser__write_nstring(browser, symbol_dso, browser->width + 1); | |
| 609 | + return 0; | |
| 610 | +} | |
| 611 | + | |
| 595 | 612 | static int annotate_browser__run(struct annotate_browser *browser, |
| 596 | 613 | struct perf_evsel *evsel, |
| 597 | 614 | struct hist_browser_timer *hbt) |
| 598 | 615 | { |
| 599 | 616 | struct rb_node *nd = NULL; |
| 617 | + struct hists *hists = evsel__hists(evsel); | |
| 600 | 618 | struct map_symbol *ms = browser->b.priv; |
| 601 | 619 | struct symbol *sym = ms->sym; |
| 602 | 620 | struct annotation *notes = symbol__annotation(ms->sym); |
| 603 | 621 | const char *help = "Press 'h' for help on key bindings"; |
| 604 | 622 | int delay_secs = hbt ? hbt->refresh : 0; |
| 623 | + char title[256]; | |
| 605 | 624 | int key; |
| 606 | − char title[SYM_TITLE_MAX_SIZE]; | |
| 607 | 625 | |
| 608 | − sym_title(sym, ms->map, title, sizeof(title)); | |
| 609 | − if (ui_browser__show(&browser->b, title, help) < 0) | |
| 626 | + annotation__scnprintf_samples_period(notes, title, sizeof(title), evsel); | |
| 627 | + | |
| 628 | + if (annotate_browser__show(&browser->b, title, help) < 0) | |
| 610 | 629 | return -1; |
| 611 | 630 | |
| 612 | 631 | annotate_browser__calc_percent(browser, evsel); |
| @@ -637,8 +656,11 @@ static int annotate_browser__run(struct annotate_browser *browser, · 24 unmodified lines | ||
| 637 | 656 | if (hbt) |
| 638 | 657 | hbt->timer(hbt->arg); |
| 639 | 658 | |
| 640 | − if (delay_secs != 0) | |
| 659 | + if (delay_secs != 0) { | |
| 641 | 660 | symbol__annotate_decay_histogram(sym, evsel->idx); |
| 661 | + hists__scnprintf_title(hists, title, sizeof(title)); | |
| 662 | + annotate_browser__show(&browser->b, title, help); | |
| 663 | + } | |
| 642 | 664 | continue; |
| 643 | 665 | case K_TAB: |
| 644 | 666 | if (nd != NULL) { |
| @@ -812,6 +834,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, · 167 unmodified lines | ||
| 812 | 834 | .seek = ui_browser__list_head_seek, |
| 813 | 835 | .write = annotate_browser__write, |
| 814 | 836 | .filter = disasm_line__filter, |
| 837 | + .extra_title_lines = 1, /* for hists__scnprintf_title() */ | |
| 815 | 838 | .priv = &ms, |
| 816 | 839 | .use_navkeypressed = true, |
| 817 | 840 | }, |
| @@ -32,8 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | |
| 33 | 33 | extern void hist_browser__init_hpp(void); |
| 34 | 34 | |
| 35 | −static int perf_evsel_browser_title(struct hist_browser *browser, | |
| 36 | − char *bf, size_t size); | |
| 35 | +static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size); | |
| 37 | 36 | static void hist_browser__update_nr_entries(struct hist_browser *hb); |
| 38 | 37 | |
| 39 | 38 | static struct rb_node *hists__filter_entries(struct rb_node *nd, |
| @@ -62,6 +61,15 @@ static int hist_browser__get_folding(struct hist_browser *browser) · 22 unmodified lines | ||
| 62 | 61 | return unfolded_rows; |
| 63 | 62 | } |
| 64 | 63 | |
| 64 | +static void hist_browser__set_title_space(struct hist_browser *hb) | |
| 65 | +{ | |
| 66 | + struct ui_browser *browser = &hb->b; | |
| 67 | + struct hists *hists = hb->hists; | |
| 68 | + struct perf_hpp_list *hpp_list = hists->hpp_list; | |
| 69 | + | |
| 70 | + browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0; | |
| 71 | +} | |
| 72 | + | |
| 65 | 73 | static u32 hist_browser__nr_entries(struct hist_browser *hb) |
| 66 | 74 | { |
| 67 | 75 | u32 nr_entries; |
| @@ -82,10 +90,16 @@ static void hist_browser__update_rows(struct hist_browser *hb) · 14 unmodified lines | ||
| 82 | 90 | struct ui_browser *browser = &hb->b; |
| 83 | 91 | struct hists *hists = hb->hists; |
| 84 | 92 | struct perf_hpp_list *hpp_list = hists->hpp_list; |
| 85 | − u16 header_offset, index_row; | |
| 93 | + u16 index_row; | |
| 86 | 94 | |
| 87 | − header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0; | |
| 88 | − browser->rows = browser->height - header_offset; | |
| 95 | + if (!hb->show_headers) { | |
| 96 | + browser->rows += browser->extra_title_lines; | |
| 97 | + browser->extra_title_lines = 0; | |
| 98 | + return; | |
| 99 | + } | |
| 100 | + | |
| 101 | + browser->extra_title_lines = hpp_list->nr_header_lines; | |
| 102 | + browser->rows -= browser->extra_title_lines; | |
| 89 | 103 | /* |
| 90 | 104 | * Verify if we were at the last line and that line isn't |
| 91 | 105 | * visibe because we now show the header line(s). |
| @@ -108,17 +122,6 @@ static void hist_browser__refresh_dimensions(struct ui_browser *browser) · 16 unmodified lines | ||
| 108 | 122 | * changeset. |
| 109 | 123 | */ |
| 110 | 124 | ui_browser__refresh_dimensions(browser); |
| 111 | − hist_browser__update_rows(hb); | |
| 112 | −} | |
| 113 | − | |
| 114 | −static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) | |
| 115 | −{ | |
| 116 | − struct hists *hists = browser->hists; | |
| 117 | − struct perf_hpp_list *hpp_list = hists->hpp_list; | |
| 118 | − u16 header_offset; | |
| 119 | − | |
| 120 | − header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0; | |
| 121 | − ui_browser__gotorc(&browser->b, row + header_offset, column); | |
| 122 | 125 | } |
| 123 | 126 | |
| 124 | 127 | static void hist_browser__reset(struct hist_browser *browser) |
| @@ -656,9 +659,10 @@ int hist_browser__run(struct hist_browser *browser, const char *help, · 531 unmodified lines | ||
| 656 | 659 | struct hist_entry *h = rb_entry(browser->b.top, |
| 657 | 660 | struct hist_entry, rb_node); |
| 658 | 661 | ui_helpline__pop(); |
| 659 | − ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", | |
| 662 | + ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", | |
| 660 | 663 | seq++, browser->b.nr_entries, |
| 661 | 664 | browser->hists->nr_entries, |
| 665 | + browser->b.extra_title_lines, | |
| 662 | 666 | browser->b.rows, |
| 663 | 667 | browser->b.index, |
| 664 | 668 | browser->b.top_idx, |
| @@ -733,7 +737,7 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser, · 68 unmodified lines | ||
| 733 | 737 | } |
| 734 | 738 | |
| 735 | 739 | ui_browser__set_color(&browser->b, color); |
| 736 | − hist_browser__gotorc(browser, row, 0); | |
| 740 | + ui_browser__gotorc(&browser->b, row, 0); | |
| 737 | 741 | ui_browser__write_nstring(&browser->b, " ", offset); |
| 738 | 742 | ui_browser__printf(&browser->b, "%c", folded_sign); |
| 739 | 743 | ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); |
| @@ -1249,7 +1253,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, · 509 unmodified lines | ||
| 1249 | 1253 | }; |
| 1250 | 1254 | int column = 0; |
| 1251 | 1255 | |
| 1252 | − hist_browser__gotorc(browser, row, 0); | |
| 1256 | + ui_browser__gotorc(&browser->b, row, 0); | |
| 1253 | 1257 | |
| 1254 | 1258 | hists__for_each_format(browser->hists, fmt) { |
| 1255 | 1259 | char s[2048]; |
| @@ -1358,7 +1362,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, · 102 unmodified lines | ||
| 1358 | 1362 | goto show_callchain; |
| 1359 | 1363 | } |
| 1360 | 1364 | |
| 1361 | − hist_browser__gotorc(browser, row, 0); | |
| 1365 | + ui_browser__gotorc(&browser->b, row, 0); | |
| 1362 | 1366 | |
| 1363 | 1367 | if (current_entry && browser->b.navkeypressed) |
| 1364 | 1368 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); |
| @@ -1507,7 +1511,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser, · 142 unmodified lines | ||
| 1507 | 1511 | browser->selection = NULL; |
| 1508 | 1512 | } |
| 1509 | 1513 | |
| 1510 | − hist_browser__gotorc(browser, row, 0); | |
| 1514 | + ui_browser__gotorc(&browser->b, row, 0); | |
| 1511 | 1515 | |
| 1512 | 1516 | if (current_entry && browser->b.navkeypressed) |
| 1513 | 1517 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); |
| @@ -1713,7 +1717,7 @@ static void hists_browser__headers(struct hist_browser *browser) · 199 unmodified lines | ||
| 1713 | 1717 | hists_browser__scnprintf_headers(browser, headers, |
| 1714 | 1718 | sizeof(headers), line); |
| 1715 | 1719 | |
| 1716 | − ui_browser__gotorc(&browser->b, line, 0); | |
| 1720 | + ui_browser__gotorc_title(&browser->b, line, 0); | |
| 1717 | 1721 | ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); |
| 1718 | 1722 | ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); |
| 1719 | 1723 | } |
| @@ -1740,17 +1744,11 @@ static void ui_browser__hists_init_top(struct ui_browser *browser) · 20 unmodified lines | ||
| 1740 | 1744 | static unsigned int hist_browser__refresh(struct ui_browser *browser) |
| 1741 | 1745 | { |
| 1742 | 1746 | unsigned row = 0; |
| 1743 | − u16 header_offset = 0; | |
| 1744 | 1747 | struct rb_node *nd; |
| 1745 | 1748 | struct hist_browser *hb = container_of(browser, struct hist_browser, b); |
| 1746 | − struct hists *hists = hb->hists; | |
| 1747 | − | |
| 1748 | − if (hb->show_headers) { | |
| 1749 | − struct perf_hpp_list *hpp_list = hists->hpp_list; | |
| 1750 | 1749 | |
| 1750 | + if (hb->show_headers) | |
| 1751 | 1751 | hist_browser__show_headers(hb); |
| 1752 | − header_offset = hpp_list->nr_header_lines; | |
| 1753 | − } | |
| 1754 | 1752 | |
| 1755 | 1753 | ui_browser__hists_init_top(browser); |
| 1756 | 1754 | hb->he_selection = NULL; |
| @@ -1788,7 +1786,7 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) · 31 unmodified lines | ||
| 1788 | 1786 | break; |
| 1789 | 1787 | } |
| 1790 | 1788 | |
| 1791 | − return row + header_offset; | |
| 1789 | + return row; | |
| 1792 | 1790 | } |
| 1793 | 1791 | |
| 1794 | 1792 | static struct rb_node *hists__filter_entries(struct rb_node *nd, |
| @@ -2143,6 +2141,7 @@ void hist_browser__init(struct hist_browser *browser, · 348 unmodified lines | ||
| 2143 | 2141 | browser->b.seek = ui_browser__hists_seek; |
| 2144 | 2142 | browser->b.use_navkeypressed = true; |
| 2145 | 2143 | browser->show_headers = symbol_conf.show_hist_headers; |
| 2144 | + hist_browser__set_title_space(browser); | |
| 2146 | 2145 | |
| 2147 | 2146 | if (symbol_conf.report_hierarchy) { |
| 2148 | 2147 | struct perf_hpp_list_node *fmt_node; |
| @@ -2183,7 +2182,7 @@ perf_evsel_browser__new(struct perf_evsel *evsel, · 34 unmodified lines | ||
| 2183 | 2182 | if (browser) { |
| 2184 | 2183 | browser->hbt = hbt; |
| 2185 | 2184 | browser->env = env; |
| 2186 | − browser->title = perf_evsel_browser_title; | |
| 2185 | + browser->title = hists_browser__scnprintf_title; | |
| 2187 | 2186 | } |
| 2188 | 2187 | return browser; |
| 2189 | 2188 | } |
| @@ -2209,84 +2208,11 @@ static inline bool is_report_browser(void *timer) · 19 unmodified lines | ||
| 2209 | 2208 | return timer == NULL; |
| 2210 | 2209 | } |
| 2211 | 2210 | |
| 2212 | −static int perf_evsel_browser_title(struct hist_browser *browser, | |
| 2213 | − char *bf, size_t size) | |
| 2211 | +static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size) | |
| 2214 | 2212 | { |
| 2215 | 2213 | struct hist_browser_timer *hbt = browser->hbt; |
| 2216 | − struct hists *hists = browser->hists; | |
| 2217 | − char unit; | |
| 2218 | − int printed; | |
| 2219 | − const struct dso *dso = hists->dso_filter; | |
| 2220 | − const struct thread *thread = hists->thread_filter; | |
| 2221 | − int socket_id = hists->socket_filter; | |
| 2222 | − unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; | |
| 2223 | − u64 nr_events = hists->stats.total_period; | |
| 2224 | − struct perf_evsel *evsel = hists_to_evsel(hists); | |
| 2225 | − const char *ev_name = perf_evsel__name(evsel); | |
| 2226 | − char buf[512], sample_freq_str[64] = ""; | |
| 2227 | − size_t buflen = sizeof(buf); | |
| 2228 | − char ref[30] = " show reference callgraph, "; | |
| 2229 | − bool enable_ref = false; | |
| 2214 | + int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt)); | |
| 2230 | 2215 | |
| 2231 | − if (symbol_conf.filter_relative) { | |
| 2232 | − nr_samples = hists->stats.nr_non_filtered_samples; | |
| 2233 | − nr_events = hists->stats.total_non_filtered_period; | |
| 2234 | − } | |
| 2235 | − | |
| 2236 | − if (perf_evsel__is_group_event(evsel)) { | |
| 2237 | − struct perf_evsel *pos; | |
| 2238 | − | |
| 2239 | − perf_evsel__group_desc(evsel, buf, buflen); | |
| 2240 | − ev_name = buf; | |
| 2241 | − | |
| 2242 | − for_each_group_member(pos, evsel) { | |
| 2243 | − struct hists *pos_hists = evsel__hists(pos); | |
| 2244 | − | |
| 2245 | − if (symbol_conf.filter_relative) { | |
| 2246 | − nr_samples += pos_hists->stats.nr_non_filtered_samples; | |
| 2247 | − nr_events += pos_hists->stats.total_non_filtered_period; | |
| 2248 | − } else { | |
| 2249 | − nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; | |
| 2250 | − nr_events += pos_hists->stats.total_period; | |
| 2251 | − } | |
| 2252 | − } | |
| 2253 | − } | |
| 2254 | − | |
| 2255 | − if (symbol_conf.show_ref_callgraph && | |
| 2256 | − strstr(ev_name, "call-graph=no")) | |
| 2257 | − enable_ref = true; | |
| 2258 | − | |
| 2259 | − if (!is_report_browser(hbt)) | |
| 2260 | − scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | |
| 2261 | − | |
| 2262 | − nr_samples = convert_unit(nr_samples, &unit); | |
| 2263 | − printed = scnprintf(bf, size, | |
| 2264 | − "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | |
| 2265 | − nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | |
| 2266 | − ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | |
| 2267 | − | |
| 2268 | − | |
| 2269 | − if (hists->uid_filter_str) | |
| 2270 | − printed += snprintf(bf + printed, size - printed, | |
| 2271 | − ", UID: %s", hists->uid_filter_str); | |
| 2272 | − if (thread) { | |
| 2273 | − if (hists__has(hists, thread)) { | |
| 2274 | − printed += scnprintf(bf + printed, size - printed, | |
| 2275 | − ", Thread: %s(%d)", | |
| 2276 | − (thread->comm_set ? thread__comm_str(thread) : ""), | |
| 2277 | − thread->tid); | |
| 2278 | − } else { | |
| 2279 | − printed += scnprintf(bf + printed, size - printed, | |
| 2280 | − ", Thread: %s", | |
| 2281 | − (thread->comm_set ? thread__comm_str(thread) : "")); | |
| 2282 | − } | |
| 2283 | − } | |
| 2284 | − if (dso) | |
| 2285 | − printed += scnprintf(bf + printed, size - printed, | |
| 2286 | − ", DSO: %s", dso->short_name); | |
| 2287 | − if (socket_id > -1) | |
| 2288 | − printed += scnprintf(bf + printed, size - printed, | |
| 2289 | − ", Processor Socket: %d", socket_id); | |
| 2290 | 2216 | if (!is_report_browser(hbt)) { |
| 2291 | 2217 | struct perf_top *top = hbt->arg; |
| 2292 | 2218 | |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include "config.h" |
| 18 | 18 | #include "cache.h" |
| 19 | 19 | #include "symbol.h" |
| 20 | +#include "units.h" | |
| 20 | 21 | #include "debug.h" |
| 21 | 22 | #include "annotate.h" |
| 22 | 23 | #include "evsel.h" |
| @@ -2324,7 +2325,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, · 2301 unmodified lines | ||
| 2324 | 2325 | struct dso *dso = map->dso; |
| 2325 | 2326 | struct rb_root source_line = RB_ROOT; |
| 2326 | 2327 | struct annotation_options opts = annotation__default_options; |
| 2327 | − const char *ev_name = perf_evsel__name(evsel); | |
| 2328 | + struct annotation *notes = symbol__annotation(sym); | |
| 2328 | 2329 | char buf[1024]; |
| 2329 | 2330 | |
| 2330 | 2331 | if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) |
| @@ -2336,12 +2337,8 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, · 5 unmodified lines | ||
| 2336 | 2337 | print_summary(&source_line, dso->long_name); |
| 2337 | 2338 | } |
| 2338 | 2339 | |
| 2339 | − if (perf_evsel__is_group_event(evsel)) { | |
| 2340 | − perf_evsel__group_desc(evsel, buf, sizeof(buf)); | |
| 2341 | − ev_name = buf; | |
| 2342 | − } | |
| 2343 | − | |
| 2344 | − fprintf(stdout, "%s() %s\nEvent: %s\n\n", sym->name, dso->long_name, ev_name); | |
| 2340 | + annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel); | |
| 2341 | + fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name); | |
| 2345 | 2342 | symbol__annotate_fprintf2(sym, stdout); |
| 2346 | 2343 | |
| 2347 | 2344 | annotated_source__purge(symbol__annotation(sym)->src); |
| @@ -2597,6 +2594,46 @@ out_free_offsets: · 249 unmodified lines | ||
| 2597 | 2594 | return -1; |
| 2598 | 2595 | } |
| 2599 | 2596 | |
| 2597 | +int __annotation__scnprintf_samples_period(struct annotation *notes, | |
| 2598 | + char *bf, size_t size, | |
| 2599 | + struct perf_evsel *evsel, | |
| 2600 | + bool show_freq) | |
| 2601 | +{ | |
| 2602 | + const char *ev_name = perf_evsel__name(evsel); | |
| 2603 | + char buf[1024], ref[30] = " show reference callgraph, "; | |
| 2604 | + char sample_freq_str[64] = ""; | |
| 2605 | + unsigned long nr_samples = 0; | |
| 2606 | + int nr_members = 1; | |
| 2607 | + bool enable_ref = false; | |
| 2608 | + u64 nr_events = 0; | |
| 2609 | + char unit; | |
| 2610 | + int i; | |
| 2611 | + | |
| 2612 | + if (perf_evsel__is_group_event(evsel)) { | |
| 2613 | + perf_evsel__group_desc(evsel, buf, sizeof(buf)); | |
| 2614 | + ev_name = buf; | |
| 2615 | + nr_members = evsel->nr_members; | |
| 2616 | + } | |
| 2617 | + | |
| 2618 | + for (i = 0; i < nr_members; i++) { | |
| 2619 | + struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i); | |
| 2620 | + | |
| 2621 | + nr_samples += ah->nr_samples; | |
| 2622 | + nr_events += ah->period; | |
| 2623 | + } | |
| 2624 | + | |
| 2625 | + if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no")) | |
| 2626 | + enable_ref = true; | |
| 2627 | + | |
| 2628 | + if (show_freq) | |
| 2629 | + scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | |
| 2630 | + | |
| 2631 | + nr_samples = convert_unit(nr_samples, &unit); | |
| 2632 | + return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | |
| 2633 | + nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | |
| 2634 | + ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | |
| 2635 | +} | |
| 2636 | + | |
| 2600 | 2637 | #define ANNOTATION__CFG(n) \ |
| 2601 | 2638 | { .name = #n, .value = &annotation__default_options.n, } |
| 2602 | 2639 | |
| @@ -151,6 +151,18 @@ double annotation_line__max_percent(struct annotation_line *al, struct annotatio · 150 unmodified lines | ||
| 151 | 151 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, |
| 152 | 152 | struct annotation_write_ops *ops); |
| 153 | 153 | |
| 154 | +int __annotation__scnprintf_samples_period(struct annotation *notes, | |
| 155 | + char *bf, size_t size, | |
| 156 | + struct perf_evsel *evsel, | |
| 157 | + bool show_freq); | |
| 158 | + | |
| 159 | +static inline int annotation__scnprintf_samples_period(struct annotation *notes, | |
| 160 | + char *bf, size_t size, | |
| 161 | + struct perf_evsel *evsel) | |
| 162 | +{ | |
| 163 | + return __annotation__scnprintf_samples_period(notes, bf, size, evsel, true); | |
| 164 | +} | |
| 165 | + | |
| 154 | 166 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); |
| 155 | 167 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
| 156 | 168 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); |
| @@ -302,13 +302,27 @@ static int auxtrace_queues__split_buffer(struct auxtrace_queues *queues, · 301 unmodified lines | ||
| 302 | 302 | return 0; |
| 303 | 303 | } |
| 304 | 304 | |
| 305 | +static bool filter_cpu(struct perf_session *session, int cpu) | |
| 306 | +{ | |
| 307 | + unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; | |
| 308 | + | |
| 309 | + return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap); | |
| 310 | +} | |
| 311 | + | |
| 305 | 312 | static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, |
| 306 | 313 | struct perf_session *session, |
| 307 | 314 | unsigned int idx, |
| 308 | 315 | struct auxtrace_buffer *buffer, |
| 309 | 316 | struct auxtrace_buffer **buffer_ptr) |
| 310 | 317 | { |
| 311 | − int err; | |
| 318 | + int err = -ENOMEM; | |
| 319 | + | |
| 320 | + if (filter_cpu(session, buffer->cpu)) | |
| 321 | + return 0; | |
| 322 | + | |
| 323 | + buffer = memdup(buffer, sizeof(*buffer)); | |
| 324 | + if (!buffer) | |
| 325 | + return -ENOMEM; | |
| 312 | 326 | |
| 313 | 327 | if (session->one_mmap) { |
| 314 | 328 | buffer->data = buffer->data_offset - session->one_mmap_offset + |
| @@ -316,31 +330,28 @@ static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, · 1 unmodified line | ||
| 316 | 330 | } else if (perf_data__is_pipe(session->data)) { |
| 317 | 331 | buffer->data = auxtrace_copy_data(buffer->size, session); |
| 318 | 332 | if (!buffer->data) |
| 319 | − return -ENOMEM; | |
| 333 | + goto out_free; | |
| 320 | 334 | buffer->data_needs_freeing = true; |
| 321 | 335 | } else if (BITS_PER_LONG == 32 && |
| 322 | 336 | buffer->size > BUFFER_LIMIT_FOR_32_BIT) { |
| 323 | 337 | err = auxtrace_queues__split_buffer(queues, idx, buffer); |
| 324 | 338 | if (err) |
| 325 | − return err; | |
| 339 | + goto out_free; | |
| 326 | 340 | } |
| 327 | 341 | |
| 328 | 342 | err = auxtrace_queues__queue_buffer(queues, idx, buffer); |
| 329 | 343 | if (err) |
| 330 | − return err; | |
| 344 | + goto out_free; | |
| 331 | 345 | |
| 332 | 346 | /* FIXME: Doesn't work for split buffer */ |
| 333 | 347 | if (buffer_ptr) |
| 334 | 348 | *buffer_ptr = buffer; |
| 335 | 349 | |
| 336 | 350 | return 0; |
| 337 | −} | |
| 338 | 351 | |
| 339 | −static bool filter_cpu(struct perf_session *session, int cpu) | |
| 340 | −{ | |
| 341 | − unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; | |
| 342 | − | |
| 343 | − return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap); | |
| 352 | +out_free: | |
| 353 | + auxtrace_buffer__free(buffer); | |
| 354 | + return err; | |
| 344 | 355 | } |
| 345 | 356 | |
| 346 | 357 | int auxtrace_queues__add_event(struct auxtrace_queues *queues, |
| @@ -348,36 +359,19 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues, · 1 unmodified line | ||
| 348 | 359 | union perf_event *event, off_t data_offset, |
| 349 | 360 | struct auxtrace_buffer **buffer_ptr) |
| 350 | 361 | { |
| 351 | − struct auxtrace_buffer *buffer; | |
| 352 | − unsigned int idx; | |
| 353 | − int err; | |
| 354 | − | |
| 355 | − if (filter_cpu(session, event->auxtrace.cpu)) | |
| 356 | − return 0; | |
| 357 | − | |
| 358 | − buffer = zalloc(sizeof(struct auxtrace_buffer)); | |
| 359 | − if (!buffer) | |
| 360 | − return -ENOMEM; | |
| 361 | − | |
| 362 | − buffer->pid = -1; | |
| 363 | − buffer->tid = event->auxtrace.tid; | |
| 364 | − buffer->cpu = event->auxtrace.cpu; | |
| 365 | − buffer->data_offset = data_offset; | |
| 366 | − buffer->offset = event->auxtrace.offset; | |
| 367 | − buffer->reference = event->auxtrace.reference; | |
| 368 | − buffer->size = event->auxtrace.size; | |
| 369 | − idx = event->auxtrace.idx; | |
| 370 | − | |
| 371 | − err = auxtrace_queues__add_buffer(queues, session, idx, buffer, | |
| 372 | − buffer_ptr); | |
| 373 | − if (err) | |
| 374 | − goto out_err; | |
| 375 | − | |
| 376 | − return 0; | |
| 362 | + struct auxtrace_buffer buffer = { | |
| 363 | + .pid = -1, | |
| 364 | + .tid = event->auxtrace.tid, | |
| 365 | + .cpu = event->auxtrace.cpu, | |
| 366 | + .data_offset = data_offset, | |
| 367 | + .offset = event->auxtrace.offset, | |
| 368 | + .reference = event->auxtrace.reference, | |
| 369 | + .size = event->auxtrace.size, | |
| 370 | + }; | |
| 371 | + unsigned int idx = event->auxtrace.idx; | |
| 377 | 372 | |
| 378 | −out_err: | |
| 379 | − auxtrace_buffer__free(buffer); | |
| 380 | − return err; | |
| 373 | + return auxtrace_queues__add_buffer(queues, session, idx, &buffer, | |
| 374 | + buffer_ptr); | |
| 381 | 375 | } |
| 382 | 376 | |
| 383 | 377 | static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, |
| @@ -41,7 +41,7 @@ int test__clang_to_IR(void) · 40 unmodified lines | ||
| 41 | 41 | if (!M) |
| 42 | 42 | return -1; |
| 43 | 43 | for (llvm::Function& F : *M) |
| 44 | − if (F.getName() == "bpf_func__SyS_epoll_wait") | |
| 44 | + if (F.getName() == "bpf_func__SyS_epoll_pwait") | |
| 45 | 45 | return 0; |
| 46 | 46 | return -1; |
| 47 | 47 | } |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | * Copyright (C) 2016 Huawei Inc. |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | +#include "clang/Basic/Version.h" | |
| 12 | 13 | #include "clang/CodeGen/CodeGenAction.h" |
| 13 | 14 | #include "clang/Frontend/CompilerInvocation.h" |
| 14 | 15 | #include "clang/Frontend/CompilerInstance.h" |
| @@ -58,7 +59,8 @@ createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path, · 43 unmodified lines | ||
| 58 | 59 | |
| 59 | 60 | FrontendOptions& Opts = CI->getFrontendOpts(); |
| 60 | 61 | Opts.Inputs.clear(); |
| 61 | − Opts.Inputs.emplace_back(Path, IK_C); | |
| 62 | + Opts.Inputs.emplace_back(Path, | |
| 63 | + FrontendOptions::getInputKindForExtension("c")); | |
| 62 | 64 | return CI; |
| 63 | 65 | } |
| 64 | 66 | |
| @@ -71,10 +73,17 @@ getModuleFromSource(llvm::opt::ArgStringList CFlags, · 6 unmodified lines | ||
| 71 | 73 | |
| 72 | 74 | Clang.setVirtualFileSystem(&*VFS); |
| 73 | 75 | |
| 76 | +#if CLANG_VERSION_MAJOR < 4 | |
| 74 | 77 | IntrusiveRefCntPtr<CompilerInvocation> CI = |
| 75 | 78 | createCompilerInvocation(std::move(CFlags), Path, |
| 76 | 79 | Clang.getDiagnostics()); |
| 77 | 80 | Clang.setInvocation(&*CI); |
| 81 | +#else | |
| 82 | + std::shared_ptr<CompilerInvocation> CI( | |
| 83 | + createCompilerInvocation(std::move(CFlags), Path, | |
| 84 | + Clang.getDiagnostics())); | |
| 85 | + Clang.setInvocation(CI); | |
| 86 | +#endif | |
| 78 | 87 | |
| 79 | 88 | std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx)); |
| 80 | 89 | if (!Clang.ExecuteAction(*Act)) |
| @@ -979,7 +979,7 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) · 978 unmodified lines | ||
| 979 | 979 | return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); |
| 980 | 980 | } |
| 981 | 981 | |
| 982 | −#ifdef HAVE_DWARF_GETLOCATIONS | |
| 982 | +#ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT | |
| 983 | 983 | /** |
| 984 | 984 | * die_get_var_innermost_scope - Get innermost scope range of given variable DIE |
| 985 | 985 | * @sp_die: a subprogram DIE |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include "session.h" |
| 7 | 7 | #include "namespaces.h" |
| 8 | 8 | #include "sort.h" |
| 9 | +#include "units.h" | |
| 9 | 10 | #include "evlist.h" |
| 10 | 11 | #include "evsel.h" |
| 11 | 12 | #include "annotate.h" |
| @@ -14,6 +15,7 @@ · 2 unmodified lines | ||
| 14 | 15 | #include "ui/progress.h" |
| 15 | 16 | #include <errno.h> |
| 16 | 17 | #include <math.h> |
| 18 | +#include <inttypes.h> | |
| 17 | 19 | #include <sys/param.h> |
| 18 | 20 | |
| 19 | 21 | static bool hists__filter_entry_by_dso(struct hists *hists, |
| @@ -2454,6 +2456,85 @@ u64 hists__total_period(struct hists *hists) · 2434 unmodified lines | ||
| 2454 | 2456 | hists->stats.total_period; |
| 2455 | 2457 | } |
| 2456 | 2458 | |
| 2459 | +int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq) | |
| 2460 | +{ | |
| 2461 | + char unit; | |
| 2462 | + int printed; | |
| 2463 | + const struct dso *dso = hists->dso_filter; | |
| 2464 | + const struct thread *thread = hists->thread_filter; | |
| 2465 | + int socket_id = hists->socket_filter; | |
| 2466 | + unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; | |
| 2467 | + u64 nr_events = hists->stats.total_period; | |
| 2468 | + struct perf_evsel *evsel = hists_to_evsel(hists); | |
| 2469 | + const char *ev_name = perf_evsel__name(evsel); | |
| 2470 | + char buf[512], sample_freq_str[64] = ""; | |
| 2471 | + size_t buflen = sizeof(buf); | |
| 2472 | + char ref[30] = " show reference callgraph, "; | |
| 2473 | + bool enable_ref = false; | |
| 2474 | + | |
| 2475 | + if (symbol_conf.filter_relative) { | |
| 2476 | + nr_samples = hists->stats.nr_non_filtered_samples; | |
| 2477 | + nr_events = hists->stats.total_non_filtered_period; | |
| 2478 | + } | |
| 2479 | + | |
| 2480 | + if (perf_evsel__is_group_event(evsel)) { | |
| 2481 | + struct perf_evsel *pos; | |
| 2482 | + | |
| 2483 | + perf_evsel__group_desc(evsel, buf, buflen); | |
| 2484 | + ev_name = buf; | |
| 2485 | + | |
| 2486 | + for_each_group_member(pos, evsel) { | |
| 2487 | + struct hists *pos_hists = evsel__hists(pos); | |
| 2488 | + | |
| 2489 | + if (symbol_conf.filter_relative) { | |
| 2490 | + nr_samples += pos_hists->stats.nr_non_filtered_samples; | |
| 2491 | + nr_events += pos_hists->stats.total_non_filtered_period; | |
| 2492 | + } else { | |
| 2493 | + nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; | |
| 2494 | + nr_events += pos_hists->stats.total_period; | |
| 2495 | + } | |
| 2496 | + } | |
| 2497 | + } | |
| 2498 | + | |
| 2499 | + if (symbol_conf.show_ref_callgraph && | |
| 2500 | + strstr(ev_name, "call-graph=no")) | |
| 2501 | + enable_ref = true; | |
| 2502 | + | |
| 2503 | + if (show_freq) | |
| 2504 | + scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | |
| 2505 | + | |
| 2506 | + nr_samples = convert_unit(nr_samples, &unit); | |
| 2507 | + printed = scnprintf(bf, size, | |
| 2508 | + "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | |
| 2509 | + nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | |
| 2510 | + ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | |
| 2511 | + | |
| 2512 | + | |
| 2513 | + if (hists->uid_filter_str) | |
| 2514 | + printed += snprintf(bf + printed, size - printed, | |
| 2515 | + ", UID: %s", hists->uid_filter_str); | |
| 2516 | + if (thread) { | |
| 2517 | + if (hists__has(hists, thread)) { | |
| 2518 | + printed += scnprintf(bf + printed, size - printed, | |
| 2519 | + ", Thread: %s(%d)", | |
| 2520 | + (thread->comm_set ? thread__comm_str(thread) : ""), | |
| 2521 | + thread->tid); | |
| 2522 | + } else { | |
| 2523 | + printed += scnprintf(bf + printed, size - printed, | |
| 2524 | + ", Thread: %s", | |
| 2525 | + (thread->comm_set ? thread__comm_str(thread) : "")); | |
| 2526 | + } | |
| 2527 | + } | |
| 2528 | + if (dso) | |
| 2529 | + printed += scnprintf(bf + printed, size - printed, | |
| 2530 | + ", DSO: %s", dso->short_name); | |
| 2531 | + if (socket_id > -1) | |
| 2532 | + printed += scnprintf(bf + printed, size - printed, | |
| 2533 | + ", Processor Socket: %d", socket_id); | |
| 2534 | + | |
| 2535 | + return printed; | |
| 2536 | +} | |
| 2537 | + | |
| 2457 | 2538 | int parse_filter_percentage(const struct option *opt __maybe_unused, |
| 2458 | 2539 | const char *arg, int unset __maybe_unused) |
| 2459 | 2540 | { |
| @@ -61,6 +61,7 @@ enum hist_column { · 60 unmodified lines | ||
| 61 | 61 | HISTC_SRCLINE_TO, |
| 62 | 62 | HISTC_TRACE, |
| 63 | 63 | HISTC_SYM_SIZE, |
| 64 | + HISTC_DSO_SIZE, | |
| 64 | 65 | HISTC_NR_COLS, /* Last entry */ |
| 65 | 66 | }; |
| 66 | 67 | |
| @@ -503,5 +504,11 @@ int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...); · 436 unmodified lines | ||
| 503 | 504 | int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, |
| 504 | 505 | struct perf_hpp_list *hpp_list); |
| 505 | 506 | int hists__fprintf_headers(struct hists *hists, FILE *fp); |
| 507 | +int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq); | |
| 508 | + | |
| 509 | +static inline int hists__scnprintf_title(struct hists *hists, char *bf, size_t size) | |
| 510 | +{ | |
| 511 | + return __hists__scnprintf_title(hists, bf, size, true); | |
| 512 | +} | |
| 506 | 513 | |
| 507 | 514 | #endif /* __PERF_HIST_H */ |
| @@ -103,6 +103,10 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip) · 102 unmodified lines | ||
| 103 | 103 | return ip; |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | +static inline size_t map__size(const struct map *map) | |
| 107 | +{ | |
| 108 | + return map->end - map->start; | |
| 109 | +} | |
| 106 | 110 | |
| 107 | 111 | /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ |
| 108 | 112 | u64 map__rip_2objdump(struct map *map, u64 rip); |
| @@ -1591,7 +1591,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session) · 1590 unmodified lines | ||
| 1591 | 1591 | drop_rate = (double)stats->total_lost_samples / |
| 1592 | 1592 | (double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples); |
| 1593 | 1593 | if (drop_rate > 0.05) { |
| 1594 | − ui__warning("Processed %" PRIu64 " samples and lost %3.2f%% samples!\n\n", | |
| 1594 | + ui__warning("Processed %" PRIu64 " samples and lost %3.2f%%!\n\n", | |
| 1595 | 1595 | stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples, |
| 1596 | 1596 | drop_rate * 100.0); |
| 1597 | 1597 | } |
| @@ -1545,6 +1545,46 @@ struct sort_entry sort_sym_size = { · 1544 unmodified lines | ||
| 1545 | 1545 | .se_width_idx = HISTC_SYM_SIZE, |
| 1546 | 1546 | }; |
| 1547 | 1547 | |
| 1548 | +/* --sort dso_size */ | |
| 1549 | + | |
| 1550 | +static int64_t _sort__dso_size_cmp(struct map *map_l, struct map *map_r) | |
| 1551 | +{ | |
| 1552 | + int64_t size_l = map_l != NULL ? map__size(map_l) : 0; | |
| 1553 | + int64_t size_r = map_r != NULL ? map__size(map_r) : 0; | |
| 1554 | + | |
| 1555 | + return size_l < size_r ? -1 : | |
| 1556 | + size_l == size_r ? 0 : 1; | |
| 1557 | +} | |
| 1558 | + | |
| 1559 | +static int64_t | |
| 1560 | +sort__dso_size_cmp(struct hist_entry *left, struct hist_entry *right) | |
| 1561 | +{ | |
| 1562 | + return _sort__dso_size_cmp(right->ms.map, left->ms.map); | |
| 1563 | +} | |
| 1564 | + | |
| 1565 | +static int _hist_entry__dso_size_snprintf(struct map *map, char *bf, | |
| 1566 | + size_t bf_size, unsigned int width) | |
| 1567 | +{ | |
| 1568 | + if (map && map->dso) | |
| 1569 | + return repsep_snprintf(bf, bf_size, "%*d", width, | |
| 1570 | + map__size(map)); | |
| 1571 | + | |
| 1572 | + return repsep_snprintf(bf, bf_size, "%*s", width, "unknown"); | |
| 1573 | +} | |
| 1574 | + | |
| 1575 | +static int hist_entry__dso_size_snprintf(struct hist_entry *he, char *bf, | |
| 1576 | + size_t size, unsigned int width) | |
| 1577 | +{ | |
| 1578 | + return _hist_entry__dso_size_snprintf(he->ms.map, bf, size, width); | |
| 1579 | +} | |
| 1580 | + | |
| 1581 | +struct sort_entry sort_dso_size = { | |
| 1582 | + .se_header = "DSO size", | |
| 1583 | + .se_cmp = sort__dso_size_cmp, | |
| 1584 | + .se_snprintf = hist_entry__dso_size_snprintf, | |
| 1585 | + .se_width_idx = HISTC_DSO_SIZE, | |
| 1586 | +}; | |
| 1587 | + | |
| 1548 | 1588 | |
| 1549 | 1589 | struct sort_dimension { |
| 1550 | 1590 | const char *name; |
| @@ -1569,6 +1609,7 @@ static struct sort_dimension common_sort_dimensions[] = { · 18 unmodified lines | ||
| 1569 | 1609 | DIM(SORT_TRANSACTION, "transaction", sort_transaction), |
| 1570 | 1610 | DIM(SORT_TRACE, "trace", sort_trace), |
| 1571 | 1611 | DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), |
| 1612 | + DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size), | |
| 1572 | 1613 | DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), |
| 1573 | 1614 | }; |
| 1574 | 1615 | |
| @@ -220,6 +220,7 @@ enum sort_type { · 219 unmodified lines | ||
| 220 | 220 | SORT_TRANSACTION, |
| 221 | 221 | SORT_TRACE, |
| 222 | 222 | SORT_SYM_SIZE, |
| 223 | + SORT_DSO_SIZE, | |
| 223 | 224 | SORT_CGROUP_ID, |
| 224 | 225 | |
| 225 | 226 | /* branch stack specific sort keys */ |
| @@ -11,8 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <stdlib.h> |
| 12 | 12 | #include <stdarg.h> |
| 13 | 13 | #include <linux/compiler.h> |
| 14 | −#include <linux/types.h> | |
| 15 | −#include "namespaces.h" | |
| 14 | +#include <sys/types.h> | |
| 16 | 15 | |
| 17 | 16 | /* General helper functions */ |
| 18 | 17 | void usage(const char *err) __noreturn; |
| @@ -26,6 +25,7 @@ static inline void *zalloc(size_t size) · 7 unmodified lines | ||
| 26 | 25 | #define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) |
| 27 | 26 | |
| 28 | 27 | struct dirent; |
| 28 | +struct nsinfo; | |
| 29 | 29 | struct strlist; |
| 30 | 30 | |
| 31 | 31 | int mkdir_p(char *path, mode_t mode); |