Commit 49ef0156 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 perf updates from Thomas Gleixner:
 "A larger set of perf updates.

  Not all of them are strictly fixes, but that's solely the tip
  maintainers fault as they let the timely -rc1 pull request fall
  through the cracks for various reasons including travel. So I'm
  sending this nevertheless because rebasing and distangling fixes and
  updates would be a mess and risky as well. As of tomorrow, a strict
  fixes separation is happening again. Sorry for the slip-up.

  Kernel:

   - Handle RECORD_MMAP vs. RECORD_MMAP2 correctly so different
     consumers of the mmap event get what they requested.

  Tools:

   - A larger set of updates to perf record/report/scripts vs. time
     stamp handling

   - More Python3 fixups

   - A pile of memory leak plumbing

   - perf BPF improvements and fixes

   - Finalize the perf.data directory storage"

[ Note: the kernel part is strictly a fix, the updates are purely to
  tooling       - Linus ]

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (75 commits)
  perf bpf: Show more BPF program info in print_bpf_prog_info()
  perf bpf: Extract logic to create program names from perf_event__synthesize_one_bpf_prog()
  perf tools: Save bpf_prog_info and BTF of new BPF programs
  perf evlist: Introduce side band thread
  perf annotate: Enable annotation of BPF programs
  perf build: Check what binutils's 'disassembler()' signature to use
  perf bpf: Process PERF_BPF_EVENT_PROG_LOAD for annotation
  perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO
  perf feature detection: Add -lopcodes to feature-libbfd
  perf top: Add option --no-bpf-event
  perf bpf: Save BTF information as headers to perf.data
  perf bpf: Save BTF in a rbtree in perf_env
  perf bpf: Save bpf_prog_info information as headers to perf.data
  perf bpf: Save bpf_prog_info in a rbtree in perf_env
  perf bpf: Make synthesize_bpf_events() receive perf_session pointer instead of perf_tool
  perf bpf: Synthesize bpf events with bpf_program__get_prog_info_linear()
  bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump()
  tools lib bpf: Introduce bpf_program__get_prog_info_linear()
  perf record: Replace option --bpf-event with --no-bpf-event
  perf tests: Fix a memory leak in test__perf_evsel__tp_sched_test()
  ...
parents 19caf581 d8b5297f
...@@ -7189,6 +7189,7 @@ static void perf_event_mmap_output(struct perf_event *event, ...@@ -7189,6 +7189,7 @@ static void perf_event_mmap_output(struct perf_event *event,
struct perf_output_handle handle; struct perf_output_handle handle;
struct perf_sample_data sample; struct perf_sample_data sample;
int size = mmap_event->event_id.header.size; int size = mmap_event->event_id.header.size;
u32 type = mmap_event->event_id.header.type;
int ret; int ret;
if (!perf_event_mmap_match(event, data)) if (!perf_event_mmap_match(event, data))
...@@ -7232,6 +7233,7 @@ static void perf_event_mmap_output(struct perf_event *event, ...@@ -7232,6 +7233,7 @@ static void perf_event_mmap_output(struct perf_event *event,
perf_output_end(&handle); perf_output_end(&handle);
out: out:
mmap_event->event_id.header.size = size; mmap_event->event_id.header.size = size;
mmap_event->event_id.header.type = type;
} }
static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
......
...@@ -17,5 +17,7 @@ ...@@ -17,5 +17,7 @@
#define __ARCH_WANT_RENAMEAT #define __ARCH_WANT_RENAMEAT
#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_NEW_STAT
#define __ARCH_WANT_SET_GET_RLIMIT
#define __ARCH_WANT_TIME32_SYSCALLS
#include <asm-generic/unistd.h> #include <asm-generic/unistd.h>
This diff is collapsed.
...@@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC := \ ...@@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC := \
sched_getcpu \ sched_getcpu \
sdt \ sdt \
setns \ setns \
libaio libaio \
disassembler-four-args
# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
# of all feature tests # of all feature tests
...@@ -118,7 +119,8 @@ FEATURE_DISPLAY ?= \ ...@@ -118,7 +119,8 @@ FEATURE_DISPLAY ?= \
lzma \ lzma \
get_cpuid \ get_cpuid \
bpf \ bpf \
libaio libaio \
disassembler-four-args
# Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features. # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
# If in the future we need per-feature checks/flags for features not # If in the future we need per-feature checks/flags for features not
......
...@@ -178,6 +178,10 @@ ...@@ -178,6 +178,10 @@
# include "test-reallocarray.c" # include "test-reallocarray.c"
#undef main #undef main
#define main main_test_disassembler_four_args
# include "test-disassembler-four-args.c"
#undef main
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
main_test_libpython(); main_test_libpython();
...@@ -219,6 +223,7 @@ int main(int argc, char *argv[]) ...@@ -219,6 +223,7 @@ int main(int argc, char *argv[])
main_test_setns(); main_test_setns();
main_test_libaio(); main_test_libaio();
main_test_reallocarray(); main_test_reallocarray();
main_test_disassembler_four_args();
return 0; return 0;
} }
This diff is collapsed.
...@@ -292,10 +292,11 @@ struct sockaddr_in { ...@@ -292,10 +292,11 @@ struct sockaddr_in {
#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) #define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000)
/* Defines for Multicast INADDR */ /* Defines for Multicast INADDR */
#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */ #define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */
#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ #define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ #define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ #define INADDR_ALLSNOOPERS_GROUP 0xe000006aU /* 224.0.0.106 */
#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
#endif #endif
/* <asm/byteorder.h> contains the htonl type stuff.. */ /* <asm/byteorder.h> contains the htonl type stuff.. */
......
...@@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...) ...@@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
#endif #endif
static inline __u64 ptr_to_u64(const void *ptr)
{
return (__u64) (unsigned long) ptr;
}
struct bpf_capabilities { struct bpf_capabilities {
/* v4.14: kernel support for program & map names. */ /* v4.14: kernel support for program & map names. */
__u32 name:1; __u32 name:1;
...@@ -622,7 +627,7 @@ bpf_object__init_maps(struct bpf_object *obj, int flags) ...@@ -622,7 +627,7 @@ bpf_object__init_maps(struct bpf_object *obj, int flags)
bool strict = !(flags & MAPS_RELAX_COMPAT); bool strict = !(flags & MAPS_RELAX_COMPAT);
int i, map_idx, map_def_sz, nr_maps = 0; int i, map_idx, map_def_sz, nr_maps = 0;
Elf_Scn *scn; Elf_Scn *scn;
Elf_Data *data; Elf_Data *data = NULL;
Elf_Data *symbols = obj->efile.symbols; Elf_Data *symbols = obj->efile.symbols;
if (obj->efile.maps_shndx < 0) if (obj->efile.maps_shndx < 0)
...@@ -2999,3 +3004,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size, ...@@ -2999,3 +3004,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
ring_buffer_write_tail(header, data_tail); ring_buffer_write_tail(header, data_tail);
return ret; return ret;
} }
struct bpf_prog_info_array_desc {
int array_offset; /* e.g. offset of jited_prog_insns */
int count_offset; /* e.g. offset of jited_prog_len */
int size_offset; /* > 0: offset of rec size,
* < 0: fix size of -size_offset
*/
};
static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
[BPF_PROG_INFO_JITED_INSNS] = {
offsetof(struct bpf_prog_info, jited_prog_insns),
offsetof(struct bpf_prog_info, jited_prog_len),
-1,
},
[BPF_PROG_INFO_XLATED_INSNS] = {
offsetof(struct bpf_prog_info, xlated_prog_insns),
offsetof(struct bpf_prog_info, xlated_prog_len),
-1,
},
[BPF_PROG_INFO_MAP_IDS] = {
offsetof(struct bpf_prog_info, map_ids),
offsetof(struct bpf_prog_info, nr_map_ids),
-(int)sizeof(__u32),
},
[BPF_PROG_INFO_JITED_KSYMS] = {
offsetof(struct bpf_prog_info, jited_ksyms),
offsetof(struct bpf_prog_info, nr_jited_ksyms),
-(int)sizeof(__u64),
},
[BPF_PROG_INFO_JITED_FUNC_LENS] = {
offsetof(struct bpf_prog_info, jited_func_lens),
offsetof(struct bpf_prog_info, nr_jited_func_lens),
-(int)sizeof(__u32),
},
[BPF_PROG_INFO_FUNC_INFO] = {
offsetof(struct bpf_prog_info, func_info),
offsetof(struct bpf_prog_info, nr_func_info),
offsetof(struct bpf_prog_info, func_info_rec_size),
},
[BPF_PROG_INFO_LINE_INFO] = {
offsetof(struct bpf_prog_info, line_info),
offsetof(struct bpf_prog_info, nr_line_info),
offsetof(struct bpf_prog_info, line_info_rec_size),
},
[BPF_PROG_INFO_JITED_LINE_INFO] = {
offsetof(struct bpf_prog_info, jited_line_info),
offsetof(struct bpf_prog_info, nr_jited_line_info),
offsetof(struct bpf_prog_info, jited_line_info_rec_size),
},
[BPF_PROG_INFO_PROG_TAGS] = {
offsetof(struct bpf_prog_info, prog_tags),
offsetof(struct bpf_prog_info, nr_prog_tags),
-(int)sizeof(__u8) * BPF_TAG_SIZE,
},
};
static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset)
{
__u32 *array = (__u32 *)info;
if (offset >= 0)
return array[offset / sizeof(__u32)];
return -(int)offset;
}
static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset)
{
__u64 *array = (__u64 *)info;
if (offset >= 0)
return array[offset / sizeof(__u64)];
return -(int)offset;
}
static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
__u32 val)
{
__u32 *array = (__u32 *)info;
if (offset >= 0)
array[offset / sizeof(__u32)] = val;
}
static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
__u64 val)
{
__u64 *array = (__u64 *)info;
if (offset >= 0)
array[offset / sizeof(__u64)] = val;
}
struct bpf_prog_info_linear *
bpf_program__get_prog_info_linear(int fd, __u64 arrays)
{
struct bpf_prog_info_linear *info_linear;
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
__u32 data_len = 0;
int i, err;
void *ptr;
if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
return ERR_PTR(-EINVAL);
/* step 1: get array dimensions */
err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
if (err) {
pr_debug("can't get prog info: %s", strerror(errno));
return ERR_PTR(-EFAULT);
}
/* step 2: calculate total size of all arrays */
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
bool include_array = (arrays & (1UL << i)) > 0;
struct bpf_prog_info_array_desc *desc;
__u32 count, size;
desc = bpf_prog_info_array_desc + i;
/* kernel is too old to support this field */
if (info_len < desc->array_offset + sizeof(__u32) ||
info_len < desc->count_offset + sizeof(__u32) ||
(desc->size_offset > 0 && info_len < desc->size_offset))
include_array = false;
if (!include_array) {
arrays &= ~(1UL << i); /* clear the bit */
continue;
}
count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
data_len += count * size;
}
/* step 3: allocate continuous memory */
data_len = roundup(data_len, sizeof(__u64));
info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
if (!info_linear)
return ERR_PTR(-ENOMEM);
/* step 4: fill data to info_linear->info */
info_linear->arrays = arrays;
memset(&info_linear->info, 0, sizeof(info));
ptr = info_linear->data;
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
struct bpf_prog_info_array_desc *desc;
__u32 count, size;
if ((arrays & (1UL << i)) == 0)
continue;
desc = bpf_prog_info_array_desc + i;
count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
bpf_prog_info_set_offset_u32(&info_linear->info,
desc->count_offset, count);
bpf_prog_info_set_offset_u32(&info_linear->info,
desc->size_offset, size);
bpf_prog_info_set_offset_u64(&info_linear->info,
desc->array_offset,
ptr_to_u64(ptr));
ptr += count * size;
}
/* step 5: call syscall again to get required arrays */
err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
if (err) {
pr_debug("can't get prog info: %s", strerror(errno));
free(info_linear);
return ERR_PTR(-EFAULT);
}
/* step 6: verify the data */
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
struct bpf_prog_info_array_desc *desc;
__u32 v1, v2;
if ((arrays & (1UL << i)) == 0)
continue;
desc = bpf_prog_info_array_desc + i;
v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
desc->count_offset);
if (v1 != v2)
pr_warning("%s: mismatch in element count\n", __func__);
v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
desc->size_offset);
if (v1 != v2)
pr_warning("%s: mismatch in rec size\n", __func__);
}
/* step 7: update info_len and data_len */
info_linear->info_len = sizeof(struct bpf_prog_info);
info_linear->data_len = data_len;
return info_linear;
}
void bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear)
{
int i;
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
struct bpf_prog_info_array_desc *desc;
__u64 addr, offs;
if ((info_linear->arrays & (1UL << i)) == 0)
continue;
desc = bpf_prog_info_array_desc + i;
addr = bpf_prog_info_read_offset_u64(&info_linear->info,
desc->array_offset);
offs = addr - ptr_to_u64(info_linear->data);
bpf_prog_info_set_offset_u64(&info_linear->info,
desc->array_offset, offs);
}
}
void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
{
int i;
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
struct bpf_prog_info_array_desc *desc;
__u64 addr, offs;
if ((info_linear->arrays & (1UL << i)) == 0)
continue;
desc = bpf_prog_info_array_desc + i;
offs = bpf_prog_info_read_offset_u64(&info_linear->info,
desc->array_offset);
addr = offs + ptr_to_u64(info_linear->data);
bpf_prog_info_set_offset_u64(&info_linear->info,
desc->array_offset, addr);
}
}
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#ifndef __LIBBPF_LIBBPF_H #ifndef __LIBBPF_LIBBPF_H
#define __LIBBPF_LIBBPF_H #define __LIBBPF_LIBBPF_H
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -377,6 +378,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex); ...@@ -377,6 +378,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id, LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
enum bpf_prog_type prog_type, __u32 ifindex); enum bpf_prog_type prog_type, __u32 ifindex);
/*
* Get bpf_prog_info in continuous memory
*
* struct bpf_prog_info has multiple arrays. The user has option to choose
* arrays to fetch from kernel. The following APIs provide an uniform way to
* fetch these data. All arrays in bpf_prog_info are stored in a single
* continuous memory region. This makes it easy to store the info in a
* file.
*
* Before writing bpf_prog_info_linear to files, it is necessary to
* translate pointers in bpf_prog_info to offsets. Helper functions
* bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()
* are introduced to switch between pointers and offsets.
*
* Examples:
* # To fetch map_ids and prog_tags:
* __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |
* (1UL << BPF_PROG_INFO_PROG_TAGS);
* struct bpf_prog_info_linear *info_linear =
* bpf_program__get_prog_info_linear(fd, arrays);
*
* # To save data in file
* bpf_program__bpil_addr_to_offs(info_linear);
* write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);
*
* # To read data from file
* read(f, info_linear, <proper_size>);
* bpf_program__bpil_offs_to_addr(info_linear);
*/
enum bpf_prog_info_array {
BPF_PROG_INFO_FIRST_ARRAY = 0,
BPF_PROG_INFO_JITED_INSNS = 0,
BPF_PROG_INFO_XLATED_INSNS,
BPF_PROG_INFO_MAP_IDS,
BPF_PROG_INFO_JITED_KSYMS,
BPF_PROG_INFO_JITED_FUNC_LENS,
BPF_PROG_INFO_FUNC_INFO,
BPF_PROG_INFO_LINE_INFO,
BPF_PROG_INFO_JITED_LINE_INFO,
BPF_PROG_INFO_PROG_TAGS,
BPF_PROG_INFO_LAST_ARRAY,
};
struct bpf_prog_info_linear {
/* size of struct bpf_prog_info, when the tool is compiled */
__u32 info_len;
/* total bytes allocated for data, round up to 8 bytes */
__u32 data_len;
/* which arrays are included in data */
__u64 arrays;
struct bpf_prog_info info;
__u8 data[];
};
LIBBPF_API struct bpf_prog_info_linear *
bpf_program__get_prog_info_linear(int fd, __u64 arrays);
LIBBPF_API void
bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
LIBBPF_API void
bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif
......
...@@ -153,4 +153,7 @@ LIBBPF_0.0.2 { ...@@ -153,4 +153,7 @@ LIBBPF_0.0.2 {
xsk_socket__delete; xsk_socket__delete;
xsk_umem__fd; xsk_umem__fd;
xsk_socket__fd; xsk_socket__fd;
bpf_program__get_prog_info_linear;
bpf_program__bpil_addr_to_offs;
bpf_program__bpil_offs_to_addr;
} LIBBPF_0.0.1; } LIBBPF_0.0.1;
...@@ -47,3 +47,27 @@ Those objects are then used in final linking: ...@@ -47,3 +47,27 @@ Those objects are then used in final linking:
NOTE this description is omitting other libraries involved, only NOTE this description is omitting other libraries involved, only
focusing on build framework outcomes focusing on build framework outcomes
3) Build with ASan or UBSan
==========================
$ cd tools/perf
$ make DESTDIR=/usr
$ make DESTDIR=/usr install
AddressSanitizer (or ASan) is a GCC feature that detects memory corruption bugs
such as buffer overflows and memory leaks.
$ cd tools/perf
$ make DEBUG=1 EXTRA_CFLAGS='-fno-omit-frame-pointer -fsanitize=address'
$ ASAN_OPTIONS=log_path=asan.log ./perf record -a
ASan outputs all detected issues into a log file named 'asan.log.<pid>'.
UndefinedBehaviorSanitizer (or UBSan) is a fast undefined behavior detector
supported by GCC. UBSan detects undefined behaviors of programs at runtime.
$ cd tools/perf
$ make DEBUG=1 EXTRA_CFLAGS='-fno-omit-frame-pointer -fsanitize=undefined'
$ UBSAN_OPTIONS=print_stacktrace=1 ./perf record -a
If UBSan detects any problem at runtime, it outputs a “runtime error:” message.
...@@ -114,7 +114,7 @@ Given a $HOME/.perfconfig like this: ...@@ -114,7 +114,7 @@ Given a $HOME/.perfconfig like this:
[report] [report]
# Defaults # Defaults
sort-order = comm,dso,symbol sort_order = comm,dso,symbol
percent-limit = 0 percent-limit = 0
queue-size = 0 queue-size = 0
children = true children = true
...@@ -584,6 +584,20 @@ llvm.*:: ...@@ -584,6 +584,20 @@ llvm.*::
llvm.opts:: llvm.opts::
Options passed to llc. Options passed to llc.
samples.*::
samples.context::
Define how many ns worth of time to show
around samples in perf report sample context browser.
scripts.*::
Any option defines a script that is added to the scripts menu
in the interactive perf browser and whose output is displayed.
The name of the option is the name, the value is a script command line.
The script gets the same options passed as a full perf script,
in particular -i perfdata file, --cpu, --tid
SEE ALSO SEE ALSO
-------- --------
linkperf:perf[1] linkperf:perf[1]
...@@ -495,6 +495,10 @@ overhead. You can still switch them on with: ...@@ -495,6 +495,10 @@ overhead. You can still switch them on with:
--switch-output --no-no-buildid --no-no-buildid-cache --switch-output --no-no-buildid --no-no-buildid-cache
--switch-max-files=N::
When rotating perf.data with --switch-output, only keep N files.
--dry-run:: --dry-run::
Parse options then exit. --dry-run can be used to detect errors in cmdline Parse options then exit. --dry-run can be used to detect errors in cmdline
options. options.
......
...@@ -105,6 +105,8 @@ OPTIONS ...@@ -105,6 +105,8 @@ OPTIONS
guest machine guest machine
- sample: Number of sample - sample: Number of sample
- period: Raw number of event count of sample - period: Raw number of event count of sample
- time: Separate the samples by time stamp with the resolution specified by
--time-quantum (default 100ms). Specify with overhead and before it.
By default, comm, dso and symbol keys are used. By default, comm, dso and symbol keys are used.
(i.e. --sort comm,dso,symbol) (i.e. --sort comm,dso,symbol)
...@@ -459,6 +461,10 @@ include::itrace.txt[] ...@@ -459,6 +461,10 @@ include::itrace.txt[]
--socket-filter:: --socket-filter::
Only report the samples on the processor socket that match with this filter Only report the samples on the processor socket that match with this filter
--samples=N::
Save N individual samples for each histogram entry to show context in perf
report tui browser.
--raw-trace:: --raw-trace::
When displaying traceevent output, do not use print fmt or plugins. When displaying traceevent output, do not use print fmt or plugins.
...@@ -477,6 +483,9 @@ include::itrace.txt[] ...@@ -477,6 +483,9 @@ include::itrace.txt[]
Please note that not all mmaps are stored, options affecting which ones Please note that not all mmaps are stored, options affecting which ones
are include 'perf record --data', for instance. are include 'perf record --data', for instance.
--ns::
Show time stamps in nanoseconds.
--stats:: --stats::
Display overall events statistics without any further processing. Display overall events statistics without any further processing.
(like the one at the end of the perf report -D command) (like the one at the end of the perf report -D command)
...@@ -494,6 +503,10 @@ include::itrace.txt[] ...@@ -494,6 +503,10 @@ include::itrace.txt[]
The period/hits keywords set the base the percentage is computed The period/hits keywords set the base the percentage is computed
on - the samples period or the number of samples (hits). on - the samples period or the number of samples (hits).
--time-quantum::
Configure time quantum for time sort key. Default 100ms.
Accepts s, us, ms, ns units.
include::callchain-overhead-calculation.txt[] include::callchain-overhead-calculation.txt[]
SEE ALSO SEE ALSO
......
...@@ -380,6 +380,9 @@ include::itrace.txt[] ...@@ -380,6 +380,9 @@ include::itrace.txt[]
Set the maximum number of program blocks to print with brstackasm for Set the maximum number of program blocks to print with brstackasm for
each sample. each sample.
--reltime::
Print time stamps relative to trace start.
--per-event-dump:: --per-event-dump::
Create per event files with a "perf.data.EVENT.dump" name instead of Create per event files with a "perf.data.EVENT.dump" name instead of
printing to stdout, useful, for instance, for generating flamegraphs. printing to stdout, useful, for instance, for generating flamegraphs.
......
...@@ -72,9 +72,8 @@ report:: ...@@ -72,9 +72,8 @@ report::
--all-cpus:: --all-cpus::
system-wide collection from all CPUs (default if no target is specified) system-wide collection from all CPUs (default if no target is specified)
-c:: --no-scale::
--scale:: Don't scale/normalize counter values
scale/normalize counter values
-d:: -d::
--detailed:: --detailed::
......
...@@ -15,6 +15,7 @@ To see callchains in a more compact form: perf report -g folded ...@@ -15,6 +15,7 @@ To see callchains in a more compact form: perf report -g folded
Show individual samples with: perf script Show individual samples with: perf script
Limit to show entries above 5% only: perf report --percent-limit 5 Limit to show entries above 5% only: perf report --percent-limit 5
Profiling branch (mis)predictions with: perf record -b / perf report Profiling branch (mis)predictions with: perf record -b / perf report
To show assembler sample contexts use perf record -b / perf script -F +brstackinsn --xed
Treat branches as callchains: perf report --branch-history Treat branches as callchains: perf report --branch-history
To count events in every 1000 msec: perf stat -I 1000 To count events in every 1000 msec: perf stat -I 1000
Print event counts in CSV format with: perf stat -x, Print event counts in CSV format with: perf stat -x,
...@@ -34,3 +35,9 @@ Show current config key-value pairs: perf config --list ...@@ -34,3 +35,9 @@ Show current config key-value pairs: perf config --list
Show user configuration overrides: perf config --user --list Show user configuration overrides: perf config --user --list
To add Node.js USDT(User-Level Statically Defined Tracing): perf buildid-cache --add `which node` To add Node.js USDT(User-Level Statically Defined Tracing): perf buildid-cache --add `which node`
To report cacheline events from previous recording: perf c2c report To report cacheline events from previous recording: perf c2c report
To browse sample contexts use perf report --sample 10 and select in context menu
To separate samples by time use perf report --sort time,overhead,sym
To set sample time separation other than 100ms with --sort time use --time-quantum
Add -I to perf report to sample register values visible in perf report context.
To show IPC for sampling periods use perf record -e '{cycles,instructions}:S' and then browse context
To show context switches in perf report sample context add --switch-events to perf record.
...@@ -227,6 +227,8 @@ FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS) ...@@ -227,6 +227,8 @@ FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
FEATURE_CHECK_LDFLAGS-libaio = -lrt FEATURE_CHECK_LDFLAGS-libaio = -lrt
FEATURE_CHECK_LDFLAGS-disassembler-four-args = -lbfd -lopcodes
CFLAGS += -fno-omit-frame-pointer CFLAGS += -fno-omit-frame-pointer
CFLAGS += -ggdb3 CFLAGS += -ggdb3
CFLAGS += -funwind-tables CFLAGS += -funwind-tables
...@@ -713,7 +715,7 @@ else ...@@ -713,7 +715,7 @@ else
endif endif
ifeq ($(feature-libbfd), 1) ifeq ($(feature-libbfd), 1)
EXTLIBS += -lbfd EXTLIBS += -lbfd -lopcodes
else else
# we are on a system that requires -liberty and (maybe) -lz # we are on a system that requires -liberty and (maybe) -lz
# to link against -lbfd; test each case individually here # to link against -lbfd; test each case individually here
...@@ -724,12 +726,15 @@ else ...@@ -724,12 +726,15 @@ else
$(call feature_check,libbfd-liberty-z) $(call feature_check,libbfd-liberty-z)
ifeq ($(feature-libbfd-liberty), 1) ifeq ($(feature-libbfd-liberty), 1)
EXTLIBS += -lbfd -liberty EXTLIBS += -lbfd -lopcodes -liberty
FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -ldl
else else
ifeq ($(feature-libbfd-liberty-z), 1) ifeq ($(feature-libbfd-liberty-z), 1)
EXTLIBS += -lbfd -liberty -lz EXTLIBS += -lbfd -lopcodes -liberty -lz
FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -lz -ldl
endif endif
endif endif
$(call feature_check,disassembler-four-args)
endif endif
ifdef NO_DEMANGLE ifdef NO_DEMANGLE
...@@ -808,6 +813,10 @@ ifdef HAVE_KVM_STAT_SUPPORT ...@@ -808,6 +813,10 @@ ifdef HAVE_KVM_STAT_SUPPORT
CFLAGS += -DHAVE_KVM_STAT_SUPPORT CFLAGS += -DHAVE_KVM_STAT_SUPPORT
endif endif
ifeq ($(feature-disassembler-four-args), 1)
CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
endif
ifeq (${IS_64_BIT}, 1) ifeq (${IS_64_BIT}, 1)
ifndef NO_PERF_READ_VDSO32 ifndef NO_PERF_READ_VDSO32
$(call feature_check,compile-32) $(call feature_check,compile-32)
......
...@@ -343,6 +343,8 @@ ...@@ -343,6 +343,8 @@
332 common statx __x64_sys_statx 332 common statx __x64_sys_statx
333 common io_pgetevents __x64_sys_io_pgetevents 333 common io_pgetevents __x64_sys_io_pgetevents
334 common rseq __x64_sys_rseq 334 common rseq __x64_sys_rseq
# don't use numbers 387 through 423, add new calls after the last
# 'common' entry
# #
# x32-specific system call numbers start at 512 to avoid cache impact # x32-specific system call numbers start at 512 to avoid cache impact
...@@ -361,7 +363,7 @@ ...@@ -361,7 +363,7 @@
520 x32 execve __x32_compat_sys_execve/ptregs 520 x32 execve __x32_compat_sys_execve/ptregs
521 x32 ptrace __x32_compat_sys_ptrace 521 x32 ptrace __x32_compat_sys_ptrace
522 x32 rt_sigpending __x32_compat_sys_rt_sigpending 522 x32 rt_sigpending __x32_compat_sys_rt_sigpending
523 x32 rt_sigtimedwait __x32_compat_sys_rt_sigtimedwait 523 x32 rt_sigtimedwait __x32_compat_sys_rt_sigtimedwait_time64
524 x32 rt_sigqueueinfo __x32_compat_sys_rt_sigqueueinfo 524 x32 rt_sigqueueinfo __x32_compat_sys_rt_sigqueueinfo
525 x32 sigaltstack __x32_compat_sys_sigaltstack 525 x32 sigaltstack __x32_compat_sys_sigaltstack
526 x32 timer_create __x32_compat_sys_timer_create 526 x32 timer_create __x32_compat_sys_timer_create
...@@ -375,7 +377,7 @@ ...@@ -375,7 +377,7 @@
534 x32 preadv __x32_compat_sys_preadv64 534 x32 preadv __x32_compat_sys_preadv64
535 x32 pwritev __x32_compat_sys_pwritev64 535 x32 pwritev __x32_compat_sys_pwritev64
536 x32 rt_tgsigqueueinfo __x32_compat_sys_rt_tgsigqueueinfo 536 x32 rt_tgsigqueueinfo __x32_compat_sys_rt_tgsigqueueinfo
537 x32 recvmmsg __x32_compat_sys_recvmmsg 537 x32 recvmmsg __x32_compat_sys_recvmmsg_time64
538 x32 sendmmsg __x32_compat_sys_sendmmsg 538 x32 sendmmsg __x32_compat_sys_sendmmsg
539 x32 process_vm_readv __x32_compat_sys_process_vm_readv 539 x32 process_vm_readv __x32_compat_sys_process_vm_readv
540 x32 process_vm_writev __x32_compat_sys_process_vm_writev 540 x32 process_vm_writev __x32_compat_sys_process_vm_writev
......
...@@ -14,5 +14,6 @@ perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o ...@@ -14,5 +14,6 @@ perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
perf-$(CONFIG_AUXTRACE) += auxtrace.o perf-$(CONFIG_AUXTRACE) += auxtrace.o
perf-$(CONFIG_AUXTRACE) += archinsn.o
perf-$(CONFIG_AUXTRACE) += intel-pt.o perf-$(CONFIG_AUXTRACE) += intel-pt.o
perf-$(CONFIG_AUXTRACE) += intel-bts.o perf-$(CONFIG_AUXTRACE) += intel-bts.o
// SPDX-License-Identifier: GPL-2.0
#include "perf.h"
#include "archinsn.h"
#include "util/intel-pt-decoder/insn.h"
#include "machine.h"
#include "thread.h"
#include "symbol.h"
void arch_fetch_insn(struct perf_sample *sample,
struct thread *thread,
struct machine *machine)
{
struct insn insn;
int len;
bool is64bit = false;
if (!sample->ip)
return;
len = thread__memcpy(thread, machine, sample->insn, sample->ip, sizeof(sample->insn), &is64bit);
if (len <= 0)
return;
insn_init(&insn, sample->insn, len, is64bit);
insn_get_length(&insn);
if (insn_complete(&insn) && insn.length <= len)
sample->insn_len = insn.length;
}
...@@ -224,7 +224,7 @@ static int do_threads(struct worker *worker, struct cpu_map *cpu) ...@@ -224,7 +224,7 @@ static int do_threads(struct worker *worker, struct cpu_map *cpu)
pthread_attr_t thread_attr, *attrp = NULL; pthread_attr_t thread_attr, *attrp = NULL;
cpu_set_t cpuset; cpu_set_t cpuset;
unsigned int i, j; unsigned int i, j;
int ret; int ret = 0;
if (!noaffinity) if (!noaffinity)
pthread_attr_init(&thread_attr); pthread_attr_init(&thread_attr);
......
...@@ -293,7 +293,7 @@ static int do_threads(struct worker *worker, struct cpu_map *cpu) ...@@ -293,7 +293,7 @@ static int do_threads(struct worker *worker, struct cpu_map *cpu)
pthread_attr_t thread_attr, *attrp = NULL; pthread_attr_t thread_attr, *attrp = NULL;
cpu_set_t cpuset; cpu_set_t cpuset;
unsigned int i, j; unsigned int i, j;
int ret, events = EPOLLIN; int ret = 0, events = EPOLLIN;
if (oneshot) if (oneshot)
events |= EPOLLONESHOT; events |= EPOLLONESHOT;
......
...@@ -119,7 +119,7 @@ int cmd_list(int argc, const char **argv) ...@@ -119,7 +119,7 @@ int cmd_list(int argc, const char **argv)
details_flag); details_flag);
print_tracepoint_events(NULL, s, raw_dump); print_tracepoint_events(NULL, s, raw_dump);
print_sdt_events(NULL, s, raw_dump); print_sdt_events(NULL, s, raw_dump);
metricgroup__print(true, true, NULL, raw_dump, details_flag); metricgroup__print(true, true, s, raw_dump, details_flag);
free(s); free(s);
} }
} }
......
...@@ -62,6 +62,9 @@ struct switch_output { ...@@ -62,6 +62,9 @@ struct switch_output {
unsigned long time; unsigned long time;
const char *str; const char *str;
bool set; bool set;
char **filenames;
int num_files;
int cur_file;
}; };
struct record { struct record {
...@@ -392,7 +395,7 @@ static int record__process_auxtrace(struct perf_tool *tool, ...@@ -392,7 +395,7 @@ static int record__process_auxtrace(struct perf_tool *tool,
size_t padding; size_t padding;
u8 pad[8] = {0}; u8 pad[8] = {0};
if (!perf_data__is_pipe(data)) { if (!perf_data__is_pipe(data) && !perf_data__is_dir(data)) {
off_t file_offset; off_t file_offset;
int fd = perf_data__fd(data); int fd = perf_data__fd(data);
int err; int err;
...@@ -837,6 +840,8 @@ static void record__init_features(struct record *rec) ...@@ -837,6 +840,8 @@ static void record__init_features(struct record *rec)
if (!(rec->opts.use_clockid && rec->opts.clockid_res_ns)) if (!(rec->opts.use_clockid && rec->opts.clockid_res_ns))
perf_header__clear_feat(&session->header, HEADER_CLOCKID); perf_header__clear_feat(&session->header, HEADER_CLOCKID);
perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT);
perf_header__clear_feat(&session->header, HEADER_STAT); perf_header__clear_feat(&session->header, HEADER_STAT);
} }
...@@ -890,6 +895,7 @@ record__switch_output(struct record *rec, bool at_exit) ...@@ -890,6 +895,7 @@ record__switch_output(struct record *rec, bool at_exit)
{ {
struct perf_data *data = &rec->data; struct perf_data *data = &rec->data;
int fd, err; int fd, err;
char *new_filename;
/* Same Size: "2015122520103046"*/ /* Same Size: "2015122520103046"*/
char timestamp[] = "InvalidTimestamp"; char timestamp[] = "InvalidTimestamp";
...@@ -910,7 +916,7 @@ record__switch_output(struct record *rec, bool at_exit) ...@@ -910,7 +916,7 @@ record__switch_output(struct record *rec, bool at_exit)
fd = perf_data__switch(data, timestamp, fd = perf_data__switch(data, timestamp,
rec->session->header.data_offset, rec->session->header.data_offset,
at_exit); at_exit, &new_filename);
if (fd >= 0 && !at_exit) { if (fd >= 0 && !at_exit) {
rec->bytes_written = 0; rec->bytes_written = 0;
rec->session->header.data_size = 0; rec->session->header.data_size = 0;
...@@ -920,6 +926,21 @@ record__switch_output(struct record *rec, bool at_exit) ...@@ -920,6 +926,21 @@ record__switch_output(struct record *rec, bool at_exit)
fprintf(stderr, "[ perf record: Dump %s.%s ]\n", fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
data->path, timestamp); data->path, timestamp);
if (rec->switch_output.num_files) {
int n = rec->switch_output.cur_file + 1;
if (n >= rec->switch_output.num_files)
n = 0;
rec->switch_output.cur_file = n;
if (rec->switch_output.filenames[n]) {
remove(rec->switch_output.filenames[n]);
free(rec->switch_output.filenames[n]);
}
rec->switch_output.filenames[n] = new_filename;
} else {
free(new_filename);
}
/* Output tracking events */ /* Output tracking events */
if (!at_exit) { if (!at_exit) {
record__synthesize(rec, false); record__synthesize(rec, false);
...@@ -1093,7 +1114,7 @@ static int record__synthesize(struct record *rec, bool tail) ...@@ -1093,7 +1114,7 @@ static int record__synthesize(struct record *rec, bool tail)
return err; return err;
} }
err = perf_event__synthesize_bpf_events(tool, process_synthesized_event, err = perf_event__synthesize_bpf_events(session, process_synthesized_event,
machine, opts); machine, opts);
if (err < 0) if (err < 0)
pr_warning("Couldn't synthesize bpf events.\n"); pr_warning("Couldn't synthesize bpf events.\n");
...@@ -1116,6 +1137,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -1116,6 +1137,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
struct perf_data *data = &rec->data; struct perf_data *data = &rec->data;
struct perf_session *session; struct perf_session *session;
bool disabled = false, draining = false; bool disabled = false, draining = false;
struct perf_evlist *sb_evlist = NULL;
int fd; int fd;
atexit(record__sig_exit); atexit(record__sig_exit);
...@@ -1216,6 +1238,14 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -1216,6 +1238,14 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
goto out_child; goto out_child;
} }
if (!opts->no_bpf_event)
bpf_event__add_sb_event(&sb_evlist, &session->header.env);
if (perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target)) {
pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
opts->no_bpf_event = true;
}
err = record__synthesize(rec, false); err = record__synthesize(rec, false);
if (err < 0) if (err < 0)
goto out_child; goto out_child;
...@@ -1466,6 +1496,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -1466,6 +1496,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
out_delete_session: out_delete_session:
perf_session__delete(session); perf_session__delete(session);
if (!opts->no_bpf_event)
perf_evlist__stop_sb_thread(sb_evlist);
return status; return status;
} }
...@@ -1870,7 +1903,7 @@ static struct option __record_options[] = { ...@@ -1870,7 +1903,7 @@ static struct option __record_options[] = {
OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize, OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize,
"synthesize non-sample events at the end of output"), "synthesize non-sample events at the end of output"),
OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"), OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"),
OPT_BOOLEAN(0, "bpf-event", &record.opts.bpf_event, "record bpf events"), OPT_BOOLEAN(0, "no-bpf-event", &record.opts.no_bpf_event, "record bpf events"),
OPT_BOOLEAN(0, "strict-freq", &record.opts.strict_freq, OPT_BOOLEAN(0, "strict-freq", &record.opts.strict_freq,
"Fail if the specified frequency can't be used"), "Fail if the specified frequency can't be used"),
OPT_CALLBACK('F', "freq", &record.opts, "freq or 'max'", OPT_CALLBACK('F', "freq", &record.opts, "freq or 'max'",
...@@ -1968,9 +2001,11 @@ static struct option __record_options[] = { ...@@ -1968,9 +2001,11 @@ static struct option __record_options[] = {
OPT_BOOLEAN(0, "timestamp-boundary", &record.timestamp_boundary, OPT_BOOLEAN(0, "timestamp-boundary", &record.timestamp_boundary,
"Record timestamp boundary (time of first/last samples)"), "Record timestamp boundary (time of first/last samples)"),
OPT_STRING_OPTARG_SET(0, "switch-output", &record.switch_output.str, OPT_STRING_OPTARG_SET(0, "switch-output", &record.switch_output.str,
&record.switch_output.set, "signal,size,time", &record.switch_output.set, "signal or size[BKMG] or time[smhd]",
"Switch output when receive SIGUSR2 or cross size,time threshold", "Switch output when receiving SIGUSR2 (signal) or cross a size or time threshold",
"signal"), "signal"),
OPT_INTEGER(0, "switch-max-files", &record.switch_output.num_files,
"Limit number of switch output generated files"),
OPT_BOOLEAN(0, "dry-run", &dry_run, OPT_BOOLEAN(0, "dry-run", &dry_run,
"Parse options then exit"), "Parse options then exit"),
#ifdef HAVE_AIO_SUPPORT #ifdef HAVE_AIO_SUPPORT
...@@ -2057,6 +2092,13 @@ int cmd_record(int argc, const char **argv) ...@@ -2057,6 +2092,13 @@ int cmd_record(int argc, const char **argv)
alarm(rec->switch_output.time); alarm(rec->switch_output.time);
} }
if (rec->switch_output.num_files) {
rec->switch_output.filenames = calloc(sizeof(char *),
rec->switch_output.num_files);
if (!rec->switch_output.filenames)
return -EINVAL;
}
/* /*
* Allow aliases to facilitate the lookup of symbols for address * Allow aliases to facilitate the lookup of symbols for address
* filters. Refer to auxtrace_parse_filters(). * filters. Refer to auxtrace_parse_filters().
......
...@@ -47,9 +47,11 @@ ...@@ -47,9 +47,11 @@
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
#include <regex.h> #include <regex.h>
#include "sane_ctype.h"
#include <signal.h> #include <signal.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/time64.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
...@@ -926,6 +928,43 @@ report_parse_callchain_opt(const struct option *opt, const char *arg, int unset) ...@@ -926,6 +928,43 @@ report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
return parse_callchain_report_opt(arg); return parse_callchain_report_opt(arg);
} }
static int
parse_time_quantum(const struct option *opt, const char *arg,
int unset __maybe_unused)
{
unsigned long *time_q = opt->value;
char *end;
*time_q = strtoul(arg, &end, 0);
if (end == arg)
goto parse_err;
if (*time_q == 0) {
pr_err("time quantum cannot be 0");
return -1;
}
while (isspace(*end))
end++;
if (*end == 0)
return 0;
if (!strcmp(end, "s")) {
*time_q *= NSEC_PER_SEC;
return 0;
}
if (!strcmp(end, "ms")) {
*time_q *= NSEC_PER_MSEC;
return 0;
}
if (!strcmp(end, "us")) {
*time_q *= NSEC_PER_USEC;
return 0;
}
if (!strcmp(end, "ns"))
return 0;
parse_err:
pr_err("Cannot parse time quantum `%s'\n", arg);
return -1;
}
int int
report_parse_ignore_callees_opt(const struct option *opt __maybe_unused, report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
const char *arg, int unset __maybe_unused) const char *arg, int unset __maybe_unused)
...@@ -1044,10 +1083,9 @@ int cmd_report(int argc, const char **argv) ...@@ -1044,10 +1083,9 @@ int cmd_report(int argc, const char **argv)
OPT_BOOLEAN(0, "header-only", &report.header_only, OPT_BOOLEAN(0, "header-only", &report.header_only,
"Show only data header."), "Show only data header."),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]", OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
"sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..." sort_help("sort by key(s):")),
" Please refer the man page for the complete list."),
OPT_STRING('F', "fields", &field_order, "key[,keys...]", OPT_STRING('F', "fields", &field_order, "key[,keys...]",
"output field(s): overhead, period, sample plus all of sort keys"), sort_help("output field(s): overhead period sample ")),
OPT_BOOLEAN(0, "show-cpu-utilization", &symbol_conf.show_cpu_utilization, OPT_BOOLEAN(0, "show-cpu-utilization", &symbol_conf.show_cpu_utilization,
"Show sample percentage for different cpu modes"), "Show sample percentage for different cpu modes"),
OPT_BOOLEAN_FLAG(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, OPT_BOOLEAN_FLAG(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
...@@ -1120,6 +1158,8 @@ int cmd_report(int argc, const char **argv) ...@@ -1120,6 +1158,8 @@ int cmd_report(int argc, const char **argv)
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
"Enable kernel symbol demangling"), "Enable kernel symbol demangling"),
OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
OPT_INTEGER(0, "samples", &symbol_conf.res_sample,
"Number of samples to save per histogram entry for individual browsing"),
OPT_CALLBACK(0, "percent-limit", &report, "percent", OPT_CALLBACK(0, "percent-limit", &report, "percent",
"Don't show entries under that percent", parse_percent_limit), "Don't show entries under that percent", parse_percent_limit),
OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
...@@ -1147,6 +1187,10 @@ int cmd_report(int argc, const char **argv) ...@@ -1147,6 +1187,10 @@ int cmd_report(int argc, const char **argv)
OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period", OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period",
"Set percent type local/global-period/hits", "Set percent type local/global-period/hits",
annotate_parse_percent_type), annotate_parse_percent_type),
OPT_BOOLEAN(0, "ns", &symbol_conf.nanosecs, "Show times in nanosecs"),
OPT_CALLBACK(0, "time-quantum", &symbol_conf.time_quantum, "time (ms|us|ns|s)",
"Set time quantum for time sort key (default 100ms)",
parse_time_quantum),
OPT_END() OPT_END()
}; };
struct perf_data data = { struct perf_data data = {
......
This diff is collapsed.
...@@ -718,7 +718,8 @@ static struct option stat_options[] = { ...@@ -718,7 +718,8 @@ static struct option stat_options[] = {
"system-wide collection from all CPUs"), "system-wide collection from all CPUs"),
OPT_BOOLEAN('g', "group", &group, OPT_BOOLEAN('g', "group", &group,
"put the counters into a counter group"), "put the counters into a counter group"),
OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"), OPT_BOOLEAN(0, "scale", &stat_config.scale,
"Use --no-scale to disable counter scaling for multiplexing"),
OPT_INCR('v', "verbose", &verbose, OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"), "be more verbose (show counter open errors, etc)"),
OPT_INTEGER('r', "repeat", &stat_config.run_count, OPT_INTEGER('r', "repeat", &stat_config.run_count,
......
...@@ -1189,30 +1189,26 @@ static int __cmd_top(struct perf_top *top) ...@@ -1189,30 +1189,26 @@ static int __cmd_top(struct perf_top *top)
pthread_t thread, thread_process; pthread_t thread, thread_process;
int ret; int ret;
top->session = perf_session__new(NULL, false, NULL);
if (top->session == NULL)
return -1;
if (!top->annotation_opts.objdump_path) { if (!top->annotation_opts.objdump_path) {
ret = perf_env__lookup_objdump(&top->session->header.env, ret = perf_env__lookup_objdump(&top->session->header.env,
&top->annotation_opts.objdump_path); &top->annotation_opts.objdump_path);
if (ret) if (ret)
goto out_delete; return ret;
} }
ret = callchain_param__setup_sample_type(&callchain_param); ret = callchain_param__setup_sample_type(&callchain_param);
if (ret) if (ret)
goto out_delete; return ret;
if (perf_session__register_idle_thread(top->session) < 0) if (perf_session__register_idle_thread(top->session) < 0)
goto out_delete; return ret;
if (top->nr_threads_synthesize > 1) if (top->nr_threads_synthesize > 1)
perf_set_multithreaded(); perf_set_multithreaded();
init_process_thread(top); init_process_thread(top);
ret = perf_event__synthesize_bpf_events(&top->tool, perf_event__process, ret = perf_event__synthesize_bpf_events(top->session, perf_event__process,
&top->session->machines.host, &top->session->machines.host,
&top->record_opts); &top->record_opts);
if (ret < 0) if (ret < 0)
...@@ -1227,13 +1223,18 @@ static int __cmd_top(struct perf_top *top) ...@@ -1227,13 +1223,18 @@ static int __cmd_top(struct perf_top *top)
if (perf_hpp_list.socket) { if (perf_hpp_list.socket) {
ret = perf_env__read_cpu_topology_map(&perf_env); ret = perf_env__read_cpu_topology_map(&perf_env);
if (ret < 0) if (ret < 0) {
goto out_err_cpu_topo; char errbuf[BUFSIZ];
const char *err = str_error_r(-ret, errbuf, sizeof(errbuf));
ui__error("Could not read the CPU topology map: %s\n", err);
return ret;
}
} }
ret = perf_top__start_counters(top); ret = perf_top__start_counters(top);
if (ret) if (ret)
goto out_delete; return ret;
top->session->evlist = top->evlist; top->session->evlist = top->evlist;
perf_session__set_id_hdr_size(top->session); perf_session__set_id_hdr_size(top->session);
...@@ -1252,7 +1253,7 @@ static int __cmd_top(struct perf_top *top) ...@@ -1252,7 +1253,7 @@ static int __cmd_top(struct perf_top *top)
ret = -1; ret = -1;
if (pthread_create(&thread_process, NULL, process_thread, top)) { if (pthread_create(&thread_process, NULL, process_thread, top)) {
ui__error("Could not create process thread.\n"); ui__error("Could not create process thread.\n");
goto out_delete; return ret;
} }
if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
...@@ -1296,19 +1297,7 @@ static int __cmd_top(struct perf_top *top) ...@@ -1296,19 +1297,7 @@ static int __cmd_top(struct perf_top *top)
out_join_thread: out_join_thread:
pthread_cond_signal(&top->qe.cond); pthread_cond_signal(&top->qe.cond);
pthread_join(thread_process, NULL); pthread_join(thread_process, NULL);
out_delete:
perf_session__delete(top->session);
top->session = NULL;
return ret; return ret;
out_err_cpu_topo: {
char errbuf[BUFSIZ];
const char *err = str_error_r(-ret, errbuf, sizeof(errbuf));
ui__error("Could not read the CPU topology map: %s\n", err);
goto out_delete;
}
} }
static int static int
...@@ -1480,6 +1469,7 @@ int cmd_top(int argc, const char **argv) ...@@ -1480,6 +1469,7 @@ int cmd_top(int argc, const char **argv)
"Display raw encoding of assembly instructions (default)"), "Display raw encoding of assembly instructions (default)"),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
"Enable kernel symbol demangling"), "Enable kernel symbol demangling"),
OPT_BOOLEAN(0, "no-bpf-event", &top.record_opts.no_bpf_event, "do not record bpf events"),
OPT_STRING(0, "objdump", &top.annotation_opts.objdump_path, "path", OPT_STRING(0, "objdump", &top.annotation_opts.objdump_path, "path",
"objdump binary to use for disassembly and annotations"), "objdump binary to use for disassembly and annotations"),
OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style", OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style",
...@@ -1511,6 +1501,7 @@ int cmd_top(int argc, const char **argv) ...@@ -1511,6 +1501,7 @@ int cmd_top(int argc, const char **argv)
"number of thread to run event synthesize"), "number of thread to run event synthesize"),
OPT_END() OPT_END()
}; };
struct perf_evlist *sb_evlist = NULL;
const char * const top_usage[] = { const char * const top_usage[] = {
"perf top [<options>]", "perf top [<options>]",
NULL NULL
...@@ -1628,8 +1619,9 @@ int cmd_top(int argc, const char **argv) ...@@ -1628,8 +1619,9 @@ int cmd_top(int argc, const char **argv)
annotation_config__init(); annotation_config__init();
symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
if (symbol__init(NULL) < 0) status = symbol__init(NULL);
return -1; if (status < 0)
goto out_delete_evlist;
sort__setup_elide(stdout); sort__setup_elide(stdout);
...@@ -1639,10 +1631,28 @@ int cmd_top(int argc, const char **argv) ...@@ -1639,10 +1631,28 @@ int cmd_top(int argc, const char **argv)
signal(SIGWINCH, winch_sig); signal(SIGWINCH, winch_sig);
} }
top.session = perf_session__new(NULL, false, NULL);
if (top.session == NULL) {
status = -1;
goto out_delete_evlist;
}
if (!top.record_opts.no_bpf_event)
bpf_event__add_sb_event(&sb_evlist, &perf_env);
if (perf_evlist__start_sb_thread(sb_evlist, target)) {
pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
opts->no_bpf_event = true;
}
status = __cmd_top(&top); status = __cmd_top(&top);
if (!opts->no_bpf_event)
perf_evlist__stop_sb_thread(sb_evlist);
out_delete_evlist: out_delete_evlist:
perf_evlist__delete(top.evlist); perf_evlist__delete(top.evlist);
perf_session__delete(top.session);
return status; return status;
} }
...@@ -40,5 +40,6 @@ int cmd_mem(int argc, const char **argv); ...@@ -40,5 +40,6 @@ int cmd_mem(int argc, const char **argv);
int cmd_data(int argc, const char **argv); int cmd_data(int argc, const char **argv);
int cmd_ftrace(int argc, const char **argv); int cmd_ftrace(int argc, const char **argv);
int find_scripts(char **scripts_array, char **scripts_path_array); int find_scripts(char **scripts_array, char **scripts_path_array, int num,
int pathlen);
#endif #endif
...@@ -298,6 +298,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) ...@@ -298,6 +298,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
use_pager = 1; use_pager = 1;
commit_pager_choice(); commit_pager_choice();
perf_env__init(&perf_env);
perf_env__set_cmdline(&perf_env, argc, argv); perf_env__set_cmdline(&perf_env, argc, argv);
status = p->fn(argc, argv); status = p->fn(argc, argv);
perf_config__exit(); perf_config__exit();
......
...@@ -66,7 +66,7 @@ struct record_opts { ...@@ -66,7 +66,7 @@ struct record_opts {
bool ignore_missing_thread; bool ignore_missing_thread;
bool strict_freq; bool strict_freq;
bool sample_id; bool sample_id;
bool bpf_event; bool no_bpf_event;
unsigned int freq; unsigned int freq;
unsigned int mmap_pages; unsigned int mmap_pages;
unsigned int auxtrace_mmap_pages; unsigned int auxtrace_mmap_pages;
......
[
{
"EventName": "bp_l1_btb_correct",
"EventCode": "0x8a",
"BriefDescription": "L1 BTB Correction."
},
{
"EventName": "bp_l2_btb_correct",
"EventCode": "0x8b",
"BriefDescription": "L2 BTB Correction."
}
]
This diff is collapsed.
[
{
"EventName": "ex_ret_instr",
"EventCode": "0xc0",
"BriefDescription": "Retired Instructions."
},
{
"EventName": "ex_ret_cops",
"EventCode": "0xc1",
"BriefDescription": "Retired Uops.",
"PublicDescription": "The number of uOps retired. This includes all processor activity (instructions, exceptions, interrupts, microcode assists, etc.). The number of events logged per cycle can vary from 0 to 4."
},
{
"EventName": "ex_ret_brn",
"EventCode": "0xc2",
"BriefDescription": "[Retired Branch Instructions.",
"PublicDescription": "The number of branch instructions retired. This includes all types of architectural control flow changes, including exceptions and interrupts."
},
{
"EventName": "ex_ret_brn_misp",
"EventCode": "0xc3",
"BriefDescription": "Retired Branch Instructions Mispredicted.",
"PublicDescription": "The number of branch instructions retired, of any type, that were not correctly predicted. This includes those for which prediction is not attempted (far control transfers, exceptions and interrupts)."
},
{
"EventName": "ex_ret_brn_tkn",
"EventCode": "0xc4",
"BriefDescription": "Retired Taken Branch Instructions.",
"PublicDescription": "The number of taken branches that were retired. This includes all types of architectural control flow changes, including exceptions and interrupts."
},
{
"EventName": "ex_ret_brn_tkn_misp",
"EventCode": "0xc5",
"BriefDescription": "Retired Taken Branch Instructions Mispredicted.",
"PublicDescription": "The number of retired taken branch instructions that were mispredicted."
},
{
"EventName": "ex_ret_brn_far",
"EventCode": "0xc6",
"BriefDescription": "Retired Far Control Transfers.",
"PublicDescription": "The number of far control transfers retired including far call/jump/return, IRET, SYSCALL and SYSRET, plus exceptions and interrupts. Far control transfers are not subject to branch prediction."
},
{
"EventName": "ex_ret_brn_resync",
"EventCode": "0xc7",
"BriefDescription": "Retired Branch Resyncs.",
"PublicDescription": "The number of resync branches. These reflect pipeline restarts due to certain microcode assists and events such as writes to the active instruction stream, among other things. Each occurrence reflects a restart penalty similar to a branch mispredict. This is relatively rare."
},
{
"EventName": "ex_ret_near_ret",
"EventCode": "0xc8",
"BriefDescription": "Retired Near Returns.",
"PublicDescription": "The number of near return instructions (RET or RET Iw) retired."
},
{
"EventName": "ex_ret_near_ret_mispred",
"EventCode": "0xc9",
"BriefDescription": "Retired Near Returns Mispredicted.",
"PublicDescription": "The number of near returns retired that were not correctly predicted by the return address predictor. Each such mispredict incurs the same penalty as a mispredicted conditional branch instruction."
},
{
"EventName": "ex_ret_brn_ind_misp",
"EventCode": "0xca",
"BriefDescription": "Retired Indirect Branch Instructions Mispredicted.",
"PublicDescription": "Retired Indirect Branch Instructions Mispredicted."
},
{
"EventName": "ex_ret_mmx_fp_instr.sse_instr",
"EventCode": "0xcb",
"BriefDescription": "SSE instructions (SSE, SSE2, SSE3, SSSE3, SSE4A, SSE41, SSE42, AVX).",
"PublicDescription": "The number of MMX, SSE or x87 instructions retired. The UnitMask allows the selection of the individual classes of instructions as given in the table. Each increment represents one complete instruction. Since this event includes non-numeric instructions it is not suitable for measuring MFLOPS. SSE instructions (SSE, SSE2, SSE3, SSSE3, SSE4A, SSE41, SSE42, AVX).",
"UMask": "0x4"
},
{
"EventName": "ex_ret_mmx_fp_instr.mmx_instr",
"EventCode": "0xcb",
"BriefDescription": "MMX instructions.",
"PublicDescription": "The number of MMX, SSE or x87 instructions retired. The UnitMask allows the selection of the individual classes of instructions as given in the table. Each increment represents one complete instruction. Since this event includes non-numeric instructions it is not suitable for measuring MFLOPS. MMX instructions.",
"UMask": "0x2"
},
{
"EventName": "ex_ret_mmx_fp_instr.x87_instr",
"EventCode": "0xcb",
"BriefDescription": "x87 instructions.",
"PublicDescription": "The number of MMX, SSE or x87 instructions retired. The UnitMask allows the selection of the individual classes of instructions as given in the table. Each increment represents one complete instruction. Since this event includes non-numeric instructions it is not suitable for measuring MFLOPS. x87 instructions.",
"UMask": "0x1"
},
{
"EventName": "ex_ret_cond",
"EventCode": "0xd1",
"BriefDescription": "Retired Conditional Branch Instructions."
},
{
"EventName": "ex_ret_cond_misp",
"EventCode": "0xd2",
"BriefDescription": "Retired Conditional Branch Instructions Mispredicted."
},
{
"EventName": "ex_div_busy",
"EventCode": "0xd3",
"BriefDescription": "Div Cycles Busy count."
},
{
"EventName": "ex_div_count",
"EventCode": "0xd4",
"BriefDescription": "Div Op Count."
},
{
"EventName": "ex_tagged_ibs_ops.ibs_count_rollover",
"EventCode": "0x1cf",
"BriefDescription": "Number of times an op could not be tagged by IBS because of a previous tagged op that has not retired.",
"PublicDescription": "Tagged IBS Ops. Number of times an op could not be tagged by IBS because of a previous tagged op that has not retired.",
"UMask": "0x4"
},
{
"EventName": "ex_tagged_ibs_ops.ibs_tagged_ops_ret",
"EventCode": "0x1cf",
"BriefDescription": "Number of Ops tagged by IBS that retired.",
"PublicDescription": "Tagged IBS Ops. Number of Ops tagged by IBS that retired.",
"UMask": "0x2"
},
{
"EventName": "ex_tagged_ibs_ops.ibs_tagged_ops",
"EventCode": "0x1cf",
"BriefDescription": "Number of Ops tagged by IBS.",
"PublicDescription": "Tagged IBS Ops. Number of Ops tagged by IBS.",
"UMask": "0x1"
},
{
"EventName": "ex_ret_fus_brnch_inst",
"EventCode": "0x1d0",
"BriefDescription": "The number of fused retired branch instructions retired per cycle. The number of events logged per cycle can vary from 0 to 3."
}
]
[
{
"EventName": "fpu_pipe_assignment.dual",
"EventCode": "0x00",
"BriefDescription": "Total number multi-pipe uOps.",
"PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number multi-pipe uOps assigned to Pipe 3.",
"UMask": "0xf0"
},
{
"EventName": "fpu_pipe_assignment.total",
"EventCode": "0x00",
"BriefDescription": "Total number uOps.",
"PublicDescription": "The number of operations (uOps) and dual-pipe uOps dispatched to each of the 4 FPU execution pipelines. This event reflects how busy the FPU pipelines are and may be used for workload characterization. This includes all operations performed by x87, MMX, and SSE instructions, including moves. Each increment represents a one- cycle dispatch event. This event is a speculative event. Since this event includes non-numeric operations it is not suitable for measuring MFLOPS. Total number uOps assigned to Pipe 3.",
"UMask": "0xf"
},
{
"EventName": "fp_sched_empty",
"EventCode": "0x01",
"BriefDescription": "This is a speculative event. The number of cycles in which the FPU scheduler is empty. Note that some Ops like FP loads bypass the scheduler."
},
{
"EventName": "fp_retx87_fp_ops.all",
"EventCode": "0x02",
"BriefDescription": "All Ops.",
"PublicDescription": "The number of x87 floating-point Ops that have retired. The number of events logged per cycle can vary from 0 to 8.",
"UMask": "0x7"
},
{
"EventName": "fp_retx87_fp_ops.div_sqr_r_ops",
"EventCode": "0x02",
"BriefDescription": "Divide and square root Ops.",
"PublicDescription": "The number of x87 floating-point Ops that have retired. The number of events logged per cycle can vary from 0 to 8. Divide and square root Ops.",
"UMask": "0x4"
},
{
"EventName": "fp_retx87_fp_ops.mul_ops",
"EventCode": "0x02",
"BriefDescription": "Multiply Ops.",
"PublicDescription": "The number of x87 floating-point Ops that have retired. The number of events logged per cycle can vary from 0 to 8. Multiply Ops.",
"UMask": "0x2"
},
{
"EventName": "fp_retx87_fp_ops.add_sub_ops",
"EventCode": "0x02",
"BriefDescription": "Add/subtract Ops.",
"PublicDescription": "The number of x87 floating-point Ops that have retired. The number of events logged per cycle can vary from 0 to 8. Add/subtract Ops.",
"UMask": "0x1"
},
{
"EventName": "fp_ret_sse_avx_ops.all",
"EventCode": "0x03",
"BriefDescription": "All FLOPS.",
"PublicDescription": "This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15.",
"UMask": "0xff"
},
{
"EventName": "fp_ret_sse_avx_ops.dp_mult_add_flops",
"EventCode": "0x03",
"BriefDescription": "Double precision multiply-add FLOPS. Multiply-add counts as 2 FLOPS.",
"PublicDescription": "This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15. Double precision multiply-add FLOPS. Multiply-add counts as 2 FLOPS.",
"UMask": "0x80"
},
{
"EventName": "fp_ret_sse_avx_ops.dp_div_flops",
"EventCode": "0x03",
"BriefDescription": "Double precision divide/square root FLOPS.",
"PublicDescription": "This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15. Double precision divide/square root FLOPS.",
"UMask": "0x40"
},
{
"EventName": "fp_ret_sse_avx_ops.dp_mult_flops",
"EventCode": "0x03",
"BriefDescription": "Double precision multiply FLOPS.",
"PublicDescription": "This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15. Double precision multiply FLOPS.",
"UMask": "0x20"
},
{
"EventName": "fp_ret_sse_avx_ops.dp_add_sub_flops",
"EventCode": "0x03",
"BriefDescription": "Double precision add/subtract FLOPS.",
"PublicDescription": "This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15. Double precision add/subtract FLOPS.",
"UMask": "0x10"
},
{
"EventName": "fp_ret_sse_avx_ops.sp_mult_add_flops",
"EventCode": "0x03",
"BriefDescription": "Single precision multiply-add FLOPS. Multiply-add counts as 2 FLOPS.",
"PublicDescription": "This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15. Single precision multiply-add FLOPS. Multiply-add counts as 2 FLOPS.",
"UMask": "0x8"
},
{
"EventName": "fp_ret_sse_avx_ops.sp_div_flops",
"EventCode": "0x03",
"BriefDescription": "Single-precision divide/square root FLOPS.",
"PublicDescription": "This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15. Single-precision divide/square root FLOPS.",
"UMask": "0x4"
},
{
"EventName": "fp_ret_sse_avx_ops.sp_mult_flops",
"EventCode": "0x03",
"BriefDescription": "Single-precision multiply FLOPS.",
"PublicDescription": "This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15. Single-precision multiply FLOPS.",
"UMask": "0x2"
},
{
"EventName": "fp_ret_sse_avx_ops.sp_add_sub_flops",
"EventCode": "0x03",
"BriefDescription": "Single-precision add/subtract FLOPS.",
"PublicDescription": "This is a retire-based event. The number of retired SSE/AVX FLOPS. The number of events logged per cycle can vary from 0 to 64. This event can count above 15. Single-precision add/subtract FLOPS.",
"UMask": "0x1"
},
{
"EventName": "fp_num_mov_elim_scal_op.optimized",
"EventCode": "0x04",
"BriefDescription": "Number of Scalar Ops optimized.",
"PublicDescription": "This is a dispatch based speculative event, and is useful for measuring the effectiveness of the Move elimination and Scalar code optimization schemes. Number of Scalar Ops optimized.",
"UMask": "0x8"
},
{
"EventName": "fp_num_mov_elim_scal_op.opt_potential",
"EventCode": "0x04",
"BriefDescription": "Number of Ops that are candidates for optimization (have Z-bit either set or pass).",
"PublicDescription": "This is a dispatch based speculative event, and is useful for measuring the effectiveness of the Move elimination and Scalar code optimization schemes. Number of Ops that are candidates for optimization (have Z-bit either set or pass).",
"UMask": "0x4"
},
{
"EventName": "fp_num_mov_elim_scal_op.sse_mov_ops_elim",
"EventCode": "0x04",
"BriefDescription": "Number of SSE Move Ops eliminated.",
"PublicDescription": "This is a dispatch based speculative event, and is useful for measuring the effectiveness of the Move elimination and Scalar code optimization schemes. Number of SSE Move Ops eliminated.",
"UMask": "0x2"
},
{
"EventName": "fp_num_mov_elim_scal_op.sse_mov_ops",
"EventCode": "0x04",
"BriefDescription": "Number of SSE Move Ops.",
"PublicDescription": "This is a dispatch based speculative event, and is useful for measuring the effectiveness of the Move elimination and Scalar code optimization schemes. Number of SSE Move Ops.",
"UMask": "0x1"
},
{
"EventName": "fp_retired_ser_ops.x87_ctrl_ret",
"EventCode": "0x05",
"BriefDescription": "x87 control word mispredict traps due to mispredictions in RC or PC, or changes in mask bits.",
"PublicDescription": "The number of serializing Ops retired. x87 control word mispredict traps due to mispredictions in RC or PC, or changes in mask bits.",
"UMask": "0x8"
},
{
"EventName": "fp_retired_ser_ops.x87_bot_ret",
"EventCode": "0x05",
"BriefDescription": "x87 bottom-executing uOps retired.",
"PublicDescription": "The number of serializing Ops retired. x87 bottom-executing uOps retired.",
"UMask": "0x4"
},
{
"EventName": "fp_retired_ser_ops.sse_ctrl_ret",
"EventCode": "0x05",
"BriefDescription": "SSE control word mispredict traps due to mispredictions in RC, FTZ or DAZ, or changes in mask bits.",
"PublicDescription": "The number of serializing Ops retired. SSE control word mispredict traps due to mispredictions in RC, FTZ or DAZ, or changes in mask bits.",
"UMask": "0x2"
},
{
"EventName": "fp_retired_ser_ops.sse_bot_ret",
"EventCode": "0x05",
"BriefDescription": "SSE bottom-executing uOps retired.",
"PublicDescription": "The number of serializing Ops retired. SSE bottom-executing uOps retired.",
"UMask": "0x1"
}
]
[
{
"EventName": "ls_locks.bus_lock",
"EventCode": "0x25",
"BriefDescription": "Bus lock when a locked operations crosses a cache boundary or is done on an uncacheable memory type.",
"PublicDescription": "Bus lock when a locked operations crosses a cache boundary or is done on an uncacheable memory type.",
"UMask": "0x1"
},
{
"EventName": "ls_dispatch.ld_st_dispatch",
"EventCode": "0x29",
"BriefDescription": "Load-op-Stores.",
"PublicDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed. Load-op-Stores.",
"UMask": "0x4"
},
{
"EventName": "ls_dispatch.store_dispatch",
"EventCode": "0x29",
"BriefDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.",
"PublicDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.",
"UMask": "0x2"
},
{
"EventName": "ls_dispatch.ld_dispatch",
"EventCode": "0x29",
"BriefDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.",
"PublicDescription": "Counts the number of operations dispatched to the LS unit. Unit Masks ADDed.",
"UMask": "0x1"
},
{
"EventName": "ls_stlf",
"EventCode": "0x35",
"BriefDescription": "Number of STLF hits."
},
{
"EventName": "ls_dc_accesses",
"EventCode": "0x40",
"BriefDescription": "The number of accesses to the data cache for load and store references. This may include certain microcode scratchpad accesses, although these are generally rare. Each increment represents an eight-byte access, although the instruction may only be accessing a portion of that. This event is a speculative event."
},
{
"EventName": "ls_l1_d_tlb_miss.all",
"EventCode": "0x45",
"BriefDescription": "L1 DTLB Miss or Reload off all sizes.",
"PublicDescription": "L1 DTLB Miss or Reload off all sizes.",
"UMask": "0xff"
},
{
"EventName": "ls_l1_d_tlb_miss.tlb_reload_1g_l2_miss",
"EventCode": "0x45",
"BriefDescription": "L1 DTLB Miss of a page of 1G size.",
"PublicDescription": "L1 DTLB Miss of a page of 1G size.",
"UMask": "0x80"
},
{
"EventName": "ls_l1_d_tlb_miss.tlb_reload_2m_l2_miss",
"EventCode": "0x45",
"BriefDescription": "L1 DTLB Miss of a page of 2M size.",
"PublicDescription": "L1 DTLB Miss of a page of 2M size.",
"UMask": "0x40"
},
{
"EventName": "ls_l1_d_tlb_miss.tlb_reload_32k_l2_miss",
"EventCode": "0x45",
"BriefDescription": "L1 DTLB Miss of a page of 32K size.",
"PublicDescription": "L1 DTLB Miss of a page of 32K size.",
"UMask": "0x20"
},
{
"EventName": "ls_l1_d_tlb_miss.tlb_reload_4k_l2_miss",
"EventCode": "0x45",
"BriefDescription": "L1 DTLB Miss of a page of 4K size.",
"PublicDescription": "L1 DTLB Miss of a page of 4K size.",
"UMask": "0x10"
},
{
"EventName": "ls_l1_d_tlb_miss.tlb_reload_1g_l2_hit",
"EventCode": "0x45",
"BriefDescription": "L1 DTLB Reload of a page of 1G size.",
"PublicDescription": "L1 DTLB Reload of a page of 1G size.",
"UMask": "0x8"
},
{
"EventName": "ls_l1_d_tlb_miss.tlb_reload_2m_l2_hit",
"EventCode": "0x45",
"BriefDescription": "L1 DTLB Reload of a page of 2M size.",
"PublicDescription": "L1 DTLB Reload of a page of 2M size.",
"UMask": "0x4"
},
{
"EventName": "ls_l1_d_tlb_miss.tlb_reload_32k_l2_hit",
"EventCode": "0x45",
"BriefDescription": "L1 DTLB Reload of a page of 32K size.",
"PublicDescription": "L1 DTLB Reload of a page of 32K size.",
"UMask": "0x2"
},
{
"EventName": "ls_l1_d_tlb_miss.tlb_reload_4k_l2_hit",
"EventCode": "0x45",
"BriefDescription": "L1 DTLB Reload of a page of 4K size.",
"PublicDescription": "L1 DTLB Reload of a page of 4K size.",
"UMask": "0x1"
},
{
"EventName": "ls_tablewalker.perf_mon_tablewalk_alloc_iside",
"EventCode": "0x46",
"BriefDescription": "Tablewalker allocation.",
"PublicDescription": "Tablewalker allocation.",
"UMask": "0xc"
},
{
"EventName": "ls_tablewalker.perf_mon_tablewalk_alloc_dside",
"EventCode": "0x46",
"BriefDescription": "Tablewalker allocation.",
"PublicDescription": "Tablewalker allocation.",
"UMask": "0x3"
},
{
"EventName": "ls_misal_accesses",
"EventCode": "0x47",
"BriefDescription": "Misaligned loads."
},
{
"EventName": "ls_pref_instr_disp.prefetch_nta",
"EventCode": "0x4b",
"BriefDescription": "Software Prefetch Instructions (PREFETCHNTA instruction) Dispatched.",
"PublicDescription": "Software Prefetch Instructions (PREFETCHNTA instruction) Dispatched.",
"UMask": "0x4"
},
{
"EventName": "ls_pref_instr_disp.store_prefetch_w",
"EventCode": "0x4b",
"BriefDescription": "Software Prefetch Instructions (3DNow PREFETCHW instruction) Dispatched.",
"PublicDescription": "Software Prefetch Instructions (3DNow PREFETCHW instruction) Dispatched.",
"UMask": "0x2"
},
{
"EventName": "ls_pref_instr_disp.load_prefetch_w",
"EventCode": "0x4b",
"BriefDescription": "Prefetch, Prefetch_T0_T1_T2.",
"PublicDescription": "Software Prefetch Instructions Dispatched. Prefetch, Prefetch_T0_T1_T2.",
"UMask": "0x1"
},
{
"EventName": "ls_inef_sw_pref.mab_mch_cnt",
"EventCode": "0x52",
"BriefDescription": "The number of software prefetches that did not fetch data outside of the processor core.",
"PublicDescription": "The number of software prefetches that did not fetch data outside of the processor core.",
"UMask": "0x2"
},
{
"EventName": "ls_inef_sw_pref.data_pipe_sw_pf_dc_hit",
"EventCode": "0x52",
"BriefDescription": "The number of software prefetches that did not fetch data outside of the processor core.",
"PublicDescription": "The number of software prefetches that did not fetch data outside of the processor core.",
"UMask": "0x1"
},
{
"EventName": "ls_not_halted_cyc",
"EventCode": "0x76",
"BriefDescription": "Cycles not in Halt."
}
]
[
{
"EventName": "ic_oc_mode_switch.oc_ic_mode_switch",
"EventCode": "0x28a",
"BriefDescription": "OC to IC mode switch.",
"PublicDescription": "OC Mode Switch. OC to IC mode switch.",
"UMask": "0x2"
},
{
"EventName": "ic_oc_mode_switch.ic_oc_mode_switch",
"EventCode": "0x28a",
"BriefDescription": "IC to OC mode switch.",
"PublicDescription": "OC Mode Switch. IC to OC mode switch.",
"UMask": "0x1"
},
{
"EventName": "de_dis_dispatch_token_stalls0.retire_token_stall",
"EventCode": "0xaf",
"BriefDescription": "RETIRE Tokens unavailable.",
"PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. RETIRE Tokens unavailable.",
"UMask": "0x40"
},
{
"EventName": "de_dis_dispatch_token_stalls0.agsq_token_stall",
"EventCode": "0xaf",
"BriefDescription": "AGSQ Tokens unavailable.",
"PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. AGSQ Tokens unavailable.",
"UMask": "0x20"
},
{
"EventName": "de_dis_dispatch_token_stalls0.alu_token_stall",
"EventCode": "0xaf",
"BriefDescription": "ALU tokens total unavailable.",
"PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALU tokens total unavailable.",
"UMask": "0x10"
},
{
"EventName": "de_dis_dispatch_token_stalls0.alsq3_0_token_stall",
"EventCode": "0xaf",
"BriefDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall.",
"PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall.",
"UMask": "0x8"
},
{
"EventName": "de_dis_dispatch_token_stalls0.alsq3_token_stall",
"EventCode": "0xaf",
"BriefDescription": "ALSQ 3 Tokens unavailable.",
"PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 3 Tokens unavailable.",
"UMask": "0x4"
},
{
"EventName": "de_dis_dispatch_token_stalls0.alsq2_token_stall",
"EventCode": "0xaf",
"BriefDescription": "ALSQ 2 Tokens unavailable.",
"PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 2 Tokens unavailable.",
"UMask": "0x2"
},
{
"EventName": "de_dis_dispatch_token_stalls0.alsq1_token_stall",
"EventCode": "0xaf",
"BriefDescription": "ALSQ 1 Tokens unavailable.",
"PublicDescription": "Cycles where a dispatch group is valid but does not get dispatched due to a token stall. ALSQ 1 Tokens unavailable.",
"UMask": "0x1"
}
]
...@@ -33,3 +33,4 @@ GenuineIntel-6-25,v2,westmereep-sp,core ...@@ -33,3 +33,4 @@ GenuineIntel-6-25,v2,westmereep-sp,core
GenuineIntel-6-2F,v2,westmereex,core GenuineIntel-6-2F,v2,westmereex,core
GenuineIntel-6-55-[01234],v1,skylakex,core GenuineIntel-6-55-[01234],v1,skylakex,core
GenuineIntel-6-55-[56789ABCDEF],v1,cascadelakex,core GenuineIntel-6-55-[56789ABCDEF],v1,cascadelakex,core
AuthenticAMD-23-[[:xdigit:]]+,v1,amdfam17h,core
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details. # more details.
from __future__ import print_function
import os import os
import sys import sys
import struct import struct
...@@ -199,6 +201,18 @@ import datetime ...@@ -199,6 +201,18 @@ import datetime
from PySide.QtSql import * from PySide.QtSql import *
if sys.version_info < (3, 0):
def toserverstr(str):
return str
def toclientstr(str):
return str
else:
# Assume UTF-8 server_encoding and client_encoding
def toserverstr(str):
return bytes(str, "UTF_8")
def toclientstr(str):
return bytes(str, "UTF_8")
# Need to access PostgreSQL C library directly to use COPY FROM STDIN # Need to access PostgreSQL C library directly to use COPY FROM STDIN
from ctypes import * from ctypes import *
libpq = CDLL("libpq.so.5") libpq = CDLL("libpq.so.5")
...@@ -234,12 +248,17 @@ perf_db_export_mode = True ...@@ -234,12 +248,17 @@ perf_db_export_mode = True
perf_db_export_calls = False perf_db_export_calls = False
perf_db_export_callchains = False perf_db_export_callchains = False
def printerr(*args, **kw_args):
print(*args, file=sys.stderr, **kw_args)
def printdate(*args, **kw_args):
print(datetime.datetime.today(), *args, sep=' ', **kw_args)
def usage(): def usage():
print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>]" printerr("Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>]")
print >> sys.stderr, "where: columns 'all' or 'branches'" printerr("where: columns 'all' or 'branches'")
print >> sys.stderr, " calls 'calls' => create calls and call_paths table" printerr(" calls 'calls' => create calls and call_paths table")
print >> sys.stderr, " callchains 'callchains' => create call_paths table" printerr(" callchains 'callchains' => create call_paths table")
raise Exception("Too few arguments") raise Exception("Too few arguments")
if (len(sys.argv) < 2): if (len(sys.argv) < 2):
...@@ -273,7 +292,7 @@ def do_query(q, s): ...@@ -273,7 +292,7 @@ def do_query(q, s):
return return
raise Exception("Query failed: " + q.lastError().text()) raise Exception("Query failed: " + q.lastError().text())
print datetime.datetime.today(), "Creating database..." printdate("Creating database...")
db = QSqlDatabase.addDatabase('QPSQL') db = QSqlDatabase.addDatabase('QPSQL')
query = QSqlQuery(db) query = QSqlQuery(db)
...@@ -506,12 +525,12 @@ do_query(query, 'CREATE VIEW samples_view AS ' ...@@ -506,12 +525,12 @@ do_query(query, 'CREATE VIEW samples_view AS '
' FROM samples') ' FROM samples')
file_header = struct.pack("!11sii", "PGCOPY\n\377\r\n\0", 0, 0) file_header = struct.pack("!11sii", b"PGCOPY\n\377\r\n\0", 0, 0)
file_trailer = "\377\377" file_trailer = b"\377\377"
def open_output_file(file_name): def open_output_file(file_name):
path_name = output_dir_name + "/" + file_name path_name = output_dir_name + "/" + file_name
file = open(path_name, "w+") file = open(path_name, "wb+")
file.write(file_header) file.write(file_header)
return file return file
...@@ -526,13 +545,13 @@ def copy_output_file_direct(file, table_name): ...@@ -526,13 +545,13 @@ def copy_output_file_direct(file, table_name):
# Use COPY FROM STDIN because security may prevent postgres from accessing the files directly # Use COPY FROM STDIN because security may prevent postgres from accessing the files directly
def copy_output_file(file, table_name): def copy_output_file(file, table_name):
conn = PQconnectdb("dbname = " + dbname) conn = PQconnectdb(toclientstr("dbname = " + dbname))
if (PQstatus(conn)): if (PQstatus(conn)):
raise Exception("COPY FROM STDIN PQconnectdb failed") raise Exception("COPY FROM STDIN PQconnectdb failed")
file.write(file_trailer) file.write(file_trailer)
file.seek(0) file.seek(0)
sql = "COPY " + table_name + " FROM STDIN (FORMAT 'binary')" sql = "COPY " + table_name + " FROM STDIN (FORMAT 'binary')"
res = PQexec(conn, sql) res = PQexec(conn, toclientstr(sql))
if (PQresultStatus(res) != 4): if (PQresultStatus(res) != 4):
raise Exception("COPY FROM STDIN PQexec failed") raise Exception("COPY FROM STDIN PQexec failed")
data = file.read(65536) data = file.read(65536)
...@@ -566,7 +585,7 @@ if perf_db_export_calls: ...@@ -566,7 +585,7 @@ if perf_db_export_calls:
call_file = open_output_file("call_table.bin") call_file = open_output_file("call_table.bin")
def trace_begin(): def trace_begin():
print datetime.datetime.today(), "Writing to intermediate files..." printdate("Writing to intermediate files...")
# id == 0 means unknown. It is easier to create records for them than replace the zeroes with NULLs # id == 0 means unknown. It is easier to create records for them than replace the zeroes with NULLs
evsel_table(0, "unknown") evsel_table(0, "unknown")
machine_table(0, 0, "unknown") machine_table(0, 0, "unknown")
...@@ -582,7 +601,7 @@ def trace_begin(): ...@@ -582,7 +601,7 @@ def trace_begin():
unhandled_count = 0 unhandled_count = 0
def trace_end(): def trace_end():
print datetime.datetime.today(), "Copying to database..." printdate("Copying to database...")
copy_output_file(evsel_file, "selected_events") copy_output_file(evsel_file, "selected_events")
copy_output_file(machine_file, "machines") copy_output_file(machine_file, "machines")
copy_output_file(thread_file, "threads") copy_output_file(thread_file, "threads")
...@@ -597,7 +616,7 @@ def trace_end(): ...@@ -597,7 +616,7 @@ def trace_end():
if perf_db_export_calls: if perf_db_export_calls:
copy_output_file(call_file, "calls") copy_output_file(call_file, "calls")
print datetime.datetime.today(), "Removing intermediate files..." printdate("Removing intermediate files...")
remove_output_file(evsel_file) remove_output_file(evsel_file)
remove_output_file(machine_file) remove_output_file(machine_file)
remove_output_file(thread_file) remove_output_file(thread_file)
...@@ -612,7 +631,7 @@ def trace_end(): ...@@ -612,7 +631,7 @@ def trace_end():
if perf_db_export_calls: if perf_db_export_calls:
remove_output_file(call_file) remove_output_file(call_file)
os.rmdir(output_dir_name) os.rmdir(output_dir_name)
print datetime.datetime.today(), "Adding primary keys" printdate("Adding primary keys")
do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)') do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE machines ADD PRIMARY KEY (id)') do_query(query, 'ALTER TABLE machines ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE threads ADD PRIMARY KEY (id)') do_query(query, 'ALTER TABLE threads ADD PRIMARY KEY (id)')
...@@ -627,7 +646,7 @@ def trace_end(): ...@@ -627,7 +646,7 @@ def trace_end():
if perf_db_export_calls: if perf_db_export_calls:
do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)') do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)')
print datetime.datetime.today(), "Adding foreign keys" printdate("Adding foreign keys")
do_query(query, 'ALTER TABLE threads ' do_query(query, 'ALTER TABLE threads '
'ADD CONSTRAINT machinefk FOREIGN KEY (machine_id) REFERENCES machines (id),' 'ADD CONSTRAINT machinefk FOREIGN KEY (machine_id) REFERENCES machines (id),'
'ADD CONSTRAINT processfk FOREIGN KEY (process_id) REFERENCES threads (id)') 'ADD CONSTRAINT processfk FOREIGN KEY (process_id) REFERENCES threads (id)')
...@@ -663,8 +682,8 @@ def trace_end(): ...@@ -663,8 +682,8 @@ def trace_end():
do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)') do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
if (unhandled_count): if (unhandled_count):
print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events" printdate("Warning: ", unhandled_count, " unhandled events")
print datetime.datetime.today(), "Done" printdate("Done")
def trace_unhandled(event_name, context, event_fields_dict): def trace_unhandled(event_name, context, event_fields_dict):
global unhandled_count global unhandled_count
...@@ -674,12 +693,14 @@ def sched__sched_switch(*x): ...@@ -674,12 +693,14 @@ def sched__sched_switch(*x):
pass pass
def evsel_table(evsel_id, evsel_name, *x): def evsel_table(evsel_id, evsel_name, *x):
evsel_name = toserverstr(evsel_name)
n = len(evsel_name) n = len(evsel_name)
fmt = "!hiqi" + str(n) + "s" fmt = "!hiqi" + str(n) + "s"
value = struct.pack(fmt, 2, 8, evsel_id, n, evsel_name) value = struct.pack(fmt, 2, 8, evsel_id, n, evsel_name)
evsel_file.write(value) evsel_file.write(value)
def machine_table(machine_id, pid, root_dir, *x): def machine_table(machine_id, pid, root_dir, *x):
root_dir = toserverstr(root_dir)
n = len(root_dir) n = len(root_dir)
fmt = "!hiqiii" + str(n) + "s" fmt = "!hiqiii" + str(n) + "s"
value = struct.pack(fmt, 3, 8, machine_id, 4, pid, n, root_dir) value = struct.pack(fmt, 3, 8, machine_id, 4, pid, n, root_dir)
...@@ -690,6 +711,7 @@ def thread_table(thread_id, machine_id, process_id, pid, tid, *x): ...@@ -690,6 +711,7 @@ def thread_table(thread_id, machine_id, process_id, pid, tid, *x):
thread_file.write(value) thread_file.write(value)
def comm_table(comm_id, comm_str, *x): def comm_table(comm_id, comm_str, *x):
comm_str = toserverstr(comm_str)
n = len(comm_str) n = len(comm_str)
fmt = "!hiqi" + str(n) + "s" fmt = "!hiqi" + str(n) + "s"
value = struct.pack(fmt, 2, 8, comm_id, n, comm_str) value = struct.pack(fmt, 2, 8, comm_id, n, comm_str)
...@@ -701,6 +723,9 @@ def comm_thread_table(comm_thread_id, comm_id, thread_id, *x): ...@@ -701,6 +723,9 @@ def comm_thread_table(comm_thread_id, comm_id, thread_id, *x):
comm_thread_file.write(value) comm_thread_file.write(value)
def dso_table(dso_id, machine_id, short_name, long_name, build_id, *x): def dso_table(dso_id, machine_id, short_name, long_name, build_id, *x):
short_name = toserverstr(short_name)
long_name = toserverstr(long_name)
build_id = toserverstr(build_id)
n1 = len(short_name) n1 = len(short_name)
n2 = len(long_name) n2 = len(long_name)
n3 = len(build_id) n3 = len(build_id)
...@@ -709,12 +734,14 @@ def dso_table(dso_id, machine_id, short_name, long_name, build_id, *x): ...@@ -709,12 +734,14 @@ def dso_table(dso_id, machine_id, short_name, long_name, build_id, *x):
dso_file.write(value) dso_file.write(value)
def symbol_table(symbol_id, dso_id, sym_start, sym_end, binding, symbol_name, *x): def symbol_table(symbol_id, dso_id, sym_start, sym_end, binding, symbol_name, *x):
symbol_name = toserverstr(symbol_name)
n = len(symbol_name) n = len(symbol_name)
fmt = "!hiqiqiqiqiii" + str(n) + "s" fmt = "!hiqiqiqiqiii" + str(n) + "s"
value = struct.pack(fmt, 6, 8, symbol_id, 8, dso_id, 8, sym_start, 8, sym_end, 4, binding, n, symbol_name) value = struct.pack(fmt, 6, 8, symbol_id, 8, dso_id, 8, sym_start, 8, sym_end, 4, binding, n, symbol_name)
symbol_file.write(value) symbol_file.write(value)
def branch_type_table(branch_type, name, *x): def branch_type_table(branch_type, name, *x):
name = toserverstr(name)
n = len(name) n = len(name)
fmt = "!hiii" + str(n) + "s" fmt = "!hiii" + str(n) + "s"
value = struct.pack(fmt, 2, 4, branch_type, n, name) value = struct.pack(fmt, 2, 4, branch_type, n, name)
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details. # more details.
from __future__ import print_function
import os import os
import sys import sys
import struct import struct
...@@ -60,11 +62,17 @@ perf_db_export_mode = True ...@@ -60,11 +62,17 @@ perf_db_export_mode = True
perf_db_export_calls = False perf_db_export_calls = False
perf_db_export_callchains = False perf_db_export_callchains = False
def printerr(*args, **keyword_args):
print(*args, file=sys.stderr, **keyword_args)
def printdate(*args, **kw_args):
print(datetime.datetime.today(), *args, sep=' ', **kw_args)
def usage(): def usage():
print >> sys.stderr, "Usage is: export-to-sqlite.py <database name> [<columns>] [<calls>] [<callchains>]" printerr("Usage is: export-to-sqlite.py <database name> [<columns>] [<calls>] [<callchains>]");
print >> sys.stderr, "where: columns 'all' or 'branches'" printerr("where: columns 'all' or 'branches'");
print >> sys.stderr, " calls 'calls' => create calls and call_paths table" printerr(" calls 'calls' => create calls and call_paths table");
print >> sys.stderr, " callchains 'callchains' => create call_paths table" printerr(" callchains 'callchains' => create call_paths table");
raise Exception("Too few arguments") raise Exception("Too few arguments")
if (len(sys.argv) < 2): if (len(sys.argv) < 2):
...@@ -100,7 +108,7 @@ def do_query_(q): ...@@ -100,7 +108,7 @@ def do_query_(q):
return return
raise Exception("Query failed: " + q.lastError().text()) raise Exception("Query failed: " + q.lastError().text())
print datetime.datetime.today(), "Creating database..." printdate("Creating database ...")
db_exists = False db_exists = False
try: try:
...@@ -378,7 +386,7 @@ if perf_db_export_calls: ...@@ -378,7 +386,7 @@ if perf_db_export_calls:
call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
def trace_begin(): def trace_begin():
print datetime.datetime.today(), "Writing records..." printdate("Writing records...")
do_query(query, 'BEGIN TRANSACTION') do_query(query, 'BEGIN TRANSACTION')
# id == 0 means unknown. It is easier to create records for them than replace the zeroes with NULLs # id == 0 means unknown. It is easier to create records for them than replace the zeroes with NULLs
evsel_table(0, "unknown") evsel_table(0, "unknown")
...@@ -397,14 +405,14 @@ unhandled_count = 0 ...@@ -397,14 +405,14 @@ unhandled_count = 0
def trace_end(): def trace_end():
do_query(query, 'END TRANSACTION') do_query(query, 'END TRANSACTION')
print datetime.datetime.today(), "Adding indexes" printdate("Adding indexes")
if perf_db_export_calls: if perf_db_export_calls:
do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)') do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)') do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
if (unhandled_count): if (unhandled_count):
print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events" printdate("Warning: ", unhandled_count, " unhandled events")
print datetime.datetime.today(), "Done" printdate("Done")
def trace_unhandled(event_name, context, event_fields_dict): def trace_unhandled(event_name, context, event_fields_dict):
global unhandled_count global unhandled_count
......
...@@ -88,11 +88,20 @@ ...@@ -88,11 +88,20 @@
# 7fab593ea956 48 89 15 3b 13 22 00 movq %rdx, 0x22133b(%rip) # 7fab593ea956 48 89 15 3b 13 22 00 movq %rdx, 0x22133b(%rip)
# 8107675243232 2 ls 22011 22011 hardware interrupt No 7fab593ea956 _dl_start+0x26 (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel]) # 8107675243232 2 ls 22011 22011 hardware interrupt No 7fab593ea956 _dl_start+0x26 (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel])
from __future__ import print_function
import sys import sys
import weakref import weakref
import threading import threading
import string import string
import cPickle try:
# Python2
import cPickle as pickle
# size of pickled integer big enough for record size
glb_nsz = 8
except ImportError:
import pickle
glb_nsz = 16
import re import re
import os import os
from PySide.QtCore import * from PySide.QtCore import *
...@@ -102,6 +111,15 @@ from decimal import * ...@@ -102,6 +111,15 @@ from decimal import *
from ctypes import * from ctypes import *
from multiprocessing import Process, Array, Value, Event from multiprocessing import Process, Array, Value, Event
# xrange is range in Python3
try:
xrange
except NameError:
xrange = range
def printerr(*args, **keyword_args):
print(*args, file=sys.stderr, **keyword_args)
# Data formatting helpers # Data formatting helpers
def tohex(ip): def tohex(ip):
...@@ -1004,10 +1022,6 @@ class ChildDataItemFinder(): ...@@ -1004,10 +1022,6 @@ class ChildDataItemFinder():
glb_chunk_sz = 10000 glb_chunk_sz = 10000
# size of pickled integer big enough for record size
glb_nsz = 8
# Background process for SQL data fetcher # Background process for SQL data fetcher
class SQLFetcherProcess(): class SQLFetcherProcess():
...@@ -1066,7 +1080,7 @@ class SQLFetcherProcess(): ...@@ -1066,7 +1080,7 @@ class SQLFetcherProcess():
return True return True
if space >= glb_nsz: if space >= glb_nsz:
# Use 0 (or space < glb_nsz) to mean there is no more at the top of the buffer # Use 0 (or space < glb_nsz) to mean there is no more at the top of the buffer
nd = cPickle.dumps(0, cPickle.HIGHEST_PROTOCOL) nd = pickle.dumps(0, pickle.HIGHEST_PROTOCOL)
self.buffer[self.local_head : self.local_head + len(nd)] = nd self.buffer[self.local_head : self.local_head + len(nd)] = nd
self.local_head = 0 self.local_head = 0
if self.local_tail - self.local_head > sz: if self.local_tail - self.local_head > sz:
...@@ -1084,9 +1098,9 @@ class SQLFetcherProcess(): ...@@ -1084,9 +1098,9 @@ class SQLFetcherProcess():
self.wait_event.wait() self.wait_event.wait()
def AddToBuffer(self, obj): def AddToBuffer(self, obj):
d = cPickle.dumps(obj, cPickle.HIGHEST_PROTOCOL) d = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)
n = len(d) n = len(d)
nd = cPickle.dumps(n, cPickle.HIGHEST_PROTOCOL) nd = pickle.dumps(n, pickle.HIGHEST_PROTOCOL)
sz = n + glb_nsz sz = n + glb_nsz
self.WaitForSpace(sz) self.WaitForSpace(sz)
pos = self.local_head pos = self.local_head
...@@ -1198,12 +1212,12 @@ class SQLFetcher(QObject): ...@@ -1198,12 +1212,12 @@ class SQLFetcher(QObject):
pos = self.local_tail pos = self.local_tail
if len(self.buffer) - pos < glb_nsz: if len(self.buffer) - pos < glb_nsz:
pos = 0 pos = 0
n = cPickle.loads(self.buffer[pos : pos + glb_nsz]) n = pickle.loads(self.buffer[pos : pos + glb_nsz])
if n == 0: if n == 0:
pos = 0 pos = 0
n = cPickle.loads(self.buffer[0 : glb_nsz]) n = pickle.loads(self.buffer[0 : glb_nsz])
pos += glb_nsz pos += glb_nsz
obj = cPickle.loads(self.buffer[pos : pos + n]) obj = pickle.loads(self.buffer[pos : pos + n])
self.local_tail = pos + n self.local_tail = pos + n
return obj return obj
...@@ -2973,7 +2987,7 @@ class DBRef(): ...@@ -2973,7 +2987,7 @@ class DBRef():
def Main(): def Main():
if (len(sys.argv) < 2): if (len(sys.argv) < 2):
print >> sys.stderr, "Usage is: exported-sql-viewer.py {<database name> | --help-only}" printerr("Usage is: exported-sql-viewer.py {<database name> | --help-only}");
raise Exception("Too few arguments") raise Exception("Too few arguments")
dbname = sys.argv[1] dbname = sys.argv[1]
...@@ -2986,8 +3000,8 @@ def Main(): ...@@ -2986,8 +3000,8 @@ def Main():
is_sqlite3 = False is_sqlite3 = False
try: try:
f = open(dbname) f = open(dbname, "rb")
if f.read(15) == "SQLite format 3": if f.read(15) == b'SQLite format 3':
is_sqlite3 = True is_sqlite3 = True
f.close() f.close()
except: except:
......
[config] [config]
command = record command = record
args = -C 0 kill >/dev/null 2>&1 args = --no-bpf-event -C 0 kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = kill >/dev/null 2>&1 args = --no-bpf-event kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
[config] [config]
command = record command = record
args = -b kill >/dev/null 2>&1 args = --no-bpf-event -b kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -j any kill >/dev/null 2>&1 args = --no-bpf-event -j any kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -j any_call kill >/dev/null 2>&1 args = --no-bpf-event -j any_call kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -j any_ret kill >/dev/null 2>&1 args = --no-bpf-event -j any_ret kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -j hv kill >/dev/null 2>&1 args = --no-bpf-event -j hv kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -j ind_call kill >/dev/null 2>&1 args = --no-bpf-event -j ind_call kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -j k kill >/dev/null 2>&1 args = --no-bpf-event -j k kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -j u kill >/dev/null 2>&1 args = --no-bpf-event -j u kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -c 123 kill >/dev/null 2>&1 args = --no-bpf-event -c 123 kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -d kill >/dev/null 2>&1 args = --no-bpf-event -d kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -F 100 kill >/dev/null 2>&1 args = --no-bpf-event -F 100 kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -g kill >/dev/null 2>&1 args = --no-bpf-event -g kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = --call-graph dwarf -- kill >/dev/null 2>&1 args = --no-bpf-event --call-graph dwarf -- kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = --call-graph fp kill >/dev/null 2>&1 args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = --group -e cycles,instructions kill >/dev/null 2>&1 args = --no-bpf-event --group -e cycles,instructions kill >/dev/null 2>&1
ret = 1 ret = 1
[event-1:base-record] [event-1:base-record]
......
[config] [config]
command = record command = record
args = -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1 args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
ret = 1 ret = 1
[event-1:base-record] [event-1:base-record]
......
[config] [config]
command = record command = record
args = -e '{cycles,instructions}' kill >/dev/null 2>&1 args = --no-bpf-event -e '{cycles,instructions}' kill >/dev/null 2>&1
ret = 1 ret = 1
[event-1:base-record] [event-1:base-record]
......
[config] [config]
command = record command = record
args = --no-buffering kill >/dev/null 2>&1 args = --no-bpf-event --no-buffering kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -i kill >/dev/null 2>&1 args = --no-bpf-event -i kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -n kill >/dev/null 2>&1 args = --no-bpf-event -n kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -c 100 -P kill >/dev/null 2>&1 args = --no-bpf-event -c 100 -P kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
[config] [config]
command = record command = record
args = -R kill >/dev/null 2>&1 args = --no-bpf-event -R kill >/dev/null 2>&1
ret = 1 ret = 1
[event:base-record] [event:base-record]
......
...@@ -18,7 +18,7 @@ static void testcase(void) ...@@ -18,7 +18,7 @@ static void testcase(void)
int i; int i;
for (i = 0; i < NR_ITERS; i++) { for (i = 0; i < NR_ITERS; i++) {
char proc_name[10]; char proc_name[15];
snprintf(proc_name, sizeof(proc_name), "p:%d\n", i); snprintf(proc_name, sizeof(proc_name), "p:%d\n", i);
prctl(PR_SET_NAME, proc_name); prctl(PR_SET_NAME, proc_name);
......
...@@ -85,5 +85,6 @@ int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtes ...@@ -85,5 +85,6 @@ int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtes
if (perf_evsel__test_field(evsel, "target_cpu", 4, true)) if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
ret = -1; ret = -1;
perf_evsel__delete(evsel);
return ret; return ret;
} }
...@@ -19,7 +19,7 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) ...@@ -19,7 +19,7 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused)
const char *p; const char *p;
const char **other; const char **other;
double val; double val;
int ret; int i, ret;
struct parse_ctx ctx; struct parse_ctx ctx;
int num_other; int num_other;
...@@ -56,6 +56,9 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) ...@@ -56,6 +56,9 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused)
TEST_ASSERT_VAL("find other", !strcmp(other[1], "BAZ")); TEST_ASSERT_VAL("find other", !strcmp(other[1], "BAZ"));
TEST_ASSERT_VAL("find other", !strcmp(other[2], "BOZO")); TEST_ASSERT_VAL("find other", !strcmp(other[2], "BOZO"));
TEST_ASSERT_VAL("find other", other[3] == NULL); TEST_ASSERT_VAL("find other", other[3] == NULL);
for (i = 0; i < num_other; i++)
free((void *)other[i]);
free((void *)other); free((void *)other);
return 0; return 0;
......
...@@ -45,7 +45,7 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int ...@@ -45,7 +45,7 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int
if (IS_ERR(evsel)) { if (IS_ERR(evsel)) {
tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat");
pr_debug("%s\n", errbuf); pr_debug("%s\n", errbuf);
goto out_thread_map_delete; goto out_cpu_map_delete;
} }
if (perf_evsel__open(evsel, cpus, threads) < 0) { if (perf_evsel__open(evsel, cpus, threads) < 0) {
...@@ -119,6 +119,8 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int ...@@ -119,6 +119,8 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int
perf_evsel__close_fd(evsel); perf_evsel__close_fd(evsel);
out_evsel_delete: out_evsel_delete:
perf_evsel__delete(evsel); perf_evsel__delete(evsel);
out_cpu_map_delete:
cpu_map__put(cpus);
out_thread_map_delete: out_thread_map_delete:
thread_map__put(threads); thread_map__put(threads);
return err; return err;
......
...@@ -611,14 +611,16 @@ void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence) ...@@ -611,14 +611,16 @@ void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
browser->top = browser->entries; browser->top = browser->entries;
break; break;
case SEEK_CUR: case SEEK_CUR:
browser->top = browser->top + browser->top_idx + offset; browser->top = (char **)browser->top + offset;
break; break;
case SEEK_END: case SEEK_END:
browser->top = browser->top + browser->nr_entries - 1 + offset; browser->top = (char **)browser->entries + browser->nr_entries - 1 + offset;
break; break;
default: default:
return; return;
} }
assert((char **)browser->top < (char **)browser->entries + browser->nr_entries);
assert((char **)browser->top >= (char **)browser->entries);
} }
unsigned int ui_browser__argv_refresh(struct ui_browser *browser) unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
...@@ -630,7 +632,9 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser) ...@@ -630,7 +632,9 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
browser->top = browser->entries; browser->top = browser->entries;
pos = (char **)browser->top; pos = (char **)browser->top;
while (idx < browser->nr_entries) { while (idx < browser->nr_entries &&
row < (unsigned)SLtt_Screen_Rows - 1) {
assert(pos < (char **)browser->entries + browser->nr_entries);
if (!browser->filter || !browser->filter(browser, *pos)) { if (!browser->filter || !browser->filter(browser, *pos)) {
ui_browser__gotorc(browser, row, 0); ui_browser__gotorc(browser, row, 0);
browser->write(browser, pos, row); browser->write(browser, pos, row);
......
...@@ -3,6 +3,7 @@ perf-y += hists.o ...@@ -3,6 +3,7 @@ perf-y += hists.o
perf-y += map.o perf-y += map.o
perf-y += scripts.o perf-y += scripts.o
perf-y += header.o perf-y += header.o
perf-y += res_sample.o
CFLAGS_annotate.o += -DENABLE_SLFUTURE_CONST CFLAGS_annotate.o += -DENABLE_SLFUTURE_CONST
CFLAGS_hists.o += -DENABLE_SLFUTURE_CONST CFLAGS_hists.o += -DENABLE_SLFUTURE_CONST
......
...@@ -750,7 +750,7 @@ static int annotate_browser__run(struct annotate_browser *browser, ...@@ -750,7 +750,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
continue; continue;
case 'r': case 'r':
{ {
script_browse(NULL); script_browse(NULL, NULL);
continue; continue;
} }
case 'k': case 'k':
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <string.h> #include <string.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <sys/ttydefaults.h> #include <sys/ttydefaults.h>
#include <linux/time64.h>
#include "../../util/callchain.h" #include "../../util/callchain.h"
#include "../../util/evsel.h" #include "../../util/evsel.h"
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
#include "srcline.h" #include "srcline.h"
#include "string2.h" #include "string2.h"
#include "units.h" #include "units.h"
#include "time-utils.h"
#include "sane_ctype.h" #include "sane_ctype.h"
...@@ -1224,6 +1226,8 @@ void hist_browser__init_hpp(void) ...@@ -1224,6 +1226,8 @@ void hist_browser__init_hpp(void)
hist_browser__hpp_color_overhead_guest_us; hist_browser__hpp_color_overhead_guest_us;
perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
hist_browser__hpp_color_overhead_acc; hist_browser__hpp_color_overhead_acc;
res_sample_init();
} }
static int hist_browser__show_entry(struct hist_browser *browser, static int hist_browser__show_entry(struct hist_browser *browser,
...@@ -2338,9 +2342,12 @@ static int switch_data_file(void) ...@@ -2338,9 +2342,12 @@ static int switch_data_file(void)
} }
struct popup_action { struct popup_action {
unsigned long time;
struct thread *thread; struct thread *thread;
struct map_symbol ms; struct map_symbol ms;
int socket; int socket;
struct perf_evsel *evsel;
enum rstype rstype;
int (*fn)(struct hist_browser *browser, struct popup_action *act); int (*fn)(struct hist_browser *browser, struct popup_action *act);
}; };
...@@ -2527,45 +2534,136 @@ static int ...@@ -2527,45 +2534,136 @@ static int
do_run_script(struct hist_browser *browser __maybe_unused, do_run_script(struct hist_browser *browser __maybe_unused,
struct popup_action *act) struct popup_action *act)
{ {
char script_opt[64]; char *script_opt;
memset(script_opt, 0, sizeof(script_opt)); int len;
int n = 0;
len = 100;
if (act->thread)
len += strlen(thread__comm_str(act->thread));
else if (act->ms.sym)
len += strlen(act->ms.sym->name);
script_opt = malloc(len);
if (!script_opt)
return -1;
script_opt[0] = 0;
if (act->thread) { if (act->thread) {
scnprintf(script_opt, sizeof(script_opt), " -c %s ", n = scnprintf(script_opt, len, " -c %s ",
thread__comm_str(act->thread)); thread__comm_str(act->thread));
} else if (act->ms.sym) { } else if (act->ms.sym) {
scnprintf(script_opt, sizeof(script_opt), " -S %s ", n = scnprintf(script_opt, len, " -S %s ",
act->ms.sym->name); act->ms.sym->name);
} }
script_browse(script_opt); if (act->time) {
char start[32], end[32];
unsigned long starttime = act->time;
unsigned long endtime = act->time + symbol_conf.time_quantum;
if (starttime == endtime) { /* Display 1ms as fallback */
starttime -= 1*NSEC_PER_MSEC;
endtime += 1*NSEC_PER_MSEC;
}
timestamp__scnprintf_usec(starttime, start, sizeof start);
timestamp__scnprintf_usec(endtime, end, sizeof end);
n += snprintf(script_opt + n, len - n, " --time %s,%s", start, end);
}
script_browse(script_opt, act->evsel);
free(script_opt);
return 0; return 0;
} }
static int static int
add_script_opt(struct hist_browser *browser __maybe_unused, do_res_sample_script(struct hist_browser *browser __maybe_unused,
struct popup_action *act)
{
struct hist_entry *he;
he = hist_browser__selected_entry(browser);
res_sample_browse(he->res_samples, he->num_res, act->evsel, act->rstype);
return 0;
}
static int
add_script_opt_2(struct hist_browser *browser __maybe_unused,
struct popup_action *act, char **optstr, struct popup_action *act, char **optstr,
struct thread *thread, struct symbol *sym) struct thread *thread, struct symbol *sym,
struct perf_evsel *evsel, const char *tstr)
{ {
if (thread) { if (thread) {
if (asprintf(optstr, "Run scripts for samples of thread [%s]", if (asprintf(optstr, "Run scripts for samples of thread [%s]%s",
thread__comm_str(thread)) < 0) thread__comm_str(thread), tstr) < 0)
return 0; return 0;
} else if (sym) { } else if (sym) {
if (asprintf(optstr, "Run scripts for samples of symbol [%s]", if (asprintf(optstr, "Run scripts for samples of symbol [%s]%s",
sym->name) < 0) sym->name, tstr) < 0)
return 0; return 0;
} else { } else {
if (asprintf(optstr, "Run scripts for all samples") < 0) if (asprintf(optstr, "Run scripts for all samples%s", tstr) < 0)
return 0; return 0;
} }
act->thread = thread; act->thread = thread;
act->ms.sym = sym; act->ms.sym = sym;
act->evsel = evsel;
act->fn = do_run_script; act->fn = do_run_script;
return 1; return 1;
} }
static int
add_script_opt(struct hist_browser *browser,
struct popup_action *act, char **optstr,
struct thread *thread, struct symbol *sym,
struct perf_evsel *evsel)
{
int n, j;
struct hist_entry *he;
n = add_script_opt_2(browser, act, optstr, thread, sym, evsel, "");
he = hist_browser__selected_entry(browser);
if (sort_order && strstr(sort_order, "time")) {
char tstr[128];
optstr++;
act++;
j = sprintf(tstr, " in ");
j += timestamp__scnprintf_usec(he->time, tstr + j,
sizeof tstr - j);
j += sprintf(tstr + j, "-");
timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum,
tstr + j, sizeof tstr - j);
n += add_script_opt_2(browser, act, optstr, thread, sym,
evsel, tstr);
act->time = he->time;
}
return n;
}
static int
add_res_sample_opt(struct hist_browser *browser __maybe_unused,
struct popup_action *act, char **optstr,
struct res_sample *res_sample,
struct perf_evsel *evsel,
enum rstype type)
{
if (!res_sample)
return 0;
if (asprintf(optstr, "Show context for individual samples %s",
type == A_ASM ? "with assembler" :
type == A_SOURCE ? "with source" : "") < 0)
return 0;
act->fn = do_res_sample_script;
act->evsel = evsel;
act->rstype = type;
return 1;
}
static int static int
do_switch_data(struct hist_browser *browser __maybe_unused, do_switch_data(struct hist_browser *browser __maybe_unused,
struct popup_action *act __maybe_unused) struct popup_action *act __maybe_unused)
...@@ -3031,7 +3129,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -3031,7 +3129,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
nr_options += add_script_opt(browser, nr_options += add_script_opt(browser,
&actions[nr_options], &actions[nr_options],
&options[nr_options], &options[nr_options],
thread, NULL); thread, NULL, evsel);
} }
/* /*
* Note that browser->selection != NULL * Note that browser->selection != NULL
...@@ -3046,11 +3144,24 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -3046,11 +3144,24 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
nr_options += add_script_opt(browser, nr_options += add_script_opt(browser,
&actions[nr_options], &actions[nr_options],
&options[nr_options], &options[nr_options],
NULL, browser->selection->sym); NULL, browser->selection->sym,
evsel);
} }
} }
nr_options += add_script_opt(browser, &actions[nr_options], nr_options += add_script_opt(browser, &actions[nr_options],
&options[nr_options], NULL, NULL); &options[nr_options], NULL, NULL, evsel);
nr_options += add_res_sample_opt(browser, &actions[nr_options],
&options[nr_options],
hist_browser__selected_entry(browser)->res_samples,
evsel, A_NORMAL);
nr_options += add_res_sample_opt(browser, &actions[nr_options],
&options[nr_options],
hist_browser__selected_entry(browser)->res_samples,
evsel, A_ASM);
nr_options += add_res_sample_opt(browser, &actions[nr_options],
&options[nr_options],
hist_browser__selected_entry(browser)->res_samples,
evsel, A_SOURCE);
nr_options += add_switch_opt(browser, &actions[nr_options], nr_options += add_switch_opt(browser, &actions[nr_options],
&options[nr_options]); &options[nr_options]);
skip_scripting: skip_scripting:
......
// SPDX-License-Identifier: GPL-2.0
/* Display a menu with individual samples to browse with perf script */
#include "util.h"
#include "hist.h"
#include "evsel.h"
#include "hists.h"
#include "sort.h"
#include "config.h"
#include "time-utils.h"
#include <linux/time64.h>
static u64 context_len = 10 * NSEC_PER_MSEC;
static int res_sample_config(const char *var, const char *value, void *data __maybe_unused)
{
if (!strcmp(var, "samples.context"))
return perf_config_u64(&context_len, var, value);
return 0;
}
void res_sample_init(void)
{
perf_config(res_sample_config, NULL);
}
int res_sample_browse(struct res_sample *res_samples, int num_res,
struct perf_evsel *evsel, enum rstype rstype)
{
char **names;
int i, n;
int choice;
char *cmd;
char pbuf[256], tidbuf[32], cpubuf[32];
const char *perf = perf_exe(pbuf, sizeof pbuf);
char trange[128], tsample[64];
struct res_sample *r;
char extra_format[256];
names = calloc(num_res, sizeof(char *));
if (!names)
return -1;
for (i = 0; i < num_res; i++) {
char tbuf[64];
timestamp__scnprintf_nsec(res_samples[i].time, tbuf, sizeof tbuf);
if (asprintf(&names[i], "%s: CPU %d tid %d", tbuf,
res_samples[i].cpu, res_samples[i].tid) < 0) {
while (--i >= 0)
free(names[i]);
free(names);
return -1;
}
}
choice = ui__popup_menu(num_res, names);
for (i = 0; i < num_res; i++)
free(names[i]);
free(names);
if (choice < 0 || choice >= num_res)
return -1;
r = &res_samples[choice];
n = timestamp__scnprintf_nsec(r->time - context_len, trange, sizeof trange);
trange[n++] = ',';
timestamp__scnprintf_nsec(r->time + context_len, trange + n, sizeof trange - n);
timestamp__scnprintf_nsec(r->time, tsample, sizeof tsample);
attr_to_script(extra_format, &evsel->attr);
if (asprintf(&cmd, "%s script %s%s --time %s %s%s %s%s --ns %s %s %s %s %s | less +/%s",
perf,
input_name ? "-i " : "",
input_name ? input_name : "",
trange,
r->cpu >= 0 ? "--cpu " : "",
r->cpu >= 0 ? (sprintf(cpubuf, "%d", r->cpu), cpubuf) : "",
r->tid ? "--tid " : "",
r->tid ? (sprintf(tidbuf, "%d", r->tid), tidbuf) : "",
extra_format,
rstype == A_ASM ? "-F +insn --xed" :
rstype == A_SOURCE ? "-F +srcline,+srccode" : "",
symbol_conf.inline_name ? "--inline" : "",
"--show-lost-events ",
r->tid ? "--show-switch-events --show-task-events " : "",
tsample) < 0)
return -1;
run_script(cmd);
free(cmd);
return 0;
}
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <elf.h>
#include <inttypes.h>
#include <sys/ttydefaults.h>
#include <string.h>
#include "../../util/sort.h" #include "../../util/sort.h"
#include "../../util/util.h" #include "../../util/util.h"
#include "../../util/hist.h" #include "../../util/hist.h"
#include "../../util/debug.h" #include "../../util/debug.h"
#include "../../util/symbol.h" #include "../../util/symbol.h"
#include "../browser.h" #include "../browser.h"
#include "../helpline.h"
#include "../libslang.h" #include "../libslang.h"
#include "config.h"
/* 2048 lines should be enough for a script output */
#define MAX_LINES 2048
/* 160 bytes for one output line */
#define AVERAGE_LINE_LEN 160
struct script_line {
struct list_head node;
char line[AVERAGE_LINE_LEN];
};
struct perf_script_browser {
struct ui_browser b;
struct list_head entries;
const char *script_name;
int nr_lines;
};
#define SCRIPT_NAMELEN 128 #define SCRIPT_NAMELEN 128
#define SCRIPT_MAX_NO 64 #define SCRIPT_MAX_NO 64
...@@ -40,149 +18,169 @@ struct perf_script_browser { ...@@ -40,149 +18,169 @@ struct perf_script_browser {
*/ */
#define SCRIPT_FULLPATH_LEN 256 #define SCRIPT_FULLPATH_LEN 256
struct script_config {
const char **names;
char **paths;
int index;
const char *perf;
char extra_format[256];
};
void attr_to_script(char *extra_format, struct perf_event_attr *attr)
{
extra_format[0] = 0;
if (attr->read_format & PERF_FORMAT_GROUP)
strcat(extra_format, " -F +metric");
if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK)
strcat(extra_format, " -F +brstackinsn --xed");
if (attr->sample_type & PERF_SAMPLE_REGS_INTR)
strcat(extra_format, " -F +iregs");
if (attr->sample_type & PERF_SAMPLE_REGS_USER)
strcat(extra_format, " -F +uregs");
if (attr->sample_type & PERF_SAMPLE_PHYS_ADDR)
strcat(extra_format, " -F +phys_addr");
}
static int add_script_option(const char *name, const char *opt,
struct script_config *c)
{
c->names[c->index] = name;
if (asprintf(&c->paths[c->index],
"%s script %s -F +metric %s %s",
c->perf, opt, symbol_conf.inline_name ? " --inline" : "",
c->extra_format) < 0)
return -1;
c->index++;
return 0;
}
static int scripts_config(const char *var, const char *value, void *data)
{
struct script_config *c = data;
if (!strstarts(var, "scripts."))
return -1;
if (c->index >= SCRIPT_MAX_NO)
return -1;
c->names[c->index] = strdup(var + 7);
if (!c->names[c->index])
return -1;
if (asprintf(&c->paths[c->index], "%s %s", value,
c->extra_format) < 0)
return -1;
c->index++;
return 0;
}
/* /*
* When success, will copy the full path of the selected script * When success, will copy the full path of the selected script
* into the buffer pointed by script_name, and return 0. * into the buffer pointed by script_name, and return 0.
* Return -1 on failure. * Return -1 on failure.
*/ */
static int list_scripts(char *script_name) static int list_scripts(char *script_name, bool *custom,
struct perf_evsel *evsel)
{ {
char *buf, *names[SCRIPT_MAX_NO], *paths[SCRIPT_MAX_NO]; char *buf, *paths[SCRIPT_MAX_NO], *names[SCRIPT_MAX_NO];
int i, num, choice, ret = -1; int i, num, choice;
int ret = 0;
int max_std, custom_perf;
char pbuf[256];
const char *perf = perf_exe(pbuf, sizeof pbuf);
struct script_config scriptc = {
.names = (const char **)names,
.paths = paths,
.perf = perf
};
script_name[0] = 0;
/* Preset the script name to SCRIPT_NAMELEN */ /* Preset the script name to SCRIPT_NAMELEN */
buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN)); buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
if (!buf) if (!buf)
return ret; return -1;
for (i = 0; i < SCRIPT_MAX_NO; i++) { if (evsel)
names[i] = buf + i * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN); attr_to_script(scriptc.extra_format, &evsel->attr);
add_script_option("Show individual samples", "", &scriptc);
add_script_option("Show individual samples with assembler", "-F +insn --xed",
&scriptc);
add_script_option("Show individual samples with source", "-F +srcline,+srccode",
&scriptc);
perf_config(scripts_config, &scriptc);
custom_perf = scriptc.index;
add_script_option("Show samples with custom perf script arguments", "", &scriptc);
i = scriptc.index;
max_std = i;
for (; i < SCRIPT_MAX_NO; i++) {
names[i] = buf + (i - max_std) * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
paths[i] = names[i] + SCRIPT_NAMELEN; paths[i] = names[i] + SCRIPT_NAMELEN;
} }
num = find_scripts(names, paths); num = find_scripts(names + max_std, paths + max_std, SCRIPT_MAX_NO - max_std,
if (num > 0) { SCRIPT_FULLPATH_LEN);
choice = ui__popup_menu(num, names); if (num < 0)
if (choice < num && choice >= 0) { num = 0;
strcpy(script_name, paths[choice]); choice = ui__popup_menu(num + max_std, (char * const *)names);
ret = 0; if (choice < 0) {
} ret = -1;
goto out;
} }
if (choice == custom_perf) {
char script_args[50];
int key = ui_browser__input_window("perf script command",
"Enter perf script command line (without perf script prefix)",
script_args, "", 0);
if (key != K_ENTER)
return -1;
sprintf(script_name, "%s script %s", perf, script_args);
} else if (choice < num + max_std) {
strcpy(script_name, paths[choice]);
}
*custom = choice >= max_std;
out:
free(buf); free(buf);
for (i = 0; i < max_std; i++)
free(paths[i]);
return ret; return ret;
} }
static void script_browser__write(struct ui_browser *browser, void run_script(char *cmd)
void *entry, int row)
{ {
struct script_line *sline = list_entry(entry, struct script_line, node); pr_debug("Running %s\n", cmd);
bool current_entry = ui_browser__is_current_entry(browser, row); SLang_reset_tty();
if (system(cmd) < 0)
ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : pr_warning("Cannot run %s\n", cmd);
HE_COLORSET_NORMAL); /*
* SLang doesn't seem to reset the whole terminal, so be more
ui_browser__write_nstring(browser, sline->line, browser->width); * forceful to get back to the original state.
*/
printf("\033[c\033[H\033[J");
fflush(stdout);
SLang_init_tty(0, 0, 0);
SLsmg_refresh();
} }
static int script_browser__run(struct perf_script_browser *browser) int script_browse(const char *script_opt, struct perf_evsel *evsel)
{ {
int key; char *cmd, script_name[SCRIPT_FULLPATH_LEN];
bool custom = false;
if (ui_browser__show(&browser->b, browser->script_name, memset(script_name, 0, SCRIPT_FULLPATH_LEN);
"Press ESC to exit") < 0) if (list_scripts(script_name, &custom, evsel))
return -1; return -1;
while (1) { if (asprintf(&cmd, "%s%s %s %s%s 2>&1 | less",
key = ui_browser__run(&browser->b, 0); custom ? "perf script -s " : "",
script_name,
/* We can add some special key handling here if needed */ script_opt ? script_opt : "",
break; input_name ? "-i " : "",
} input_name ? input_name : "") < 0)
ui_browser__hide(&browser->b);
return key;
}
int script_browse(const char *script_opt)
{
char cmd[SCRIPT_FULLPATH_LEN*2], script_name[SCRIPT_FULLPATH_LEN];
char *line = NULL;
size_t len = 0;
ssize_t retlen;
int ret = -1, nr_entries = 0;
FILE *fp;
void *buf;
struct script_line *sline;
struct perf_script_browser script = {
.b = {
.refresh = ui_browser__list_head_refresh,
.seek = ui_browser__list_head_seek,
.write = script_browser__write,
},
.script_name = script_name,
};
INIT_LIST_HEAD(&script.entries);
/* Save each line of the output in one struct script_line object. */
buf = zalloc((sizeof(*sline)) * MAX_LINES);
if (!buf)
return -1; return -1;
sline = buf;
memset(script_name, 0, SCRIPT_FULLPATH_LEN);
if (list_scripts(script_name))
goto exit;
sprintf(cmd, "perf script -s %s ", script_name);
if (script_opt) run_script(cmd);
strcat(cmd, script_opt); free(cmd);
if (input_name) { return 0;
strcat(cmd, " -i ");
strcat(cmd, input_name);
}
strcat(cmd, " 2>&1");
fp = popen(cmd, "r");
if (!fp)
goto exit;
while ((retlen = getline(&line, &len, fp)) != -1) {
strncpy(sline->line, line, AVERAGE_LINE_LEN);
/* If one output line is very large, just cut it short */
if (retlen >= AVERAGE_LINE_LEN) {
sline->line[AVERAGE_LINE_LEN - 1] = '\0';
sline->line[AVERAGE_LINE_LEN - 2] = '\n';
}
list_add_tail(&sline->node, &script.entries);
if (script.b.width < retlen)
script.b.width = retlen;
if (nr_entries++ >= MAX_LINES - 1)
break;
sline++;
}
if (script.b.width > AVERAGE_LINE_LEN)
script.b.width = AVERAGE_LINE_LEN;
free(line);
pclose(fp);
script.nr_lines = nr_entries;
script.b.nr_entries = nr_entries;
script.b.entries = &script.entries;
ret = script_browser__run(&script);
exit:
free(buf);
return ret;
} }
This diff is collapsed.
...@@ -369,6 +369,7 @@ enum symbol_disassemble_errno { ...@@ -369,6 +369,7 @@ enum symbol_disassemble_errno {
__SYMBOL_ANNOTATE_ERRNO__START = -10000, __SYMBOL_ANNOTATE_ERRNO__START = -10000,
SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX = __SYMBOL_ANNOTATE_ERRNO__START, SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX = __SYMBOL_ANNOTATE_ERRNO__START,
SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF,
__SYMBOL_ANNOTATE_ERRNO__END, __SYMBOL_ANNOTATE_ERRNO__END,
}; };
......
#ifndef INSN_H
#define INSN_H 1
struct perf_sample;
struct machine;
struct thread;
void arch_fetch_insn(struct perf_sample *sample,
struct thread *thread,
struct machine *machine);
#endif
This diff is collapsed.
...@@ -3,22 +3,45 @@ ...@@ -3,22 +3,45 @@
#define __PERF_BPF_EVENT_H #define __PERF_BPF_EVENT_H
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/rbtree.h>
#include <pthread.h>
#include <api/fd/array.h>
#include "event.h" #include "event.h"
#include <stdio.h>
struct machine; struct machine;
union perf_event; union perf_event;
struct perf_env;
struct perf_sample; struct perf_sample;
struct perf_tool;
struct record_opts; struct record_opts;
struct evlist;
struct target;
struct bpf_prog_info_node {
struct bpf_prog_info_linear *info_linear;
struct rb_node rb_node;
};
struct btf_node {
struct rb_node rb_node;
u32 id;
u32 data_size;
char data[];
};
#ifdef HAVE_LIBBPF_SUPPORT #ifdef HAVE_LIBBPF_SUPPORT
int machine__process_bpf_event(struct machine *machine, union perf_event *event, int machine__process_bpf_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample); struct perf_sample *sample);
int perf_event__synthesize_bpf_events(struct perf_tool *tool, int perf_event__synthesize_bpf_events(struct perf_session *session,
perf_event__handler_t process, perf_event__handler_t process,
struct machine *machine, struct machine *machine,
struct record_opts *opts); struct record_opts *opts);
int bpf_event__add_sb_event(struct perf_evlist **evlist,
struct perf_env *env);
void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
struct perf_env *env,
FILE *fp);
#else #else
static inline int machine__process_bpf_event(struct machine *machine __maybe_unused, static inline int machine__process_bpf_event(struct machine *machine __maybe_unused,
union perf_event *event __maybe_unused, union perf_event *event __maybe_unused,
...@@ -27,12 +50,25 @@ static inline int machine__process_bpf_event(struct machine *machine __maybe_unu ...@@ -27,12 +50,25 @@ static inline int machine__process_bpf_event(struct machine *machine __maybe_unu
return 0; return 0;
} }
static inline int perf_event__synthesize_bpf_events(struct perf_tool *tool __maybe_unused, static inline int perf_event__synthesize_bpf_events(struct perf_session *session __maybe_unused,
perf_event__handler_t process __maybe_unused, perf_event__handler_t process __maybe_unused,
struct machine *machine __maybe_unused, struct machine *machine __maybe_unused,
struct record_opts *opts __maybe_unused) struct record_opts *opts __maybe_unused)
{ {
return 0; return 0;
} }
static inline int bpf_event__add_sb_event(struct perf_evlist **evlist __maybe_unused,
struct perf_env *env __maybe_unused)
{
return 0;
}
static inline void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info __maybe_unused,
struct perf_env *env __maybe_unused,
FILE *fp __maybe_unused)
{
}
#endif // HAVE_LIBBPF_SUPPORT #endif // HAVE_LIBBPF_SUPPORT
#endif #endif
...@@ -185,6 +185,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size) ...@@ -185,6 +185,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
return bf; return bf;
} }
/* The caller is responsible to free the returned buffer. */
char *build_id_cache__origname(const char *sbuild_id) char *build_id_cache__origname(const char *sbuild_id)
{ {
char *linkname; char *linkname;
......
...@@ -633,11 +633,10 @@ static int collect_config(const char *var, const char *value, ...@@ -633,11 +633,10 @@ static int collect_config(const char *var, const char *value,
} }
ret = set_value(item, value); ret = set_value(item, value);
return ret;
out_free: out_free:
free(key); free(key);
return -1; return ret;
} }
int perf_config_set__collect(struct perf_config_set *set, const char *file_name, int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
......
This diff is collapsed.
...@@ -19,10 +19,12 @@ struct perf_data { ...@@ -19,10 +19,12 @@ struct perf_data {
const char *path; const char *path;
struct perf_data_file file; struct perf_data_file file;
bool is_pipe; bool is_pipe;
bool is_dir;
bool force; bool force;
enum perf_data_mode mode; enum perf_data_mode mode;
struct { struct {
u64 version;
struct perf_data_file *files; struct perf_data_file *files;
int nr; int nr;
} dir; } dir;
...@@ -43,14 +45,14 @@ static inline int perf_data__is_pipe(struct perf_data *data) ...@@ -43,14 +45,14 @@ static inline int perf_data__is_pipe(struct perf_data *data)
return data->is_pipe; return data->is_pipe;
} }
static inline int perf_data__fd(struct perf_data *data) static inline bool perf_data__is_dir(struct perf_data *data)
{ {
return data->file.fd; return data->is_dir;
} }
static inline unsigned long perf_data__size(struct perf_data *data) static inline int perf_data__fd(struct perf_data *data)
{ {
return data->file.size; return data->file.fd;
} }
int perf_data__open(struct perf_data *data); int perf_data__open(struct perf_data *data);
...@@ -68,9 +70,11 @@ ssize_t perf_data_file__write(struct perf_data_file *file, ...@@ -68,9 +70,11 @@ ssize_t perf_data_file__write(struct perf_data_file *file,
*/ */
int perf_data__switch(struct perf_data *data, int perf_data__switch(struct perf_data *data,
const char *postfix, const char *postfix,
size_t pos, bool at_exit); size_t pos, bool at_exit, char **new_filepath);
int perf_data__create_dir(struct perf_data *data, int nr); int perf_data__create_dir(struct perf_data *data, int nr);
int perf_data__open_dir(struct perf_data *data); int perf_data__open_dir(struct perf_data *data);
void perf_data__close_dir(struct perf_data *data); void perf_data__close_dir(struct perf_data *data);
int perf_data__update_dir(struct perf_data *data);
unsigned long perf_data__size(struct perf_data *data);
#endif /* __PERF_DATA_H */ #endif /* __PERF_DATA_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -270,6 +270,8 @@ static int __ordered_events__flush(struct ordered_events *oe, enum oe_flush how, ...@@ -270,6 +270,8 @@ static int __ordered_events__flush(struct ordered_events *oe, enum oe_flush how,
"FINAL", "FINAL",
"ROUND", "ROUND",
"HALF ", "HALF ",
"TOP ",
"TIME ",
}; };
int err; int err;
bool show_progress = false; bool show_progress = false;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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