Commit 174e7194 authored by Linus Torvalds's avatar Linus Torvalds

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

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 ')'
  ...
parents 19ca90de 32e6e967
...@@ -1153,7 +1153,6 @@ static void setup_pebs_sample_data(struct perf_event *event, ...@@ -1153,7 +1153,6 @@ static void setup_pebs_sample_data(struct perf_event *event,
if (pebs == NULL) if (pebs == NULL)
return; return;
regs->flags &= ~PERF_EFLAGS_EXACT;
sample_type = event->attr.sample_type; sample_type = event->attr.sample_type;
dsrc = sample_type & PERF_SAMPLE_DATA_SRC; dsrc = sample_type & PERF_SAMPLE_DATA_SRC;
...@@ -1197,7 +1196,13 @@ static void setup_pebs_sample_data(struct perf_event *event, ...@@ -1197,7 +1196,13 @@ static void setup_pebs_sample_data(struct perf_event *event,
* and PMI. * and PMI.
*/ */
*regs = *iregs; *regs = *iregs;
regs->flags = pebs->flags;
/*
* Initialize regs_>flags from PEBS,
* Clear exact bit (which uses x86 EFLAGS Reserved bit 3),
* i.e., do not rely on it being zero:
*/
regs->flags = pebs->flags & ~PERF_EFLAGS_EXACT;
if (sample_type & PERF_SAMPLE_REGS_INTR) { if (sample_type & PERF_SAMPLE_REGS_INTR) {
regs->ax = pebs->ax; regs->ax = pebs->ax;
...@@ -1217,10 +1222,6 @@ static void setup_pebs_sample_data(struct perf_event *event, ...@@ -1217,10 +1222,6 @@ static void setup_pebs_sample_data(struct perf_event *event,
regs->sp = pebs->sp; regs->sp = pebs->sp;
} }
/*
* Preserve PERF_EFLAGS_VM from set_linear_ip().
*/
regs->flags = pebs->flags | (regs->flags & PERF_EFLAGS_VM);
#ifndef CONFIG_X86_32 #ifndef CONFIG_X86_32
regs->r8 = pebs->r8; regs->r8 = pebs->r8;
regs->r9 = pebs->r9; regs->r9 = pebs->r9;
...@@ -1234,20 +1235,33 @@ static void setup_pebs_sample_data(struct perf_event *event, ...@@ -1234,20 +1235,33 @@ static void setup_pebs_sample_data(struct perf_event *event,
} }
if (event->attr.precise_ip > 1) { if (event->attr.precise_ip > 1) {
/* Haswell and later have the eventing IP, so use it: */ /*
* Haswell and later processors have an 'eventing IP'
* (real IP) which fixes the off-by-1 skid in hardware.
* Use it when precise_ip >= 2 :
*/
if (x86_pmu.intel_cap.pebs_format >= 2) { if (x86_pmu.intel_cap.pebs_format >= 2) {
set_linear_ip(regs, pebs->real_ip); set_linear_ip(regs, pebs->real_ip);
regs->flags |= PERF_EFLAGS_EXACT; regs->flags |= PERF_EFLAGS_EXACT;
} else { } else {
/* Otherwise use PEBS off-by-1 IP: */ /* Otherwise, use PEBS off-by-1 IP: */
set_linear_ip(regs, pebs->ip); set_linear_ip(regs, pebs->ip);
/* ... and try to fix it up using the LBR entries: */ /*
* With precise_ip >= 2, try to fix up the off-by-1 IP
* using the LBR. If successful, the fixup function
* corrects regs->ip and calls set_linear_ip() on regs:
*/
if (intel_pmu_pebs_fixup_ip(regs)) if (intel_pmu_pebs_fixup_ip(regs))
regs->flags |= PERF_EFLAGS_EXACT; regs->flags |= PERF_EFLAGS_EXACT;
} }
} else } else {
/*
* When precise_ip == 1, return the PEBS off-by-1 IP,
* no fixup attempted:
*/
set_linear_ip(regs, pebs->ip); set_linear_ip(regs, pebs->ip);
}
if ((sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR)) && if ((sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR)) &&
......
...@@ -4447,6 +4447,9 @@ static void _free_event(struct perf_event *event) ...@@ -4447,6 +4447,9 @@ static void _free_event(struct perf_event *event)
if (event->ctx) if (event->ctx)
put_ctx(event->ctx); put_ctx(event->ctx);
if (event->hw.target)
put_task_struct(event->hw.target);
exclusive_event_destroy(event); exclusive_event_destroy(event);
module_put(event->pmu->module); module_put(event->pmu->module);
...@@ -8397,6 +8400,10 @@ static int perf_kprobe_event_init(struct perf_event *event) ...@@ -8397,6 +8400,10 @@ static int perf_kprobe_event_init(struct perf_event *event)
if (event->attr.type != perf_kprobe.type) if (event->attr.type != perf_kprobe.type)
return -ENOENT; return -ENOENT;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
/* /*
* no branch sampling for probe events * no branch sampling for probe events
*/ */
...@@ -8434,6 +8441,10 @@ static int perf_uprobe_event_init(struct perf_event *event) ...@@ -8434,6 +8441,10 @@ static int perf_uprobe_event_init(struct perf_event *event)
if (event->attr.type != perf_uprobe.type) if (event->attr.type != perf_uprobe.type)
return -ENOENT; return -ENOENT;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
/* /*
* no branch sampling for probe events * no branch sampling for probe events
*/ */
...@@ -9955,6 +9966,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, ...@@ -9955,6 +9966,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
* and we cannot use the ctx information because we need the * and we cannot use the ctx information because we need the
* pmu before we get a ctx. * pmu before we get a ctx.
*/ */
get_task_struct(task);
event->hw.target = task; event->hw.target = task;
} }
...@@ -10070,6 +10082,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, ...@@ -10070,6 +10082,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
perf_detach_cgroup(event); perf_detach_cgroup(event);
if (event->ns) if (event->ns)
put_pid_ns(event->ns); put_pid_ns(event->ns);
if (event->hw.target)
put_task_struct(event->hw.target);
kfree(event); kfree(event);
return ERR_PTR(err); return ERR_PTR(err);
......
...@@ -252,6 +252,8 @@ int perf_kprobe_init(struct perf_event *p_event, bool is_retprobe) ...@@ -252,6 +252,8 @@ int perf_kprobe_init(struct perf_event *p_event, bool is_retprobe)
ret = strncpy_from_user( ret = strncpy_from_user(
func, u64_to_user_ptr(p_event->attr.kprobe_func), func, u64_to_user_ptr(p_event->attr.kprobe_func),
KSYM_NAME_LEN); KSYM_NAME_LEN);
if (ret == KSYM_NAME_LEN)
ret = -E2BIG;
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -300,6 +302,8 @@ int perf_uprobe_init(struct perf_event *p_event, bool is_retprobe) ...@@ -300,6 +302,8 @@ int perf_uprobe_init(struct perf_event *p_event, bool is_retprobe)
return -ENOMEM; return -ENOMEM;
ret = strncpy_from_user( ret = strncpy_from_user(
path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX); path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX);
if (ret == PATH_MAX)
return -E2BIG;
if (ret < 0) if (ret < 0)
goto out; goto out;
if (path[0] == '\0') { if (path[0] == '\0') {
......
...@@ -151,6 +151,8 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, ...@@ -151,6 +151,8 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
return; return;
ret = strncpy_from_user(dst, src, maxlen); ret = strncpy_from_user(dst, src, maxlen);
if (ret == maxlen)
dst[--ret] = '\0';
if (ret < 0) { /* Failed to fetch string */ if (ret < 0) { /* Failed to fetch string */
((u8 *)get_rloc_data(dest))[0] = '\0'; ((u8 *)get_rloc_data(dest))[0] = '\0';
......
...@@ -316,6 +316,7 @@ ...@@ -316,6 +316,7 @@
#define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ #define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */
#define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ #define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */
#define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ #define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */
#define X86_FEATURE_TME (16*32+13) /* Intel Total Memory Encryption */
#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */
#define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */
#define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */
...@@ -328,6 +329,7 @@ ...@@ -328,6 +329,7 @@
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */
#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
#define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */
#define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */
#define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */
#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TOOLS_CONFIG_H
#define _TOOLS_CONFIG_H
/* Subset of include/linux/kconfig.h */
#define __ARG_PLACEHOLDER_1 0,
#define __take_second_arg(__ignored, val, ...) val
/*
* Helper macros to use CONFIG_ options in C/CPP expressions. Note that
* these only work with boolean and tristate options.
*/
/*
* Getting something that works in C and CPP for an arg that may or may
* not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1"
* we match on the placeholder define, insert the "0," for arg1 and generate
* the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one).
* When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
* the last step cherry picks the 2nd arg, we get a zero.
*/
#define __is_defined(x) ___is_defined(x)
#define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val)
#define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0)
/*
* IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
* otherwise. For boolean options, this is equivalent to
* IS_ENABLED(CONFIG_FOO).
*/
#define IS_BUILTIN(option) __is_defined(option)
#endif /* _TOOLS_CONFIG_H */
...@@ -318,6 +318,7 @@ typedef struct _drm_i915_sarea { ...@@ -318,6 +318,7 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_PERF_OPEN 0x36 #define DRM_I915_PERF_OPEN 0x36
#define DRM_I915_PERF_ADD_CONFIG 0x37 #define DRM_I915_PERF_ADD_CONFIG 0x37
#define DRM_I915_PERF_REMOVE_CONFIG 0x38 #define DRM_I915_PERF_REMOVE_CONFIG 0x38
#define DRM_I915_QUERY 0x39
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
...@@ -375,6 +376,7 @@ typedef struct _drm_i915_sarea { ...@@ -375,6 +376,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) #define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param)
#define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) #define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config)
#define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64)
#define DRM_IOCTL_I915_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query)
/* Allow drivers to submit batchbuffers directly to hardware, relying /* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware. * on the security mechanisms provided by hardware.
...@@ -1358,7 +1360,9 @@ struct drm_intel_overlay_attrs { ...@@ -1358,7 +1360,9 @@ struct drm_intel_overlay_attrs {
* active on a given plane. * active on a given plane.
*/ */
#define I915_SET_COLORKEY_NONE (1<<0) /* disable color key matching */ #define I915_SET_COLORKEY_NONE (1<<0) /* Deprecated. Instead set
* flags==0 to disable colorkeying.
*/
#define I915_SET_COLORKEY_DESTINATION (1<<1) #define I915_SET_COLORKEY_DESTINATION (1<<1)
#define I915_SET_COLORKEY_SOURCE (1<<2) #define I915_SET_COLORKEY_SOURCE (1<<2)
struct drm_intel_sprite_colorkey { struct drm_intel_sprite_colorkey {
...@@ -1604,15 +1608,115 @@ struct drm_i915_perf_oa_config { ...@@ -1604,15 +1608,115 @@ struct drm_i915_perf_oa_config {
__u32 n_flex_regs; __u32 n_flex_regs;
/* /*
* These fields are pointers to tuples of u32 values (register * These fields are pointers to tuples of u32 values (register address,
* address, value). For example the expected length of the buffer * value). For example the expected length of the buffer pointed by
* pointed by mux_regs_ptr is (2 * sizeof(u32) * n_mux_regs). * mux_regs_ptr is (2 * sizeof(u32) * n_mux_regs).
*/ */
__u64 mux_regs_ptr; __u64 mux_regs_ptr;
__u64 boolean_regs_ptr; __u64 boolean_regs_ptr;
__u64 flex_regs_ptr; __u64 flex_regs_ptr;
}; };
struct drm_i915_query_item {
__u64 query_id;
#define DRM_I915_QUERY_TOPOLOGY_INFO 1
/*
* When set to zero by userspace, this is filled with the size of the
* data to be written at the data_ptr pointer. The kernel sets this
* value to a negative value to signal an error on a particular query
* item.
*/
__s32 length;
/*
* Unused for now. Must be cleared to zero.
*/
__u32 flags;
/*
* Data will be written at the location pointed by data_ptr when the
* value of length matches the length of the data to be written by the
* kernel.
*/
__u64 data_ptr;
};
struct drm_i915_query {
__u32 num_items;
/*
* Unused for now. Must be cleared to zero.
*/
__u32 flags;
/*
* This points to an array of num_items drm_i915_query_item structures.
*/
__u64 items_ptr;
};
/*
* Data written by the kernel with query DRM_I915_QUERY_TOPOLOGY_INFO :
*
* data: contains the 3 pieces of information :
*
* - the slice mask with one bit per slice telling whether a slice is
* available. The availability of slice X can be queried with the following
* formula :
*
* (data[X / 8] >> (X % 8)) & 1
*
* - the subslice mask for each slice with one bit per subslice telling
* whether a subslice is available. The availability of subslice Y in slice
* X can be queried with the following formula :
*
* (data[subslice_offset +
* X * subslice_stride +
* Y / 8] >> (Y % 8)) & 1
*
* - the EU mask for each subslice in each slice with one bit per EU telling
* whether an EU is available. The availability of EU Z in subslice Y in
* slice X can be queried with the following formula :
*
* (data[eu_offset +
* (X * max_subslices + Y) * eu_stride +
* Z / 8] >> (Z % 8)) & 1
*/
struct drm_i915_query_topology_info {
/*
* Unused for now. Must be cleared to zero.
*/
__u16 flags;
__u16 max_slices;
__u16 max_subslices;
__u16 max_eus_per_subslice;
/*
* Offset in data[] at which the subslice masks are stored.
*/
__u16 subslice_offset;
/*
* Stride at which each of the subslice masks for each slice are
* stored.
*/
__u16 subslice_stride;
/*
* Offset in data[] at which the EU masks are stored.
*/
__u16 eu_offset;
/*
* Stride at which each of the EU masks for each subslice are stored.
*/
__u16 eu_stride;
__u8 data[];
};
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif
......
...@@ -80,6 +80,7 @@ OPTIONS ...@@ -80,6 +80,7 @@ OPTIONS
- comm: command (name) of the task which can be read via /proc/<pid>/comm - comm: command (name) of the task which can be read via /proc/<pid>/comm
- pid: command and tid of the task - pid: command and tid of the task
- dso: name of library or module executed at the time of sample - dso: name of library or module executed at the time of sample
- dso_size: size of library or module executed at the time of sample
- symbol: name of function executed at the time of sample - symbol: name of function executed at the time of sample
- symbol_size: size of function executed at the time of sample - symbol_size: size of function executed at the time of sample
- parent: name of function matched to the parent regex filter. Unmatched - 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. ...@@ -117,6 +117,9 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
--sched:: --sched::
Accrue thread runtime and provide a summary at the end of the session. Accrue thread runtime and provide a summary at the end of the session.
--failure::
Show only syscalls that failed, i.e. that returned < 0.
-i:: -i::
--input:: --input::
Process events from a given perf data file. Process events from a given perf data file.
......
perf-version(1)
===============
NAME
----
perf-version - display the version of perf binary
SYNOPSIS
--------
'perf version' [--build-options]
DESCRIPTION
-----------
With no options given, the 'perf version' prints the perf version
on the standard output.
If the option '--build-options' is given, then the status of
compiled-in libraries are printed on the standard output.
OPTIONS
-------
--build-options::
Prints the status of compiled-in libraries on the
standard output.
...@@ -346,12 +346,16 @@ else ...@@ -346,12 +346,16 @@ else
ifneq ($(feature-dwarf_getlocations), 1) ifneq ($(feature-dwarf_getlocations), 1)
msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157); msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157);
else else
CFLAGS += -DHAVE_DWARF_GETLOCATIONS CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT
endif # dwarf_getlocations endif # dwarf_getlocations
endif # Dwarf support endif # Dwarf support
endif # libelf support endif # libelf support
endif # NO_LIBELF endif # NO_LIBELF
ifeq ($(feature-glibc), 1)
CFLAGS += -DHAVE_GLIBC_SUPPORT
endif
ifdef NO_DWARF ifdef NO_DWARF
NO_LIBDW_DWARF_UNWIND := 1 NO_LIBDW_DWARF_UNWIND := 1
endif endif
...@@ -635,6 +639,7 @@ else ...@@ -635,6 +639,7 @@ else
else else
LDFLAGS += $(PERL_EMBED_LDFLAGS) LDFLAGS += $(PERL_EMBED_LDFLAGS)
EXTLIBS += $(PERL_EMBED_LIBADD) EXTLIBS += $(PERL_EMBED_LIBADD)
CFLAGS += -DHAVE_LIBPERL_SUPPORT
$(call detected,CONFIG_LIBPERL) $(call detected,CONFIG_LIBPERL)
endif endif
endif endif
...@@ -671,6 +676,7 @@ else ...@@ -671,6 +676,7 @@ else
LDFLAGS += $(PYTHON_EMBED_LDFLAGS) LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
EXTLIBS += $(PYTHON_EMBED_LIBADD) EXTLIBS += $(PYTHON_EMBED_LIBADD)
LANG_BINDINGS += $(obj-perf)python/perf.so LANG_BINDINGS += $(obj-perf)python/perf.so
CFLAGS += -DHAVE_LIBPYTHON_SUPPORT
$(call detected,CONFIG_LIBPYTHON) $(call detected,CONFIG_LIBPYTHON)
endif endif
endif endif
......
...@@ -364,7 +364,8 @@ LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive ...@@ -364,7 +364,8 @@ LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive
ifeq ($(USE_CLANG), 1) ifeq ($(USE_CLANG), 1)
CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization
LIBCLANG = $(foreach l,$(CLANGLIBS_LIST),$(wildcard $(shell $(LLVM_CONFIG) --libdir)/libclang$(l).a)) CLANGLIBS_NOEXT_LIST = $(foreach l,$(CLANGLIBS_LIST),$(shell $(LLVM_CONFIG) --libdir)/libclang$(l))
LIBCLANG = $(foreach l,$(CLANGLIBS_NOEXT_LIST),$(wildcard $(l).a $(l).so))
LIBS += -Wl,--start-group $(LIBCLANG) -Wl,--end-group LIBS += -Wl,--start-group $(LIBCLANG) -Wl,--end-group
endif endif
......
...@@ -112,6 +112,7 @@ struct trace { ...@@ -112,6 +112,7 @@ struct trace {
bool multiple_threads; bool multiple_threads;
bool summary; bool summary;
bool summary_only; bool summary_only;
bool failure_only;
bool show_comm; bool show_comm;
bool print_sample; bool print_sample;
bool show_tool_stats; bool show_tool_stats;
...@@ -1565,7 +1566,7 @@ static int trace__printf_interrupted_entry(struct trace *trace) ...@@ -1565,7 +1566,7 @@ static int trace__printf_interrupted_entry(struct trace *trace)
struct thread_trace *ttrace; struct thread_trace *ttrace;
size_t printed; size_t printed;
if (trace->current == NULL) if (trace->failure_only || trace->current == NULL)
return 0; return 0;
ttrace = thread__priv(trace->current); ttrace = thread__priv(trace->current);
...@@ -1638,7 +1639,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, ...@@ -1638,7 +1639,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
args, trace, thread); args, trace, thread);
if (sc->is_exit) { if (sc->is_exit) {
if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output); trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
fprintf(trace->output, "%-70s)\n", ttrace->entry_str); fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
} }
...@@ -1742,7 +1743,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, ...@@ -1742,7 +1743,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
} }
} }
if (trace->summary_only) if (trace->summary_only || (ret >= 0 && trace->failure_only))
goto out; goto out;
trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output); 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, ...@@ -1961,7 +1962,7 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
trace->output); trace->output);
} }
fprintf(trace->output, ")\n"); fprintf(trace->output, "\n");
if (callchain_ret > 0) if (callchain_ret > 0)
trace__fprintf_callchain(trace, sample); trace__fprintf_callchain(trace, sample);
...@@ -3087,6 +3088,8 @@ int cmd_trace(int argc, const char **argv) ...@@ -3087,6 +3088,8 @@ int cmd_trace(int argc, const char **argv)
OPT_INCR('v', "verbose", &verbose, "be more verbose"), OPT_INCR('v', "verbose", &verbose, "be more verbose"),
OPT_BOOLEAN('T', "time", &trace.full_time, OPT_BOOLEAN('T', "time", &trace.full_time,
"Show full timestamp, not time relative to first start"), "Show full timestamp, not time relative to first start"),
OPT_BOOLEAN(0, "failure", &trace.failure_only,
"Show only syscalls that failed"),
OPT_BOOLEAN('s', "summary", &trace.summary_only, OPT_BOOLEAN('s', "summary", &trace.summary_only,
"Show only syscall summary with statistics"), "Show only syscall summary with statistics"),
OPT_BOOLEAN('S', "with-summary", &trace.summary, OPT_BOOLEAN('S', "with-summary", &trace.summary,
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include "builtin.h" #include "builtin.h"
#include "perf.h" #include "perf.h"
#include "color.h"
#include <linux/compiler.h> #include <linux/compiler.h>
#include <tools/config.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <subcmd/parse-options.h>
int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused) int version_verbose;
struct version {
bool build_options;
};
static struct version version;
static struct option version_options[] = {
OPT_BOOLEAN(0, "build-options", &version.build_options,
"display the build options"),
};
static const char * const version_usage[] = {
"perf version [<options>]",
NULL
};
static void on_off_print(const char *status)
{
printf("[ ");
if (!strcmp(status, "OFF"))
color_fprintf(stdout, PERF_COLOR_RED, "%-3s", status);
else
color_fprintf(stdout, PERF_COLOR_GREEN, "%-3s", status);
printf(" ]");
}
static void status_print(const char *name, const char *macro,
const char *status)
{ {
printf("%22s: ", name);
on_off_print(status);
printf(" # %s\n", macro);
}
#define STATUS(__d, __m) \
do { \
if (IS_BUILTIN(__d)) \
status_print(#__m, #__d, "on"); \
else \
status_print(#__m, #__d, "OFF"); \
} while (0)
static void library_status(void)
{
STATUS(HAVE_DWARF_SUPPORT, dwarf);
STATUS(HAVE_DWARF_GETLOCATIONS_SUPPORT, dwarf_getlocations);
STATUS(HAVE_GLIBC_SUPPORT, glibc);
STATUS(HAVE_GTK2_SUPPORT, gtk2);
STATUS(HAVE_LIBAUDIT_SUPPORT, libaudit);
STATUS(HAVE_LIBBFD_SUPPORT, libbfd);
STATUS(HAVE_LIBELF_SUPPORT, libelf);
STATUS(HAVE_LIBNUMA_SUPPORT, libnuma);
STATUS(HAVE_LIBNUMA_SUPPORT, numa_num_possible_cpus);
STATUS(HAVE_LIBPERL_SUPPORT, libperl);
STATUS(HAVE_LIBPYTHON_SUPPORT, libpython);
STATUS(HAVE_SLANG_SUPPORT, libslang);
STATUS(HAVE_LIBCRYPTO_SUPPORT, libcrypto);
STATUS(HAVE_LIBUNWIND_SUPPORT, libunwind);
STATUS(HAVE_DWARF_SUPPORT, libdw-dwarf-unwind);
STATUS(HAVE_ZLIB_SUPPORT, zlib);
STATUS(HAVE_LZMA_SUPPORT, lzma);
STATUS(HAVE_AUXTRACE_SUPPORT, get_cpuid);
STATUS(HAVE_LIBBPF_SUPPORT, bpf);
}
int cmd_version(int argc, const char **argv)
{
argc = parse_options(argc, argv, version_options, version_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
printf("perf version %s\n", perf_version_string); printf("perf version %s\n", perf_version_string);
if (version.build_options || version_verbose == 1)
library_status();
return 0; return 0;
} }
...@@ -190,6 +190,12 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) ...@@ -190,6 +190,12 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
break; break;
} }
if (!strcmp(cmd, "-vv")) {
(*argv)[0] = "version";
version_verbose = 1;
break;
}
/* /*
* Check remaining flags. * Check remaining flags.
*/ */
......
...@@ -84,6 +84,7 @@ struct record_opts { ...@@ -84,6 +84,7 @@ struct record_opts {
struct option; struct option;
extern const char * const *record_usage; extern const char * const *record_usage;
extern struct option *record_options; extern struct option *record_options;
extern int version_verbose;
int record__parse_freq(const struct option *opt, const char *str, int unset); int record__parse_freq(const struct option *opt, const char *str, int unset);
#endif #endif
...@@ -45,11 +45,16 @@ void ui_browser__set_percent_color(struct ui_browser *browser, ...@@ -45,11 +45,16 @@ void ui_browser__set_percent_color(struct ui_browser *browser,
ui_browser__set_color(browser, color); ui_browser__set_color(browser, color);
} }
void ui_browser__gotorc(struct ui_browser *browser, int y, int x) void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x)
{ {
SLsmg_gotorc(browser->y + y, browser->x + x); SLsmg_gotorc(browser->y + y, browser->x + x);
} }
void ui_browser__gotorc(struct ui_browser *browser, int y, int x)
{
SLsmg_gotorc(browser->y + y + browser->extra_title_lines, browser->x + x);
}
void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg, void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg,
unsigned int width) unsigned int width)
{ {
...@@ -191,6 +196,7 @@ void ui_browser__refresh_dimensions(struct ui_browser *browser) ...@@ -191,6 +196,7 @@ void ui_browser__refresh_dimensions(struct ui_browser *browser)
{ {
browser->width = SLtt_Screen_Cols - 1; browser->width = SLtt_Screen_Cols - 1;
browser->height = browser->rows = SLtt_Screen_Rows - 2; browser->height = browser->rows = SLtt_Screen_Rows - 2;
browser->rows -= browser->extra_title_lines;
browser->y = 1; browser->y = 1;
browser->x = 0; browser->x = 0;
} }
...@@ -337,8 +343,8 @@ static int __ui_browser__refresh(struct ui_browser *browser) ...@@ -337,8 +343,8 @@ static int __ui_browser__refresh(struct ui_browser *browser)
else else
width += 1; width += 1;
SLsmg_fill_region(browser->y + row, browser->x, SLsmg_fill_region(browser->y + row + browser->extra_title_lines, browser->x,
browser->height - row, width, ' '); browser->rows - row, width, ' ');
return 0; return 0;
} }
......
...@@ -17,6 +17,7 @@ struct ui_browser { ...@@ -17,6 +17,7 @@ struct ui_browser {
u64 index, top_idx; u64 index, top_idx;
void *top, *entries; void *top, *entries;
u16 y, x, width, height, rows, columns, horiz_scroll; u16 y, x, width, height, rows, columns, horiz_scroll;
u8 extra_title_lines;
int current_color; int current_color;
void *priv; void *priv;
const char *title; const char *title;
...@@ -38,6 +39,7 @@ bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row); ...@@ -38,6 +39,7 @@ bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row);
void ui_browser__refresh_dimensions(struct ui_browser *browser); void ui_browser__refresh_dimensions(struct ui_browser *browser);
void ui_browser__reset_index(struct ui_browser *browser); void ui_browser__reset_index(struct ui_browser *browser);
void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x);
void ui_browser__gotorc(struct ui_browser *browser, int y, int x); void ui_browser__gotorc(struct ui_browser *browser, int y, int x);
void ui_browser__write_nstring(struct ui_browser *browser, const char *msg, void ui_browser__write_nstring(struct ui_browser *browser, const char *msg,
unsigned int width); unsigned int width);
......
...@@ -218,7 +218,7 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser) ...@@ -218,7 +218,7 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser)
annotate_browser__draw_current_jump(browser); annotate_browser__draw_current_jump(browser);
ui_browser__set_color(browser, HE_COLORSET_NORMAL); ui_browser__set_color(browser, HE_COLORSET_NORMAL);
__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1); __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
return ret; return ret;
} }
...@@ -592,21 +592,40 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, ...@@ -592,21 +592,40 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
return __annotate_browser__search_reverse(browser); return __annotate_browser__search_reverse(browser);
} }
static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
{
struct map_symbol *ms = browser->priv;
struct symbol *sym = ms->sym;
char symbol_dso[SYM_TITLE_MAX_SIZE];
if (ui_browser__show(browser, title, help) < 0)
return -1;
sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso));
ui_browser__gotorc_title(browser, 0, 0);
ui_browser__set_color(browser, HE_COLORSET_ROOT);
ui_browser__write_nstring(browser, symbol_dso, browser->width + 1);
return 0;
}
static int annotate_browser__run(struct annotate_browser *browser, static int annotate_browser__run(struct annotate_browser *browser,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct hist_browser_timer *hbt) struct hist_browser_timer *hbt)
{ {
struct rb_node *nd = NULL; struct rb_node *nd = NULL;
struct hists *hists = evsel__hists(evsel);
struct map_symbol *ms = browser->b.priv; struct map_symbol *ms = browser->b.priv;
struct symbol *sym = ms->sym; struct symbol *sym = ms->sym;
struct annotation *notes = symbol__annotation(ms->sym); struct annotation *notes = symbol__annotation(ms->sym);
const char *help = "Press 'h' for help on key bindings"; const char *help = "Press 'h' for help on key bindings";
int delay_secs = hbt ? hbt->refresh : 0; int delay_secs = hbt ? hbt->refresh : 0;
char title[256];
int key; int key;
char title[SYM_TITLE_MAX_SIZE];
sym_title(sym, ms->map, title, sizeof(title)); annotation__scnprintf_samples_period(notes, title, sizeof(title), evsel);
if (ui_browser__show(&browser->b, title, help) < 0)
if (annotate_browser__show(&browser->b, title, help) < 0)
return -1; return -1;
annotate_browser__calc_percent(browser, evsel); annotate_browser__calc_percent(browser, evsel);
...@@ -637,8 +656,11 @@ static int annotate_browser__run(struct annotate_browser *browser, ...@@ -637,8 +656,11 @@ static int annotate_browser__run(struct annotate_browser *browser,
if (hbt) if (hbt)
hbt->timer(hbt->arg); hbt->timer(hbt->arg);
if (delay_secs != 0) if (delay_secs != 0) {
symbol__annotate_decay_histogram(sym, evsel->idx); symbol__annotate_decay_histogram(sym, evsel->idx);
hists__scnprintf_title(hists, title, sizeof(title));
annotate_browser__show(&browser->b, title, help);
}
continue; continue;
case K_TAB: case K_TAB:
if (nd != NULL) { if (nd != NULL) {
...@@ -812,6 +834,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, ...@@ -812,6 +834,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
.seek = ui_browser__list_head_seek, .seek = ui_browser__list_head_seek,
.write = annotate_browser__write, .write = annotate_browser__write,
.filter = disasm_line__filter, .filter = disasm_line__filter,
.extra_title_lines = 1, /* for hists__scnprintf_title() */
.priv = &ms, .priv = &ms,
.use_navkeypressed = true, .use_navkeypressed = true,
}, },
......
...@@ -32,8 +32,7 @@ ...@@ -32,8 +32,7 @@
extern void hist_browser__init_hpp(void); extern void hist_browser__init_hpp(void);
static int perf_evsel_browser_title(struct hist_browser *browser, static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size);
char *bf, size_t size);
static void hist_browser__update_nr_entries(struct hist_browser *hb); static void hist_browser__update_nr_entries(struct hist_browser *hb);
static struct rb_node *hists__filter_entries(struct rb_node *nd, 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) ...@@ -62,6 +61,15 @@ static int hist_browser__get_folding(struct hist_browser *browser)
return unfolded_rows; return unfolded_rows;
} }
static void hist_browser__set_title_space(struct hist_browser *hb)
{
struct ui_browser *browser = &hb->b;
struct hists *hists = hb->hists;
struct perf_hpp_list *hpp_list = hists->hpp_list;
browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0;
}
static u32 hist_browser__nr_entries(struct hist_browser *hb) static u32 hist_browser__nr_entries(struct hist_browser *hb)
{ {
u32 nr_entries; u32 nr_entries;
...@@ -82,10 +90,16 @@ static void hist_browser__update_rows(struct hist_browser *hb) ...@@ -82,10 +90,16 @@ static void hist_browser__update_rows(struct hist_browser *hb)
struct ui_browser *browser = &hb->b; struct ui_browser *browser = &hb->b;
struct hists *hists = hb->hists; struct hists *hists = hb->hists;
struct perf_hpp_list *hpp_list = hists->hpp_list; struct perf_hpp_list *hpp_list = hists->hpp_list;
u16 header_offset, index_row; u16 index_row;
header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0; if (!hb->show_headers) {
browser->rows = browser->height - header_offset; browser->rows += browser->extra_title_lines;
browser->extra_title_lines = 0;
return;
}
browser->extra_title_lines = hpp_list->nr_header_lines;
browser->rows -= browser->extra_title_lines;
/* /*
* Verify if we were at the last line and that line isn't * Verify if we were at the last line and that line isn't
* visibe because we now show the header line(s). * visibe because we now show the header line(s).
...@@ -108,17 +122,6 @@ static void hist_browser__refresh_dimensions(struct ui_browser *browser) ...@@ -108,17 +122,6 @@ static void hist_browser__refresh_dimensions(struct ui_browser *browser)
* changeset. * changeset.
*/ */
ui_browser__refresh_dimensions(browser); ui_browser__refresh_dimensions(browser);
hist_browser__update_rows(hb);
}
static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
{
struct hists *hists = browser->hists;
struct perf_hpp_list *hpp_list = hists->hpp_list;
u16 header_offset;
header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
ui_browser__gotorc(&browser->b, row + header_offset, column);
} }
static void hist_browser__reset(struct hist_browser *browser) static void hist_browser__reset(struct hist_browser *browser)
...@@ -656,9 +659,10 @@ int hist_browser__run(struct hist_browser *browser, const char *help, ...@@ -656,9 +659,10 @@ int hist_browser__run(struct hist_browser *browser, const char *help,
struct hist_entry *h = rb_entry(browser->b.top, struct hist_entry *h = rb_entry(browser->b.top,
struct hist_entry, rb_node); struct hist_entry, rb_node);
ui_helpline__pop(); ui_helpline__pop();
ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
seq++, browser->b.nr_entries, seq++, browser->b.nr_entries,
browser->hists->nr_entries, browser->hists->nr_entries,
browser->b.extra_title_lines,
browser->b.rows, browser->b.rows,
browser->b.index, browser->b.index,
browser->b.top_idx, browser->b.top_idx,
...@@ -733,7 +737,7 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser, ...@@ -733,7 +737,7 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser,
} }
ui_browser__set_color(&browser->b, color); ui_browser__set_color(&browser->b, color);
hist_browser__gotorc(browser, row, 0); ui_browser__gotorc(&browser->b, row, 0);
ui_browser__write_nstring(&browser->b, " ", offset); ui_browser__write_nstring(&browser->b, " ", offset);
ui_browser__printf(&browser->b, "%c", folded_sign); ui_browser__printf(&browser->b, "%c", folded_sign);
ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); 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, ...@@ -1249,7 +1253,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
}; };
int column = 0; int column = 0;
hist_browser__gotorc(browser, row, 0); ui_browser__gotorc(&browser->b, row, 0);
hists__for_each_format(browser->hists, fmt) { hists__for_each_format(browser->hists, fmt) {
char s[2048]; char s[2048];
...@@ -1358,7 +1362,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, ...@@ -1358,7 +1362,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
goto show_callchain; goto show_callchain;
} }
hist_browser__gotorc(browser, row, 0); ui_browser__gotorc(&browser->b, row, 0);
if (current_entry && browser->b.navkeypressed) if (current_entry && browser->b.navkeypressed)
ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
...@@ -1507,7 +1511,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser, ...@@ -1507,7 +1511,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser,
browser->selection = NULL; browser->selection = NULL;
} }
hist_browser__gotorc(browser, row, 0); ui_browser__gotorc(&browser->b, row, 0);
if (current_entry && browser->b.navkeypressed) if (current_entry && browser->b.navkeypressed)
ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
...@@ -1713,7 +1717,7 @@ static void hists_browser__headers(struct hist_browser *browser) ...@@ -1713,7 +1717,7 @@ static void hists_browser__headers(struct hist_browser *browser)
hists_browser__scnprintf_headers(browser, headers, hists_browser__scnprintf_headers(browser, headers,
sizeof(headers), line); sizeof(headers), line);
ui_browser__gotorc(&browser->b, line, 0); ui_browser__gotorc_title(&browser->b, line, 0);
ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
} }
...@@ -1740,17 +1744,11 @@ static void ui_browser__hists_init_top(struct ui_browser *browser) ...@@ -1740,17 +1744,11 @@ static void ui_browser__hists_init_top(struct ui_browser *browser)
static unsigned int hist_browser__refresh(struct ui_browser *browser) static unsigned int hist_browser__refresh(struct ui_browser *browser)
{ {
unsigned row = 0; unsigned row = 0;
u16 header_offset = 0;
struct rb_node *nd; struct rb_node *nd;
struct hist_browser *hb = container_of(browser, struct hist_browser, b); struct hist_browser *hb = container_of(browser, struct hist_browser, b);
struct hists *hists = hb->hists;
if (hb->show_headers) {
struct perf_hpp_list *hpp_list = hists->hpp_list;
if (hb->show_headers)
hist_browser__show_headers(hb); hist_browser__show_headers(hb);
header_offset = hpp_list->nr_header_lines;
}
ui_browser__hists_init_top(browser); ui_browser__hists_init_top(browser);
hb->he_selection = NULL; hb->he_selection = NULL;
...@@ -1788,7 +1786,7 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) ...@@ -1788,7 +1786,7 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
break; break;
} }
return row + header_offset; return row;
} }
static struct rb_node *hists__filter_entries(struct rb_node *nd, static struct rb_node *hists__filter_entries(struct rb_node *nd,
...@@ -2143,6 +2141,7 @@ void hist_browser__init(struct hist_browser *browser, ...@@ -2143,6 +2141,7 @@ void hist_browser__init(struct hist_browser *browser,
browser->b.seek = ui_browser__hists_seek; browser->b.seek = ui_browser__hists_seek;
browser->b.use_navkeypressed = true; browser->b.use_navkeypressed = true;
browser->show_headers = symbol_conf.show_hist_headers; browser->show_headers = symbol_conf.show_hist_headers;
hist_browser__set_title_space(browser);
if (symbol_conf.report_hierarchy) { if (symbol_conf.report_hierarchy) {
struct perf_hpp_list_node *fmt_node; struct perf_hpp_list_node *fmt_node;
...@@ -2183,7 +2182,7 @@ perf_evsel_browser__new(struct perf_evsel *evsel, ...@@ -2183,7 +2182,7 @@ perf_evsel_browser__new(struct perf_evsel *evsel,
if (browser) { if (browser) {
browser->hbt = hbt; browser->hbt = hbt;
browser->env = env; browser->env = env;
browser->title = perf_evsel_browser_title; browser->title = hists_browser__scnprintf_title;
} }
return browser; return browser;
} }
...@@ -2209,84 +2208,11 @@ static inline bool is_report_browser(void *timer) ...@@ -2209,84 +2208,11 @@ static inline bool is_report_browser(void *timer)
return timer == NULL; return timer == NULL;
} }
static int perf_evsel_browser_title(struct hist_browser *browser, static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size)
char *bf, size_t size)
{ {
struct hist_browser_timer *hbt = browser->hbt; struct hist_browser_timer *hbt = browser->hbt;
struct hists *hists = browser->hists; int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt));
char unit;
int printed;
const struct dso *dso = hists->dso_filter;
const struct thread *thread = hists->thread_filter;
int socket_id = hists->socket_filter;
unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
u64 nr_events = hists->stats.total_period;
struct perf_evsel *evsel = hists_to_evsel(hists);
const char *ev_name = perf_evsel__name(evsel);
char buf[512], sample_freq_str[64] = "";
size_t buflen = sizeof(buf);
char ref[30] = " show reference callgraph, ";
bool enable_ref = false;
if (symbol_conf.filter_relative) {
nr_samples = hists->stats.nr_non_filtered_samples;
nr_events = hists->stats.total_non_filtered_period;
}
if (perf_evsel__is_group_event(evsel)) {
struct perf_evsel *pos;
perf_evsel__group_desc(evsel, buf, buflen);
ev_name = buf;
for_each_group_member(pos, evsel) {
struct hists *pos_hists = evsel__hists(pos);
if (symbol_conf.filter_relative) {
nr_samples += pos_hists->stats.nr_non_filtered_samples;
nr_events += pos_hists->stats.total_non_filtered_period;
} else {
nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
nr_events += pos_hists->stats.total_period;
}
}
}
if (symbol_conf.show_ref_callgraph &&
strstr(ev_name, "call-graph=no"))
enable_ref = true;
if (!is_report_browser(hbt))
scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq);
nr_samples = convert_unit(nr_samples, &unit);
printed = scnprintf(bf, size,
"Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
nr_samples, unit, evsel->nr_members > 1 ? "s" : "",
ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
if (hists->uid_filter_str)
printed += snprintf(bf + printed, size - printed,
", UID: %s", hists->uid_filter_str);
if (thread) {
if (hists__has(hists, thread)) {
printed += scnprintf(bf + printed, size - printed,
", Thread: %s(%d)",
(thread->comm_set ? thread__comm_str(thread) : ""),
thread->tid);
} else {
printed += scnprintf(bf + printed, size - printed,
", Thread: %s",
(thread->comm_set ? thread__comm_str(thread) : ""));
}
}
if (dso)
printed += scnprintf(bf + printed, size - printed,
", DSO: %s", dso->short_name);
if (socket_id > -1)
printed += scnprintf(bf + printed, size - printed,
", Processor Socket: %d", socket_id);
if (!is_report_browser(hbt)) { if (!is_report_browser(hbt)) {
struct perf_top *top = hbt->arg; struct perf_top *top = hbt->arg;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "config.h" #include "config.h"
#include "cache.h" #include "cache.h"
#include "symbol.h" #include "symbol.h"
#include "units.h"
#include "debug.h" #include "debug.h"
#include "annotate.h" #include "annotate.h"
#include "evsel.h" #include "evsel.h"
...@@ -2324,7 +2325,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, ...@@ -2324,7 +2325,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map,
struct dso *dso = map->dso; struct dso *dso = map->dso;
struct rb_root source_line = RB_ROOT; struct rb_root source_line = RB_ROOT;
struct annotation_options opts = annotation__default_options; struct annotation_options opts = annotation__default_options;
const char *ev_name = perf_evsel__name(evsel); struct annotation *notes = symbol__annotation(sym);
char buf[1024]; char buf[1024];
if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0)
...@@ -2336,12 +2337,8 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, ...@@ -2336,12 +2337,8 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map,
print_summary(&source_line, dso->long_name); print_summary(&source_line, dso->long_name);
} }
if (perf_evsel__is_group_event(evsel)) { annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel);
perf_evsel__group_desc(evsel, buf, sizeof(buf)); fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name);
ev_name = buf;
}
fprintf(stdout, "%s() %s\nEvent: %s\n\n", sym->name, dso->long_name, ev_name);
symbol__annotate_fprintf2(sym, stdout); symbol__annotate_fprintf2(sym, stdout);
annotated_source__purge(symbol__annotation(sym)->src); annotated_source__purge(symbol__annotation(sym)->src);
...@@ -2597,6 +2594,46 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *ev ...@@ -2597,6 +2594,46 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *ev
return -1; return -1;
} }
int __annotation__scnprintf_samples_period(struct annotation *notes,
char *bf, size_t size,
struct perf_evsel *evsel,
bool show_freq)
{
const char *ev_name = perf_evsel__name(evsel);
char buf[1024], ref[30] = " show reference callgraph, ";
char sample_freq_str[64] = "";
unsigned long nr_samples = 0;
int nr_members = 1;
bool enable_ref = false;
u64 nr_events = 0;
char unit;
int i;
if (perf_evsel__is_group_event(evsel)) {
perf_evsel__group_desc(evsel, buf, sizeof(buf));
ev_name = buf;
nr_members = evsel->nr_members;
}
for (i = 0; i < nr_members; i++) {
struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i);
nr_samples += ah->nr_samples;
nr_events += ah->period;
}
if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no"))
enable_ref = true;
if (show_freq)
scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq);
nr_samples = convert_unit(nr_samples, &unit);
return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
nr_samples, unit, evsel->nr_members > 1 ? "s" : "",
ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
}
#define ANNOTATION__CFG(n) \ #define ANNOTATION__CFG(n) \
{ .name = #n, .value = &annotation__default_options.n, } { .name = #n, .value = &annotation__default_options.n, }
......
...@@ -151,6 +151,18 @@ double annotation_line__max_percent(struct annotation_line *al, struct annotatio ...@@ -151,6 +151,18 @@ double annotation_line__max_percent(struct annotation_line *al, struct annotatio
void annotation_line__write(struct annotation_line *al, struct annotation *notes, void annotation_line__write(struct annotation_line *al, struct annotation *notes,
struct annotation_write_ops *ops); struct annotation_write_ops *ops);
int __annotation__scnprintf_samples_period(struct annotation *notes,
char *bf, size_t size,
struct perf_evsel *evsel,
bool show_freq);
static inline int annotation__scnprintf_samples_period(struct annotation *notes,
char *bf, size_t size,
struct perf_evsel *evsel)
{
return __annotation__scnprintf_samples_period(notes, bf, size, evsel, true);
}
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
size_t disasm__fprintf(struct list_head *head, FILE *fp); size_t disasm__fprintf(struct list_head *head, FILE *fp);
void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); 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, ...@@ -302,13 +302,27 @@ static int auxtrace_queues__split_buffer(struct auxtrace_queues *queues,
return 0; return 0;
} }
static bool filter_cpu(struct perf_session *session, int cpu)
{
unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap;
return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap);
}
static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues,
struct perf_session *session, struct perf_session *session,
unsigned int idx, unsigned int idx,
struct auxtrace_buffer *buffer, struct auxtrace_buffer *buffer,
struct auxtrace_buffer **buffer_ptr) struct auxtrace_buffer **buffer_ptr)
{ {
int err; int err = -ENOMEM;
if (filter_cpu(session, buffer->cpu))
return 0;
buffer = memdup(buffer, sizeof(*buffer));
if (!buffer)
return -ENOMEM;
if (session->one_mmap) { if (session->one_mmap) {
buffer->data = buffer->data_offset - session->one_mmap_offset + buffer->data = buffer->data_offset - session->one_mmap_offset +
...@@ -316,31 +330,28 @@ static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, ...@@ -316,31 +330,28 @@ static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues,
} else if (perf_data__is_pipe(session->data)) { } else if (perf_data__is_pipe(session->data)) {
buffer->data = auxtrace_copy_data(buffer->size, session); buffer->data = auxtrace_copy_data(buffer->size, session);
if (!buffer->data) if (!buffer->data)
return -ENOMEM; goto out_free;
buffer->data_needs_freeing = true; buffer->data_needs_freeing = true;
} else if (BITS_PER_LONG == 32 && } else if (BITS_PER_LONG == 32 &&
buffer->size > BUFFER_LIMIT_FOR_32_BIT) { buffer->size > BUFFER_LIMIT_FOR_32_BIT) {
err = auxtrace_queues__split_buffer(queues, idx, buffer); err = auxtrace_queues__split_buffer(queues, idx, buffer);
if (err) if (err)
return err; goto out_free;
} }
err = auxtrace_queues__queue_buffer(queues, idx, buffer); err = auxtrace_queues__queue_buffer(queues, idx, buffer);
if (err) if (err)
return err; goto out_free;
/* FIXME: Doesn't work for split buffer */ /* FIXME: Doesn't work for split buffer */
if (buffer_ptr) if (buffer_ptr)
*buffer_ptr = buffer; *buffer_ptr = buffer;
return 0; return 0;
}
static bool filter_cpu(struct perf_session *session, int cpu) out_free:
{ auxtrace_buffer__free(buffer);
unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; return err;
return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap);
} }
int auxtrace_queues__add_event(struct auxtrace_queues *queues, int auxtrace_queues__add_event(struct auxtrace_queues *queues,
...@@ -348,36 +359,19 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues, ...@@ -348,36 +359,19 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues,
union perf_event *event, off_t data_offset, union perf_event *event, off_t data_offset,
struct auxtrace_buffer **buffer_ptr) struct auxtrace_buffer **buffer_ptr)
{ {
struct auxtrace_buffer *buffer; struct auxtrace_buffer buffer = {
unsigned int idx; .pid = -1,
int err; .tid = event->auxtrace.tid,
.cpu = event->auxtrace.cpu,
if (filter_cpu(session, event->auxtrace.cpu)) .data_offset = data_offset,
return 0; .offset = event->auxtrace.offset,
.reference = event->auxtrace.reference,
buffer = zalloc(sizeof(struct auxtrace_buffer)); .size = event->auxtrace.size,
if (!buffer) };
return -ENOMEM; unsigned int idx = event->auxtrace.idx;
buffer->pid = -1;
buffer->tid = event->auxtrace.tid;
buffer->cpu = event->auxtrace.cpu;
buffer->data_offset = data_offset;
buffer->offset = event->auxtrace.offset;
buffer->reference = event->auxtrace.reference;
buffer->size = event->auxtrace.size;
idx = event->auxtrace.idx;
err = auxtrace_queues__add_buffer(queues, session, idx, buffer,
buffer_ptr);
if (err)
goto out_err;
return 0;
out_err: return auxtrace_queues__add_buffer(queues, session, idx, &buffer,
auxtrace_buffer__free(buffer); buffer_ptr);
return err;
} }
static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues,
......
...@@ -41,7 +41,7 @@ int test__clang_to_IR(void) ...@@ -41,7 +41,7 @@ int test__clang_to_IR(void)
if (!M) if (!M)
return -1; return -1;
for (llvm::Function& F : *M) for (llvm::Function& F : *M)
if (F.getName() == "bpf_func__SyS_epoll_wait") if (F.getName() == "bpf_func__SyS_epoll_pwait")
return 0; return 0;
return -1; return -1;
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* Copyright (C) 2016 Huawei Inc. * Copyright (C) 2016 Huawei Inc.
*/ */
#include "clang/Basic/Version.h"
#include "clang/CodeGen/CodeGenAction.h" #include "clang/CodeGen/CodeGenAction.h"
#include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInstance.h"
...@@ -58,7 +59,8 @@ createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path, ...@@ -58,7 +59,8 @@ createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path,
FrontendOptions& Opts = CI->getFrontendOpts(); FrontendOptions& Opts = CI->getFrontendOpts();
Opts.Inputs.clear(); Opts.Inputs.clear();
Opts.Inputs.emplace_back(Path, IK_C); Opts.Inputs.emplace_back(Path,
FrontendOptions::getInputKindForExtension("c"));
return CI; return CI;
} }
...@@ -71,10 +73,17 @@ getModuleFromSource(llvm::opt::ArgStringList CFlags, ...@@ -71,10 +73,17 @@ getModuleFromSource(llvm::opt::ArgStringList CFlags,
Clang.setVirtualFileSystem(&*VFS); Clang.setVirtualFileSystem(&*VFS);
#if CLANG_VERSION_MAJOR < 4
IntrusiveRefCntPtr<CompilerInvocation> CI = IntrusiveRefCntPtr<CompilerInvocation> CI =
createCompilerInvocation(std::move(CFlags), Path, createCompilerInvocation(std::move(CFlags), Path,
Clang.getDiagnostics()); Clang.getDiagnostics());
Clang.setInvocation(&*CI); Clang.setInvocation(&*CI);
#else
std::shared_ptr<CompilerInvocation> CI(
createCompilerInvocation(std::move(CFlags), Path,
Clang.getDiagnostics()));
Clang.setInvocation(CI);
#endif
std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx)); std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx));
if (!Clang.ExecuteAction(*Act)) if (!Clang.ExecuteAction(*Act))
......
...@@ -979,7 +979,7 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) ...@@ -979,7 +979,7 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf)
return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die));
} }
#ifdef HAVE_DWARF_GETLOCATIONS #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT
/** /**
* die_get_var_innermost_scope - Get innermost scope range of given variable DIE * die_get_var_innermost_scope - Get innermost scope range of given variable DIE
* @sp_die: a subprogram DIE * @sp_die: a subprogram DIE
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "session.h" #include "session.h"
#include "namespaces.h" #include "namespaces.h"
#include "sort.h" #include "sort.h"
#include "units.h"
#include "evlist.h" #include "evlist.h"
#include "evsel.h" #include "evsel.h"
#include "annotate.h" #include "annotate.h"
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
#include "ui/progress.h" #include "ui/progress.h"
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
#include <inttypes.h>
#include <sys/param.h> #include <sys/param.h>
static bool hists__filter_entry_by_dso(struct hists *hists, static bool hists__filter_entry_by_dso(struct hists *hists,
...@@ -2454,6 +2456,85 @@ u64 hists__total_period(struct hists *hists) ...@@ -2454,6 +2456,85 @@ u64 hists__total_period(struct hists *hists)
hists->stats.total_period; hists->stats.total_period;
} }
int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq)
{
char unit;
int printed;
const struct dso *dso = hists->dso_filter;
const struct thread *thread = hists->thread_filter;
int socket_id = hists->socket_filter;
unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
u64 nr_events = hists->stats.total_period;
struct perf_evsel *evsel = hists_to_evsel(hists);
const char *ev_name = perf_evsel__name(evsel);
char buf[512], sample_freq_str[64] = "";
size_t buflen = sizeof(buf);
char ref[30] = " show reference callgraph, ";
bool enable_ref = false;
if (symbol_conf.filter_relative) {
nr_samples = hists->stats.nr_non_filtered_samples;
nr_events = hists->stats.total_non_filtered_period;
}
if (perf_evsel__is_group_event(evsel)) {
struct perf_evsel *pos;
perf_evsel__group_desc(evsel, buf, buflen);
ev_name = buf;
for_each_group_member(pos, evsel) {
struct hists *pos_hists = evsel__hists(pos);
if (symbol_conf.filter_relative) {
nr_samples += pos_hists->stats.nr_non_filtered_samples;
nr_events += pos_hists->stats.total_non_filtered_period;
} else {
nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
nr_events += pos_hists->stats.total_period;
}
}
}
if (symbol_conf.show_ref_callgraph &&
strstr(ev_name, "call-graph=no"))
enable_ref = true;
if (show_freq)
scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq);
nr_samples = convert_unit(nr_samples, &unit);
printed = scnprintf(bf, size,
"Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
nr_samples, unit, evsel->nr_members > 1 ? "s" : "",
ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
if (hists->uid_filter_str)
printed += snprintf(bf + printed, size - printed,
", UID: %s", hists->uid_filter_str);
if (thread) {
if (hists__has(hists, thread)) {
printed += scnprintf(bf + printed, size - printed,
", Thread: %s(%d)",
(thread->comm_set ? thread__comm_str(thread) : ""),
thread->tid);
} else {
printed += scnprintf(bf + printed, size - printed,
", Thread: %s",
(thread->comm_set ? thread__comm_str(thread) : ""));
}
}
if (dso)
printed += scnprintf(bf + printed, size - printed,
", DSO: %s", dso->short_name);
if (socket_id > -1)
printed += scnprintf(bf + printed, size - printed,
", Processor Socket: %d", socket_id);
return printed;
}
int parse_filter_percentage(const struct option *opt __maybe_unused, int parse_filter_percentage(const struct option *opt __maybe_unused,
const char *arg, int unset __maybe_unused) const char *arg, int unset __maybe_unused)
{ {
......
...@@ -61,6 +61,7 @@ enum hist_column { ...@@ -61,6 +61,7 @@ enum hist_column {
HISTC_SRCLINE_TO, HISTC_SRCLINE_TO,
HISTC_TRACE, HISTC_TRACE,
HISTC_SYM_SIZE, HISTC_SYM_SIZE,
HISTC_DSO_SIZE,
HISTC_NR_COLS, /* Last entry */ HISTC_NR_COLS, /* Last entry */
}; };
...@@ -503,5 +504,11 @@ int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...); ...@@ -503,5 +504,11 @@ int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...);
int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp,
struct perf_hpp_list *hpp_list); struct perf_hpp_list *hpp_list);
int hists__fprintf_headers(struct hists *hists, FILE *fp); int hists__fprintf_headers(struct hists *hists, FILE *fp);
int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq);
static inline int hists__scnprintf_title(struct hists *hists, char *bf, size_t size)
{
return __hists__scnprintf_title(hists, bf, size, true);
}
#endif /* __PERF_HIST_H */ #endif /* __PERF_HIST_H */
...@@ -103,6 +103,10 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip) ...@@ -103,6 +103,10 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip)
return ip; return ip;
} }
static inline size_t map__size(const struct map *map)
{
return map->end - map->start;
}
/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
u64 map__rip_2objdump(struct map *map, u64 rip); 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) ...@@ -1591,7 +1591,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session)
drop_rate = (double)stats->total_lost_samples / drop_rate = (double)stats->total_lost_samples /
(double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples); (double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples);
if (drop_rate > 0.05) { if (drop_rate > 0.05) {
ui__warning("Processed %" PRIu64 " samples and lost %3.2f%% samples!\n\n", ui__warning("Processed %" PRIu64 " samples and lost %3.2f%%!\n\n",
stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples, stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples,
drop_rate * 100.0); drop_rate * 100.0);
} }
......
...@@ -1545,6 +1545,46 @@ struct sort_entry sort_sym_size = { ...@@ -1545,6 +1545,46 @@ struct sort_entry sort_sym_size = {
.se_width_idx = HISTC_SYM_SIZE, .se_width_idx = HISTC_SYM_SIZE,
}; };
/* --sort dso_size */
static int64_t _sort__dso_size_cmp(struct map *map_l, struct map *map_r)
{
int64_t size_l = map_l != NULL ? map__size(map_l) : 0;
int64_t size_r = map_r != NULL ? map__size(map_r) : 0;
return size_l < size_r ? -1 :
size_l == size_r ? 0 : 1;
}
static int64_t
sort__dso_size_cmp(struct hist_entry *left, struct hist_entry *right)
{
return _sort__dso_size_cmp(right->ms.map, left->ms.map);
}
static int _hist_entry__dso_size_snprintf(struct map *map, char *bf,
size_t bf_size, unsigned int width)
{
if (map && map->dso)
return repsep_snprintf(bf, bf_size, "%*d", width,
map__size(map));
return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
}
static int hist_entry__dso_size_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return _hist_entry__dso_size_snprintf(he->ms.map, bf, size, width);
}
struct sort_entry sort_dso_size = {
.se_header = "DSO size",
.se_cmp = sort__dso_size_cmp,
.se_snprintf = hist_entry__dso_size_snprintf,
.se_width_idx = HISTC_DSO_SIZE,
};
struct sort_dimension { struct sort_dimension {
const char *name; const char *name;
...@@ -1569,6 +1609,7 @@ static struct sort_dimension common_sort_dimensions[] = { ...@@ -1569,6 +1609,7 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_TRANSACTION, "transaction", sort_transaction), DIM(SORT_TRANSACTION, "transaction", sort_transaction),
DIM(SORT_TRACE, "trace", sort_trace), DIM(SORT_TRACE, "trace", sort_trace),
DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size),
DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size),
DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
}; };
......
...@@ -220,6 +220,7 @@ enum sort_type { ...@@ -220,6 +220,7 @@ enum sort_type {
SORT_TRANSACTION, SORT_TRANSACTION,
SORT_TRACE, SORT_TRACE,
SORT_SYM_SIZE, SORT_SYM_SIZE,
SORT_DSO_SIZE,
SORT_CGROUP_ID, SORT_CGROUP_ID,
/* branch stack specific sort keys */ /* branch stack specific sort keys */
......
...@@ -11,8 +11,7 @@ ...@@ -11,8 +11,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/types.h> #include <sys/types.h>
#include "namespaces.h"
/* General helper functions */ /* General helper functions */
void usage(const char *err) __noreturn; void usage(const char *err) __noreturn;
...@@ -26,6 +25,7 @@ static inline void *zalloc(size_t size) ...@@ -26,6 +25,7 @@ static inline void *zalloc(size_t size)
#define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) #define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
struct dirent; struct dirent;
struct nsinfo;
struct strlist; struct strlist;
int mkdir_p(char *path, mode_t mode); int mkdir_p(char *path, mode_t mode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment