mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 01:04:08 +08:00
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Thomas Gleixner: "Kernel: - Improve kallsyms coverage - Add x86 entry trampolines to kcore - Fix ARM SPE handling - Correct PPC event post processing Tools: - Make the build system more robust - Small fixes and enhancements all over the place - Update kernel ABI header copies - Preparatory work for converting libtraceevnt to a shared library - License cleanups" * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (100 commits) tools arch: Update arch/x86/lib/memcpy_64.S copy used in 'perf bench mem memcpy' tools arch x86: Update tools's copy of cpufeatures.h perf python: Fix pyrf_evlist__read_on_cpu() interface perf mmap: Store real cpu number in 'struct perf_mmap' perf tools: Remove ext from struct kmod_path perf tools: Add gzip_is_compressed function perf tools: Add lzma_is_compressed function perf tools: Add is_compressed callback to compressions array perf tools: Move the temp file processing into decompress_kmodule perf tools: Use compression id in decompress_kmodule() perf tools: Store compression id into struct dso perf tools: Add compression id into 'struct kmod_path' perf tools: Make is_supported_compression() static perf tools: Make decompress_to_file() function static perf tools: Get rid of dso__needs_decompress() call in __open_dso() perf tools: Get rid of dso__needs_decompress() call in symbol__disassemble() perf tools: Get rid of dso__needs_decompress() call in read_object_code() tools lib traceevent: Change to SPDX License format perf llvm: Allow passing options to llc in addition to clang perf parser: Improve error message for PMU address filters ...
This commit is contained in:
commit
d207ea8e74
@ -2,6 +2,8 @@
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/kcore.h>
|
||||
|
||||
#include <asm/cpu_entry_area.h>
|
||||
#include <asm/pgtable.h>
|
||||
@ -13,6 +15,7 @@ static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage)
|
||||
#ifdef CONFIG_X86_64
|
||||
static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
|
||||
[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]);
|
||||
static DEFINE_PER_CPU(struct kcore_list, kcore_entry_trampoline);
|
||||
#endif
|
||||
|
||||
struct cpu_entry_area *get_cpu_entry_area(int cpu)
|
||||
@ -146,10 +149,40 @@ static void __init setup_cpu_entry_area(int cpu)
|
||||
|
||||
cea_set_pte(&get_cpu_entry_area(cpu)->entry_trampoline,
|
||||
__pa_symbol(_entry_trampoline), PAGE_KERNEL_RX);
|
||||
/*
|
||||
* The cpu_entry_area alias addresses are not in the kernel binary
|
||||
* so they do not show up in /proc/kcore normally. This adds entries
|
||||
* for them manually.
|
||||
*/
|
||||
kclist_add_remap(&per_cpu(kcore_entry_trampoline, cpu),
|
||||
_entry_trampoline,
|
||||
&get_cpu_entry_area(cpu)->entry_trampoline, PAGE_SIZE);
|
||||
#endif
|
||||
percpu_setup_debug_store(cpu);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
int arch_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
|
||||
char *name)
|
||||
{
|
||||
unsigned int cpu, ncpu = 0;
|
||||
|
||||
if (symnum >= num_possible_cpus())
|
||||
return -EINVAL;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (ncpu++ >= symnum)
|
||||
break;
|
||||
}
|
||||
|
||||
*value = (unsigned long)&get_cpu_entry_area(cpu)->entry_trampoline;
|
||||
*type = 't';
|
||||
strlcpy(name, "__entry_SYSCALL_64_trampoline", KSYM_NAME_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static __init void setup_cpu_entry_area_ptes(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_32
|
||||
|
@ -359,8 +359,11 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
|
||||
phdr->p_type = PT_LOAD;
|
||||
phdr->p_flags = PF_R | PF_W | PF_X;
|
||||
phdr->p_offset = kc_vaddr_to_offset(m->addr) + data_offset;
|
||||
phdr->p_vaddr = (size_t)m->addr;
|
||||
if (m->type == KCORE_RAM)
|
||||
if (m->type == KCORE_REMAP)
|
||||
phdr->p_vaddr = (size_t)m->vaddr;
|
||||
else
|
||||
phdr->p_vaddr = (size_t)m->addr;
|
||||
if (m->type == KCORE_RAM || m->type == KCORE_REMAP)
|
||||
phdr->p_paddr = __pa(m->addr);
|
||||
else if (m->type == KCORE_TEXT)
|
||||
phdr->p_paddr = __pa_symbol(m->addr);
|
||||
|
@ -12,11 +12,13 @@ enum kcore_type {
|
||||
KCORE_VMEMMAP,
|
||||
KCORE_USER,
|
||||
KCORE_OTHER,
|
||||
KCORE_REMAP,
|
||||
};
|
||||
|
||||
struct kcore_list {
|
||||
struct list_head list;
|
||||
unsigned long addr;
|
||||
unsigned long vaddr;
|
||||
size_t size;
|
||||
int type;
|
||||
};
|
||||
@ -36,11 +38,22 @@ struct vmcoredd_node {
|
||||
|
||||
#ifdef CONFIG_PROC_KCORE
|
||||
void __init kclist_add(struct kcore_list *, void *, size_t, int type);
|
||||
static inline
|
||||
void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz)
|
||||
{
|
||||
m->vaddr = (unsigned long)vaddr;
|
||||
kclist_add(m, addr, sz, KCORE_REMAP);
|
||||
}
|
||||
#else
|
||||
static inline
|
||||
void kclist_add(struct kcore_list *new, void *addr, size_t size, int type)
|
||||
{
|
||||
}
|
||||
|
||||
static inline
|
||||
void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_KCORE_H */
|
||||
|
@ -432,6 +432,7 @@ int sprint_backtrace(char *buffer, unsigned long address)
|
||||
/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
|
||||
struct kallsym_iter {
|
||||
loff_t pos;
|
||||
loff_t pos_arch_end;
|
||||
loff_t pos_mod_end;
|
||||
loff_t pos_ftrace_mod_end;
|
||||
unsigned long value;
|
||||
@ -443,9 +444,29 @@ struct kallsym_iter {
|
||||
int show_value;
|
||||
};
|
||||
|
||||
int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value,
|
||||
char *type, char *name)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int get_ksymbol_arch(struct kallsym_iter *iter)
|
||||
{
|
||||
int ret = arch_get_kallsym(iter->pos - kallsyms_num_syms,
|
||||
&iter->value, &iter->type,
|
||||
iter->name);
|
||||
|
||||
if (ret < 0) {
|
||||
iter->pos_arch_end = iter->pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_ksymbol_mod(struct kallsym_iter *iter)
|
||||
{
|
||||
int ret = module_get_kallsym(iter->pos - kallsyms_num_syms,
|
||||
int ret = module_get_kallsym(iter->pos - iter->pos_arch_end,
|
||||
&iter->value, &iter->type,
|
||||
iter->name, iter->module_name,
|
||||
&iter->exported);
|
||||
@ -501,32 +522,34 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
|
||||
iter->nameoff = get_symbol_offset(new_pos);
|
||||
iter->pos = new_pos;
|
||||
if (new_pos == 0) {
|
||||
iter->pos_arch_end = 0;
|
||||
iter->pos_mod_end = 0;
|
||||
iter->pos_ftrace_mod_end = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The end position (last + 1) of each additional kallsyms section is recorded
|
||||
* in iter->pos_..._end as each section is added, and so can be used to
|
||||
* determine which get_ksymbol_...() function to call next.
|
||||
*/
|
||||
static int update_iter_mod(struct kallsym_iter *iter, loff_t pos)
|
||||
{
|
||||
iter->pos = pos;
|
||||
|
||||
if (iter->pos_ftrace_mod_end > 0 &&
|
||||
iter->pos_ftrace_mod_end < iter->pos)
|
||||
return get_ksymbol_bpf(iter);
|
||||
|
||||
if (iter->pos_mod_end > 0 &&
|
||||
iter->pos_mod_end < iter->pos) {
|
||||
if (!get_ksymbol_ftrace_mod(iter))
|
||||
return get_ksymbol_bpf(iter);
|
||||
if ((!iter->pos_arch_end || iter->pos_arch_end > pos) &&
|
||||
get_ksymbol_arch(iter))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!get_ksymbol_mod(iter)) {
|
||||
if (!get_ksymbol_ftrace_mod(iter))
|
||||
return get_ksymbol_bpf(iter);
|
||||
}
|
||||
if ((!iter->pos_mod_end || iter->pos_mod_end > pos) &&
|
||||
get_ksymbol_mod(iter))
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
if ((!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > pos) &&
|
||||
get_ksymbol_ftrace_mod(iter))
|
||||
return 1;
|
||||
|
||||
return get_ksymbol_bpf(iter);
|
||||
}
|
||||
|
||||
/* Returns false if pos at or past end of file. */
|
||||
|
@ -220,6 +220,7 @@
|
||||
#define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */
|
||||
#define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */
|
||||
#define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */
|
||||
#define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */
|
||||
|
||||
/* Virtualization flags: Linux defined, word 8 */
|
||||
#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */
|
||||
@ -230,7 +231,7 @@
|
||||
|
||||
#define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */
|
||||
#define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */
|
||||
|
||||
#define X86_FEATURE_EPT_AD ( 8*32+17) /* Intel Extended Page Table access-dirty bit */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */
|
||||
#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
|
||||
|
@ -256,7 +256,7 @@ ENTRY(__memcpy_mcsafe)
|
||||
|
||||
/* Copy successful. Return zero */
|
||||
.L_done_memcpy_trap:
|
||||
xorq %rax, %rax
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
ENDPROC(__memcpy_mcsafe)
|
||||
EXPORT_SYMBOL_GPL(__memcpy_mcsafe)
|
||||
|
@ -129,12 +129,12 @@ $(OUTPUT)liblockdep.a: $(LIB_IN)
|
||||
tags: force
|
||||
$(RM) tags
|
||||
find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
|
||||
--regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
|
||||
--regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/'
|
||||
|
||||
TAGS: force
|
||||
$(RM) TAGS
|
||||
find . -name '*.[ch]' | xargs etags \
|
||||
--regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
|
||||
--regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/'
|
||||
|
||||
define do_install
|
||||
$(print_install) \
|
||||
|
@ -233,12 +233,12 @@ endef
|
||||
tags: force
|
||||
$(RM) tags
|
||||
find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
|
||||
--regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
|
||||
--regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/'
|
||||
|
||||
TAGS: force
|
||||
$(RM) TAGS
|
||||
find . -name '*.[ch]' | xargs etags \
|
||||
--regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
|
||||
--regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/'
|
||||
|
||||
define do_install_mkdir
|
||||
if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -41,7 +41,7 @@
|
||||
#define DEBUG_RECORD 0
|
||||
#endif
|
||||
|
||||
struct pevent_record {
|
||||
struct tep_record {
|
||||
unsigned long long ts;
|
||||
unsigned long long offset;
|
||||
long long missed_events; /* buffer dropped events before */
|
||||
@ -53,8 +53,8 @@ struct pevent_record {
|
||||
int locked; /* Do not free, even if ref_count is zero */
|
||||
void *priv;
|
||||
#if DEBUG_RECORD
|
||||
struct pevent_record *prev;
|
||||
struct pevent_record *next;
|
||||
struct tep_record *prev;
|
||||
struct tep_record *next;
|
||||
long alloc_addr;
|
||||
#endif
|
||||
};
|
||||
@ -98,19 +98,19 @@ extern int trace_seq_do_printf(struct trace_seq *s);
|
||||
|
||||
/* ----------------------- pevent ----------------------- */
|
||||
|
||||
struct pevent;
|
||||
struct tep_handle;
|
||||
struct event_format;
|
||||
|
||||
typedef int (*pevent_event_handler_func)(struct trace_seq *s,
|
||||
struct pevent_record *record,
|
||||
struct event_format *event,
|
||||
void *context);
|
||||
typedef int (*tep_event_handler_func)(struct trace_seq *s,
|
||||
struct tep_record *record,
|
||||
struct event_format *event,
|
||||
void *context);
|
||||
|
||||
typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
|
||||
typedef int (*pevent_plugin_unload_func)(struct pevent *pevent);
|
||||
typedef int (*tep_plugin_load_func)(struct tep_handle *pevent);
|
||||
typedef int (*tep_plugin_unload_func)(struct tep_handle *pevent);
|
||||
|
||||
struct pevent_plugin_option {
|
||||
struct pevent_plugin_option *next;
|
||||
struct tep_plugin_option {
|
||||
struct tep_plugin_option *next;
|
||||
void *handle;
|
||||
char *file;
|
||||
char *name;
|
||||
@ -124,20 +124,20 @@ struct pevent_plugin_option {
|
||||
/*
|
||||
* Plugin hooks that can be called:
|
||||
*
|
||||
* PEVENT_PLUGIN_LOADER: (required)
|
||||
* TEP_PLUGIN_LOADER: (required)
|
||||
* The function name to initialized the plugin.
|
||||
*
|
||||
* int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
* int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
*
|
||||
* PEVENT_PLUGIN_UNLOADER: (optional)
|
||||
* TEP_PLUGIN_UNLOADER: (optional)
|
||||
* The function called just before unloading
|
||||
*
|
||||
* int PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
* int TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
*
|
||||
* PEVENT_PLUGIN_OPTIONS: (optional)
|
||||
* TEP_PLUGIN_OPTIONS: (optional)
|
||||
* Plugin options that can be set before loading
|
||||
*
|
||||
* struct pevent_plugin_option PEVENT_PLUGIN_OPTIONS[] = {
|
||||
* struct tep_plugin_option TEP_PLUGIN_OPTIONS[] = {
|
||||
* {
|
||||
* .name = "option-name",
|
||||
* .plugin_alias = "override-file-name", (optional)
|
||||
@ -158,19 +158,19 @@ struct pevent_plugin_option {
|
||||
* .set will be processed. If .value is defined, then it is considered
|
||||
* a string option and .set will be ignored.
|
||||
*
|
||||
* PEVENT_PLUGIN_ALIAS: (optional)
|
||||
* TEP_PLUGIN_ALIAS: (optional)
|
||||
* The name to use for finding options (uses filename if not defined)
|
||||
*/
|
||||
#define PEVENT_PLUGIN_LOADER pevent_plugin_loader
|
||||
#define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader
|
||||
#define PEVENT_PLUGIN_OPTIONS pevent_plugin_options
|
||||
#define PEVENT_PLUGIN_ALIAS pevent_plugin_alias
|
||||
#define TEP_PLUGIN_LOADER tep_plugin_loader
|
||||
#define TEP_PLUGIN_UNLOADER tep_plugin_unloader
|
||||
#define TEP_PLUGIN_OPTIONS tep_plugin_options
|
||||
#define TEP_PLUGIN_ALIAS tep_plugin_alias
|
||||
#define _MAKE_STR(x) #x
|
||||
#define MAKE_STR(x) _MAKE_STR(x)
|
||||
#define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER)
|
||||
#define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER)
|
||||
#define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS)
|
||||
#define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS)
|
||||
#define TEP_PLUGIN_LOADER_NAME MAKE_STR(TEP_PLUGIN_LOADER)
|
||||
#define TEP_PLUGIN_UNLOADER_NAME MAKE_STR(TEP_PLUGIN_UNLOADER)
|
||||
#define TEP_PLUGIN_OPTIONS_NAME MAKE_STR(TEP_PLUGIN_OPTIONS)
|
||||
#define TEP_PLUGIN_ALIAS_NAME MAKE_STR(TEP_PLUGIN_ALIAS)
|
||||
|
||||
enum format_flags {
|
||||
FIELD_IS_ARRAY = 1,
|
||||
@ -269,10 +269,10 @@ struct print_arg_op {
|
||||
struct print_arg *right;
|
||||
};
|
||||
|
||||
struct pevent_function_handler;
|
||||
struct tep_function_handler;
|
||||
|
||||
struct print_arg_func {
|
||||
struct pevent_function_handler *func;
|
||||
struct tep_function_handler *func;
|
||||
struct print_arg *args;
|
||||
};
|
||||
|
||||
@ -320,14 +320,14 @@ struct print_fmt {
|
||||
};
|
||||
|
||||
struct event_format {
|
||||
struct pevent *pevent;
|
||||
struct tep_handle *pevent;
|
||||
char *name;
|
||||
int id;
|
||||
int flags;
|
||||
struct format format;
|
||||
struct print_fmt print_fmt;
|
||||
char *system;
|
||||
pevent_event_handler_func handler;
|
||||
tep_event_handler_func handler;
|
||||
void *context;
|
||||
};
|
||||
|
||||
@ -361,25 +361,25 @@ enum event_type {
|
||||
EVENT_SQUOTE,
|
||||
};
|
||||
|
||||
typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s,
|
||||
unsigned long long *args);
|
||||
typedef unsigned long long (*tep_func_handler)(struct trace_seq *s,
|
||||
unsigned long long *args);
|
||||
|
||||
enum pevent_func_arg_type {
|
||||
PEVENT_FUNC_ARG_VOID,
|
||||
PEVENT_FUNC_ARG_INT,
|
||||
PEVENT_FUNC_ARG_LONG,
|
||||
PEVENT_FUNC_ARG_STRING,
|
||||
PEVENT_FUNC_ARG_PTR,
|
||||
PEVENT_FUNC_ARG_MAX_TYPES
|
||||
enum tep_func_arg_type {
|
||||
TEP_FUNC_ARG_VOID,
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_LONG,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
TEP_FUNC_ARG_PTR,
|
||||
TEP_FUNC_ARG_MAX_TYPES
|
||||
};
|
||||
|
||||
enum pevent_flag {
|
||||
PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */
|
||||
PEVENT_DISABLE_SYS_PLUGINS = 1 << 1,
|
||||
PEVENT_DISABLE_PLUGINS = 1 << 2,
|
||||
enum tep_flag {
|
||||
TEP_NSEC_OUTPUT = 1, /* output in NSECS */
|
||||
TEP_DISABLE_SYS_PLUGINS = 1 << 1,
|
||||
TEP_DISABLE_PLUGINS = 1 << 2,
|
||||
};
|
||||
|
||||
#define PEVENT_ERRORS \
|
||||
#define TEP_ERRORS \
|
||||
_PE(MEM_ALLOC_FAILED, "failed to allocate memory"), \
|
||||
_PE(PARSE_EVENT_FAILED, "failed to parse event"), \
|
||||
_PE(READ_ID_FAILED, "failed to read event id"), \
|
||||
@ -411,10 +411,10 @@ enum pevent_flag {
|
||||
_PE(FILTER_MISS, "record does not match to filter")
|
||||
|
||||
#undef _PE
|
||||
#define _PE(__code, __str) PEVENT_ERRNO__ ## __code
|
||||
enum pevent_errno {
|
||||
PEVENT_ERRNO__SUCCESS = 0,
|
||||
PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS,
|
||||
#define _PE(__code, __str) TEP_ERRNO__ ## __code
|
||||
enum tep_errno {
|
||||
TEP_ERRNO__SUCCESS = 0,
|
||||
TEP_ERRNO__FILTER_MATCH = TEP_ERRNO__SUCCESS,
|
||||
|
||||
/*
|
||||
* Choose an arbitrary negative big number not to clash with standard
|
||||
@ -423,11 +423,11 @@ enum pevent_errno {
|
||||
*
|
||||
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
|
||||
*/
|
||||
__PEVENT_ERRNO__START = -100000,
|
||||
__TEP_ERRNO__START = -100000,
|
||||
|
||||
PEVENT_ERRORS,
|
||||
TEP_ERRORS,
|
||||
|
||||
__PEVENT_ERRNO__END,
|
||||
__TEP_ERRNO__END,
|
||||
};
|
||||
#undef _PE
|
||||
|
||||
@ -435,17 +435,17 @@ struct plugin_list;
|
||||
|
||||
#define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1))
|
||||
|
||||
struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
|
||||
void traceevent_unload_plugins(struct plugin_list *plugin_list,
|
||||
struct pevent *pevent);
|
||||
char **traceevent_plugin_list_options(void);
|
||||
void traceevent_plugin_free_options_list(char **list);
|
||||
int traceevent_plugin_add_options(const char *name,
|
||||
struct pevent_plugin_option *options);
|
||||
void traceevent_plugin_remove_options(struct pevent_plugin_option *options);
|
||||
void traceevent_print_plugins(struct trace_seq *s,
|
||||
const char *prefix, const char *suffix,
|
||||
const struct plugin_list *list);
|
||||
struct plugin_list *tep_load_plugins(struct tep_handle *pevent);
|
||||
void tep_unload_plugins(struct plugin_list *plugin_list,
|
||||
struct tep_handle *pevent);
|
||||
char **tep_plugin_list_options(void);
|
||||
void tep_plugin_free_options_list(char **list);
|
||||
int tep_plugin_add_options(const char *name,
|
||||
struct tep_plugin_option *options);
|
||||
void tep_plugin_remove_options(struct tep_plugin_option *options);
|
||||
void tep_print_plugins(struct trace_seq *s,
|
||||
const char *prefix, const char *suffix,
|
||||
const struct plugin_list *list);
|
||||
|
||||
struct cmdline;
|
||||
struct cmdline_list;
|
||||
@ -454,10 +454,10 @@ struct func_list;
|
||||
struct event_handler;
|
||||
struct func_resolver;
|
||||
|
||||
typedef char *(pevent_func_resolver_t)(void *priv,
|
||||
unsigned long long *addrp, char **modp);
|
||||
typedef char *(tep_func_resolver_t)(void *priv,
|
||||
unsigned long long *addrp, char **modp);
|
||||
|
||||
struct pevent {
|
||||
struct tep_handle {
|
||||
int ref_count;
|
||||
|
||||
int header_page_ts_offset;
|
||||
@ -524,7 +524,7 @@ struct pevent {
|
||||
struct format_field *bprint_buf_field;
|
||||
|
||||
struct event_handler *handlers;
|
||||
struct pevent_function_handler *func_handlers;
|
||||
struct tep_function_handler *func_handlers;
|
||||
|
||||
/* cache */
|
||||
struct event_format *last_event;
|
||||
@ -532,13 +532,13 @@ struct pevent {
|
||||
char *trace_clock;
|
||||
};
|
||||
|
||||
static inline void pevent_set_flag(struct pevent *pevent, int flag)
|
||||
static inline void tep_set_flag(struct tep_handle *pevent, int flag)
|
||||
{
|
||||
pevent->flags |= flag;
|
||||
}
|
||||
|
||||
static inline unsigned short
|
||||
__data2host2(struct pevent *pevent, unsigned short data)
|
||||
__data2host2(struct tep_handle *pevent, unsigned short data)
|
||||
{
|
||||
unsigned short swap;
|
||||
|
||||
@ -552,7 +552,7 @@ __data2host2(struct pevent *pevent, unsigned short data)
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
__data2host4(struct pevent *pevent, unsigned int data)
|
||||
__data2host4(struct tep_handle *pevent, unsigned int data)
|
||||
{
|
||||
unsigned int swap;
|
||||
|
||||
@ -568,7 +568,7 @@ __data2host4(struct pevent *pevent, unsigned int data)
|
||||
}
|
||||
|
||||
static inline unsigned long long
|
||||
__data2host8(struct pevent *pevent, unsigned long long data)
|
||||
__data2host8(struct tep_handle *pevent, unsigned long long data)
|
||||
{
|
||||
unsigned long long swap;
|
||||
|
||||
@ -597,7 +597,7 @@ __data2host8(struct pevent *pevent, unsigned long long data)
|
||||
__data2host8(pevent, __val); \
|
||||
})
|
||||
|
||||
static inline int traceevent_host_bigendian(void)
|
||||
static inline int tep_host_bigendian(void)
|
||||
{
|
||||
unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
|
||||
unsigned int val;
|
||||
@ -615,198 +615,198 @@ enum trace_flag_type {
|
||||
TRACE_FLAG_SOFTIRQ = 0x10,
|
||||
};
|
||||
|
||||
int pevent_set_function_resolver(struct pevent *pevent,
|
||||
pevent_func_resolver_t *func, void *priv);
|
||||
void pevent_reset_function_resolver(struct pevent *pevent);
|
||||
int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
|
||||
int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock);
|
||||
int pevent_register_function(struct pevent *pevent, char *name,
|
||||
unsigned long long addr, char *mod);
|
||||
int pevent_register_print_string(struct pevent *pevent, const char *fmt,
|
||||
unsigned long long addr);
|
||||
int pevent_pid_is_registered(struct pevent *pevent, int pid);
|
||||
int tep_set_function_resolver(struct tep_handle *pevent,
|
||||
tep_func_resolver_t *func, void *priv);
|
||||
void tep_reset_function_resolver(struct tep_handle *pevent);
|
||||
int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid);
|
||||
int tep_register_trace_clock(struct tep_handle *pevent, const char *trace_clock);
|
||||
int tep_register_function(struct tep_handle *pevent, char *name,
|
||||
unsigned long long addr, char *mod);
|
||||
int tep_register_print_string(struct tep_handle *pevent, const char *fmt,
|
||||
unsigned long long addr);
|
||||
int tep_pid_is_registered(struct tep_handle *pevent, int pid);
|
||||
|
||||
void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s,
|
||||
struct event_format *event,
|
||||
struct pevent_record *record);
|
||||
void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s,
|
||||
struct event_format *event,
|
||||
struct pevent_record *record,
|
||||
bool use_trace_clock);
|
||||
void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s,
|
||||
struct event_format *event,
|
||||
struct pevent_record *record);
|
||||
void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
|
||||
struct pevent_record *record, bool use_trace_clock);
|
||||
void tep_print_event_task(struct tep_handle *pevent, struct trace_seq *s,
|
||||
struct event_format *event,
|
||||
struct tep_record *record);
|
||||
void tep_print_event_time(struct tep_handle *pevent, struct trace_seq *s,
|
||||
struct event_format *event,
|
||||
struct tep_record *record,
|
||||
bool use_trace_clock);
|
||||
void tep_print_event_data(struct tep_handle *pevent, struct trace_seq *s,
|
||||
struct event_format *event,
|
||||
struct tep_record *record);
|
||||
void tep_print_event(struct tep_handle *pevent, struct trace_seq *s,
|
||||
struct tep_record *record, bool use_trace_clock);
|
||||
|
||||
int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
|
||||
int long_size);
|
||||
int tep_parse_header_page(struct tep_handle *pevent, char *buf, unsigned long size,
|
||||
int long_size);
|
||||
|
||||
enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
|
||||
unsigned long size, const char *sys);
|
||||
enum pevent_errno pevent_parse_format(struct pevent *pevent,
|
||||
struct event_format **eventp,
|
||||
const char *buf,
|
||||
unsigned long size, const char *sys);
|
||||
void pevent_free_format(struct event_format *event);
|
||||
void pevent_free_format_field(struct format_field *field);
|
||||
enum tep_errno tep_parse_event(struct tep_handle *pevent, const char *buf,
|
||||
unsigned long size, const char *sys);
|
||||
enum tep_errno tep_parse_format(struct tep_handle *pevent,
|
||||
struct event_format **eventp,
|
||||
const char *buf,
|
||||
unsigned long size, const char *sys);
|
||||
void tep_free_format(struct event_format *event);
|
||||
void tep_free_format_field(struct format_field *field);
|
||||
|
||||
void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
|
||||
const char *name, struct pevent_record *record,
|
||||
int *len, int err);
|
||||
void *tep_get_field_raw(struct trace_seq *s, struct event_format *event,
|
||||
const char *name, struct tep_record *record,
|
||||
int *len, int err);
|
||||
|
||||
int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
|
||||
const char *name, struct pevent_record *record,
|
||||
unsigned long long *val, int err);
|
||||
int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
|
||||
const char *name, struct pevent_record *record,
|
||||
unsigned long long *val, int err);
|
||||
int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
|
||||
const char *name, struct pevent_record *record,
|
||||
int tep_get_field_val(struct trace_seq *s, struct event_format *event,
|
||||
const char *name, struct tep_record *record,
|
||||
unsigned long long *val, int err);
|
||||
int tep_get_common_field_val(struct trace_seq *s, struct event_format *event,
|
||||
const char *name, struct tep_record *record,
|
||||
unsigned long long *val, int err);
|
||||
int tep_get_any_field_val(struct trace_seq *s, struct event_format *event,
|
||||
const char *name, struct tep_record *record,
|
||||
unsigned long long *val, int err);
|
||||
|
||||
int pevent_print_num_field(struct trace_seq *s, const char *fmt,
|
||||
int tep_print_num_field(struct trace_seq *s, const char *fmt,
|
||||
struct event_format *event, const char *name,
|
||||
struct pevent_record *record, int err);
|
||||
struct tep_record *record, int err);
|
||||
|
||||
int pevent_print_func_field(struct trace_seq *s, const char *fmt,
|
||||
struct event_format *event, const char *name,
|
||||
struct pevent_record *record, int err);
|
||||
int tep_print_func_field(struct trace_seq *s, const char *fmt,
|
||||
struct event_format *event, const char *name,
|
||||
struct tep_record *record, int err);
|
||||
|
||||
int pevent_register_event_handler(struct pevent *pevent, int id,
|
||||
const char *sys_name, const char *event_name,
|
||||
pevent_event_handler_func func, void *context);
|
||||
int pevent_unregister_event_handler(struct pevent *pevent, int id,
|
||||
const char *sys_name, const char *event_name,
|
||||
pevent_event_handler_func func, void *context);
|
||||
int pevent_register_print_function(struct pevent *pevent,
|
||||
pevent_func_handler func,
|
||||
enum pevent_func_arg_type ret_type,
|
||||
char *name, ...);
|
||||
int pevent_unregister_print_function(struct pevent *pevent,
|
||||
pevent_func_handler func, char *name);
|
||||
int tep_register_event_handler(struct tep_handle *pevent, int id,
|
||||
const char *sys_name, const char *event_name,
|
||||
tep_event_handler_func func, void *context);
|
||||
int tep_unregister_event_handler(struct tep_handle *pevent, int id,
|
||||
const char *sys_name, const char *event_name,
|
||||
tep_event_handler_func func, void *context);
|
||||
int tep_register_print_function(struct tep_handle *pevent,
|
||||
tep_func_handler func,
|
||||
enum tep_func_arg_type ret_type,
|
||||
char *name, ...);
|
||||
int tep_unregister_print_function(struct tep_handle *pevent,
|
||||
tep_func_handler func, char *name);
|
||||
|
||||
struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
|
||||
struct format_field *pevent_find_field(struct event_format *event, const char *name);
|
||||
struct format_field *pevent_find_any_field(struct event_format *event, const char *name);
|
||||
struct format_field *tep_find_common_field(struct event_format *event, const char *name);
|
||||
struct format_field *tep_find_field(struct event_format *event, const char *name);
|
||||
struct format_field *tep_find_any_field(struct event_format *event, const char *name);
|
||||
|
||||
const char *pevent_find_function(struct pevent *pevent, unsigned long long addr);
|
||||
const char *tep_find_function(struct tep_handle *pevent, unsigned long long addr);
|
||||
unsigned long long
|
||||
pevent_find_function_address(struct pevent *pevent, unsigned long long addr);
|
||||
unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size);
|
||||
int pevent_read_number_field(struct format_field *field, const void *data,
|
||||
unsigned long long *value);
|
||||
tep_find_function_address(struct tep_handle *pevent, unsigned long long addr);
|
||||
unsigned long long tep_read_number(struct tep_handle *pevent, const void *ptr, int size);
|
||||
int tep_read_number_field(struct format_field *field, const void *data,
|
||||
unsigned long long *value);
|
||||
|
||||
struct event_format *pevent_find_event(struct pevent *pevent, int id);
|
||||
struct event_format *tep_find_event(struct tep_handle *pevent, int id);
|
||||
|
||||
struct event_format *
|
||||
pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
|
||||
tep_find_event_by_name(struct tep_handle *pevent, const char *sys, const char *name);
|
||||
|
||||
struct event_format *
|
||||
pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record);
|
||||
tep_find_event_by_record(struct tep_handle *pevent, struct tep_record *record);
|
||||
|
||||
void pevent_data_lat_fmt(struct pevent *pevent,
|
||||
struct trace_seq *s, struct pevent_record *record);
|
||||
int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
|
||||
struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
|
||||
int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec);
|
||||
int pevent_data_preempt_count(struct pevent *pevent, struct pevent_record *rec);
|
||||
int pevent_data_flags(struct pevent *pevent, struct pevent_record *rec);
|
||||
const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
|
||||
void tep_data_lat_fmt(struct tep_handle *pevent,
|
||||
struct trace_seq *s, struct tep_record *record);
|
||||
int tep_data_type(struct tep_handle *pevent, struct tep_record *rec);
|
||||
struct event_format *tep_data_event_from_type(struct tep_handle *pevent, int type);
|
||||
int tep_data_pid(struct tep_handle *pevent, struct tep_record *rec);
|
||||
int tep_data_preempt_count(struct tep_handle *pevent, struct tep_record *rec);
|
||||
int tep_data_flags(struct tep_handle *pevent, struct tep_record *rec);
|
||||
const char *tep_data_comm_from_pid(struct tep_handle *pevent, int pid);
|
||||
struct cmdline;
|
||||
struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm,
|
||||
struct cmdline *next);
|
||||
int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline);
|
||||
struct cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm,
|
||||
struct cmdline *next);
|
||||
int tep_cmdline_pid(struct tep_handle *pevent, struct cmdline *cmdline);
|
||||
|
||||
void pevent_print_field(struct trace_seq *s, void *data,
|
||||
struct format_field *field);
|
||||
void pevent_print_fields(struct trace_seq *s, void *data,
|
||||
int size __maybe_unused, struct event_format *event);
|
||||
void pevent_event_info(struct trace_seq *s, struct event_format *event,
|
||||
struct pevent_record *record);
|
||||
int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
|
||||
void tep_print_field(struct trace_seq *s, void *data,
|
||||
struct format_field *field);
|
||||
void tep_print_fields(struct trace_seq *s, void *data,
|
||||
int size __maybe_unused, struct event_format *event);
|
||||
void tep_event_info(struct trace_seq *s, struct event_format *event,
|
||||
struct tep_record *record);
|
||||
int tep_strerror(struct tep_handle *pevent, enum tep_errno errnum,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
|
||||
struct format_field **pevent_event_common_fields(struct event_format *event);
|
||||
struct format_field **pevent_event_fields(struct event_format *event);
|
||||
struct event_format **tep_list_events(struct tep_handle *pevent, enum event_sort_type);
|
||||
struct format_field **tep_event_common_fields(struct event_format *event);
|
||||
struct format_field **tep_event_fields(struct event_format *event);
|
||||
|
||||
static inline int pevent_get_cpus(struct pevent *pevent)
|
||||
static inline int tep_get_cpus(struct tep_handle *pevent)
|
||||
{
|
||||
return pevent->cpus;
|
||||
}
|
||||
|
||||
static inline void pevent_set_cpus(struct pevent *pevent, int cpus)
|
||||
static inline void tep_set_cpus(struct tep_handle *pevent, int cpus)
|
||||
{
|
||||
pevent->cpus = cpus;
|
||||
}
|
||||
|
||||
static inline int pevent_get_long_size(struct pevent *pevent)
|
||||
static inline int tep_get_long_size(struct tep_handle *pevent)
|
||||
{
|
||||
return pevent->long_size;
|
||||
}
|
||||
|
||||
static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
|
||||
static inline void tep_set_long_size(struct tep_handle *pevent, int long_size)
|
||||
{
|
||||
pevent->long_size = long_size;
|
||||
}
|
||||
|
||||
static inline int pevent_get_page_size(struct pevent *pevent)
|
||||
static inline int tep_get_page_size(struct tep_handle *pevent)
|
||||
{
|
||||
return pevent->page_size;
|
||||
}
|
||||
|
||||
static inline void pevent_set_page_size(struct pevent *pevent, int _page_size)
|
||||
static inline void tep_set_page_size(struct tep_handle *pevent, int _page_size)
|
||||
{
|
||||
pevent->page_size = _page_size;
|
||||
}
|
||||
|
||||
static inline int pevent_is_file_bigendian(struct pevent *pevent)
|
||||
static inline int tep_is_file_bigendian(struct tep_handle *pevent)
|
||||
{
|
||||
return pevent->file_bigendian;
|
||||
}
|
||||
|
||||
static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian)
|
||||
static inline void tep_set_file_bigendian(struct tep_handle *pevent, int endian)
|
||||
{
|
||||
pevent->file_bigendian = endian;
|
||||
}
|
||||
|
||||
static inline int pevent_is_host_bigendian(struct pevent *pevent)
|
||||
static inline int tep_is_host_bigendian(struct tep_handle *pevent)
|
||||
{
|
||||
return pevent->host_bigendian;
|
||||
}
|
||||
|
||||
static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian)
|
||||
static inline void tep_set_host_bigendian(struct tep_handle *pevent, int endian)
|
||||
{
|
||||
pevent->host_bigendian = endian;
|
||||
}
|
||||
|
||||
static inline int pevent_is_latency_format(struct pevent *pevent)
|
||||
static inline int tep_is_latency_format(struct tep_handle *pevent)
|
||||
{
|
||||
return pevent->latency_format;
|
||||
}
|
||||
|
||||
static inline void pevent_set_latency_format(struct pevent *pevent, int lat)
|
||||
static inline void tep_set_latency_format(struct tep_handle *pevent, int lat)
|
||||
{
|
||||
pevent->latency_format = lat;
|
||||
}
|
||||
|
||||
struct pevent *pevent_alloc(void);
|
||||
void pevent_free(struct pevent *pevent);
|
||||
void pevent_ref(struct pevent *pevent);
|
||||
void pevent_unref(struct pevent *pevent);
|
||||
struct tep_handle *tep_alloc(void);
|
||||
void tep_free(struct tep_handle *pevent);
|
||||
void tep_ref(struct tep_handle *pevent);
|
||||
void tep_unref(struct tep_handle *pevent);
|
||||
|
||||
/* access to the internal parser */
|
||||
void pevent_buffer_init(const char *buf, unsigned long long size);
|
||||
enum event_type pevent_read_token(char **tok);
|
||||
void pevent_free_token(char *token);
|
||||
int pevent_peek_char(void);
|
||||
const char *pevent_get_input_buf(void);
|
||||
unsigned long long pevent_get_input_buf_ptr(void);
|
||||
void tep_buffer_init(const char *buf, unsigned long long size);
|
||||
enum event_type tep_read_token(char **tok);
|
||||
void tep_free_token(char *token);
|
||||
int tep_peek_char(void);
|
||||
const char *tep_get_input_buf(void);
|
||||
unsigned long long tep_get_input_buf_ptr(void);
|
||||
|
||||
/* for debugging */
|
||||
void pevent_print_funcs(struct pevent *pevent);
|
||||
void pevent_print_printk(struct pevent *pevent);
|
||||
void tep_print_funcs(struct tep_handle *pevent);
|
||||
void tep_print_printk(struct tep_handle *pevent);
|
||||
|
||||
/* ----------------------- filtering ----------------------- */
|
||||
|
||||
@ -930,22 +930,22 @@ struct filter_type {
|
||||
struct filter_arg *filter;
|
||||
};
|
||||
|
||||
#define PEVENT_FILTER_ERROR_BUFSZ 1024
|
||||
#define TEP_FILTER_ERROR_BUFSZ 1024
|
||||
|
||||
struct event_filter {
|
||||
struct pevent *pevent;
|
||||
struct tep_handle *pevent;
|
||||
int filters;
|
||||
struct filter_type *event_filters;
|
||||
char error_buffer[PEVENT_FILTER_ERROR_BUFSZ];
|
||||
char error_buffer[TEP_FILTER_ERROR_BUFSZ];
|
||||
};
|
||||
|
||||
struct event_filter *pevent_filter_alloc(struct pevent *pevent);
|
||||
struct event_filter *tep_filter_alloc(struct tep_handle *pevent);
|
||||
|
||||
/* for backward compatibility */
|
||||
#define FILTER_NONE PEVENT_ERRNO__NO_FILTER
|
||||
#define FILTER_NOEXIST PEVENT_ERRNO__FILTER_NOT_FOUND
|
||||
#define FILTER_MISS PEVENT_ERRNO__FILTER_MISS
|
||||
#define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH
|
||||
#define FILTER_NONE TEP_ERRNO__NO_FILTER
|
||||
#define FILTER_NOEXIST TEP_ERRNO__FILTER_NOT_FOUND
|
||||
#define FILTER_MISS TEP_ERRNO__FILTER_MISS
|
||||
#define FILTER_MATCH TEP_ERRNO__FILTER_MATCH
|
||||
|
||||
enum filter_trivial_type {
|
||||
FILTER_TRIVIAL_FALSE,
|
||||
@ -953,39 +953,39 @@ enum filter_trivial_type {
|
||||
FILTER_TRIVIAL_BOTH,
|
||||
};
|
||||
|
||||
enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
|
||||
const char *filter_str);
|
||||
enum tep_errno tep_filter_add_filter_str(struct event_filter *filter,
|
||||
const char *filter_str);
|
||||
|
||||
enum pevent_errno pevent_filter_match(struct event_filter *filter,
|
||||
struct pevent_record *record);
|
||||
enum tep_errno tep_filter_match(struct event_filter *filter,
|
||||
struct tep_record *record);
|
||||
|
||||
int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
|
||||
char *buf, size_t buflen);
|
||||
int tep_filter_strerror(struct event_filter *filter, enum tep_errno err,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
int pevent_event_filtered(struct event_filter *filter,
|
||||
int event_id);
|
||||
int tep_event_filtered(struct event_filter *filter,
|
||||
int event_id);
|
||||
|
||||
void pevent_filter_reset(struct event_filter *filter);
|
||||
void tep_filter_reset(struct event_filter *filter);
|
||||
|
||||
int pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
int tep_filter_clear_trivial(struct event_filter *filter,
|
||||
enum filter_trivial_type type);
|
||||
|
||||
void tep_filter_free(struct event_filter *filter);
|
||||
|
||||
char *tep_filter_make_string(struct event_filter *filter, int event_id);
|
||||
|
||||
int tep_filter_remove_event(struct event_filter *filter,
|
||||
int event_id);
|
||||
|
||||
int tep_filter_event_has_trivial(struct event_filter *filter,
|
||||
int event_id,
|
||||
enum filter_trivial_type type);
|
||||
|
||||
void pevent_filter_free(struct event_filter *filter);
|
||||
int tep_filter_copy(struct event_filter *dest, struct event_filter *source);
|
||||
|
||||
char *pevent_filter_make_string(struct event_filter *filter, int event_id);
|
||||
int tep_update_trivial(struct event_filter *dest, struct event_filter *source,
|
||||
enum filter_trivial_type type);
|
||||
|
||||
int pevent_filter_remove_event(struct event_filter *filter,
|
||||
int event_id);
|
||||
|
||||
int pevent_filter_event_has_trivial(struct event_filter *filter,
|
||||
int event_id,
|
||||
enum filter_trivial_type type);
|
||||
|
||||
int pevent_filter_copy(struct event_filter *dest, struct event_filter *source);
|
||||
|
||||
int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
|
||||
enum filter_trivial_type type);
|
||||
|
||||
int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2);
|
||||
int tep_filter_compare(struct event_filter *filter1, struct event_filter *filter2);
|
||||
|
||||
#endif /* _PARSE_EVENTS_H */
|
||||
|
@ -1,21 +1,7 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License (not later!)
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, see <http://www.gnu.org/licenses>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
@ -34,7 +20,7 @@
|
||||
|
||||
static struct registered_plugin_options {
|
||||
struct registered_plugin_options *next;
|
||||
struct pevent_plugin_option *options;
|
||||
struct tep_plugin_option *options;
|
||||
} *registered_options;
|
||||
|
||||
static struct trace_plugin_options {
|
||||
@ -58,7 +44,7 @@ static void lower_case(char *str)
|
||||
*str = tolower(*str);
|
||||
}
|
||||
|
||||
static int update_option_value(struct pevent_plugin_option *op, const char *val)
|
||||
static int update_option_value(struct tep_plugin_option *op, const char *val)
|
||||
{
|
||||
char *op_val;
|
||||
|
||||
@ -97,7 +83,7 @@ static int update_option_value(struct pevent_plugin_option *op, const char *val)
|
||||
}
|
||||
|
||||
/**
|
||||
* traceevent_plugin_list_options - get list of plugin options
|
||||
* tep_plugin_list_options - get list of plugin options
|
||||
*
|
||||
* Returns an array of char strings that list the currently registered
|
||||
* plugin options in the format of <plugin>:<option>. This list can be
|
||||
@ -106,12 +92,12 @@ static int update_option_value(struct pevent_plugin_option *op, const char *val)
|
||||
* Returns NULL if there's no options registered. On error it returns
|
||||
* INVALID_PLUGIN_LIST_OPTION
|
||||
*
|
||||
* Must be freed with traceevent_plugin_free_options_list().
|
||||
* Must be freed with tep_plugin_free_options_list().
|
||||
*/
|
||||
char **traceevent_plugin_list_options(void)
|
||||
char **tep_plugin_list_options(void)
|
||||
{
|
||||
struct registered_plugin_options *reg;
|
||||
struct pevent_plugin_option *op;
|
||||
struct tep_plugin_option *op;
|
||||
char **list = NULL;
|
||||
char *name;
|
||||
int count = 0;
|
||||
@ -146,7 +132,7 @@ char **traceevent_plugin_list_options(void)
|
||||
return INVALID_PLUGIN_LIST_OPTION;
|
||||
}
|
||||
|
||||
void traceevent_plugin_free_options_list(char **list)
|
||||
void tep_plugin_free_options_list(char **list)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -163,7 +149,7 @@ void traceevent_plugin_free_options_list(char **list)
|
||||
}
|
||||
|
||||
static int
|
||||
update_option(const char *file, struct pevent_plugin_option *option)
|
||||
update_option(const char *file, struct tep_plugin_option *option)
|
||||
{
|
||||
struct trace_plugin_options *op;
|
||||
char *plugin;
|
||||
@ -215,14 +201,14 @@ update_option(const char *file, struct pevent_plugin_option *option)
|
||||
}
|
||||
|
||||
/**
|
||||
* traceevent_plugin_add_options - Add a set of options by a plugin
|
||||
* tep_plugin_add_options - Add a set of options by a plugin
|
||||
* @name: The name of the plugin adding the options
|
||||
* @options: The set of options being loaded
|
||||
*
|
||||
* Sets the options with the values that have been added by user.
|
||||
*/
|
||||
int traceevent_plugin_add_options(const char *name,
|
||||
struct pevent_plugin_option *options)
|
||||
int tep_plugin_add_options(const char *name,
|
||||
struct tep_plugin_option *options)
|
||||
{
|
||||
struct registered_plugin_options *reg;
|
||||
|
||||
@ -241,10 +227,10 @@ int traceevent_plugin_add_options(const char *name,
|
||||
}
|
||||
|
||||
/**
|
||||
* traceevent_plugin_remove_options - remove plugin options that were registered
|
||||
* @options: Options to removed that were registered with traceevent_plugin_add_options
|
||||
* tep_plugin_remove_options - remove plugin options that were registered
|
||||
* @options: Options to removed that were registered with tep_plugin_add_options
|
||||
*/
|
||||
void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
|
||||
void tep_plugin_remove_options(struct tep_plugin_option *options)
|
||||
{
|
||||
struct registered_plugin_options **last;
|
||||
struct registered_plugin_options *reg;
|
||||
@ -260,19 +246,19 @@ void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
|
||||
}
|
||||
|
||||
/**
|
||||
* traceevent_print_plugins - print out the list of plugins loaded
|
||||
* tep_print_plugins - print out the list of plugins loaded
|
||||
* @s: the trace_seq descripter to write to
|
||||
* @prefix: The prefix string to add before listing the option name
|
||||
* @suffix: The suffix string ot append after the option name
|
||||
* @list: The list of plugins (usually returned by traceevent_load_plugins()
|
||||
* @list: The list of plugins (usually returned by tep_load_plugins()
|
||||
*
|
||||
* Writes to the trace_seq @s the list of plugins (files) that is
|
||||
* returned by traceevent_load_plugins(). Use @prefix and @suffix for formating:
|
||||
* returned by tep_load_plugins(). Use @prefix and @suffix for formating:
|
||||
* @prefix = " ", @suffix = "\n".
|
||||
*/
|
||||
void traceevent_print_plugins(struct trace_seq *s,
|
||||
const char *prefix, const char *suffix,
|
||||
const struct plugin_list *list)
|
||||
void tep_print_plugins(struct trace_seq *s,
|
||||
const char *prefix, const char *suffix,
|
||||
const struct plugin_list *list)
|
||||
{
|
||||
while (list) {
|
||||
trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
|
||||
@ -281,11 +267,11 @@ void traceevent_print_plugins(struct trace_seq *s,
|
||||
}
|
||||
|
||||
static void
|
||||
load_plugin(struct pevent *pevent, const char *path,
|
||||
load_plugin(struct tep_handle *pevent, const char *path,
|
||||
const char *file, void *data)
|
||||
{
|
||||
struct plugin_list **plugin_list = data;
|
||||
pevent_plugin_load_func func;
|
||||
tep_plugin_load_func func;
|
||||
struct plugin_list *list;
|
||||
const char *alias;
|
||||
char *plugin;
|
||||
@ -305,14 +291,14 @@ load_plugin(struct pevent *pevent, const char *path,
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME);
|
||||
alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME);
|
||||
if (!alias)
|
||||
alias = file;
|
||||
|
||||
func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME);
|
||||
func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
|
||||
if (!func) {
|
||||
warning("could not find func '%s' in plugin '%s'\n%s\n",
|
||||
PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror());
|
||||
TEP_PLUGIN_LOADER_NAME, plugin, dlerror());
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
@ -336,9 +322,9 @@ load_plugin(struct pevent *pevent, const char *path,
|
||||
}
|
||||
|
||||
static void
|
||||
load_plugins_dir(struct pevent *pevent, const char *suffix,
|
||||
load_plugins_dir(struct tep_handle *pevent, const char *suffix,
|
||||
const char *path,
|
||||
void (*load_plugin)(struct pevent *pevent,
|
||||
void (*load_plugin)(struct tep_handle *pevent,
|
||||
const char *path,
|
||||
const char *name,
|
||||
void *data),
|
||||
@ -378,8 +364,8 @@ load_plugins_dir(struct pevent *pevent, const char *suffix,
|
||||
}
|
||||
|
||||
static void
|
||||
load_plugins(struct pevent *pevent, const char *suffix,
|
||||
void (*load_plugin)(struct pevent *pevent,
|
||||
load_plugins(struct tep_handle *pevent, const char *suffix,
|
||||
void (*load_plugin)(struct tep_handle *pevent,
|
||||
const char *path,
|
||||
const char *name,
|
||||
void *data),
|
||||
@ -390,7 +376,7 @@ load_plugins(struct pevent *pevent, const char *suffix,
|
||||
char *envdir;
|
||||
int ret;
|
||||
|
||||
if (pevent->flags & PEVENT_DISABLE_PLUGINS)
|
||||
if (pevent->flags & TEP_DISABLE_PLUGINS)
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -398,7 +384,7 @@ load_plugins(struct pevent *pevent, const char *suffix,
|
||||
* check that first.
|
||||
*/
|
||||
#ifdef PLUGIN_DIR
|
||||
if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS))
|
||||
if (!(pevent->flags & TEP_DISABLE_SYS_PLUGINS))
|
||||
load_plugins_dir(pevent, suffix, PLUGIN_DIR,
|
||||
load_plugin, data);
|
||||
#endif
|
||||
@ -431,7 +417,7 @@ load_plugins(struct pevent *pevent, const char *suffix,
|
||||
}
|
||||
|
||||
struct plugin_list*
|
||||
traceevent_load_plugins(struct pevent *pevent)
|
||||
tep_load_plugins(struct tep_handle *pevent)
|
||||
{
|
||||
struct plugin_list *list = NULL;
|
||||
|
||||
@ -440,15 +426,15 @@ traceevent_load_plugins(struct pevent *pevent)
|
||||
}
|
||||
|
||||
void
|
||||
traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent)
|
||||
tep_unload_plugins(struct plugin_list *plugin_list, struct tep_handle *pevent)
|
||||
{
|
||||
pevent_plugin_unload_func func;
|
||||
tep_plugin_unload_func func;
|
||||
struct plugin_list *list;
|
||||
|
||||
while (plugin_list) {
|
||||
list = plugin_list;
|
||||
plugin_list = list->next;
|
||||
func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME);
|
||||
func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
|
||||
if (func)
|
||||
func(pevent);
|
||||
dlclose(list->handle);
|
||||
|
@ -1,21 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License (not later!)
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, see <http://www.gnu.org/licenses>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
#ifndef __UTIL_H
|
||||
#define __UTIL_H
|
||||
|
@ -1,22 +1,7 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License (not later!)
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -1,21 +1,7 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License (not later!)
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, see <http://www.gnu.org/licenses>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -51,8 +37,8 @@ static void show_error(char *error_buf, const char *fmt, ...)
|
||||
int len;
|
||||
int i;
|
||||
|
||||
input = pevent_get_input_buf();
|
||||
index = pevent_get_input_buf_ptr();
|
||||
input = tep_get_input_buf();
|
||||
index = tep_get_input_buf_ptr();
|
||||
len = input ? strlen(input) : 0;
|
||||
|
||||
if (len) {
|
||||
@ -66,13 +52,13 @@ static void show_error(char *error_buf, const char *fmt, ...)
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(error_buf + len, PEVENT_FILTER_ERROR_BUFSZ - len, fmt, ap);
|
||||
vsnprintf(error_buf + len, TEP_FILTER_ERROR_BUFSZ - len, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void free_token(char *token)
|
||||
{
|
||||
pevent_free_token(token);
|
||||
tep_free_token(token);
|
||||
}
|
||||
|
||||
static enum event_type read_token(char **tok)
|
||||
@ -82,13 +68,13 @@ static enum event_type read_token(char **tok)
|
||||
|
||||
do {
|
||||
free_token(token);
|
||||
type = pevent_read_token(&token);
|
||||
type = tep_read_token(&token);
|
||||
} while (type == EVENT_NEWLINE || type == EVENT_SPACE);
|
||||
|
||||
/* If token is = or ! check to see if the next char is ~ */
|
||||
if (token &&
|
||||
(strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
|
||||
pevent_peek_char() == '~') {
|
||||
tep_peek_char() == '~') {
|
||||
/* append it */
|
||||
*tok = malloc(3);
|
||||
if (*tok == NULL) {
|
||||
@ -98,7 +84,7 @@ static enum event_type read_token(char **tok)
|
||||
sprintf(*tok, "%c%c", *token, '~');
|
||||
free_token(token);
|
||||
/* Now remove the '~' from the buffer */
|
||||
pevent_read_token(&token);
|
||||
tep_read_token(&token);
|
||||
free_token(token);
|
||||
} else
|
||||
*tok = token;
|
||||
@ -167,7 +153,7 @@ add_filter_type(struct event_filter *filter, int id)
|
||||
|
||||
filter_type = &filter->event_filters[i];
|
||||
filter_type->event_id = id;
|
||||
filter_type->event = pevent_find_event(filter->pevent, id);
|
||||
filter_type->event = tep_find_event(filter->pevent, id);
|
||||
filter_type->filter = NULL;
|
||||
|
||||
filter->filters++;
|
||||
@ -176,10 +162,10 @@ add_filter_type(struct event_filter *filter, int id)
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_alloc - create a new event filter
|
||||
* tep_filter_alloc - create a new event filter
|
||||
* @pevent: The pevent that this filter is associated with
|
||||
*/
|
||||
struct event_filter *pevent_filter_alloc(struct pevent *pevent)
|
||||
struct event_filter *tep_filter_alloc(struct tep_handle *pevent)
|
||||
{
|
||||
struct event_filter *filter;
|
||||
|
||||
@ -189,7 +175,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent)
|
||||
|
||||
memset(filter, 0, sizeof(*filter));
|
||||
filter->pevent = pevent;
|
||||
pevent_ref(pevent);
|
||||
tep_ref(pevent);
|
||||
|
||||
return filter;
|
||||
}
|
||||
@ -268,8 +254,8 @@ static int event_match(struct event_format *event,
|
||||
!regexec(ereg, event->name, 0, NULL, 0);
|
||||
}
|
||||
|
||||
static enum pevent_errno
|
||||
find_event(struct pevent *pevent, struct event_list **events,
|
||||
static enum tep_errno
|
||||
find_event(struct tep_handle *pevent, struct event_list **events,
|
||||
char *sys_name, char *event_name)
|
||||
{
|
||||
struct event_format *event;
|
||||
@ -289,26 +275,26 @@ find_event(struct pevent *pevent, struct event_list **events,
|
||||
|
||||
ret = asprintf(®, "^%s$", event_name);
|
||||
if (ret < 0)
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
|
||||
ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
|
||||
free(reg);
|
||||
|
||||
if (ret)
|
||||
return PEVENT_ERRNO__INVALID_EVENT_NAME;
|
||||
return TEP_ERRNO__INVALID_EVENT_NAME;
|
||||
|
||||
if (sys_name) {
|
||||
ret = asprintf(®, "^%s$", sys_name);
|
||||
if (ret < 0) {
|
||||
regfree(&ereg);
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
|
||||
free(reg);
|
||||
if (ret) {
|
||||
regfree(&ereg);
|
||||
return PEVENT_ERRNO__INVALID_EVENT_NAME;
|
||||
return TEP_ERRNO__INVALID_EVENT_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,9 +314,9 @@ find_event(struct pevent *pevent, struct event_list **events,
|
||||
regfree(&sreg);
|
||||
|
||||
if (!match)
|
||||
return PEVENT_ERRNO__EVENT_NOT_FOUND;
|
||||
return TEP_ERRNO__EVENT_NOT_FOUND;
|
||||
if (fail)
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -346,7 +332,7 @@ static void free_events(struct event_list *events)
|
||||
}
|
||||
}
|
||||
|
||||
static enum pevent_errno
|
||||
static enum tep_errno
|
||||
create_arg_item(struct event_format *event, const char *token,
|
||||
enum event_type type, struct filter_arg **parg, char *error_str)
|
||||
{
|
||||
@ -356,7 +342,7 @@ create_arg_item(struct event_format *event, const char *token,
|
||||
arg = allocate_arg();
|
||||
if (arg == NULL) {
|
||||
show_error(error_str, "failed to allocate filter arg");
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
@ -370,7 +356,7 @@ create_arg_item(struct event_format *event, const char *token,
|
||||
if (!arg->value.str) {
|
||||
free_arg(arg);
|
||||
show_error(error_str, "failed to allocate string filter arg");
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
}
|
||||
break;
|
||||
case EVENT_ITEM:
|
||||
@ -382,7 +368,7 @@ create_arg_item(struct event_format *event, const char *token,
|
||||
break;
|
||||
}
|
||||
/* Consider this a field */
|
||||
field = pevent_find_any_field(event, token);
|
||||
field = tep_find_any_field(event, token);
|
||||
if (!field) {
|
||||
/* If token is 'COMM' or 'CPU' then it is special */
|
||||
if (strcmp(token, COMM) == 0) {
|
||||
@ -402,7 +388,7 @@ create_arg_item(struct event_format *event, const char *token,
|
||||
default:
|
||||
free_arg(arg);
|
||||
show_error(error_str, "expected a value but found %s", token);
|
||||
return PEVENT_ERRNO__UNEXPECTED_TYPE;
|
||||
return TEP_ERRNO__UNEXPECTED_TYPE;
|
||||
}
|
||||
*parg = arg;
|
||||
return 0;
|
||||
@ -454,7 +440,7 @@ create_arg_cmp(enum filter_cmp_type ctype)
|
||||
return arg;
|
||||
}
|
||||
|
||||
static enum pevent_errno
|
||||
static enum tep_errno
|
||||
add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
|
||||
{
|
||||
struct filter_arg *left;
|
||||
@ -487,7 +473,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
|
||||
break;
|
||||
default:
|
||||
show_error(error_str, "Illegal rvalue");
|
||||
return PEVENT_ERRNO__ILLEGAL_RVALUE;
|
||||
return TEP_ERRNO__ILLEGAL_RVALUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -534,7 +520,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
|
||||
if (left->type != FILTER_ARG_FIELD) {
|
||||
show_error(error_str,
|
||||
"Illegal lvalue for string comparison");
|
||||
return PEVENT_ERRNO__ILLEGAL_LVALUE;
|
||||
return TEP_ERRNO__ILLEGAL_LVALUE;
|
||||
}
|
||||
|
||||
/* Make sure this is a valid string compare */
|
||||
@ -553,13 +539,13 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
|
||||
show_error(error_str,
|
||||
"RegEx '%s' did not compute",
|
||||
str);
|
||||
return PEVENT_ERRNO__INVALID_REGEX;
|
||||
return TEP_ERRNO__INVALID_REGEX;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
show_error(error_str,
|
||||
"Illegal comparison for string");
|
||||
return PEVENT_ERRNO__ILLEGAL_STRING_CMP;
|
||||
return TEP_ERRNO__ILLEGAL_STRING_CMP;
|
||||
}
|
||||
|
||||
op->type = FILTER_ARG_STR;
|
||||
@ -568,7 +554,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
|
||||
op->str.val = strdup(str);
|
||||
if (!op->str.val) {
|
||||
show_error(error_str, "Failed to allocate string filter");
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
}
|
||||
/*
|
||||
* Need a buffer to copy data for tests
|
||||
@ -576,7 +562,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
|
||||
op->str.buffer = malloc(op->str.field->size + 1);
|
||||
if (!op->str.buffer) {
|
||||
show_error(error_str, "Failed to allocate string filter");
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
}
|
||||
/* Null terminate this buffer */
|
||||
op->str.buffer[op->str.field->size] = 0;
|
||||
@ -595,7 +581,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
|
||||
case FILTER_CMP_NOT_REGEX:
|
||||
show_error(error_str,
|
||||
"Op not allowed with integers");
|
||||
return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
|
||||
return TEP_ERRNO__ILLEGAL_INTEGER_CMP;
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -616,7 +602,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
|
||||
|
||||
out_fail:
|
||||
show_error(error_str, "Syntax error");
|
||||
return PEVENT_ERRNO__SYNTAX_ERROR;
|
||||
return TEP_ERRNO__SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
static struct filter_arg *
|
||||
@ -629,7 +615,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b)
|
||||
return arg;
|
||||
}
|
||||
|
||||
static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg)
|
||||
static enum tep_errno add_left(struct filter_arg *op, struct filter_arg *arg)
|
||||
{
|
||||
switch (op->type) {
|
||||
case FILTER_ARG_EXP:
|
||||
@ -648,11 +634,11 @@ static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg)
|
||||
/* left arg of compares must be a field */
|
||||
if (arg->type != FILTER_ARG_FIELD &&
|
||||
arg->type != FILTER_ARG_BOOLEAN)
|
||||
return PEVENT_ERRNO__INVALID_ARG_TYPE;
|
||||
return TEP_ERRNO__INVALID_ARG_TYPE;
|
||||
op->num.left = arg;
|
||||
break;
|
||||
default:
|
||||
return PEVENT_ERRNO__INVALID_ARG_TYPE;
|
||||
return TEP_ERRNO__INVALID_ARG_TYPE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -765,7 +751,7 @@ enum filter_vals {
|
||||
FILTER_VAL_TRUE,
|
||||
};
|
||||
|
||||
static enum pevent_errno
|
||||
static enum tep_errno
|
||||
reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
|
||||
struct filter_arg *arg, char *error_str)
|
||||
{
|
||||
@ -775,7 +761,7 @@ reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
|
||||
if (parent->type != FILTER_ARG_OP &&
|
||||
arg->type != FILTER_ARG_OP) {
|
||||
show_error(error_str, "can not reparent other than OP");
|
||||
return PEVENT_ERRNO__REPARENT_NOT_OP;
|
||||
return TEP_ERRNO__REPARENT_NOT_OP;
|
||||
}
|
||||
|
||||
/* Get the sibling */
|
||||
@ -787,7 +773,7 @@ reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
|
||||
other_child = old_child->op.right;
|
||||
} else {
|
||||
show_error(error_str, "Error in reparent op, find other child");
|
||||
return PEVENT_ERRNO__REPARENT_FAILED;
|
||||
return TEP_ERRNO__REPARENT_FAILED;
|
||||
}
|
||||
|
||||
/* Detach arg from old_child */
|
||||
@ -808,7 +794,7 @@ reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
|
||||
ptr = &parent->op.left;
|
||||
else {
|
||||
show_error(error_str, "Error in reparent op");
|
||||
return PEVENT_ERRNO__REPARENT_FAILED;
|
||||
return TEP_ERRNO__REPARENT_FAILED;
|
||||
}
|
||||
|
||||
*ptr = arg;
|
||||
@ -817,7 +803,7 @@ reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns either filter_vals (success) or pevent_errno (failfure) */
|
||||
/* Returns either filter_vals (success) or tep_errno (failfure) */
|
||||
static int test_arg(struct filter_arg *parent, struct filter_arg *arg,
|
||||
char *error_str)
|
||||
{
|
||||
@ -912,7 +898,7 @@ static int test_arg(struct filter_arg *parent, struct filter_arg *arg,
|
||||
return rval;
|
||||
default:
|
||||
show_error(error_str, "bad arg in filter tree");
|
||||
return PEVENT_ERRNO__BAD_FILTER_ARG;
|
||||
return TEP_ERRNO__BAD_FILTER_ARG;
|
||||
}
|
||||
return FILTER_VAL_NORM;
|
||||
}
|
||||
@ -937,7 +923,7 @@ static int collapse_tree(struct filter_arg *arg,
|
||||
arg->boolean.value = ret == FILTER_VAL_TRUE;
|
||||
} else {
|
||||
show_error(error_str, "Failed to allocate filter arg");
|
||||
ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
ret = TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -952,7 +938,7 @@ static int collapse_tree(struct filter_arg *arg,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum pevent_errno
|
||||
static enum tep_errno
|
||||
process_filter(struct event_format *event, struct filter_arg **parg,
|
||||
char *error_str, int not)
|
||||
{
|
||||
@ -966,7 +952,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
||||
enum filter_op_type btype;
|
||||
enum filter_exp_type etype;
|
||||
enum filter_cmp_type ctype;
|
||||
enum pevent_errno ret;
|
||||
enum tep_errno ret;
|
||||
|
||||
*parg = NULL;
|
||||
|
||||
@ -1004,7 +990,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
||||
case EVENT_DELIM:
|
||||
if (*token == ',') {
|
||||
show_error(error_str, "Illegal token ','");
|
||||
ret = PEVENT_ERRNO__ILLEGAL_TOKEN;
|
||||
ret = TEP_ERRNO__ILLEGAL_TOKEN;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -1012,22 +998,22 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
||||
if (left_item) {
|
||||
show_error(error_str,
|
||||
"Open paren can not come after item");
|
||||
ret = PEVENT_ERRNO__INVALID_PAREN;
|
||||
ret = TEP_ERRNO__INVALID_PAREN;
|
||||
goto fail;
|
||||
}
|
||||
if (current_exp) {
|
||||
show_error(error_str,
|
||||
"Open paren can not come after expression");
|
||||
ret = PEVENT_ERRNO__INVALID_PAREN;
|
||||
ret = TEP_ERRNO__INVALID_PAREN;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = process_filter(event, &arg, error_str, 0);
|
||||
if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) {
|
||||
if (ret != TEP_ERRNO__UNBALANCED_PAREN) {
|
||||
if (ret == 0) {
|
||||
show_error(error_str,
|
||||
"Unbalanced number of '('");
|
||||
ret = PEVENT_ERRNO__UNBALANCED_PAREN;
|
||||
ret = TEP_ERRNO__UNBALANCED_PAREN;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
@ -1064,7 +1050,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
||||
else
|
||||
*parg = current_exp;
|
||||
free(token);
|
||||
return PEVENT_ERRNO__UNBALANCED_PAREN;
|
||||
return TEP_ERRNO__UNBALANCED_PAREN;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1091,7 +1077,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
||||
case OP_NONE:
|
||||
show_error(error_str,
|
||||
"Unknown op token %s", token);
|
||||
ret = PEVENT_ERRNO__UNKNOWN_TOKEN;
|
||||
ret = TEP_ERRNO__UNKNOWN_TOKEN;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -1179,11 +1165,11 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
||||
|
||||
fail_alloc:
|
||||
show_error(error_str, "failed to allocate filter arg");
|
||||
ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
ret = TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
goto fail;
|
||||
fail_syntax:
|
||||
show_error(error_str, "Syntax error");
|
||||
ret = PEVENT_ERRNO__SYNTAX_ERROR;
|
||||
ret = TEP_ERRNO__SYNTAX_ERROR;
|
||||
fail:
|
||||
free_arg(current_op);
|
||||
free_arg(current_exp);
|
||||
@ -1192,13 +1178,13 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum pevent_errno
|
||||
static enum tep_errno
|
||||
process_event(struct event_format *event, const char *filter_str,
|
||||
struct filter_arg **parg, char *error_str)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pevent_buffer_init(filter_str, strlen(filter_str));
|
||||
tep_buffer_init(filter_str, strlen(filter_str));
|
||||
|
||||
ret = process_filter(event, parg, error_str, 0);
|
||||
if (ret < 0)
|
||||
@ -1208,7 +1194,7 @@ process_event(struct event_format *event, const char *filter_str,
|
||||
if (!*parg) {
|
||||
*parg = allocate_arg();
|
||||
if (*parg == NULL)
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
|
||||
(*parg)->type = FILTER_ARG_BOOLEAN;
|
||||
(*parg)->boolean.value = FILTER_FALSE;
|
||||
@ -1217,13 +1203,13 @@ process_event(struct event_format *event, const char *filter_str,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum pevent_errno
|
||||
static enum tep_errno
|
||||
filter_event(struct event_filter *filter, struct event_format *event,
|
||||
const char *filter_str, char *error_str)
|
||||
{
|
||||
struct filter_type *filter_type;
|
||||
struct filter_arg *arg;
|
||||
enum pevent_errno ret;
|
||||
enum tep_errno ret;
|
||||
|
||||
if (filter_str) {
|
||||
ret = process_event(event, filter_str, &arg, error_str);
|
||||
@ -1234,7 +1220,7 @@ filter_event(struct event_filter *filter, struct event_format *event,
|
||||
/* just add a TRUE arg */
|
||||
arg = allocate_arg();
|
||||
if (arg == NULL)
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
|
||||
arg->type = FILTER_ARG_BOOLEAN;
|
||||
arg->boolean.value = FILTER_TRUE;
|
||||
@ -1242,7 +1228,7 @@ filter_event(struct event_filter *filter, struct event_format *event,
|
||||
|
||||
filter_type = add_filter_type(filter, event->id);
|
||||
if (filter_type == NULL)
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
|
||||
if (filter_type->filter)
|
||||
free_arg(filter_type->filter);
|
||||
@ -1254,23 +1240,23 @@ filter_event(struct event_filter *filter, struct event_format *event,
|
||||
static void filter_init_error_buf(struct event_filter *filter)
|
||||
{
|
||||
/* clear buffer to reset show error */
|
||||
pevent_buffer_init("", 0);
|
||||
tep_buffer_init("", 0);
|
||||
filter->error_buffer[0] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_add_filter_str - add a new filter
|
||||
* tep_filter_add_filter_str - add a new filter
|
||||
* @filter: the event filter to add to
|
||||
* @filter_str: the filter string that contains the filter
|
||||
*
|
||||
* Returns 0 if the filter was successfully added or a
|
||||
* negative error code. Use pevent_filter_strerror() to see
|
||||
* negative error code. Use tep_filter_strerror() to see
|
||||
* actual error message in case of error.
|
||||
*/
|
||||
enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
|
||||
const char *filter_str)
|
||||
enum tep_errno tep_filter_add_filter_str(struct event_filter *filter,
|
||||
const char *filter_str)
|
||||
{
|
||||
struct pevent *pevent = filter->pevent;
|
||||
struct tep_handle *pevent = filter->pevent;
|
||||
struct event_list *event;
|
||||
struct event_list *events = NULL;
|
||||
const char *filter_start;
|
||||
@ -1279,7 +1265,7 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
|
||||
char *event_name = NULL;
|
||||
char *sys_name = NULL;
|
||||
char *sp;
|
||||
enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */
|
||||
enum tep_errno rtn = 0; /* TEP_ERRNO__SUCCESS */
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
@ -1305,7 +1291,7 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
|
||||
if (this_event == NULL) {
|
||||
/* This can only happen when events is NULL, but still */
|
||||
free_events(events);
|
||||
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
return TEP_ERRNO__MEM_ALLOC_FAILED;
|
||||
}
|
||||
memcpy(this_event, filter_str, len);
|
||||
this_event[len] = 0;
|
||||
@ -1322,7 +1308,7 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
|
||||
/* This can only happen when events is NULL, but still */
|
||||
free_events(events);
|
||||
free(this_event);
|
||||
return PEVENT_ERRNO__FILTER_NOT_FOUND;
|
||||
return TEP_ERRNO__FILTER_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Find this event */
|
||||
@ -1349,7 +1335,7 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
|
||||
|
||||
if (ret >= 0 && pevent->test_filters) {
|
||||
char *test;
|
||||
test = pevent_filter_make_string(filter, event->event->id);
|
||||
test = tep_filter_make_string(filter, event->event->id);
|
||||
if (test) {
|
||||
printf(" '%s: %s'\n", event->event->name, test);
|
||||
free(test);
|
||||
@ -1371,7 +1357,7 @@ static void free_filter_type(struct filter_type *filter_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_strerror - fill error message in a buffer
|
||||
* tep_filter_strerror - fill error message in a buffer
|
||||
* @filter: the event filter contains error
|
||||
* @err: the error code
|
||||
* @buf: the buffer to be filled in
|
||||
@ -1379,10 +1365,10 @@ static void free_filter_type(struct filter_type *filter_type)
|
||||
*
|
||||
* Returns 0 if message was filled successfully, -1 if error
|
||||
*/
|
||||
int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
|
||||
char *buf, size_t buflen)
|
||||
int tep_filter_strerror(struct event_filter *filter, enum tep_errno err,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
if (err <= __PEVENT_ERRNO__START || err >= __PEVENT_ERRNO__END)
|
||||
if (err <= __TEP_ERRNO__START || err >= __TEP_ERRNO__END)
|
||||
return -1;
|
||||
|
||||
if (strlen(filter->error_buffer) > 0) {
|
||||
@ -1393,11 +1379,11 @@ int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pevent_strerror(filter->pevent, err, buf, buflen);
|
||||
return tep_strerror(filter->pevent, err, buf, buflen);
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_remove_event - remove a filter for an event
|
||||
* tep_filter_remove_event - remove a filter for an event
|
||||
* @filter: the event filter to remove from
|
||||
* @event_id: the event to remove a filter for
|
||||
*
|
||||
@ -1407,8 +1393,8 @@ int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
|
||||
* Returns 1: if an event was removed
|
||||
* 0: if the event was not found
|
||||
*/
|
||||
int pevent_filter_remove_event(struct event_filter *filter,
|
||||
int event_id)
|
||||
int tep_filter_remove_event(struct event_filter *filter,
|
||||
int event_id)
|
||||
{
|
||||
struct filter_type *filter_type;
|
||||
unsigned long len;
|
||||
@ -1437,12 +1423,12 @@ int pevent_filter_remove_event(struct event_filter *filter,
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_reset - clear all filters in a filter
|
||||
* tep_filter_reset - clear all filters in a filter
|
||||
* @filter: the event filter to reset
|
||||
*
|
||||
* Removes all filters from a filter and resets it.
|
||||
*/
|
||||
void pevent_filter_reset(struct event_filter *filter)
|
||||
void tep_filter_reset(struct event_filter *filter)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1454,11 +1440,11 @@ void pevent_filter_reset(struct event_filter *filter)
|
||||
filter->event_filters = NULL;
|
||||
}
|
||||
|
||||
void pevent_filter_free(struct event_filter *filter)
|
||||
void tep_filter_free(struct event_filter *filter)
|
||||
{
|
||||
pevent_unref(filter->pevent);
|
||||
tep_unref(filter->pevent);
|
||||
|
||||
pevent_filter_reset(filter);
|
||||
tep_filter_reset(filter);
|
||||
|
||||
free(filter);
|
||||
}
|
||||
@ -1478,7 +1464,7 @@ static int copy_filter_type(struct event_filter *filter,
|
||||
/* Can't assume that the pevent's are the same */
|
||||
sys = filter_type->event->system;
|
||||
name = filter_type->event->name;
|
||||
event = pevent_find_event_by_name(filter->pevent, sys, name);
|
||||
event = tep_find_event_by_name(filter->pevent, sys, name);
|
||||
if (!event)
|
||||
return -1;
|
||||
|
||||
@ -1515,18 +1501,18 @@ static int copy_filter_type(struct event_filter *filter,
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_copy - copy a filter using another filter
|
||||
* tep_filter_copy - copy a filter using another filter
|
||||
* @dest - the filter to copy to
|
||||
* @source - the filter to copy from
|
||||
*
|
||||
* Returns 0 on success and -1 if not all filters were copied
|
||||
*/
|
||||
int pevent_filter_copy(struct event_filter *dest, struct event_filter *source)
|
||||
int tep_filter_copy(struct event_filter *dest, struct event_filter *source)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
pevent_filter_reset(dest);
|
||||
tep_filter_reset(dest);
|
||||
|
||||
for (i = 0; i < source->filters; i++) {
|
||||
if (copy_filter_type(dest, source, &source->event_filters[i]))
|
||||
@ -1537,7 +1523,7 @@ int pevent_filter_copy(struct event_filter *dest, struct event_filter *source)
|
||||
|
||||
|
||||
/**
|
||||
* pevent_update_trivial - update the trivial filters with the given filter
|
||||
* tep_update_trivial - update the trivial filters with the given filter
|
||||
* @dest - the filter to update
|
||||
* @source - the filter as the source of the update
|
||||
* @type - the type of trivial filter to update.
|
||||
@ -1547,11 +1533,11 @@ int pevent_filter_copy(struct event_filter *dest, struct event_filter *source)
|
||||
* Returns 0 on success and -1 if there was a problem updating, but
|
||||
* events may have still been updated on error.
|
||||
*/
|
||||
int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
|
||||
enum filter_trivial_type type)
|
||||
int tep_update_trivial(struct event_filter *dest, struct event_filter *source,
|
||||
enum filter_trivial_type type)
|
||||
{
|
||||
struct pevent *src_pevent;
|
||||
struct pevent *dest_pevent;
|
||||
struct tep_handle *src_pevent;
|
||||
struct tep_handle *dest_pevent;
|
||||
struct event_format *event;
|
||||
struct filter_type *filter_type;
|
||||
struct filter_arg *arg;
|
||||
@ -1578,14 +1564,14 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source
|
||||
|
||||
if (src_pevent != dest_pevent) {
|
||||
/* do a look up */
|
||||
event = pevent_find_event_by_name(src_pevent,
|
||||
event->system,
|
||||
event->name);
|
||||
event = tep_find_event_by_name(src_pevent,
|
||||
event->system,
|
||||
event->name);
|
||||
if (!event)
|
||||
return -1;
|
||||
}
|
||||
|
||||
str = pevent_filter_make_string(source, event->id);
|
||||
str = tep_filter_make_string(source, event->id);
|
||||
if (!str)
|
||||
continue;
|
||||
|
||||
@ -1598,7 +1584,7 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_clear_trivial - clear TRUE and FALSE filters
|
||||
* tep_filter_clear_trivial - clear TRUE and FALSE filters
|
||||
* @filter: the filter to remove trivial filters from
|
||||
* @type: remove only true, false, or both
|
||||
*
|
||||
@ -1606,8 +1592,8 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source
|
||||
*
|
||||
* Returns 0 on success and -1 if there was a problem.
|
||||
*/
|
||||
int pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
enum filter_trivial_type type)
|
||||
int tep_filter_clear_trivial(struct event_filter *filter,
|
||||
enum filter_trivial_type type)
|
||||
{
|
||||
struct filter_type *filter_type;
|
||||
int count = 0;
|
||||
@ -1653,14 +1639,14 @@ int pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
pevent_filter_remove_event(filter, ids[i]);
|
||||
tep_filter_remove_event(filter, ids[i]);
|
||||
|
||||
free(ids);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_event_has_trivial - return true event contains trivial filter
|
||||
* tep_filter_event_has_trivial - return true event contains trivial filter
|
||||
* @filter: the filter with the information
|
||||
* @event_id: the id of the event to test
|
||||
* @type: trivial type to test for (TRUE, FALSE, EITHER)
|
||||
@ -1668,9 +1654,9 @@ int pevent_filter_clear_trivial(struct event_filter *filter,
|
||||
* Returns 1 if the event contains a matching trivial type
|
||||
* otherwise 0.
|
||||
*/
|
||||
int pevent_filter_event_has_trivial(struct event_filter *filter,
|
||||
int event_id,
|
||||
enum filter_trivial_type type)
|
||||
int tep_filter_event_has_trivial(struct event_filter *filter,
|
||||
int event_id,
|
||||
enum filter_trivial_type type)
|
||||
{
|
||||
struct filter_type *filter_type;
|
||||
|
||||
@ -1697,22 +1683,22 @@ int pevent_filter_event_has_trivial(struct event_filter *filter,
|
||||
}
|
||||
|
||||
static int test_filter(struct event_format *event, struct filter_arg *arg,
|
||||
struct pevent_record *record, enum pevent_errno *err);
|
||||
struct tep_record *record, enum tep_errno *err);
|
||||
|
||||
static const char *
|
||||
get_comm(struct event_format *event, struct pevent_record *record)
|
||||
get_comm(struct event_format *event, struct tep_record *record)
|
||||
{
|
||||
const char *comm;
|
||||
int pid;
|
||||
|
||||
pid = pevent_data_pid(event->pevent, record);
|
||||
comm = pevent_data_comm_from_pid(event->pevent, pid);
|
||||
pid = tep_data_pid(event->pevent, record);
|
||||
comm = tep_data_comm_from_pid(event->pevent, pid);
|
||||
return comm;
|
||||
}
|
||||
|
||||
static unsigned long long
|
||||
get_value(struct event_format *event,
|
||||
struct format_field *field, struct pevent_record *record)
|
||||
struct format_field *field, struct tep_record *record)
|
||||
{
|
||||
unsigned long long val;
|
||||
|
||||
@ -1728,7 +1714,7 @@ get_value(struct event_format *event,
|
||||
if (field == &cpu)
|
||||
return record->cpu;
|
||||
|
||||
pevent_read_number_field(field, record->data, &val);
|
||||
tep_read_number_field(field, record->data, &val);
|
||||
|
||||
if (!(field->flags & FIELD_IS_SIGNED))
|
||||
return val;
|
||||
@ -1748,11 +1734,11 @@ get_value(struct event_format *event,
|
||||
|
||||
static unsigned long long
|
||||
get_arg_value(struct event_format *event, struct filter_arg *arg,
|
||||
struct pevent_record *record, enum pevent_errno *err);
|
||||
struct tep_record *record, enum tep_errno *err);
|
||||
|
||||
static unsigned long long
|
||||
get_exp_value(struct event_format *event, struct filter_arg *arg,
|
||||
struct pevent_record *record, enum pevent_errno *err)
|
||||
struct tep_record *record, enum tep_errno *err)
|
||||
{
|
||||
unsigned long long lval, rval;
|
||||
|
||||
@ -1800,14 +1786,14 @@ get_exp_value(struct event_format *event, struct filter_arg *arg,
|
||||
case FILTER_EXP_NOT:
|
||||
default:
|
||||
if (!*err)
|
||||
*err = PEVENT_ERRNO__INVALID_EXP_TYPE;
|
||||
*err = TEP_ERRNO__INVALID_EXP_TYPE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long long
|
||||
get_arg_value(struct event_format *event, struct filter_arg *arg,
|
||||
struct pevent_record *record, enum pevent_errno *err)
|
||||
struct tep_record *record, enum tep_errno *err)
|
||||
{
|
||||
switch (arg->type) {
|
||||
case FILTER_ARG_FIELD:
|
||||
@ -1816,7 +1802,7 @@ get_arg_value(struct event_format *event, struct filter_arg *arg,
|
||||
case FILTER_ARG_VALUE:
|
||||
if (arg->value.type != FILTER_NUMBER) {
|
||||
if (!*err)
|
||||
*err = PEVENT_ERRNO__NOT_A_NUMBER;
|
||||
*err = TEP_ERRNO__NOT_A_NUMBER;
|
||||
}
|
||||
return arg->value.val;
|
||||
|
||||
@ -1825,13 +1811,13 @@ get_arg_value(struct event_format *event, struct filter_arg *arg,
|
||||
|
||||
default:
|
||||
if (!*err)
|
||||
*err = PEVENT_ERRNO__INVALID_ARG_TYPE;
|
||||
*err = TEP_ERRNO__INVALID_ARG_TYPE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_num(struct event_format *event, struct filter_arg *arg,
|
||||
struct pevent_record *record, enum pevent_errno *err)
|
||||
struct tep_record *record, enum tep_errno *err)
|
||||
{
|
||||
unsigned long long lval, rval;
|
||||
|
||||
@ -1866,15 +1852,15 @@ static int test_num(struct event_format *event, struct filter_arg *arg,
|
||||
|
||||
default:
|
||||
if (!*err)
|
||||
*err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
|
||||
*err = TEP_ERRNO__ILLEGAL_INTEGER_CMP;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record)
|
||||
static const char *get_field_str(struct filter_arg *arg, struct tep_record *record)
|
||||
{
|
||||
struct event_format *event;
|
||||
struct pevent *pevent;
|
||||
struct tep_handle *pevent;
|
||||
unsigned long long addr;
|
||||
const char *val = NULL;
|
||||
unsigned int size;
|
||||
@ -1909,7 +1895,7 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r
|
||||
|
||||
if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG))
|
||||
/* convert to a kernel symbol */
|
||||
val = pevent_find_function(pevent, addr);
|
||||
val = tep_find_function(pevent, addr);
|
||||
|
||||
if (val == NULL) {
|
||||
/* just use the hex of the string name */
|
||||
@ -1922,7 +1908,7 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r
|
||||
}
|
||||
|
||||
static int test_str(struct event_format *event, struct filter_arg *arg,
|
||||
struct pevent_record *record, enum pevent_errno *err)
|
||||
struct tep_record *record, enum tep_errno *err)
|
||||
{
|
||||
const char *val;
|
||||
|
||||
@ -1947,13 +1933,13 @@ static int test_str(struct event_format *event, struct filter_arg *arg,
|
||||
|
||||
default:
|
||||
if (!*err)
|
||||
*err = PEVENT_ERRNO__ILLEGAL_STRING_CMP;
|
||||
*err = TEP_ERRNO__ILLEGAL_STRING_CMP;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int test_op(struct event_format *event, struct filter_arg *arg,
|
||||
struct pevent_record *record, enum pevent_errno *err)
|
||||
struct tep_record *record, enum tep_errno *err)
|
||||
{
|
||||
switch (arg->op.type) {
|
||||
case FILTER_OP_AND:
|
||||
@ -1969,13 +1955,13 @@ static int test_op(struct event_format *event, struct filter_arg *arg,
|
||||
|
||||
default:
|
||||
if (!*err)
|
||||
*err = PEVENT_ERRNO__INVALID_OP_TYPE;
|
||||
*err = TEP_ERRNO__INVALID_OP_TYPE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int test_filter(struct event_format *event, struct filter_arg *arg,
|
||||
struct pevent_record *record, enum pevent_errno *err)
|
||||
struct tep_record *record, enum tep_errno *err)
|
||||
{
|
||||
if (*err) {
|
||||
/*
|
||||
@ -2009,20 +1995,20 @@ static int test_filter(struct event_format *event, struct filter_arg *arg,
|
||||
|
||||
default:
|
||||
if (!*err)
|
||||
*err = PEVENT_ERRNO__INVALID_ARG_TYPE;
|
||||
*err = TEP_ERRNO__INVALID_ARG_TYPE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_event_filtered - return true if event has filter
|
||||
* tep_event_filtered - return true if event has filter
|
||||
* @filter: filter struct with filter information
|
||||
* @event_id: event id to test if filter exists
|
||||
*
|
||||
* Returns 1 if filter found for @event_id
|
||||
* otherwise 0;
|
||||
*/
|
||||
int pevent_event_filtered(struct event_filter *filter, int event_id)
|
||||
int tep_event_filtered(struct event_filter *filter, int event_id)
|
||||
{
|
||||
struct filter_type *filter_type;
|
||||
|
||||
@ -2035,42 +2021,42 @@ int pevent_event_filtered(struct event_filter *filter, int event_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_match - test if a record matches a filter
|
||||
* tep_filter_match - test if a record matches a filter
|
||||
* @filter: filter struct with filter information
|
||||
* @record: the record to test against the filter
|
||||
*
|
||||
* Returns: match result or error code (prefixed with PEVENT_ERRNO__)
|
||||
* Returns: match result or error code (prefixed with TEP_ERRNO__)
|
||||
* FILTER_MATCH - filter found for event and @record matches
|
||||
* FILTER_MISS - filter found for event and @record does not match
|
||||
* FILTER_NOT_FOUND - no filter found for @record's event
|
||||
* NO_FILTER - if no filters exist
|
||||
* otherwise - error occurred during test
|
||||
*/
|
||||
enum pevent_errno pevent_filter_match(struct event_filter *filter,
|
||||
struct pevent_record *record)
|
||||
enum tep_errno tep_filter_match(struct event_filter *filter,
|
||||
struct tep_record *record)
|
||||
{
|
||||
struct pevent *pevent = filter->pevent;
|
||||
struct tep_handle *pevent = filter->pevent;
|
||||
struct filter_type *filter_type;
|
||||
int event_id;
|
||||
int ret;
|
||||
enum pevent_errno err = 0;
|
||||
enum tep_errno err = 0;
|
||||
|
||||
filter_init_error_buf(filter);
|
||||
|
||||
if (!filter->filters)
|
||||
return PEVENT_ERRNO__NO_FILTER;
|
||||
return TEP_ERRNO__NO_FILTER;
|
||||
|
||||
event_id = pevent_data_type(pevent, record);
|
||||
event_id = tep_data_type(pevent, record);
|
||||
|
||||
filter_type = find_filter_type(filter, event_id);
|
||||
if (!filter_type)
|
||||
return PEVENT_ERRNO__FILTER_NOT_FOUND;
|
||||
return TEP_ERRNO__FILTER_NOT_FOUND;
|
||||
|
||||
ret = test_filter(filter_type->event, filter_type->filter, record, &err);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS;
|
||||
return ret ? TEP_ERRNO__FILTER_MATCH : TEP_ERRNO__FILTER_MISS;
|
||||
}
|
||||
|
||||
static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||
@ -2364,7 +2350,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_make_string - return a string showing the filter
|
||||
* tep_filter_make_string - return a string showing the filter
|
||||
* @filter: filter struct with filter information
|
||||
* @event_id: the event id to return the filter string with
|
||||
*
|
||||
@ -2373,7 +2359,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||
* NULL is returned if no filter is found or allocation failed.
|
||||
*/
|
||||
char *
|
||||
pevent_filter_make_string(struct event_filter *filter, int event_id)
|
||||
tep_filter_make_string(struct event_filter *filter, int event_id)
|
||||
{
|
||||
struct filter_type *filter_type;
|
||||
|
||||
@ -2389,7 +2375,7 @@ pevent_filter_make_string(struct event_filter *filter, int event_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_filter_compare - compare two filters and return if they are the same
|
||||
* tep_filter_compare - compare two filters and return if they are the same
|
||||
* @filter1: Filter to compare with @filter2
|
||||
* @filter2: Filter to compare with @filter1
|
||||
*
|
||||
@ -2397,7 +2383,7 @@ pevent_filter_make_string(struct event_filter *filter, int event_id)
|
||||
* 1 if the two filters hold the same content.
|
||||
* 0 if they do not.
|
||||
*/
|
||||
int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2)
|
||||
int tep_filter_compare(struct event_filter *filter1, struct event_filter *filter2)
|
||||
{
|
||||
struct filter_type *filter_type1;
|
||||
struct filter_type *filter_type2;
|
||||
|
@ -1,21 +1,7 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License (not later!)
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, see <http://www.gnu.org/licenses>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -25,19 +25,19 @@ process___le16_to_cpup(struct trace_seq *s, unsigned long long *args)
|
||||
return val ? (long long) le16toh(*val) : 0;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_register_print_function(pevent,
|
||||
process___le16_to_cpup,
|
||||
PEVENT_FUNC_ARG_INT,
|
||||
"__le16_to_cpup",
|
||||
PEVENT_FUNC_ARG_PTR,
|
||||
PEVENT_FUNC_ARG_VOID);
|
||||
tep_register_print_function(pevent,
|
||||
process___le16_to_cpup,
|
||||
TEP_FUNC_ARG_INT,
|
||||
"__le16_to_cpup",
|
||||
TEP_FUNC_ARG_PTR,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_unregister_print_function(pevent, process___le16_to_cpup,
|
||||
"__le16_to_cpup");
|
||||
tep_unregister_print_function(pevent, process___le16_to_cpup,
|
||||
"__le16_to_cpup");
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ static int cpus = -1;
|
||||
|
||||
#define STK_BLK 10
|
||||
|
||||
struct pevent_plugin_option plugin_options[] =
|
||||
struct tep_plugin_option plugin_options[] =
|
||||
{
|
||||
{
|
||||
.name = "parent",
|
||||
@ -53,8 +53,8 @@ struct pevent_plugin_option plugin_options[] =
|
||||
}
|
||||
};
|
||||
|
||||
static struct pevent_plugin_option *ftrace_parent = &plugin_options[0];
|
||||
static struct pevent_plugin_option *ftrace_indent = &plugin_options[1];
|
||||
static struct tep_plugin_option *ftrace_parent = &plugin_options[0];
|
||||
static struct tep_plugin_option *ftrace_indent = &plugin_options[1];
|
||||
|
||||
static void add_child(struct func_stack *stack, const char *child, int pos)
|
||||
{
|
||||
@ -122,25 +122,25 @@ static int add_and_get_index(const char *parent, const char *child, int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int function_handler(struct trace_seq *s, struct pevent_record *record,
|
||||
static int function_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
struct pevent *pevent = event->pevent;
|
||||
struct tep_handle *pevent = event->pevent;
|
||||
unsigned long long function;
|
||||
unsigned long long pfunction;
|
||||
const char *func;
|
||||
const char *parent;
|
||||
int index = 0;
|
||||
|
||||
if (pevent_get_field_val(s, event, "ip", record, &function, 1))
|
||||
if (tep_get_field_val(s, event, "ip", record, &function, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
func = pevent_find_function(pevent, function);
|
||||
func = tep_find_function(pevent, function);
|
||||
|
||||
if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
|
||||
if (tep_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
parent = pevent_find_function(pevent, pfunction);
|
||||
parent = tep_find_function(pevent, pfunction);
|
||||
|
||||
if (parent && ftrace_indent->set)
|
||||
index = add_and_get_index(parent, func, record->cpu);
|
||||
@ -163,22 +163,22 @@ static int function_handler(struct trace_seq *s, struct pevent_record *record,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_register_event_handler(pevent, -1, "ftrace", "function",
|
||||
function_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "ftrace", "function",
|
||||
function_handler, NULL);
|
||||
|
||||
traceevent_plugin_add_options("ftrace", plugin_options);
|
||||
tep_plugin_add_options("ftrace", plugin_options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
int i, x;
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "ftrace", "function",
|
||||
function_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "ftrace", "function",
|
||||
function_handler, NULL);
|
||||
|
||||
for (i = 0; i <= cpus; i++) {
|
||||
for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
|
||||
@ -186,7 +186,7 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
free(fstack[i].stack);
|
||||
}
|
||||
|
||||
traceevent_plugin_remove_options(plugin_options);
|
||||
tep_plugin_remove_options(plugin_options);
|
||||
|
||||
free(fstack);
|
||||
fstack = NULL;
|
||||
|
@ -25,64 +25,64 @@
|
||||
#include "event-parse.h"
|
||||
|
||||
static int timer_expire_handler(struct trace_seq *s,
|
||||
struct pevent_record *record,
|
||||
struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
trace_seq_printf(s, "hrtimer=");
|
||||
|
||||
if (pevent_print_num_field(s, "0x%llx", event, "timer",
|
||||
record, 0) == -1)
|
||||
pevent_print_num_field(s, "0x%llx", event, "hrtimer",
|
||||
record, 1);
|
||||
if (tep_print_num_field(s, "0x%llx", event, "timer",
|
||||
record, 0) == -1)
|
||||
tep_print_num_field(s, "0x%llx", event, "hrtimer",
|
||||
record, 1);
|
||||
|
||||
trace_seq_printf(s, " now=");
|
||||
|
||||
pevent_print_num_field(s, "%llu", event, "now", record, 1);
|
||||
tep_print_num_field(s, "%llu", event, "now", record, 1);
|
||||
|
||||
pevent_print_func_field(s, " function=%s", event, "function",
|
||||
tep_print_func_field(s, " function=%s", event, "function",
|
||||
record, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timer_start_handler(struct trace_seq *s,
|
||||
struct pevent_record *record,
|
||||
struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
trace_seq_printf(s, "hrtimer=");
|
||||
|
||||
if (pevent_print_num_field(s, "0x%llx", event, "timer",
|
||||
record, 0) == -1)
|
||||
pevent_print_num_field(s, "0x%llx", event, "hrtimer",
|
||||
record, 1);
|
||||
if (tep_print_num_field(s, "0x%llx", event, "timer",
|
||||
record, 0) == -1)
|
||||
tep_print_num_field(s, "0x%llx", event, "hrtimer",
|
||||
record, 1);
|
||||
|
||||
pevent_print_func_field(s, " function=%s", event, "function",
|
||||
record, 0);
|
||||
tep_print_func_field(s, " function=%s", event, "function",
|
||||
record, 0);
|
||||
|
||||
trace_seq_printf(s, " expires=");
|
||||
pevent_print_num_field(s, "%llu", event, "expires", record, 1);
|
||||
tep_print_num_field(s, "%llu", event, "expires", record, 1);
|
||||
|
||||
trace_seq_printf(s, " softexpires=");
|
||||
pevent_print_num_field(s, "%llu", event, "softexpires", record, 1);
|
||||
tep_print_num_field(s, "%llu", event, "softexpires", record, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_register_event_handler(pevent, -1,
|
||||
"timer", "hrtimer_expire_entry",
|
||||
timer_expire_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1,
|
||||
"timer", "hrtimer_expire_entry",
|
||||
timer_expire_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start",
|
||||
timer_start_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "timer", "hrtimer_start",
|
||||
timer_start_handler, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_unregister_event_handler(pevent, -1,
|
||||
"timer", "hrtimer_expire_entry",
|
||||
timer_expire_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1,
|
||||
"timer", "hrtimer_expire_entry",
|
||||
timer_expire_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start",
|
||||
timer_start_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "timer", "hrtimer_start",
|
||||
timer_start_handler, NULL);
|
||||
}
|
||||
|
@ -47,29 +47,29 @@ process_jiffies_to_msecs(struct trace_seq *s, unsigned long long *args)
|
||||
return jiffies;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_register_print_function(pevent,
|
||||
process_jbd2_dev_to_name,
|
||||
PEVENT_FUNC_ARG_STRING,
|
||||
"jbd2_dev_to_name",
|
||||
PEVENT_FUNC_ARG_INT,
|
||||
PEVENT_FUNC_ARG_VOID);
|
||||
tep_register_print_function(pevent,
|
||||
process_jbd2_dev_to_name,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
"jbd2_dev_to_name",
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
|
||||
pevent_register_print_function(pevent,
|
||||
process_jiffies_to_msecs,
|
||||
PEVENT_FUNC_ARG_LONG,
|
||||
"jiffies_to_msecs",
|
||||
PEVENT_FUNC_ARG_LONG,
|
||||
PEVENT_FUNC_ARG_VOID);
|
||||
tep_register_print_function(pevent,
|
||||
process_jiffies_to_msecs,
|
||||
TEP_FUNC_ARG_LONG,
|
||||
"jiffies_to_msecs",
|
||||
TEP_FUNC_ARG_LONG,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_unregister_print_function(pevent, process_jbd2_dev_to_name,
|
||||
"jbd2_dev_to_name");
|
||||
tep_unregister_print_function(pevent, process_jbd2_dev_to_name,
|
||||
"jbd2_dev_to_name");
|
||||
|
||||
pevent_unregister_print_function(pevent, process_jiffies_to_msecs,
|
||||
"jiffies_to_msecs");
|
||||
tep_unregister_print_function(pevent, process_jiffies_to_msecs,
|
||||
"jiffies_to_msecs");
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#include "event-parse.h"
|
||||
|
||||
static int call_site_handler(struct trace_seq *s, struct pevent_record *record,
|
||||
static int call_site_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
struct format_field *field;
|
||||
@ -31,64 +31,64 @@ static int call_site_handler(struct trace_seq *s, struct pevent_record *record,
|
||||
void *data = record->data;
|
||||
const char *func;
|
||||
|
||||
field = pevent_find_field(event, "call_site");
|
||||
field = tep_find_field(event, "call_site");
|
||||
if (!field)
|
||||
return 1;
|
||||
|
||||
if (pevent_read_number_field(field, data, &val))
|
||||
if (tep_read_number_field(field, data, &val))
|
||||
return 1;
|
||||
|
||||
func = pevent_find_function(event->pevent, val);
|
||||
func = tep_find_function(event->pevent, val);
|
||||
if (!func)
|
||||
return 1;
|
||||
|
||||
addr = pevent_find_function_address(event->pevent, val);
|
||||
addr = tep_find_function_address(event->pevent, val);
|
||||
|
||||
trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_register_event_handler(pevent, -1, "kmem", "kfree",
|
||||
call_site_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kmem", "kfree",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kmem", "kmalloc",
|
||||
call_site_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kmem", "kmalloc",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node",
|
||||
call_site_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kmem", "kmalloc_node",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
|
||||
call_site_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kmem",
|
||||
"kmem_cache_alloc_node",
|
||||
call_site_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kmem",
|
||||
"kmem_cache_alloc_node",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free",
|
||||
call_site_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_free",
|
||||
call_site_handler, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_unregister_event_handler(pevent, -1, "kmem", "kfree",
|
||||
call_site_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kmem", "kfree",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc",
|
||||
call_site_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node",
|
||||
call_site_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
|
||||
call_site_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kmem",
|
||||
"kmem_cache_alloc_node",
|
||||
call_site_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kmem",
|
||||
"kmem_cache_alloc_node",
|
||||
call_site_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free",
|
||||
call_site_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free",
|
||||
call_site_handler, NULL);
|
||||
}
|
||||
|
@ -247,17 +247,17 @@ static const char *find_exit_reason(unsigned isa, int val)
|
||||
return strings[i].str;
|
||||
}
|
||||
|
||||
static int print_exit_reason(struct trace_seq *s, struct pevent_record *record,
|
||||
static int print_exit_reason(struct trace_seq *s, struct tep_record *record,
|
||||
struct event_format *event, const char *field)
|
||||
{
|
||||
unsigned long long isa;
|
||||
unsigned long long val;
|
||||
const char *reason;
|
||||
|
||||
if (pevent_get_field_val(s, event, field, record, &val, 1) < 0)
|
||||
if (tep_get_field_val(s, event, field, record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0)
|
||||
if (tep_get_field_val(s, event, "isa", record, &isa, 0) < 0)
|
||||
isa = 1;
|
||||
|
||||
reason = find_exit_reason(isa, val);
|
||||
@ -268,7 +268,7 @@ static int print_exit_reason(struct trace_seq *s, struct pevent_record *record,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record,
|
||||
static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
unsigned long long info1 = 0, info2 = 0;
|
||||
@ -276,10 +276,10 @@ static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record,
|
||||
if (print_exit_reason(s, record, event, "exit_reason") < 0)
|
||||
return -1;
|
||||
|
||||
pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
|
||||
tep_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
|
||||
|
||||
if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0
|
||||
&& pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
|
||||
if (tep_get_field_val(s, event, "info1", record, &info1, 0) >= 0
|
||||
&& tep_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
|
||||
trace_seq_printf(s, " info %llx %llx", info1, info2);
|
||||
|
||||
return 0;
|
||||
@ -291,7 +291,7 @@ static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record,
|
||||
#define KVM_EMUL_INSN_F_CS_L (1 << 3)
|
||||
|
||||
static int kvm_emulate_insn_handler(struct trace_seq *s,
|
||||
struct pevent_record *record,
|
||||
struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
unsigned long long rip, csbase, len, flags, failed;
|
||||
@ -299,22 +299,22 @@ static int kvm_emulate_insn_handler(struct trace_seq *s,
|
||||
uint8_t *insn;
|
||||
const char *disasm;
|
||||
|
||||
if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0)
|
||||
if (tep_get_field_val(s, event, "rip", record, &rip, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
|
||||
if (tep_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0)
|
||||
if (tep_get_field_val(s, event, "len", record, &len, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0)
|
||||
if (tep_get_field_val(s, event, "flags", record, &flags, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0)
|
||||
if (tep_get_field_val(s, event, "failed", record, &failed, 1) < 0)
|
||||
return -1;
|
||||
|
||||
insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1);
|
||||
insn = tep_get_field_raw(s, event, "insn", record, &llen, 1);
|
||||
if (!insn)
|
||||
return -1;
|
||||
|
||||
@ -330,24 +330,24 @@ static int kvm_emulate_insn_handler(struct trace_seq *s,
|
||||
}
|
||||
|
||||
|
||||
static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct pevent_record *record,
|
||||
static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
if (print_exit_reason(s, record, event, "exit_code") < 0)
|
||||
return -1;
|
||||
|
||||
pevent_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1);
|
||||
pevent_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1);
|
||||
pevent_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1);
|
||||
pevent_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1);
|
||||
tep_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1);
|
||||
tep_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1);
|
||||
tep_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1);
|
||||
tep_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_nested_vmexit_handler(struct trace_seq *s, struct pevent_record *record,
|
||||
static int kvm_nested_vmexit_handler(struct trace_seq *s, struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
pevent_print_num_field(s, "rip %llx ", event, "rip", record, 1);
|
||||
tep_print_num_field(s, "rip %llx ", event, "rip", record, 1);
|
||||
|
||||
return kvm_nested_vmexit_inject_handler(s, record, event, context);
|
||||
}
|
||||
@ -370,7 +370,7 @@ union kvm_mmu_page_role {
|
||||
};
|
||||
};
|
||||
|
||||
static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
|
||||
static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
unsigned long long val;
|
||||
@ -379,7 +379,7 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
|
||||
};
|
||||
union kvm_mmu_page_role role;
|
||||
|
||||
if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0)
|
||||
if (tep_get_field_val(s, event, "role", record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
role.word = (int)val;
|
||||
@ -388,8 +388,8 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
|
||||
* We can only use the structure if file is of the same
|
||||
* endianess.
|
||||
*/
|
||||
if (pevent_is_file_bigendian(event->pevent) ==
|
||||
pevent_is_host_bigendian(event->pevent)) {
|
||||
if (tep_is_file_bigendian(event->pevent) ==
|
||||
tep_is_host_bigendian(event->pevent)) {
|
||||
|
||||
trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s",
|
||||
role.level,
|
||||
@ -406,10 +406,10 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
|
||||
} else
|
||||
trace_seq_printf(s, "WORD: %08x", role.word);
|
||||
|
||||
pevent_print_num_field(s, " root %u ", event,
|
||||
"root_count", record, 1);
|
||||
tep_print_num_field(s, " root %u ", event,
|
||||
"root_count", record, 1);
|
||||
|
||||
if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0)
|
||||
if (tep_get_field_val(s, event, "unsync", record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0);
|
||||
@ -417,17 +417,17 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
|
||||
}
|
||||
|
||||
static int kvm_mmu_get_page_handler(struct trace_seq *s,
|
||||
struct pevent_record *record,
|
||||
struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
unsigned long long val;
|
||||
|
||||
if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0)
|
||||
if (tep_get_field_val(s, event, "created", record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
trace_seq_printf(s, "%s ", val ? "new" : "existing");
|
||||
|
||||
if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0)
|
||||
if (tep_get_field_val(s, event, "gfn", record, &val, 1) < 0)
|
||||
return -1;
|
||||
|
||||
trace_seq_printf(s, "sp gfn %llx ", val);
|
||||
@ -444,79 +444,79 @@ process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
|
||||
return pte & PT_WRITABLE_MASK;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
init_disassembler();
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit",
|
||||
kvm_exit_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kvm", "kvm_exit",
|
||||
kvm_exit_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
|
||||
kvm_emulate_insn_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
|
||||
kvm_emulate_insn_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
|
||||
kvm_nested_vmexit_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
|
||||
kvm_nested_vmexit_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
|
||||
kvm_nested_vmexit_inject_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
|
||||
kvm_nested_vmexit_inject_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
|
||||
kvm_mmu_get_page_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
|
||||
kvm_mmu_get_page_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1,
|
||||
"kvmmmu", "kvm_mmu_unsync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
tep_register_event_handler(pevent, -1,
|
||||
"kvmmmu", "kvm_mmu_unsync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "kvmmmu",
|
||||
tep_register_event_handler(pevent, -1, "kvmmmu",
|
||||
"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
|
||||
NULL);
|
||||
|
||||
pevent_register_print_function(pevent,
|
||||
process_is_writable_pte,
|
||||
PEVENT_FUNC_ARG_INT,
|
||||
"is_writable_pte",
|
||||
PEVENT_FUNC_ARG_LONG,
|
||||
PEVENT_FUNC_ARG_VOID);
|
||||
tep_register_print_function(pevent,
|
||||
process_is_writable_pte,
|
||||
TEP_FUNC_ARG_INT,
|
||||
"is_writable_pte",
|
||||
TEP_FUNC_ARG_LONG,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit",
|
||||
kvm_exit_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kvm", "kvm_exit",
|
||||
kvm_exit_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
|
||||
kvm_emulate_insn_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
|
||||
kvm_emulate_insn_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
|
||||
kvm_nested_vmexit_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
|
||||
kvm_nested_vmexit_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
|
||||
kvm_nested_vmexit_inject_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
|
||||
kvm_nested_vmexit_inject_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
|
||||
kvm_mmu_get_page_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
|
||||
kvm_mmu_get_page_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1,
|
||||
"kvmmmu", "kvm_mmu_unsync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
tep_unregister_event_handler(pevent, -1,
|
||||
"kvmmmu", "kvm_mmu_unsync_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
|
||||
kvm_mmu_print_role, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "kvmmmu",
|
||||
tep_unregister_event_handler(pevent, -1, "kvmmmu",
|
||||
"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
|
||||
NULL);
|
||||
|
||||
pevent_unregister_print_function(pevent, process_is_writable_pte,
|
||||
"is_writable_pte");
|
||||
tep_unregister_print_function(pevent, process_is_writable_pte,
|
||||
"is_writable_pte");
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
static void print_string(struct trace_seq *s, struct event_format *event,
|
||||
const char *name, const void *data)
|
||||
{
|
||||
struct format_field *f = pevent_find_field(event, name);
|
||||
struct format_field *f = tep_find_field(event, name);
|
||||
int offset;
|
||||
int length;
|
||||
|
||||
@ -42,7 +42,7 @@ static void print_string(struct trace_seq *s, struct event_format *event,
|
||||
|
||||
if (!strncmp(f->type, "__data_loc", 10)) {
|
||||
unsigned long long v;
|
||||
if (pevent_read_number_field(f, data, &v)) {
|
||||
if (tep_read_number_field(f, data, &v)) {
|
||||
trace_seq_printf(s, "invalid_data_loc");
|
||||
return;
|
||||
}
|
||||
@ -53,12 +53,12 @@ static void print_string(struct trace_seq *s, struct event_format *event,
|
||||
trace_seq_printf(s, "%.*s", length, (char *)data + offset);
|
||||
}
|
||||
|
||||
#define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0)
|
||||
#define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0)
|
||||
#define SF(fn) tep_print_num_field(s, fn ":%d", event, fn, record, 0)
|
||||
#define SFX(fn) tep_print_num_field(s, fn ":%#x", event, fn, record, 0)
|
||||
#define SP() trace_seq_putc(s, ' ')
|
||||
|
||||
static int drv_bss_info_changed(struct trace_seq *s,
|
||||
struct pevent_record *record,
|
||||
struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
void *data = record->data;
|
||||
@ -66,7 +66,7 @@ static int drv_bss_info_changed(struct trace_seq *s,
|
||||
print_string(s, event, "wiphy_name", data);
|
||||
trace_seq_printf(s, " vif:");
|
||||
print_string(s, event, "vif_name", data);
|
||||
pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1);
|
||||
tep_print_num_field(s, "(%d)", event, "vif_type", record, 1);
|
||||
|
||||
trace_seq_printf(s, "\n%*s", INDENT, "");
|
||||
SF("assoc"); SP();
|
||||
@ -86,17 +86,17 @@ static int drv_bss_info_changed(struct trace_seq *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_register_event_handler(pevent, -1, "mac80211",
|
||||
"drv_bss_info_changed",
|
||||
drv_bss_info_changed, NULL);
|
||||
tep_register_event_handler(pevent, -1, "mac80211",
|
||||
"drv_bss_info_changed",
|
||||
drv_bss_info_changed, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_unregister_event_handler(pevent, -1, "mac80211",
|
||||
"drv_bss_info_changed",
|
||||
drv_bss_info_changed, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "mac80211",
|
||||
"drv_bss_info_changed",
|
||||
drv_bss_info_changed, NULL);
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ static void write_state(struct trace_seq *s, int val)
|
||||
}
|
||||
|
||||
static void write_and_save_comm(struct format_field *field,
|
||||
struct pevent_record *record,
|
||||
struct tep_record *record,
|
||||
struct trace_seq *s, int pid)
|
||||
{
|
||||
const char *comm;
|
||||
@ -61,100 +61,100 @@ static void write_and_save_comm(struct format_field *field,
|
||||
comm = &s->buffer[len];
|
||||
|
||||
/* Help out the comm to ids. This will handle dups */
|
||||
pevent_register_comm(field->event->pevent, comm, pid);
|
||||
tep_register_comm(field->event->pevent, comm, pid);
|
||||
}
|
||||
|
||||
static int sched_wakeup_handler(struct trace_seq *s,
|
||||
struct pevent_record *record,
|
||||
struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
struct format_field *field;
|
||||
unsigned long long val;
|
||||
|
||||
if (pevent_get_field_val(s, event, "pid", record, &val, 1))
|
||||
if (tep_get_field_val(s, event, "pid", record, &val, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
field = pevent_find_any_field(event, "comm");
|
||||
field = tep_find_any_field(event, "comm");
|
||||
if (field) {
|
||||
write_and_save_comm(field, record, s, val);
|
||||
trace_seq_putc(s, ':');
|
||||
}
|
||||
trace_seq_printf(s, "%lld", val);
|
||||
|
||||
if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0)
|
||||
if (tep_get_field_val(s, event, "prio", record, &val, 0) == 0)
|
||||
trace_seq_printf(s, " [%lld]", val);
|
||||
|
||||
if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0)
|
||||
if (tep_get_field_val(s, event, "success", record, &val, 1) == 0)
|
||||
trace_seq_printf(s, " success=%lld", val);
|
||||
|
||||
if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
|
||||
if (tep_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
|
||||
trace_seq_printf(s, " CPU:%03llu", val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sched_switch_handler(struct trace_seq *s,
|
||||
struct pevent_record *record,
|
||||
struct tep_record *record,
|
||||
struct event_format *event, void *context)
|
||||
{
|
||||
struct format_field *field;
|
||||
unsigned long long val;
|
||||
|
||||
if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1))
|
||||
if (tep_get_field_val(s, event, "prev_pid", record, &val, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
field = pevent_find_any_field(event, "prev_comm");
|
||||
field = tep_find_any_field(event, "prev_comm");
|
||||
if (field) {
|
||||
write_and_save_comm(field, record, s, val);
|
||||
trace_seq_putc(s, ':');
|
||||
}
|
||||
trace_seq_printf(s, "%lld ", val);
|
||||
|
||||
if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
|
||||
if (tep_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
|
||||
trace_seq_printf(s, "[%d] ", (int) val);
|
||||
|
||||
if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0)
|
||||
if (tep_get_field_val(s, event, "prev_state", record, &val, 0) == 0)
|
||||
write_state(s, val);
|
||||
|
||||
trace_seq_puts(s, " ==> ");
|
||||
|
||||
if (pevent_get_field_val(s, event, "next_pid", record, &val, 1))
|
||||
if (tep_get_field_val(s, event, "next_pid", record, &val, 1))
|
||||
return trace_seq_putc(s, '!');
|
||||
|
||||
field = pevent_find_any_field(event, "next_comm");
|
||||
field = tep_find_any_field(event, "next_comm");
|
||||
if (field) {
|
||||
write_and_save_comm(field, record, s, val);
|
||||
trace_seq_putc(s, ':');
|
||||
}
|
||||
trace_seq_printf(s, "%lld", val);
|
||||
|
||||
if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
|
||||
if (tep_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
|
||||
trace_seq_printf(s, " [%d]", (int) val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_register_event_handler(pevent, -1, "sched", "sched_switch",
|
||||
sched_switch_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "sched", "sched_switch",
|
||||
sched_switch_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup",
|
||||
sched_wakeup_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "sched", "sched_wakeup",
|
||||
sched_wakeup_handler, NULL);
|
||||
|
||||
pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new",
|
||||
sched_wakeup_handler, NULL);
|
||||
tep_register_event_handler(pevent, -1, "sched", "sched_wakeup_new",
|
||||
sched_wakeup_handler, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch",
|
||||
sched_switch_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "sched", "sched_switch",
|
||||
sched_switch_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup",
|
||||
sched_wakeup_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup",
|
||||
sched_wakeup_handler, NULL);
|
||||
|
||||
pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new",
|
||||
sched_wakeup_handler, NULL);
|
||||
tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new",
|
||||
sched_wakeup_handler, NULL);
|
||||
}
|
||||
|
@ -413,21 +413,21 @@ unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_register_print_function(pevent,
|
||||
process_scsi_trace_parse_cdb,
|
||||
PEVENT_FUNC_ARG_STRING,
|
||||
"scsi_trace_parse_cdb",
|
||||
PEVENT_FUNC_ARG_PTR,
|
||||
PEVENT_FUNC_ARG_PTR,
|
||||
PEVENT_FUNC_ARG_INT,
|
||||
PEVENT_FUNC_ARG_VOID);
|
||||
tep_register_print_function(pevent,
|
||||
process_scsi_trace_parse_cdb,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
"scsi_trace_parse_cdb",
|
||||
TEP_FUNC_ARG_PTR,
|
||||
TEP_FUNC_ARG_PTR,
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb,
|
||||
"scsi_trace_parse_cdb");
|
||||
tep_unregister_print_function(pevent, process_scsi_trace_parse_cdb,
|
||||
"scsi_trace_parse_cdb");
|
||||
}
|
||||
|
@ -119,19 +119,19 @@ unsigned long long process_xen_hypercall_name(struct trace_seq *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_register_print_function(pevent,
|
||||
process_xen_hypercall_name,
|
||||
PEVENT_FUNC_ARG_STRING,
|
||||
"xen_hypercall_name",
|
||||
PEVENT_FUNC_ARG_INT,
|
||||
PEVENT_FUNC_ARG_VOID);
|
||||
tep_register_print_function(pevent,
|
||||
process_xen_hypercall_name,
|
||||
TEP_FUNC_ARG_STRING,
|
||||
"xen_hypercall_name",
|
||||
TEP_FUNC_ARG_INT,
|
||||
TEP_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
|
||||
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
|
||||
{
|
||||
pevent_unregister_print_function(pevent, process_xen_hypercall_name,
|
||||
"xen_hypercall_name");
|
||||
tep_unregister_print_function(pevent, process_xen_hypercall_name,
|
||||
"xen_hypercall_name");
|
||||
}
|
||||
|
@ -1,21 +1,7 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License (not later!)
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, see <http://www.gnu.org/licenses>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -118,6 +118,15 @@ OPTIONS
|
||||
--group::
|
||||
Show event group information together
|
||||
|
||||
--percent-type::
|
||||
Set annotation percent type from following choices:
|
||||
global-period, local-period, global-hits, local-hits
|
||||
|
||||
The local/global keywords set if the percentage is computed
|
||||
in the scope of the function (local) or the whole data (global).
|
||||
The period/hits keywords set the base the percentage is computed
|
||||
on - the samples period or the number of samples (hits).
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-record[1], linkperf:perf-report[1]
|
||||
|
@ -477,6 +477,15 @@ include::itrace.txt[]
|
||||
Display monitored tasks stored in perf data. Displaying pid/tid/ppid
|
||||
plus the command string aligned to distinguish parent and child tasks.
|
||||
|
||||
--percent-type::
|
||||
Set annotation percent type from following choices:
|
||||
global-period, local-period, global-hits, local-hits
|
||||
|
||||
The local/global keywords set if the percentage is computed
|
||||
in the scope of the function (local) or the whole data (global).
|
||||
The period/hits keywords set the base the percentage is computed
|
||||
on - the samples period or the number of samples (hits).
|
||||
|
||||
include::callchain-overhead-calculation.txt[]
|
||||
|
||||
SEE ALSO
|
||||
|
@ -84,10 +84,10 @@ endif # has_clean
|
||||
endif # MAKECMDGOALS
|
||||
|
||||
#
|
||||
# The clean target is not really parallel, don't print the jobs info:
|
||||
# Explicitly disable parallelism for the clean target.
|
||||
#
|
||||
clean:
|
||||
$(make)
|
||||
$(make) -j1
|
||||
|
||||
#
|
||||
# The build-test target is not really parallel, don't print the jobs info,
|
||||
|
@ -194,6 +194,7 @@ struct auxtrace_record *arm_spe_recording_init(int *err,
|
||||
sper->itr.read_finish = arm_spe_read_finish;
|
||||
sper->itr.alignment = 0;
|
||||
|
||||
*err = 0;
|
||||
return &sper->itr;
|
||||
}
|
||||
|
||||
|
@ -141,8 +141,10 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
|
||||
for (i = 0; i < ntevs; i++) {
|
||||
tev = &pev->tevs[i];
|
||||
map__for_each_symbol(map, sym, tmp) {
|
||||
if (map->unmap_ip(map, sym->start) == tev->point.address)
|
||||
if (map->unmap_ip(map, sym->start) == tev->point.address) {
|
||||
arch__fix_tev_from_maps(pev, tev, map, sym);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused,
|
||||
struct auxtrace_info_event *auxtrace_info __maybe_unused,
|
||||
size_t priv_size __maybe_unused)
|
||||
{
|
||||
auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,6 @@ systbl := $(sys)/syscalltbl.sh
|
||||
_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)')
|
||||
|
||||
$(header): $(sys)/syscall_64.tbl $(systbl)
|
||||
@(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \
|
||||
(diff -B arch/x86/entry/syscalls/syscall_64.tbl ../../arch/x86/entry/syscalls/syscall_64.tbl >/dev/null) \
|
||||
|| echo "Warning: Kernel ABI header at 'tools/perf/arch/x86/entry/syscalls/syscall_64.tbl' differs from latest version at 'arch/x86/entry/syscalls/syscall_64.tbl'" >&2 )) || true
|
||||
$(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@
|
||||
|
||||
clean::
|
||||
|
@ -542,6 +542,10 @@ int cmd_annotate(int argc, const char **argv)
|
||||
OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode",
|
||||
"'always' (default), 'never' or 'auto' only applicable to --stdio mode",
|
||||
stdio__config_color, "always"),
|
||||
OPT_CALLBACK(0, "percent-type", &annotate.opts, "local-period",
|
||||
"Set percent type local/global-period/hits",
|
||||
annotate_parse_percent_type),
|
||||
|
||||
OPT_END()
|
||||
};
|
||||
int ret;
|
||||
|
@ -729,7 +729,7 @@ static char *compact_gfp_string(unsigned long gfp_flags)
|
||||
static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
unsigned int gfp_flags)
|
||||
{
|
||||
struct pevent_record record = {
|
||||
struct tep_record record = {
|
||||
.cpu = sample->cpu,
|
||||
.data = sample->raw_data,
|
||||
.size = sample->raw_size,
|
||||
@ -747,7 +747,7 @@ static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
}
|
||||
|
||||
trace_seq_init(&seq);
|
||||
pevent_event_info(&seq, evsel->tp_format, &record);
|
||||
tep_event_info(&seq, evsel->tp_format, &record);
|
||||
|
||||
str = strtok_r(seq.buffer, " ", &pos);
|
||||
while (str) {
|
||||
@ -1974,7 +1974,7 @@ int cmd_kmem(int argc, const char **argv)
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent);
|
||||
kmem_page_size = tep_get_page_size(evsel->tp_format->pevent);
|
||||
symbol_conf.use_callchain = true;
|
||||
}
|
||||
|
||||
|
@ -1124,6 +1124,9 @@ int cmd_report(int argc, const char **argv)
|
||||
"Time span of interest (start,stop)"),
|
||||
OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name,
|
||||
"Show inline function"),
|
||||
OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period",
|
||||
"Set percent type local/global-period/hits",
|
||||
annotate_parse_percent_type),
|
||||
OPT_END()
|
||||
};
|
||||
struct perf_data data = {
|
||||
@ -1366,9 +1369,9 @@ repeat:
|
||||
}
|
||||
|
||||
if (session->tevent.pevent &&
|
||||
pevent_set_function_resolver(session->tevent.pevent,
|
||||
machine__resolve_kernel_addr,
|
||||
&session->machines.host) < 0) {
|
||||
tep_set_function_resolver(session->tevent.pevent,
|
||||
machine__resolve_kernel_addr,
|
||||
&session->machines.host) < 0) {
|
||||
pr_err("%s: failed to set libtraceevent function resolver\n",
|
||||
__func__);
|
||||
return -1;
|
||||
|
@ -3429,9 +3429,9 @@ int cmd_script(int argc, const char **argv)
|
||||
symbol_conf.use_callchain = false;
|
||||
|
||||
if (session->tevent.pevent &&
|
||||
pevent_set_function_resolver(session->tevent.pevent,
|
||||
machine__resolve_kernel_addr,
|
||||
&session->machines.host) < 0) {
|
||||
tep_set_function_resolver(session->tevent.pevent,
|
||||
machine__resolve_kernel_addr,
|
||||
&session->machines.host) < 0) {
|
||||
pr_err("%s: failed to set libtraceevent function resolver\n", __func__);
|
||||
err = -1;
|
||||
goto out_delete;
|
||||
|
@ -77,7 +77,8 @@ struct trace {
|
||||
struct syscall *table;
|
||||
struct {
|
||||
struct perf_evsel *sys_enter,
|
||||
*sys_exit;
|
||||
*sys_exit,
|
||||
*augmented;
|
||||
} events;
|
||||
} syscalls;
|
||||
struct record_opts opts;
|
||||
@ -121,7 +122,6 @@ struct trace {
|
||||
bool force;
|
||||
bool vfs_getname;
|
||||
int trace_pgfaults;
|
||||
int open_id;
|
||||
};
|
||||
|
||||
struct tp_field {
|
||||
@ -157,13 +157,11 @@ TP_UINT_FIELD__SWAPPED(16);
|
||||
TP_UINT_FIELD__SWAPPED(32);
|
||||
TP_UINT_FIELD__SWAPPED(64);
|
||||
|
||||
static int tp_field__init_uint(struct tp_field *field,
|
||||
struct format_field *format_field,
|
||||
bool needs_swap)
|
||||
static int __tp_field__init_uint(struct tp_field *field, int size, int offset, bool needs_swap)
|
||||
{
|
||||
field->offset = format_field->offset;
|
||||
field->offset = offset;
|
||||
|
||||
switch (format_field->size) {
|
||||
switch (size) {
|
||||
case 1:
|
||||
field->integer = tp_field__u8;
|
||||
break;
|
||||
@ -183,18 +181,28 @@ static int tp_field__init_uint(struct tp_field *field,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tp_field__init_uint(struct tp_field *field, struct format_field *format_field, bool needs_swap)
|
||||
{
|
||||
return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap);
|
||||
}
|
||||
|
||||
static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
|
||||
{
|
||||
return sample->raw_data + field->offset;
|
||||
}
|
||||
|
||||
static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
|
||||
static int __tp_field__init_ptr(struct tp_field *field, int offset)
|
||||
{
|
||||
field->offset = format_field->offset;
|
||||
field->offset = offset;
|
||||
field->pointer = tp_field__ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
|
||||
{
|
||||
return __tp_field__init_ptr(field, format_field->offset);
|
||||
}
|
||||
|
||||
struct syscall_tp {
|
||||
struct tp_field id;
|
||||
union {
|
||||
@ -240,7 +248,47 @@ static void perf_evsel__delete_priv(struct perf_evsel *evsel)
|
||||
perf_evsel__delete(evsel);
|
||||
}
|
||||
|
||||
static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
|
||||
static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel)
|
||||
{
|
||||
struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
|
||||
|
||||
if (evsel->priv != NULL) {
|
||||
if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr"))
|
||||
goto out_delete;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
out_delete:
|
||||
zfree(&evsel->priv);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel)
|
||||
{
|
||||
struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
|
||||
|
||||
if (evsel->priv != NULL) { /* field, sizeof_field, offsetof_field */
|
||||
if (__tp_field__init_uint(&sc->id, sizeof(long), sizeof(long long), evsel->needs_swap))
|
||||
goto out_delete;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
out_delete:
|
||||
zfree(&evsel->priv);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int perf_evsel__init_augmented_syscall_tp_args(struct perf_evsel *evsel)
|
||||
{
|
||||
struct syscall_tp *sc = evsel->priv;
|
||||
|
||||
return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64));
|
||||
}
|
||||
|
||||
static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler)
|
||||
{
|
||||
evsel->priv = malloc(sizeof(struct syscall_tp));
|
||||
if (evsel->priv != NULL) {
|
||||
@ -258,7 +306,7 @@ out_delete:
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
|
||||
static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
|
||||
{
|
||||
struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
|
||||
|
||||
@ -269,7 +317,7 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void
|
||||
if (IS_ERR(evsel))
|
||||
return NULL;
|
||||
|
||||
if (perf_evsel__init_syscall_tp(evsel, handler))
|
||||
if (perf_evsel__init_raw_syscall_tp(evsel, handler))
|
||||
goto out_delete;
|
||||
|
||||
return evsel;
|
||||
@ -805,12 +853,17 @@ static struct syscall_fmt *syscall_fmt__find(const char *name)
|
||||
return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* is_exit: is this "exit" or "exit_group"?
|
||||
* is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter.
|
||||
*/
|
||||
struct syscall {
|
||||
struct event_format *tp_format;
|
||||
int nr_args;
|
||||
bool is_exit;
|
||||
bool is_open;
|
||||
struct format_field *args;
|
||||
const char *name;
|
||||
bool is_exit;
|
||||
struct syscall_fmt *fmt;
|
||||
struct syscall_arg_fmt *arg_fmt;
|
||||
};
|
||||
@ -1299,6 +1352,7 @@ static int trace__read_syscall_info(struct trace *trace, int id)
|
||||
}
|
||||
|
||||
sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
|
||||
sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
|
||||
|
||||
return syscall__set_arg_fmts(sc);
|
||||
}
|
||||
@ -1661,6 +1715,37 @@ out_put:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
struct thread_trace *ttrace;
|
||||
struct thread *thread;
|
||||
int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
|
||||
struct syscall *sc = trace__syscall_info(trace, evsel, id);
|
||||
char msg[1024];
|
||||
void *args;
|
||||
|
||||
if (sc == NULL)
|
||||
return -1;
|
||||
|
||||
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
|
||||
ttrace = thread__trace(thread, trace->output);
|
||||
/*
|
||||
* We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
|
||||
* and the rest of the beautifiers accessing it via struct syscall_arg touches it.
|
||||
*/
|
||||
if (ttrace == NULL)
|
||||
goto out_put;
|
||||
|
||||
args = perf_evsel__sc_tp_ptr(evsel, args, sample);
|
||||
syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread);
|
||||
fprintf(trace->output, "%s", msg);
|
||||
err = 0;
|
||||
out_put:
|
||||
thread__put(thread);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
|
||||
struct perf_sample *sample,
|
||||
struct callchain_cursor *cursor)
|
||||
@ -1722,7 +1807,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
|
||||
|
||||
ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
|
||||
|
||||
if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
|
||||
if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
|
||||
trace__set_fd_pathname(thread, ret, ttrace->filename.name);
|
||||
ttrace->filename.pending_open = false;
|
||||
++trace->stats.vfs_getname;
|
||||
@ -1957,11 +2042,17 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
|
||||
fprintf(trace->output, "%s:", evsel->name);
|
||||
|
||||
if (perf_evsel__is_bpf_output(evsel)) {
|
||||
bpf_output__fprintf(trace, sample);
|
||||
if (evsel == trace->syscalls.events.augmented)
|
||||
trace__fprintf_sys_enter(trace, evsel, sample);
|
||||
else
|
||||
bpf_output__fprintf(trace, sample);
|
||||
} else if (evsel->tp_format) {
|
||||
event_format__fprintf(evsel->tp_format, sample->cpu,
|
||||
sample->raw_data, sample->raw_size,
|
||||
trace->output);
|
||||
if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
|
||||
trace__fprintf_sys_enter(trace, evsel, sample)) {
|
||||
event_format__fprintf(evsel->tp_format, sample->cpu,
|
||||
sample->raw_data, sample->raw_size,
|
||||
trace->output);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(trace->output, "\n");
|
||||
@ -2242,14 +2333,14 @@ static int trace__add_syscall_newtp(struct trace *trace)
|
||||
struct perf_evlist *evlist = trace->evlist;
|
||||
struct perf_evsel *sys_enter, *sys_exit;
|
||||
|
||||
sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
|
||||
sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
|
||||
if (sys_enter == NULL)
|
||||
goto out;
|
||||
|
||||
if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
|
||||
goto out_delete_sys_enter;
|
||||
|
||||
sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
|
||||
sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
|
||||
if (sys_exit == NULL)
|
||||
goto out_delete_sys_enter;
|
||||
|
||||
@ -2671,7 +2762,7 @@ static int trace__replay(struct trace *trace)
|
||||
"syscalls:sys_enter");
|
||||
|
||||
if (evsel &&
|
||||
(perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
|
||||
(perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
|
||||
perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
|
||||
pr_err("Error during initialize raw_syscalls:sys_enter event\n");
|
||||
goto out;
|
||||
@ -2683,7 +2774,7 @@ static int trace__replay(struct trace *trace)
|
||||
evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
|
||||
"syscalls:sys_exit");
|
||||
if (evsel &&
|
||||
(perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
|
||||
(perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
|
||||
perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
|
||||
pr_err("Error during initialize raw_syscalls:sys_exit event\n");
|
||||
goto out;
|
||||
@ -2923,6 +3014,36 @@ static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
|
||||
evsel->handler = handler;
|
||||
}
|
||||
|
||||
static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
evlist__for_each_entry(evlist, evsel) {
|
||||
if (evsel->priv || !evsel->tp_format)
|
||||
continue;
|
||||
|
||||
if (strcmp(evsel->tp_format->system, "syscalls"))
|
||||
continue;
|
||||
|
||||
if (perf_evsel__init_syscall_tp(evsel))
|
||||
return -1;
|
||||
|
||||
if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
|
||||
struct syscall_tp *sc = evsel->priv;
|
||||
|
||||
if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
|
||||
return -1;
|
||||
} else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
|
||||
struct syscall_tp *sc = evsel->priv;
|
||||
|
||||
if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: Hackish, just splitting the combined -e+--event (syscalls
|
||||
* (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
|
||||
@ -3123,8 +3244,9 @@ int cmd_trace(int argc, const char **argv)
|
||||
};
|
||||
bool __maybe_unused max_stack_user_set = true;
|
||||
bool mmap_pages_user_set = true;
|
||||
struct perf_evsel *evsel;
|
||||
const char * const trace_subcommands[] = { "record", NULL };
|
||||
int err;
|
||||
int err = -1;
|
||||
char bf[BUFSIZ];
|
||||
|
||||
signal(SIGSEGV, sighandler_dump_stack);
|
||||
@ -3147,6 +3269,20 @@ int cmd_trace(int argc, const char **argv)
|
||||
"cgroup monitoring only available in system-wide mode");
|
||||
}
|
||||
|
||||
evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__");
|
||||
if (IS_ERR(evsel)) {
|
||||
bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf));
|
||||
pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (evsel) {
|
||||
if (perf_evsel__init_augmented_syscall_tp(evsel) ||
|
||||
perf_evsel__init_augmented_syscall_tp_args(evsel))
|
||||
goto out;
|
||||
trace.syscalls.events.augmented = evsel;
|
||||
}
|
||||
|
||||
err = bpf__setup_stdout(trace.evlist);
|
||||
if (err) {
|
||||
bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
|
||||
@ -3182,8 +3318,13 @@ int cmd_trace(int argc, const char **argv)
|
||||
symbol_conf.use_callchain = true;
|
||||
}
|
||||
|
||||
if (trace.evlist->nr_entries > 0)
|
||||
if (trace.evlist->nr_entries > 0) {
|
||||
evlist__set_evsel_handler(trace.evlist, trace__event_handler);
|
||||
if (evlist__set_syscall_tp_fields(trace.evlist)) {
|
||||
perror("failed to set syscalls:* tracepoint fields");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
|
||||
return trace__record(&trace, argc-1, &argv[1]);
|
||||
@ -3205,8 +3346,6 @@ int cmd_trace(int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
trace.open_id = syscalltbl__id(trace.sctbl, "open");
|
||||
|
||||
err = target__validate(&trace.opts.target);
|
||||
if (err) {
|
||||
target__strerror(&trace.opts.target, err, bf, sizeof(bf));
|
||||
|
@ -67,8 +67,12 @@ check_2 () {
|
||||
|
||||
cmd="diff $* $file1 $file2 > /dev/null"
|
||||
|
||||
test -f $file2 &&
|
||||
eval $cmd || echo "Warning: Kernel ABI header at 'tools/$file' differs from latest version at '$file'" >&2
|
||||
test -f $file2 && {
|
||||
eval $cmd || {
|
||||
echo "Warning: Kernel ABI header at '$file1' differs from latest version at '$file2'" >&2
|
||||
echo diff -u $file1 $file2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check () {
|
||||
@ -76,7 +80,7 @@ check () {
|
||||
|
||||
shift
|
||||
|
||||
check_2 ../$file ../../$file $*
|
||||
check_2 tools/$file $file $*
|
||||
}
|
||||
|
||||
# Check if we have the kernel headers (tools/perf/../../include), else
|
||||
@ -84,6 +88,8 @@ check () {
|
||||
# differences.
|
||||
test -d ../../include || exit 0
|
||||
|
||||
cd ../..
|
||||
|
||||
# simple diff check
|
||||
for i in $HEADERS; do
|
||||
check $i -B
|
||||
@ -94,3 +100,8 @@ check arch/x86/lib/memcpy_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/ex
|
||||
check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"'
|
||||
check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common.h>"'
|
||||
check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"'
|
||||
|
||||
# diff non-symmetric files
|
||||
check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl
|
||||
|
||||
cd tools/perf
|
||||
|
55
tools/perf/examples/bpf/augmented_syscalls.c
Normal file
55
tools/perf/examples/bpf/augmented_syscalls.c
Normal file
@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Augment the openat syscall with the contents of the filename pointer argument.
|
||||
*
|
||||
* Test it with:
|
||||
*
|
||||
* perf trace -e tools/perf/examples/bpf/augmented_syscalls.c cat /etc/passwd > /dev/null
|
||||
*
|
||||
* It'll catch some openat syscalls related to the dynamic linked and
|
||||
* the last one should be the one for '/etc/passwd'.
|
||||
*
|
||||
* This matches what is marshalled into the raw_syscall:sys_enter payload
|
||||
* expected by the 'perf trace' beautifiers, and can be used by them unmodified,
|
||||
* which will be done as that feature is implemented in the next csets, for now
|
||||
* it will appear in a dump done by the default tracepoint handler in 'perf trace',
|
||||
* that uses bpf_output__fprintf() to just dump those contents, as done with
|
||||
* the bpf-output event associated with the __bpf_output__ map declared in
|
||||
* tools/perf/include/bpf/stdio.h.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct bpf_map SEC("maps") __augmented_syscalls__ = {
|
||||
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(u32),
|
||||
.max_entries = __NR_CPUS__,
|
||||
};
|
||||
|
||||
struct syscall_enter_openat_args {
|
||||
unsigned long long common_tp_fields;
|
||||
long syscall_nr;
|
||||
long dfd;
|
||||
char *filename_ptr;
|
||||
long flags;
|
||||
long mode;
|
||||
};
|
||||
|
||||
struct augmented_enter_openat_args {
|
||||
struct syscall_enter_openat_args args;
|
||||
char filename[64];
|
||||
};
|
||||
|
||||
int syscall_enter(openat)(struct syscall_enter_openat_args *args)
|
||||
{
|
||||
struct augmented_enter_openat_args augmented_args;
|
||||
|
||||
probe_read(&augmented_args.args, sizeof(augmented_args.args), args);
|
||||
probe_read_str(&augmented_args.filename, sizeof(augmented_args.filename), args->filename_ptr);
|
||||
perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU,
|
||||
&augmented_args, sizeof(augmented_args));
|
||||
return 1;
|
||||
}
|
||||
|
||||
license(GPL);
|
9
tools/perf/examples/bpf/hello.c
Normal file
9
tools/perf/examples/bpf/hello.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int syscall_enter(openat)(void *args)
|
||||
{
|
||||
puts("Hello, world\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
license(GPL);
|
33
tools/perf/examples/bpf/sys_enter_openat.c
Normal file
33
tools/perf/examples/bpf/sys_enter_openat.c
Normal file
@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Hook into 'openat' syscall entry tracepoint
|
||||
*
|
||||
* Test it with:
|
||||
*
|
||||
* perf trace -e tools/perf/examples/bpf/sys_enter_openat.c cat /etc/passwd > /dev/null
|
||||
*
|
||||
* It'll catch some openat syscalls related to the dynamic linked and
|
||||
* the last one should be the one for '/etc/passwd'.
|
||||
*
|
||||
* The syscall_enter_openat_args can be used to get the syscall fields
|
||||
* and use them for filtering calls, i.e. use in expressions for
|
||||
* the return value.
|
||||
*/
|
||||
|
||||
#include <bpf.h>
|
||||
|
||||
struct syscall_enter_openat_args {
|
||||
unsigned long long unused;
|
||||
long syscall_nr;
|
||||
long dfd;
|
||||
char *filename_ptr;
|
||||
long flags;
|
||||
long mode;
|
||||
};
|
||||
|
||||
int syscall_enter(openat)(struct syscall_enter_openat_args *args)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
license(GPL);
|
@ -4,13 +4,33 @@
|
||||
|
||||
#include <uapi/linux/bpf.h>
|
||||
|
||||
/*
|
||||
* A helper structure used by eBPF C program to describe map attributes to
|
||||
* elf_bpf loader, taken from tools/testing/selftests/bpf/bpf_helpers.h:
|
||||
*/
|
||||
struct bpf_map {
|
||||
unsigned int type;
|
||||
unsigned int key_size;
|
||||
unsigned int value_size;
|
||||
unsigned int max_entries;
|
||||
unsigned int map_flags;
|
||||
unsigned int inner_map_idx;
|
||||
unsigned int numa_node;
|
||||
};
|
||||
|
||||
#define SEC(NAME) __attribute__((section(NAME), used))
|
||||
|
||||
#define probe(function, vars) \
|
||||
SEC(#function "=" #function " " #vars) function
|
||||
|
||||
#define syscall_enter(name) \
|
||||
SEC("syscalls:sys_enter_" #name) syscall_enter_ ## name
|
||||
|
||||
#define license(name) \
|
||||
char _license[] SEC("license") = #name; \
|
||||
int _version SEC("version") = LINUX_VERSION_CODE;
|
||||
|
||||
static int (*probe_read)(void *dst, int size, const void *unsafe_addr) = (void *)BPF_FUNC_probe_read;
|
||||
static int (*probe_read_str)(void *dst, int size, const void *unsafe_addr) = (void *)BPF_FUNC_probe_read_str;
|
||||
|
||||
#endif /* _PERF_BPF_H */
|
||||
|
19
tools/perf/include/bpf/stdio.h
Normal file
19
tools/perf/include/bpf/stdio.h
Normal file
@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <bpf.h>
|
||||
|
||||
struct bpf_map SEC("maps") __bpf_stdout__ = {
|
||||
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(u32),
|
||||
.max_entries = __NR_CPUS__,
|
||||
};
|
||||
|
||||
static int (*perf_event_output)(void *, struct bpf_map *, int, void *, unsigned long) =
|
||||
(void *)BPF_FUNC_perf_event_output;
|
||||
|
||||
#define puts(from) \
|
||||
({ const int __len = sizeof(from); \
|
||||
char __from[__len] = from; \
|
||||
perf_event_output(args, &__bpf_stdout__, BPF_F_CURRENT_CPU, \
|
||||
&__from, __len & (sizeof(from) - 1)); })
|
@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"ArchStdEvent": "L1D_CACHE_RD",
|
||||
},
|
||||
{
|
||||
"ArchStdEvent": "L1D_CACHE_WR",
|
||||
},
|
||||
{
|
||||
"ArchStdEvent": "L1D_CACHE_REFILL_RD",
|
||||
},
|
||||
{
|
||||
"ArchStdEvent": "L1D_CACHE_REFILL_WR",
|
||||
},
|
||||
{
|
||||
"ArchStdEvent": "L1D_TLB_REFILL_RD",
|
||||
},
|
||||
{
|
||||
"ArchStdEvent": "L1D_TLB_REFILL_WR",
|
||||
},
|
||||
{
|
||||
"ArchStdEvent": "L1D_TLB_RD",
|
||||
},
|
||||
{
|
||||
"ArchStdEvent": "L1D_TLB_WR",
|
||||
},
|
||||
{
|
||||
"ArchStdEvent": "BUS_ACCESS_RD",
|
||||
},
|
||||
{
|
||||
"ArchStdEvent": "BUS_ACCESS_WR",
|
||||
}
|
||||
]
|
@ -16,3 +16,4 @@
|
||||
0x00000000420f5160,v1,cavium/thunderx2,core
|
||||
0x00000000430f0af0,v1,cavium/thunderx2,core
|
||||
0x00000000480fd010,v1,hisilicon/hip08,core
|
||||
0x00000000500f0000,v1,ampere/emag,core
|
||||
|
|
@ -16,8 +16,6 @@ static unsigned long *get_bitmap(const char *str, int nbits)
|
||||
bm = bitmap_alloc(nbits);
|
||||
|
||||
if (map && bm) {
|
||||
bitmap_zero(bm, nbits);
|
||||
|
||||
for (i = 0; i < map->nr; i++)
|
||||
set_bit(map->map[i], bm);
|
||||
}
|
||||
|
@ -232,6 +232,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
|
||||
u64 objdump_addr;
|
||||
const char *objdump_name;
|
||||
char decomp_name[KMOD_DECOMP_LEN];
|
||||
bool decomp = false;
|
||||
int ret;
|
||||
|
||||
pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
|
||||
@ -305,6 +306,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
|
||||
return -1;
|
||||
}
|
||||
|
||||
decomp = true;
|
||||
objdump_name = decomp_name;
|
||||
}
|
||||
|
||||
@ -312,7 +314,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
|
||||
objdump_addr = map__rip_2objdump(al.map, al.addr);
|
||||
ret = read_via_objdump(objdump_name, objdump_addr, buf2, len);
|
||||
|
||||
if (dso__needs_decompress(al.map->dso))
|
||||
if (decomp)
|
||||
unlink(objdump_name);
|
||||
|
||||
if (ret > 0) {
|
||||
|
@ -5,34 +5,28 @@
|
||||
#include "dso.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int test(const char *path, bool alloc_name, bool alloc_ext,
|
||||
bool kmod, bool comp, const char *name, const char *ext)
|
||||
static int test(const char *path, bool alloc_name, bool kmod,
|
||||
int comp, const char *name)
|
||||
{
|
||||
struct kmod_path m;
|
||||
|
||||
memset(&m, 0x0, sizeof(m));
|
||||
|
||||
TEST_ASSERT_VAL("kmod_path__parse",
|
||||
!__kmod_path__parse(&m, path, alloc_name, alloc_ext));
|
||||
!__kmod_path__parse(&m, path, alloc_name));
|
||||
|
||||
pr_debug("%s - alloc name %d, alloc ext %d, kmod %d, comp %d, name '%s', ext '%s'\n",
|
||||
path, alloc_name, alloc_ext, m.kmod, m.comp, m.name, m.ext);
|
||||
pr_debug("%s - alloc name %d, kmod %d, comp %d, name '%s'\n",
|
||||
path, alloc_name, m.kmod, m.comp, m.name);
|
||||
|
||||
TEST_ASSERT_VAL("wrong kmod", m.kmod == kmod);
|
||||
TEST_ASSERT_VAL("wrong comp", m.comp == comp);
|
||||
|
||||
if (ext)
|
||||
TEST_ASSERT_VAL("wrong ext", m.ext && !strcmp(ext, m.ext));
|
||||
else
|
||||
TEST_ASSERT_VAL("wrong ext", !m.ext);
|
||||
|
||||
if (name)
|
||||
TEST_ASSERT_VAL("wrong name", m.name && !strcmp(name, m.name));
|
||||
else
|
||||
TEST_ASSERT_VAL("wrong name", !m.name);
|
||||
|
||||
free(m.name);
|
||||
free(m.ext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -45,118 +39,118 @@ static int test_is_kernel_module(const char *path, int cpumode, bool expect)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define T(path, an, ae, k, c, n, e) \
|
||||
TEST_ASSERT_VAL("failed", !test(path, an, ae, k, c, n, e))
|
||||
#define T(path, an, k, c, n) \
|
||||
TEST_ASSERT_VAL("failed", !test(path, an, k, c, n))
|
||||
|
||||
#define M(path, c, e) \
|
||||
TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e))
|
||||
|
||||
int test__kmod_path__parse(struct test *t __maybe_unused, int subtest __maybe_unused)
|
||||
{
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("/xxxx/xxxx/x-x.ko", true , true , true, false, "[x_x]", NULL);
|
||||
T("/xxxx/xxxx/x-x.ko", false , true , true, false, NULL , NULL);
|
||||
T("/xxxx/xxxx/x-x.ko", true , false , true, false, "[x_x]", NULL);
|
||||
T("/xxxx/xxxx/x-x.ko", false , false , true, false, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("/xxxx/xxxx/x-x.ko", true , true, 0 , "[x_x]");
|
||||
T("/xxxx/xxxx/x-x.ko", false , true, 0 , NULL );
|
||||
T("/xxxx/xxxx/x-x.ko", true , true, 0 , "[x_x]");
|
||||
T("/xxxx/xxxx/x-x.ko", false , true, 0 , NULL );
|
||||
M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
|
||||
M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_KERNEL, true);
|
||||
M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
#ifdef HAVE_ZLIB_SUPPORT
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("/xxxx/xxxx/x.ko.gz", true , true , true, true, "[x]", "gz");
|
||||
T("/xxxx/xxxx/x.ko.gz", false , true , true, true, NULL , "gz");
|
||||
T("/xxxx/xxxx/x.ko.gz", true , false , true, true, "[x]", NULL);
|
||||
T("/xxxx/xxxx/x.ko.gz", false , false , true, true, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("/xxxx/xxxx/x.ko.gz", true , true, 1 , "[x]");
|
||||
T("/xxxx/xxxx/x.ko.gz", false , true, 1 , NULL );
|
||||
T("/xxxx/xxxx/x.ko.gz", true , true, 1 , "[x]");
|
||||
T("/xxxx/xxxx/x.ko.gz", false , true, 1 , NULL );
|
||||
M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
|
||||
M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_KERNEL, true);
|
||||
M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("/xxxx/xxxx/x.gz", true , true , false, true, "x.gz" ,"gz");
|
||||
T("/xxxx/xxxx/x.gz", false , true , false, true, NULL ,"gz");
|
||||
T("/xxxx/xxxx/x.gz", true , false , false, true, "x.gz" , NULL);
|
||||
T("/xxxx/xxxx/x.gz", false , false , false, true, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("/xxxx/xxxx/x.gz", true , false, 1 , "x.gz");
|
||||
T("/xxxx/xxxx/x.gz", false , false, 1 , NULL );
|
||||
T("/xxxx/xxxx/x.gz", true , false, 1 , "x.gz");
|
||||
T("/xxxx/xxxx/x.gz", false , false, 1 , NULL );
|
||||
M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
|
||||
M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_KERNEL, false);
|
||||
M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("x.gz", true , true , false, true, "x.gz", "gz");
|
||||
T("x.gz", false , true , false, true, NULL , "gz");
|
||||
T("x.gz", true , false , false, true, "x.gz", NULL);
|
||||
T("x.gz", false , false , false, true, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("x.gz", true , false, 1 , "x.gz");
|
||||
T("x.gz", false , false, 1 , NULL );
|
||||
T("x.gz", true , false, 1 , "x.gz");
|
||||
T("x.gz", false , false, 1 , NULL );
|
||||
M("x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
|
||||
M("x.gz", PERF_RECORD_MISC_KERNEL, false);
|
||||
M("x.gz", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("x.ko.gz", true , true , true, true, "[x]", "gz");
|
||||
T("x.ko.gz", false , true , true, true, NULL , "gz");
|
||||
T("x.ko.gz", true , false , true, true, "[x]", NULL);
|
||||
T("x.ko.gz", false , false , true, true, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("x.ko.gz", true , true, 1 , "[x]");
|
||||
T("x.ko.gz", false , true, 1 , NULL );
|
||||
T("x.ko.gz", true , true, 1 , "[x]");
|
||||
T("x.ko.gz", false , true, 1 , NULL );
|
||||
M("x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
|
||||
M("x.ko.gz", PERF_RECORD_MISC_KERNEL, true);
|
||||
M("x.ko.gz", PERF_RECORD_MISC_USER, false);
|
||||
#endif
|
||||
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("[test_module]", true , true , true, false, "[test_module]", NULL);
|
||||
T("[test_module]", false , true , true, false, NULL , NULL);
|
||||
T("[test_module]", true , false , true, false, "[test_module]", NULL);
|
||||
T("[test_module]", false , false , true, false, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("[test_module]", true , true, false, "[test_module]");
|
||||
T("[test_module]", false , true, false, NULL );
|
||||
T("[test_module]", true , true, false, "[test_module]");
|
||||
T("[test_module]", false , true, false, NULL );
|
||||
M("[test_module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
|
||||
M("[test_module]", PERF_RECORD_MISC_KERNEL, true);
|
||||
M("[test_module]", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("[test.module]", true , true , true, false, "[test.module]", NULL);
|
||||
T("[test.module]", false , true , true, false, NULL , NULL);
|
||||
T("[test.module]", true , false , true, false, "[test.module]", NULL);
|
||||
T("[test.module]", false , false , true, false, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("[test.module]", true , true, false, "[test.module]");
|
||||
T("[test.module]", false , true, false, NULL );
|
||||
T("[test.module]", true , true, false, "[test.module]");
|
||||
T("[test.module]", false , true, false, NULL );
|
||||
M("[test.module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
|
||||
M("[test.module]", PERF_RECORD_MISC_KERNEL, true);
|
||||
M("[test.module]", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("[vdso]", true , true , false, false, "[vdso]", NULL);
|
||||
T("[vdso]", false , true , false, false, NULL , NULL);
|
||||
T("[vdso]", true , false , false, false, "[vdso]", NULL);
|
||||
T("[vdso]", false , false , false, false, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("[vdso]", true , false, false, "[vdso]");
|
||||
T("[vdso]", false , false, false, NULL );
|
||||
T("[vdso]", true , false, false, "[vdso]");
|
||||
T("[vdso]", false , false, false, NULL );
|
||||
M("[vdso]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
|
||||
M("[vdso]", PERF_RECORD_MISC_KERNEL, false);
|
||||
M("[vdso]", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
T("[vdso32]", true , true , false, false, "[vdso32]", NULL);
|
||||
T("[vdso32]", false , true , false, false, NULL , NULL);
|
||||
T("[vdso32]", true , false , false, false, "[vdso32]", NULL);
|
||||
T("[vdso32]", false , false , false, false, NULL , NULL);
|
||||
T("[vdso32]", true , false, false, "[vdso32]");
|
||||
T("[vdso32]", false , false, false, NULL );
|
||||
T("[vdso32]", true , false, false, "[vdso32]");
|
||||
T("[vdso32]", false , false, false, NULL );
|
||||
M("[vdso32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
|
||||
M("[vdso32]", PERF_RECORD_MISC_KERNEL, false);
|
||||
M("[vdso32]", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
T("[vdsox32]", true , true , false, false, "[vdsox32]", NULL);
|
||||
T("[vdsox32]", false , true , false, false, NULL , NULL);
|
||||
T("[vdsox32]", true , false , false, false, "[vdsox32]", NULL);
|
||||
T("[vdsox32]", false , false , false, false, NULL , NULL);
|
||||
T("[vdsox32]", true , false, false, "[vdsox32]");
|
||||
T("[vdsox32]", false , false, false, NULL );
|
||||
T("[vdsox32]", true , false, false, "[vdsox32]");
|
||||
T("[vdsox32]", false , false, false, NULL );
|
||||
M("[vdsox32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
|
||||
M("[vdsox32]", PERF_RECORD_MISC_KERNEL, false);
|
||||
M("[vdsox32]", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("[vsyscall]", true , true , false, false, "[vsyscall]", NULL);
|
||||
T("[vsyscall]", false , true , false, false, NULL , NULL);
|
||||
T("[vsyscall]", true , false , false, false, "[vsyscall]", NULL);
|
||||
T("[vsyscall]", false , false , false, false, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("[vsyscall]", true , false, false, "[vsyscall]");
|
||||
T("[vsyscall]", false , false, false, NULL );
|
||||
T("[vsyscall]", true , false, false, "[vsyscall]");
|
||||
T("[vsyscall]", false , false, false, NULL );
|
||||
M("[vsyscall]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
|
||||
M("[vsyscall]", PERF_RECORD_MISC_KERNEL, false);
|
||||
M("[vsyscall]", PERF_RECORD_MISC_USER, false);
|
||||
|
||||
/* path alloc_name alloc_ext kmod comp name ext */
|
||||
T("[kernel.kallsyms]", true , true , false, false, "[kernel.kallsyms]", NULL);
|
||||
T("[kernel.kallsyms]", false , true , false, false, NULL , NULL);
|
||||
T("[kernel.kallsyms]", true , false , false, false, "[kernel.kallsyms]", NULL);
|
||||
T("[kernel.kallsyms]", false , false , false, false, NULL , NULL);
|
||||
/* path alloc_name kmod comp name */
|
||||
T("[kernel.kallsyms]", true , false, false, "[kernel.kallsyms]");
|
||||
T("[kernel.kallsyms]", false , false, false, NULL );
|
||||
T("[kernel.kallsyms]", true , false, false, "[kernel.kallsyms]");
|
||||
T("[kernel.kallsyms]", false , false, false, NULL );
|
||||
M("[kernel.kallsyms]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
|
||||
M("[kernel.kallsyms]", PERF_RECORD_MISC_KERNEL, false);
|
||||
M("[kernel.kallsyms]", PERF_RECORD_MISC_USER, false);
|
||||
|
@ -24,8 +24,6 @@ static unsigned long *get_bitmap(const char *str, int nbits)
|
||||
bm = bitmap_alloc(nbits);
|
||||
|
||||
if (map && bm) {
|
||||
bitmap_zero(bm, nbits);
|
||||
|
||||
for (i = 0; i < map->nr; i++) {
|
||||
set_bit(map->map[i], bm);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <sys/ttydefaults.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
struct disasm_line_samples {
|
||||
double percent;
|
||||
@ -115,7 +116,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
|
||||
if (!browser->navkeypressed)
|
||||
ops.width += 1;
|
||||
|
||||
annotation_line__write(al, notes, &ops);
|
||||
annotation_line__write(al, notes, &ops, ab->opts);
|
||||
|
||||
if (ops.current_entry)
|
||||
ab->selection = al;
|
||||
@ -227,10 +228,10 @@ static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < a->samples_nr; i++) {
|
||||
if (a->samples[i].percent == b->samples[i].percent)
|
||||
for (i = 0; i < a->data_nr; i++) {
|
||||
if (a->data[i].percent == b->data[i].percent)
|
||||
continue;
|
||||
return a->samples[i].percent < b->samples[i].percent;
|
||||
return a->data[i].percent < b->data[i].percent;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -314,11 +315,14 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < pos->al.samples_nr; i++) {
|
||||
struct annotation_data *sample = &pos->al.samples[i];
|
||||
for (i = 0; i < pos->al.data_nr; i++) {
|
||||
double percent;
|
||||
|
||||
if (max_percent < sample->percent)
|
||||
max_percent = sample->percent;
|
||||
percent = annotation_data__percent(&pos->al.data[i],
|
||||
browser->opts->percent_type);
|
||||
|
||||
if (max_percent < percent)
|
||||
max_percent = percent;
|
||||
}
|
||||
|
||||
if (max_percent < 0.01 && pos->al.ipc == 0) {
|
||||
@ -380,9 +384,10 @@ static void ui_browser__init_asm_mode(struct ui_browser *browser)
|
||||
#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
|
||||
|
||||
static int sym_title(struct symbol *sym, struct map *map, char *title,
|
||||
size_t sz)
|
||||
size_t sz, int percent_type)
|
||||
{
|
||||
return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
|
||||
return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name,
|
||||
percent_type_str(percent_type));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -420,7 +425,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
|
||||
|
||||
pthread_mutex_unlock(¬es->lock);
|
||||
symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts);
|
||||
sym_title(ms->sym, ms->map, title, sizeof(title));
|
||||
sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
|
||||
ui_browser__show_title(&browser->b, title);
|
||||
return true;
|
||||
}
|
||||
@ -595,6 +600,7 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
|
||||
|
||||
static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
|
||||
{
|
||||
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
|
||||
struct map_symbol *ms = browser->priv;
|
||||
struct symbol *sym = ms->sym;
|
||||
char symbol_dso[SYM_TITLE_MAX_SIZE];
|
||||
@ -602,7 +608,7 @@ static int annotate_browser__show(struct ui_browser *browser, char *title, const
|
||||
if (ui_browser__show(browser, title, help) < 0)
|
||||
return -1;
|
||||
|
||||
sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso));
|
||||
sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
|
||||
|
||||
ui_browser__gotorc_title(browser, 0, 0);
|
||||
ui_browser__set_color(browser, HE_COLORSET_ROOT);
|
||||
@ -610,6 +616,39 @@ static int annotate_browser__show(struct ui_browser *browser, char *title, const
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
switch_percent_type(struct annotation_options *opts, bool base)
|
||||
{
|
||||
switch (opts->percent_type) {
|
||||
case PERCENT_HITS_LOCAL:
|
||||
if (base)
|
||||
opts->percent_type = PERCENT_PERIOD_LOCAL;
|
||||
else
|
||||
opts->percent_type = PERCENT_HITS_GLOBAL;
|
||||
break;
|
||||
case PERCENT_HITS_GLOBAL:
|
||||
if (base)
|
||||
opts->percent_type = PERCENT_PERIOD_GLOBAL;
|
||||
else
|
||||
opts->percent_type = PERCENT_HITS_LOCAL;
|
||||
break;
|
||||
case PERCENT_PERIOD_LOCAL:
|
||||
if (base)
|
||||
opts->percent_type = PERCENT_HITS_LOCAL;
|
||||
else
|
||||
opts->percent_type = PERCENT_PERIOD_GLOBAL;
|
||||
break;
|
||||
case PERCENT_PERIOD_GLOBAL:
|
||||
if (base)
|
||||
opts->percent_type = PERCENT_HITS_GLOBAL;
|
||||
else
|
||||
opts->percent_type = PERCENT_PERIOD_LOCAL;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int annotate_browser__run(struct annotate_browser *browser,
|
||||
struct perf_evsel *evsel,
|
||||
struct hist_browser_timer *hbt)
|
||||
@ -624,8 +663,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
|
||||
char title[256];
|
||||
int key;
|
||||
|
||||
annotation__scnprintf_samples_period(notes, title, sizeof(title), evsel);
|
||||
|
||||
hists__scnprintf_title(hists, title, sizeof(title));
|
||||
if (annotate_browser__show(&browser->b, title, help) < 0)
|
||||
return -1;
|
||||
|
||||
@ -701,6 +739,8 @@ static int annotate_browser__run(struct annotate_browser *browser,
|
||||
"k Toggle line numbers\n"
|
||||
"P Print to [symbol_name].annotation file.\n"
|
||||
"r Run available scripts\n"
|
||||
"p Toggle percent type [local/global]\n"
|
||||
"b Toggle percent base [period/hits]\n"
|
||||
"? Search string backwards\n");
|
||||
continue;
|
||||
case 'r':
|
||||
@ -781,7 +821,7 @@ show_sup_ins:
|
||||
continue;
|
||||
}
|
||||
case 'P':
|
||||
map_symbol__annotation_dump(ms, evsel);
|
||||
map_symbol__annotation_dump(ms, evsel, browser->opts);
|
||||
continue;
|
||||
case 't':
|
||||
if (notes->options->show_total_period) {
|
||||
@ -800,6 +840,12 @@ show_sup_ins:
|
||||
notes->options->show_minmax_cycle = true;
|
||||
annotation__update_column_widths(notes);
|
||||
continue;
|
||||
case 'p':
|
||||
case 'b':
|
||||
switch_percent_type(browser->opts, key == 'b');
|
||||
hists__scnprintf_title(hists, title, sizeof(title));
|
||||
annotate_browser__show(&browser->b, title, help);
|
||||
continue;
|
||||
case K_LEFT:
|
||||
case K_ESC:
|
||||
case 'q':
|
||||
|
@ -87,6 +87,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
|
||||
libperf-$(CONFIG_AUXTRACE) += intel-bts.o
|
||||
libperf-$(CONFIG_AUXTRACE) += arm-spe.o
|
||||
libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o
|
||||
libperf-$(CONFIG_AUXTRACE) += s390-cpumsf.o
|
||||
|
||||
ifdef CONFIG_LIBOPENCSD
|
||||
libperf-$(CONFIG_AUXTRACE) += cs-etm.o
|
||||
|
@ -49,6 +49,7 @@ struct annotation_options annotation__default_options = {
|
||||
.jump_arrows = true,
|
||||
.annotate_src = true,
|
||||
.offset_level = ANNOTATION__OFFSET_JUMP_TARGETS,
|
||||
.percent_type = PERCENT_PERIOD_LOCAL,
|
||||
};
|
||||
|
||||
static regex_t file_lineno;
|
||||
@ -1108,7 +1109,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize)
|
||||
if (perf_evsel__is_group_event(evsel))
|
||||
nr = evsel->nr_members;
|
||||
|
||||
size += sizeof(al->samples[0]) * nr;
|
||||
size += sizeof(al->data[0]) * nr;
|
||||
|
||||
al = zalloc(size);
|
||||
if (al) {
|
||||
@ -1117,7 +1118,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize)
|
||||
al->offset = args->offset;
|
||||
al->line = strdup(args->line);
|
||||
al->line_nr = args->line_nr;
|
||||
al->samples_nr = nr;
|
||||
al->data_nr = nr;
|
||||
}
|
||||
|
||||
return al;
|
||||
@ -1297,7 +1298,8 @@ static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_wi
|
||||
static int
|
||||
annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start,
|
||||
struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
|
||||
int max_lines, struct annotation_line *queue, int addr_fmt_width)
|
||||
int max_lines, struct annotation_line *queue, int addr_fmt_width,
|
||||
int percent_type)
|
||||
{
|
||||
struct disasm_line *dl = container_of(al, struct disasm_line, al);
|
||||
static const char *prev_line;
|
||||
@ -1309,15 +1311,18 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
|
||||
const char *color;
|
||||
struct annotation *notes = symbol__annotation(sym);
|
||||
|
||||
for (i = 0; i < al->samples_nr; i++) {
|
||||
struct annotation_data *sample = &al->samples[i];
|
||||
for (i = 0; i < al->data_nr; i++) {
|
||||
double percent;
|
||||
|
||||
if (sample->percent > max_percent)
|
||||
max_percent = sample->percent;
|
||||
percent = annotation_data__percent(&al->data[i],
|
||||
percent_type);
|
||||
|
||||
if (percent > max_percent)
|
||||
max_percent = percent;
|
||||
}
|
||||
|
||||
if (al->samples_nr > nr_percent)
|
||||
nr_percent = al->samples_nr;
|
||||
if (al->data_nr > nr_percent)
|
||||
nr_percent = al->data_nr;
|
||||
|
||||
if (max_percent < min_pcnt)
|
||||
return -1;
|
||||
@ -1330,7 +1335,8 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
|
||||
if (queue == al)
|
||||
break;
|
||||
annotation_line__print(queue, sym, start, evsel, len,
|
||||
0, 0, 1, NULL, addr_fmt_width);
|
||||
0, 0, 1, NULL, addr_fmt_width,
|
||||
percent_type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1351,18 +1357,20 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_percent; i++) {
|
||||
struct annotation_data *sample = &al->samples[i];
|
||||
struct annotation_data *data = &al->data[i];
|
||||
double percent;
|
||||
|
||||
color = get_percent_color(sample->percent);
|
||||
percent = annotation_data__percent(data, percent_type);
|
||||
color = get_percent_color(percent);
|
||||
|
||||
if (symbol_conf.show_total_period)
|
||||
color_fprintf(stdout, color, " %11" PRIu64,
|
||||
sample->he.period);
|
||||
data->he.period);
|
||||
else if (symbol_conf.show_nr_samples)
|
||||
color_fprintf(stdout, color, " %7" PRIu64,
|
||||
sample->he.nr_samples);
|
||||
data->he.nr_samples);
|
||||
else
|
||||
color_fprintf(stdout, color, " %7.2f", sample->percent);
|
||||
color_fprintf(stdout, color, " %7.2f", percent);
|
||||
}
|
||||
|
||||
printf(" : ");
|
||||
@ -1621,6 +1629,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
||||
char symfs_filename[PATH_MAX];
|
||||
struct kcore_extract kce;
|
||||
bool delete_extract = false;
|
||||
bool decomp = false;
|
||||
int stdout_fd[2];
|
||||
int lineno = 0;
|
||||
int nline;
|
||||
@ -1654,6 +1663,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
||||
tmp, sizeof(tmp)) < 0)
|
||||
goto out;
|
||||
|
||||
decomp = true;
|
||||
strcpy(symfs_filename, tmp);
|
||||
}
|
||||
|
||||
@ -1740,7 +1750,7 @@ out_free_command:
|
||||
out_remove_tmp:
|
||||
close(stdout_fd[0]);
|
||||
|
||||
if (dso__needs_decompress(dso))
|
||||
if (decomp)
|
||||
unlink(symfs_filename);
|
||||
|
||||
if (delete_extract)
|
||||
@ -1753,34 +1763,45 @@ out_close_stdout:
|
||||
goto out_free_command;
|
||||
}
|
||||
|
||||
static void calc_percent(struct sym_hist *hist,
|
||||
struct annotation_data *sample,
|
||||
static void calc_percent(struct sym_hist *sym_hist,
|
||||
struct hists *hists,
|
||||
struct annotation_data *data,
|
||||
s64 offset, s64 end)
|
||||
{
|
||||
unsigned int hits = 0;
|
||||
u64 period = 0;
|
||||
|
||||
while (offset < end) {
|
||||
hits += hist->addr[offset].nr_samples;
|
||||
period += hist->addr[offset].period;
|
||||
hits += sym_hist->addr[offset].nr_samples;
|
||||
period += sym_hist->addr[offset].period;
|
||||
++offset;
|
||||
}
|
||||
|
||||
if (hist->nr_samples) {
|
||||
sample->he.period = period;
|
||||
sample->he.nr_samples = hits;
|
||||
sample->percent = 100.0 * hits / hist->nr_samples;
|
||||
if (sym_hist->nr_samples) {
|
||||
data->he.period = period;
|
||||
data->he.nr_samples = hits;
|
||||
data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples;
|
||||
}
|
||||
|
||||
if (hists->stats.nr_non_filtered_samples)
|
||||
data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples;
|
||||
|
||||
if (sym_hist->period)
|
||||
data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period;
|
||||
|
||||
if (hists->stats.total_period)
|
||||
data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period;
|
||||
}
|
||||
|
||||
static void annotation__calc_percent(struct annotation *notes,
|
||||
struct perf_evsel *evsel, s64 len)
|
||||
struct perf_evsel *leader, s64 len)
|
||||
{
|
||||
struct annotation_line *al, *next;
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
list_for_each_entry(al, ¬es->src->source, node) {
|
||||
s64 end;
|
||||
int i;
|
||||
int i = 0;
|
||||
|
||||
if (al->offset == -1)
|
||||
continue;
|
||||
@ -1788,14 +1809,17 @@ static void annotation__calc_percent(struct annotation *notes,
|
||||
next = annotation_line__next(al, ¬es->src->source);
|
||||
end = next ? next->offset : len;
|
||||
|
||||
for (i = 0; i < al->samples_nr; i++) {
|
||||
struct annotation_data *sample;
|
||||
struct sym_hist *hist;
|
||||
for_each_group_evsel(evsel, leader) {
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct annotation_data *data;
|
||||
struct sym_hist *sym_hist;
|
||||
|
||||
hist = annotation__histogram(notes, evsel->idx + i);
|
||||
sample = &al->samples[i];
|
||||
BUG_ON(i >= al->data_nr);
|
||||
|
||||
calc_percent(hist, sample, al->offset, end);
|
||||
sym_hist = annotation__histogram(notes, evsel->idx);
|
||||
data = &al->data[i++];
|
||||
|
||||
calc_percent(sym_hist, hists, data, al->offset, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1846,7 +1870,8 @@ int symbol__annotate(struct symbol *sym, struct map *map,
|
||||
return symbol__disassemble(sym, &args);
|
||||
}
|
||||
|
||||
static void insert_source_line(struct rb_root *root, struct annotation_line *al)
|
||||
static void insert_source_line(struct rb_root *root, struct annotation_line *al,
|
||||
struct annotation_options *opts)
|
||||
{
|
||||
struct annotation_line *iter;
|
||||
struct rb_node **p = &root->rb_node;
|
||||
@ -1859,8 +1884,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al)
|
||||
|
||||
ret = strcmp(iter->path, al->path);
|
||||
if (ret == 0) {
|
||||
for (i = 0; i < al->samples_nr; i++)
|
||||
iter->samples[i].percent_sum += al->samples[i].percent;
|
||||
for (i = 0; i < al->data_nr; i++) {
|
||||
iter->data[i].percent_sum += annotation_data__percent(&al->data[i],
|
||||
opts->percent_type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1870,8 +1897,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al)
|
||||
p = &(*p)->rb_right;
|
||||
}
|
||||
|
||||
for (i = 0; i < al->samples_nr; i++)
|
||||
al->samples[i].percent_sum = al->samples[i].percent;
|
||||
for (i = 0; i < al->data_nr; i++) {
|
||||
al->data[i].percent_sum = annotation_data__percent(&al->data[i],
|
||||
opts->percent_type);
|
||||
}
|
||||
|
||||
rb_link_node(&al->rb_node, parent, p);
|
||||
rb_insert_color(&al->rb_node, root);
|
||||
@ -1881,10 +1910,10 @@ static int cmp_source_line(struct annotation_line *a, struct annotation_line *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < a->samples_nr; i++) {
|
||||
if (a->samples[i].percent_sum == b->samples[i].percent_sum)
|
||||
for (i = 0; i < a->data_nr; i++) {
|
||||
if (a->data[i].percent_sum == b->data[i].percent_sum)
|
||||
continue;
|
||||
return a->samples[i].percent_sum > b->samples[i].percent_sum;
|
||||
return a->data[i].percent_sum > b->data[i].percent_sum;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1949,8 +1978,8 @@ static void print_summary(struct rb_root *root, const char *filename)
|
||||
int i;
|
||||
|
||||
al = rb_entry(node, struct annotation_line, rb_node);
|
||||
for (i = 0; i < al->samples_nr; i++) {
|
||||
percent = al->samples[i].percent_sum;
|
||||
for (i = 0; i < al->data_nr; i++) {
|
||||
percent = al->data[i].percent_sum;
|
||||
color = get_percent_color(percent);
|
||||
color_fprintf(stdout, color, " %7.2f", percent);
|
||||
|
||||
@ -2029,10 +2058,12 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
|
||||
evsel_name = buf;
|
||||
}
|
||||
|
||||
graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n",
|
||||
graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples, "
|
||||
"percent: %s)\n",
|
||||
width, width, symbol_conf.show_total_period ? "Period" :
|
||||
symbol_conf.show_nr_samples ? "Samples" : "Percent",
|
||||
d_filename, evsel_name, h->nr_samples);
|
||||
d_filename, evsel_name, h->nr_samples,
|
||||
percent_type_str(opts->percent_type));
|
||||
|
||||
printf("%-*.*s----\n",
|
||||
graph_dotted_len, graph_dotted_len, graph_dotted_line);
|
||||
@ -2052,7 +2083,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
|
||||
|
||||
err = annotation_line__print(pos, sym, start, evsel, len,
|
||||
opts->min_pcnt, printed, opts->max_lines,
|
||||
queue, addr_fmt_width);
|
||||
queue, addr_fmt_width, opts->percent_type);
|
||||
|
||||
switch (err) {
|
||||
case 0:
|
||||
@ -2129,10 +2160,11 @@ static void FILE__write_graph(void *fp, int graph)
|
||||
fputs(s, fp);
|
||||
}
|
||||
|
||||
int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp)
|
||||
static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp,
|
||||
struct annotation_options *opts)
|
||||
{
|
||||
struct annotation *notes = symbol__annotation(sym);
|
||||
struct annotation_write_ops ops = {
|
||||
struct annotation_write_ops wops = {
|
||||
.first_line = true,
|
||||
.obj = fp,
|
||||
.set_color = FILE__set_color,
|
||||
@ -2146,15 +2178,16 @@ int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp)
|
||||
list_for_each_entry(al, ¬es->src->source, node) {
|
||||
if (annotation_line__filter(al, notes))
|
||||
continue;
|
||||
annotation_line__write(al, notes, &ops);
|
||||
annotation_line__write(al, notes, &wops, opts);
|
||||
fputc('\n', fp);
|
||||
ops.first_line = false;
|
||||
wops.first_line = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel)
|
||||
int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel,
|
||||
struct annotation_options *opts)
|
||||
{
|
||||
const char *ev_name = perf_evsel__name(evsel);
|
||||
char buf[1024];
|
||||
@ -2176,7 +2209,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel)
|
||||
|
||||
fprintf(fp, "%s() %s\nEvent: %s\n\n",
|
||||
ms->sym->name, ms->map->dso->long_name, ev_name);
|
||||
symbol__annotate_fprintf2(ms->sym, fp);
|
||||
symbol__annotate_fprintf2(ms->sym, fp, opts);
|
||||
|
||||
fclose(fp);
|
||||
err = 0;
|
||||
@ -2346,7 +2379,8 @@ void annotation__update_column_widths(struct annotation *notes)
|
||||
}
|
||||
|
||||
static void annotation__calc_lines(struct annotation *notes, struct map *map,
|
||||
struct rb_root *root)
|
||||
struct rb_root *root,
|
||||
struct annotation_options *opts)
|
||||
{
|
||||
struct annotation_line *al;
|
||||
struct rb_root tmp_root = RB_ROOT;
|
||||
@ -2355,13 +2389,14 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map,
|
||||
double percent_max = 0.0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < al->samples_nr; i++) {
|
||||
struct annotation_data *sample;
|
||||
for (i = 0; i < al->data_nr; i++) {
|
||||
double percent;
|
||||
|
||||
sample = &al->samples[i];
|
||||
percent = annotation_data__percent(&al->data[i],
|
||||
opts->percent_type);
|
||||
|
||||
if (sample->percent > percent_max)
|
||||
percent_max = sample->percent;
|
||||
if (percent > percent_max)
|
||||
percent_max = percent;
|
||||
}
|
||||
|
||||
if (percent_max <= 0.5)
|
||||
@ -2369,18 +2404,19 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map,
|
||||
|
||||
al->path = get_srcline(map->dso, notes->start + al->offset, NULL,
|
||||
false, true, notes->start + al->offset);
|
||||
insert_source_line(&tmp_root, al);
|
||||
insert_source_line(&tmp_root, al, opts);
|
||||
}
|
||||
|
||||
resort_source_line(root, &tmp_root);
|
||||
}
|
||||
|
||||
static void symbol__calc_lines(struct symbol *sym, struct map *map,
|
||||
struct rb_root *root)
|
||||
struct rb_root *root,
|
||||
struct annotation_options *opts)
|
||||
{
|
||||
struct annotation *notes = symbol__annotation(sym);
|
||||
|
||||
annotation__calc_lines(notes, map, root);
|
||||
annotation__calc_lines(notes, map, root, opts);
|
||||
}
|
||||
|
||||
int symbol__tty_annotate2(struct symbol *sym, struct map *map,
|
||||
@ -2389,7 +2425,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map,
|
||||
{
|
||||
struct dso *dso = map->dso;
|
||||
struct rb_root source_line = RB_ROOT;
|
||||
struct annotation *notes = symbol__annotation(sym);
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
char buf[1024];
|
||||
|
||||
if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0)
|
||||
@ -2397,13 +2433,14 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map,
|
||||
|
||||
if (opts->print_lines) {
|
||||
srcline_full_filename = opts->full_path;
|
||||
symbol__calc_lines(sym, map, &source_line);
|
||||
symbol__calc_lines(sym, map, &source_line, opts);
|
||||
print_summary(&source_line, dso->long_name);
|
||||
}
|
||||
|
||||
annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel);
|
||||
fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name);
|
||||
symbol__annotate_fprintf2(sym, stdout);
|
||||
hists__scnprintf_title(hists, buf, sizeof(buf));
|
||||
fprintf(stdout, "%s, [percent: %s]\n%s() %s\n",
|
||||
buf, percent_type_str(opts->percent_type), sym->name, dso->long_name);
|
||||
symbol__annotate_fprintf2(sym, stdout, opts);
|
||||
|
||||
annotated_source__purge(symbol__annotation(sym)->src);
|
||||
|
||||
@ -2424,7 +2461,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
|
||||
|
||||
if (opts->print_lines) {
|
||||
srcline_full_filename = opts->full_path;
|
||||
symbol__calc_lines(sym, map, &source_line);
|
||||
symbol__calc_lines(sym, map, &source_line, opts);
|
||||
print_summary(&source_line, dso->long_name);
|
||||
}
|
||||
|
||||
@ -2441,14 +2478,21 @@ bool ui__has_annotation(void)
|
||||
}
|
||||
|
||||
|
||||
double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes)
|
||||
static double annotation_line__max_percent(struct annotation_line *al,
|
||||
struct annotation *notes,
|
||||
unsigned int percent_type)
|
||||
{
|
||||
double percent_max = 0.0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < notes->nr_events; i++) {
|
||||
if (al->samples[i].percent > percent_max)
|
||||
percent_max = al->samples[i].percent;
|
||||
double percent;
|
||||
|
||||
percent = annotation_data__percent(&al->data[i],
|
||||
percent_type);
|
||||
|
||||
if (percent > percent_max)
|
||||
percent_max = percent;
|
||||
}
|
||||
|
||||
return percent_max;
|
||||
@ -2487,7 +2531,7 @@ call_like:
|
||||
|
||||
static void __annotation_line__write(struct annotation_line *al, struct annotation *notes,
|
||||
bool first_line, bool current_entry, bool change_color, int width,
|
||||
void *obj,
|
||||
void *obj, unsigned int percent_type,
|
||||
int (*obj__set_color)(void *obj, int color),
|
||||
void (*obj__set_percent_color)(void *obj, double percent, bool current),
|
||||
int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current),
|
||||
@ -2495,7 +2539,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
|
||||
void (*obj__write_graph)(void *obj, int graph))
|
||||
|
||||
{
|
||||
double percent_max = annotation_line__max_percent(al, notes);
|
||||
double percent_max = annotation_line__max_percent(al, notes, percent_type);
|
||||
int pcnt_width = annotation__pcnt_width(notes),
|
||||
cycles_width = annotation__cycles_width(notes);
|
||||
bool show_title = false;
|
||||
@ -2514,15 +2558,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
|
||||
int i;
|
||||
|
||||
for (i = 0; i < notes->nr_events; i++) {
|
||||
obj__set_percent_color(obj, al->samples[i].percent, current_entry);
|
||||
double percent;
|
||||
|
||||
percent = annotation_data__percent(&al->data[i], percent_type);
|
||||
|
||||
obj__set_percent_color(obj, percent, current_entry);
|
||||
if (notes->options->show_total_period) {
|
||||
obj__printf(obj, "%11" PRIu64 " ", al->samples[i].he.period);
|
||||
obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
|
||||
} else if (notes->options->show_nr_samples) {
|
||||
obj__printf(obj, "%6" PRIu64 " ",
|
||||
al->samples[i].he.nr_samples);
|
||||
al->data[i].he.nr_samples);
|
||||
} else {
|
||||
obj__printf(obj, "%6.2f ",
|
||||
al->samples[i].percent);
|
||||
obj__printf(obj, "%6.2f ", percent);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -2640,13 +2687,15 @@ print_addr:
|
||||
}
|
||||
|
||||
void annotation_line__write(struct annotation_line *al, struct annotation *notes,
|
||||
struct annotation_write_ops *ops)
|
||||
struct annotation_write_ops *wops,
|
||||
struct annotation_options *opts)
|
||||
{
|
||||
__annotation_line__write(al, notes, ops->first_line, ops->current_entry,
|
||||
ops->change_color, ops->width, ops->obj,
|
||||
ops->set_color, ops->set_percent_color,
|
||||
ops->set_jumps_percent_color, ops->printf,
|
||||
ops->write_graph);
|
||||
__annotation_line__write(al, notes, wops->first_line, wops->current_entry,
|
||||
wops->change_color, wops->width, wops->obj,
|
||||
opts->percent_type,
|
||||
wops->set_color, wops->set_percent_color,
|
||||
wops->set_jumps_percent_color, wops->printf,
|
||||
wops->write_graph);
|
||||
}
|
||||
|
||||
int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel,
|
||||
@ -2688,46 +2737,6 @@ out_free_offsets:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __annotation__scnprintf_samples_period(struct annotation *notes,
|
||||
char *bf, size_t size,
|
||||
struct perf_evsel *evsel,
|
||||
bool show_freq)
|
||||
{
|
||||
const char *ev_name = perf_evsel__name(evsel);
|
||||
char buf[1024], ref[30] = " show reference callgraph, ";
|
||||
char sample_freq_str[64] = "";
|
||||
unsigned long nr_samples = 0;
|
||||
int nr_members = 1;
|
||||
bool enable_ref = false;
|
||||
u64 nr_events = 0;
|
||||
char unit;
|
||||
int i;
|
||||
|
||||
if (perf_evsel__is_group_event(evsel)) {
|
||||
perf_evsel__group_desc(evsel, buf, sizeof(buf));
|
||||
ev_name = buf;
|
||||
nr_members = evsel->nr_members;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_members; i++) {
|
||||
struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i);
|
||||
|
||||
nr_samples += ah->nr_samples;
|
||||
nr_events += ah->period;
|
||||
}
|
||||
|
||||
if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no"))
|
||||
enable_ref = true;
|
||||
|
||||
if (show_freq)
|
||||
scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq);
|
||||
|
||||
nr_samples = convert_unit(nr_samples, &unit);
|
||||
return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
|
||||
nr_samples, unit, evsel->nr_members > 1 ? "s" : "",
|
||||
ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
|
||||
}
|
||||
|
||||
#define ANNOTATION__CFG(n) \
|
||||
{ .name = #n, .value = &annotation__default_options.n, }
|
||||
|
||||
@ -2792,3 +2801,55 @@ void annotation_config__init(void)
|
||||
annotation__default_options.show_total_period = symbol_conf.show_total_period;
|
||||
annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples;
|
||||
}
|
||||
|
||||
static unsigned int parse_percent_type(char *str1, char *str2)
|
||||
{
|
||||
unsigned int type = (unsigned int) -1;
|
||||
|
||||
if (!strcmp("period", str1)) {
|
||||
if (!strcmp("local", str2))
|
||||
type = PERCENT_PERIOD_LOCAL;
|
||||
else if (!strcmp("global", str2))
|
||||
type = PERCENT_PERIOD_GLOBAL;
|
||||
}
|
||||
|
||||
if (!strcmp("hits", str1)) {
|
||||
if (!strcmp("local", str2))
|
||||
type = PERCENT_HITS_LOCAL;
|
||||
else if (!strcmp("global", str2))
|
||||
type = PERCENT_HITS_GLOBAL;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
int annotate_parse_percent_type(const struct option *opt, const char *_str,
|
||||
int unset __maybe_unused)
|
||||
{
|
||||
struct annotation_options *opts = opt->value;
|
||||
unsigned int type;
|
||||
char *str1, *str2;
|
||||
int err = -1;
|
||||
|
||||
str1 = strdup(_str);
|
||||
if (!str1)
|
||||
return -ENOMEM;
|
||||
|
||||
str2 = strchr(str1, '-');
|
||||
if (!str2)
|
||||
goto out;
|
||||
|
||||
*str2++ = 0;
|
||||
|
||||
type = parse_percent_type(str1, str2);
|
||||
if (type == (unsigned int) -1)
|
||||
type = parse_percent_type(str2, str1);
|
||||
if (type != (unsigned int) -1) {
|
||||
opts->percent_type = type;
|
||||
err = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
free(str1);
|
||||
return err;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <pthread.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
struct ins_ops;
|
||||
|
||||
@ -82,6 +83,7 @@ struct annotation_options {
|
||||
int context;
|
||||
const char *objdump_path;
|
||||
const char *disassembler_style;
|
||||
unsigned int percent_type;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -101,8 +103,16 @@ struct sym_hist_entry {
|
||||
u64 period;
|
||||
};
|
||||
|
||||
enum {
|
||||
PERCENT_HITS_LOCAL,
|
||||
PERCENT_HITS_GLOBAL,
|
||||
PERCENT_PERIOD_LOCAL,
|
||||
PERCENT_PERIOD_GLOBAL,
|
||||
PERCENT_MAX,
|
||||
};
|
||||
|
||||
struct annotation_data {
|
||||
double percent;
|
||||
double percent[PERCENT_MAX];
|
||||
double percent_sum;
|
||||
struct sym_hist_entry he;
|
||||
};
|
||||
@ -122,8 +132,8 @@ struct annotation_line {
|
||||
char *path;
|
||||
u32 idx;
|
||||
int idx_asm;
|
||||
int samples_nr;
|
||||
struct annotation_data samples[0];
|
||||
int data_nr;
|
||||
struct annotation_data data[0];
|
||||
};
|
||||
|
||||
struct disasm_line {
|
||||
@ -134,6 +144,27 @@ struct disasm_line {
|
||||
struct annotation_line al;
|
||||
};
|
||||
|
||||
static inline double annotation_data__percent(struct annotation_data *data,
|
||||
unsigned int which)
|
||||
{
|
||||
return which < PERCENT_MAX ? data->percent[which] : -1;
|
||||
}
|
||||
|
||||
static inline const char *percent_type_str(unsigned int type)
|
||||
{
|
||||
static const char *str[PERCENT_MAX] = {
|
||||
"local hits",
|
||||
"global hits",
|
||||
"local period",
|
||||
"global period",
|
||||
};
|
||||
|
||||
if (WARN_ON(type >= PERCENT_MAX))
|
||||
return "N/A";
|
||||
|
||||
return str[type];
|
||||
}
|
||||
|
||||
static inline struct disasm_line *disasm_line(struct annotation_line *al)
|
||||
{
|
||||
return al ? container_of(al, struct disasm_line, al) : NULL;
|
||||
@ -169,22 +200,15 @@ struct annotation_write_ops {
|
||||
void (*write_graph)(void *obj, int graph);
|
||||
};
|
||||
|
||||
double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes);
|
||||
void annotation_line__write(struct annotation_line *al, struct annotation *notes,
|
||||
struct annotation_write_ops *ops);
|
||||
struct annotation_write_ops *ops,
|
||||
struct annotation_options *opts);
|
||||
|
||||
int __annotation__scnprintf_samples_period(struct annotation *notes,
|
||||
char *bf, size_t size,
|
||||
struct perf_evsel *evsel,
|
||||
bool show_freq);
|
||||
|
||||
static inline int annotation__scnprintf_samples_period(struct annotation *notes,
|
||||
char *bf, size_t size,
|
||||
struct perf_evsel *evsel)
|
||||
{
|
||||
return __annotation__scnprintf_samples_period(notes, bf, size, evsel, true);
|
||||
}
|
||||
|
||||
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
|
||||
size_t disasm__fprintf(struct list_head *head, FILE *fp);
|
||||
void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel);
|
||||
@ -340,12 +364,12 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map,
|
||||
int symbol__annotate_printf(struct symbol *sym, struct map *map,
|
||||
struct perf_evsel *evsel,
|
||||
struct annotation_options *options);
|
||||
int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp);
|
||||
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
|
||||
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
|
||||
void annotated_source__purge(struct annotated_source *as);
|
||||
|
||||
int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel);
|
||||
int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel,
|
||||
struct annotation_options *opts);
|
||||
|
||||
bool ui__has_annotation(void);
|
||||
|
||||
@ -373,4 +397,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
|
||||
|
||||
void annotation_config__init(void);
|
||||
|
||||
int annotate_parse_percent_type(const struct option *opt, const char *_str,
|
||||
int unset);
|
||||
#endif /* __PERF_ANNOTATE_H */
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "intel-pt.h"
|
||||
#include "intel-bts.h"
|
||||
#include "arm-spe.h"
|
||||
#include "s390-cpumsf.h"
|
||||
|
||||
#include "sane_ctype.h"
|
||||
#include "symbol/kallsyms.h"
|
||||
@ -202,6 +203,9 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues,
|
||||
for (i = 0; i < queues->nr_queues; i++) {
|
||||
list_splice_tail(&queues->queue_array[i].head,
|
||||
&queue_array[i].head);
|
||||
queue_array[i].tid = queues->queue_array[i].tid;
|
||||
queue_array[i].cpu = queues->queue_array[i].cpu;
|
||||
queue_array[i].set = queues->queue_array[i].set;
|
||||
queue_array[i].priv = queues->queue_array[i].priv;
|
||||
}
|
||||
|
||||
@ -920,6 +924,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
|
||||
return arm_spe_process_auxtrace_info(event, session);
|
||||
case PERF_AUXTRACE_CS_ETM:
|
||||
return cs_etm__process_auxtrace_info(event, session);
|
||||
case PERF_AUXTRACE_S390_CPUMSF:
|
||||
return s390_cpumsf_process_auxtrace_info(event, session);
|
||||
case PERF_AUXTRACE_UNKNOWN:
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -44,6 +44,7 @@ enum auxtrace_type {
|
||||
PERF_AUXTRACE_INTEL_BTS,
|
||||
PERF_AUXTRACE_CS_ETM,
|
||||
PERF_AUXTRACE_ARM_SPE,
|
||||
PERF_AUXTRACE_S390_CPUMSF,
|
||||
};
|
||||
|
||||
enum itrace_period_type {
|
||||
|
@ -1529,13 +1529,13 @@ int bpf__apply_obj_config(void)
|
||||
bpf_object__for_each_safe(obj, objtmp) \
|
||||
bpf_map__for_each(pos, obj)
|
||||
|
||||
#define bpf__for_each_stdout_map(pos, obj, objtmp) \
|
||||
#define bpf__for_each_map_named(pos, obj, objtmp, name) \
|
||||
bpf__for_each_map(pos, obj, objtmp) \
|
||||
if (bpf_map__name(pos) && \
|
||||
(strcmp("__bpf_stdout__", \
|
||||
(strcmp(name, \
|
||||
bpf_map__name(pos)) == 0))
|
||||
|
||||
int bpf__setup_stdout(struct perf_evlist *evlist)
|
||||
struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name)
|
||||
{
|
||||
struct bpf_map_priv *tmpl_priv = NULL;
|
||||
struct bpf_object *obj, *tmp;
|
||||
@ -1544,11 +1544,11 @@ int bpf__setup_stdout(struct perf_evlist *evlist)
|
||||
int err;
|
||||
bool need_init = false;
|
||||
|
||||
bpf__for_each_stdout_map(map, obj, tmp) {
|
||||
bpf__for_each_map_named(map, obj, tmp, name) {
|
||||
struct bpf_map_priv *priv = bpf_map__priv(map);
|
||||
|
||||
if (IS_ERR(priv))
|
||||
return -BPF_LOADER_ERRNO__INTERNAL;
|
||||
return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL);
|
||||
|
||||
/*
|
||||
* No need to check map type: type should have been
|
||||
@ -1561,49 +1561,61 @@ int bpf__setup_stdout(struct perf_evlist *evlist)
|
||||
}
|
||||
|
||||
if (!need_init)
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
if (!tmpl_priv) {
|
||||
err = parse_events(evlist, "bpf-output/no-inherit=1,name=__bpf_stdout__/",
|
||||
NULL);
|
||||
char *event_definition = NULL;
|
||||
|
||||
if (asprintf(&event_definition, "bpf-output/no-inherit=1,name=%s/", name) < 0)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = parse_events(evlist, event_definition, NULL);
|
||||
free(event_definition);
|
||||
|
||||
if (err) {
|
||||
pr_debug("ERROR: failed to create bpf-output event\n");
|
||||
return -err;
|
||||
pr_debug("ERROR: failed to create the \"%s\" bpf-output event\n", name);
|
||||
return ERR_PTR(-err);
|
||||
}
|
||||
|
||||
evsel = perf_evlist__last(evlist);
|
||||
}
|
||||
|
||||
bpf__for_each_stdout_map(map, obj, tmp) {
|
||||
bpf__for_each_map_named(map, obj, tmp, name) {
|
||||
struct bpf_map_priv *priv = bpf_map__priv(map);
|
||||
|
||||
if (IS_ERR(priv))
|
||||
return -BPF_LOADER_ERRNO__INTERNAL;
|
||||
return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL);
|
||||
if (priv)
|
||||
continue;
|
||||
|
||||
if (tmpl_priv) {
|
||||
priv = bpf_map_priv__clone(tmpl_priv);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = bpf_map__set_priv(map, priv, bpf_map_priv__clear);
|
||||
if (err) {
|
||||
bpf_map_priv__clear(map, priv);
|
||||
return err;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
} else if (evsel) {
|
||||
struct bpf_map_op *op;
|
||||
|
||||
op = bpf_map__add_newop(map, NULL);
|
||||
if (IS_ERR(op))
|
||||
return PTR_ERR(op);
|
||||
return ERR_PTR(PTR_ERR(op));
|
||||
op->op_type = BPF_MAP_OP_SET_EVSEL;
|
||||
op->v.evsel = evsel;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return evsel;
|
||||
}
|
||||
|
||||
int bpf__setup_stdout(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__");
|
||||
return IS_ERR(evsel) ? PTR_ERR(evsel) : 0;
|
||||
}
|
||||
|
||||
#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
|
||||
@ -1780,8 +1792,8 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused,
|
||||
int err, char *buf, size_t size)
|
||||
int bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused,
|
||||
int err, char *buf, size_t size)
|
||||
{
|
||||
bpf__strerror_head(err, buf, size);
|
||||
bpf__strerror_end(buf, size);
|
||||
|
@ -43,6 +43,7 @@ enum bpf_loader_errno {
|
||||
__BPF_LOADER_ERRNO__END,
|
||||
};
|
||||
|
||||
struct perf_evsel;
|
||||
struct bpf_object;
|
||||
struct parse_events_term;
|
||||
#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
|
||||
@ -82,9 +83,8 @@ int bpf__apply_obj_config(void);
|
||||
int bpf__strerror_apply_obj_config(int err, char *buf, size_t size);
|
||||
|
||||
int bpf__setup_stdout(struct perf_evlist *evlist);
|
||||
int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err,
|
||||
char *buf, size_t size);
|
||||
|
||||
struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name);
|
||||
int bpf__strerror_setup_output_event(struct perf_evlist *evlist, int err, char *buf, size_t size);
|
||||
#else
|
||||
#include <errno.h>
|
||||
|
||||
@ -138,6 +138,12 @@ bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct perf_evsel *
|
||||
bpf__setup_output_event(struct perf_evlist *evlist __maybe_unused, const char *name __maybe_unused)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__bpf_strerror(char *buf, size_t size)
|
||||
{
|
||||
@ -193,11 +199,16 @@ bpf__strerror_apply_obj_config(int err __maybe_unused,
|
||||
}
|
||||
|
||||
static inline int
|
||||
bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused,
|
||||
int err __maybe_unused, char *buf,
|
||||
size_t size)
|
||||
bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused,
|
||||
int err __maybe_unused, char *buf, size_t size)
|
||||
{
|
||||
return __bpf_strerror(buf, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, char *buf, size_t size)
|
||||
{
|
||||
return bpf__strerror_setup_output_event(evlist, err, buf, size);
|
||||
}
|
||||
#endif
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
#ifdef HAVE_ZLIB_SUPPORT
|
||||
int gzip_decompress_to_file(const char *input, int output_fd);
|
||||
bool gzip_is_compressed(const char *input);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LZMA_SUPPORT
|
||||
int lzma_decompress_to_file(const char *input, int output_fd);
|
||||
bool lzma_is_compressed(const char *input);
|
||||
#endif
|
||||
|
||||
#endif /* PERF_COMPRESS_H */
|
||||
|
@ -310,8 +310,8 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
|
||||
if (flags & FIELD_IS_DYNAMIC) {
|
||||
unsigned long long tmp_val;
|
||||
|
||||
tmp_val = pevent_read_number(fmtf->event->pevent,
|
||||
data + offset, len);
|
||||
tmp_val = tep_read_number(fmtf->event->pevent,
|
||||
data + offset, len);
|
||||
offset = tmp_val;
|
||||
len = offset >> 16;
|
||||
offset &= 0xffff;
|
||||
@ -353,7 +353,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
|
||||
else {
|
||||
unsigned long long value_int;
|
||||
|
||||
value_int = pevent_read_number(
|
||||
value_int = tep_read_number(
|
||||
fmtf->event->pevent,
|
||||
data + offset + i * len, len);
|
||||
|
||||
|
@ -189,28 +189,34 @@ int dso__read_binary_type_filename(const struct dso *dso,
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum {
|
||||
COMP_ID__NONE = 0,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *fmt;
|
||||
int (*decompress)(const char *input, int output);
|
||||
bool (*is_compressed)(const char *input);
|
||||
} compressions[] = {
|
||||
[COMP_ID__NONE] = { .fmt = NULL, },
|
||||
#ifdef HAVE_ZLIB_SUPPORT
|
||||
{ "gz", gzip_decompress_to_file },
|
||||
{ "gz", gzip_decompress_to_file, gzip_is_compressed },
|
||||
#endif
|
||||
#ifdef HAVE_LZMA_SUPPORT
|
||||
{ "xz", lzma_decompress_to_file },
|
||||
{ "xz", lzma_decompress_to_file, lzma_is_compressed },
|
||||
#endif
|
||||
{ NULL, NULL },
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
bool is_supported_compression(const char *ext)
|
||||
static int is_supported_compression(const char *ext)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; compressions[i].fmt; i++) {
|
||||
for (i = 1; compressions[i].fmt; i++) {
|
||||
if (!strcmp(ext, compressions[i].fmt))
|
||||
return true;
|
||||
return i;
|
||||
}
|
||||
return false;
|
||||
return COMP_ID__NONE;
|
||||
}
|
||||
|
||||
bool is_kernel_module(const char *pathname, int cpumode)
|
||||
@ -239,80 +245,73 @@ bool is_kernel_module(const char *pathname, int cpumode)
|
||||
return m.kmod;
|
||||
}
|
||||
|
||||
bool decompress_to_file(const char *ext, const char *filename, int output_fd)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; compressions[i].fmt; i++) {
|
||||
if (!strcmp(ext, compressions[i].fmt))
|
||||
return !compressions[i].decompress(filename,
|
||||
output_fd);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dso__needs_decompress(struct dso *dso)
|
||||
{
|
||||
return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
|
||||
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
|
||||
}
|
||||
|
||||
static int decompress_kmodule(struct dso *dso, const char *name, char *tmpbuf)
|
||||
static int decompress_kmodule(struct dso *dso, const char *name,
|
||||
char *pathname, size_t len)
|
||||
{
|
||||
char tmpbuf[] = KMOD_DECOMP_NAME;
|
||||
int fd = -1;
|
||||
struct kmod_path m;
|
||||
|
||||
if (!dso__needs_decompress(dso))
|
||||
return -1;
|
||||
|
||||
if (kmod_path__parse_ext(&m, dso->long_name))
|
||||
if (dso->comp == COMP_ID__NONE)
|
||||
return -1;
|
||||
|
||||
if (!m.comp)
|
||||
goto out;
|
||||
/*
|
||||
* We have proper compression id for DSO and yet the file
|
||||
* behind the 'name' can still be plain uncompressed object.
|
||||
*
|
||||
* The reason is behind the logic we open the DSO object files,
|
||||
* when we try all possible 'debug' objects until we find the
|
||||
* data. So even if the DSO is represented by 'krava.xz' module,
|
||||
* we can end up here opening ~/.debug/....23432432/debug' file
|
||||
* which is not compressed.
|
||||
*
|
||||
* To keep this transparent, we detect this and return the file
|
||||
* descriptor to the uncompressed file.
|
||||
*/
|
||||
if (!compressions[dso->comp].is_compressed(name))
|
||||
return open(name, O_RDONLY);
|
||||
|
||||
fd = mkstemp(tmpbuf);
|
||||
if (fd < 0) {
|
||||
dso->load_errno = errno;
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!decompress_to_file(m.ext, name, fd)) {
|
||||
if (compressions[dso->comp].decompress(name, fd)) {
|
||||
dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
out:
|
||||
free(m.ext);
|
||||
if (!pathname || (fd < 0))
|
||||
unlink(tmpbuf);
|
||||
|
||||
if (pathname && (fd >= 0))
|
||||
strncpy(pathname, tmpbuf, len);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int dso__decompress_kmodule_fd(struct dso *dso, const char *name)
|
||||
{
|
||||
char tmpbuf[] = KMOD_DECOMP_NAME;
|
||||
int fd;
|
||||
|
||||
fd = decompress_kmodule(dso, name, tmpbuf);
|
||||
unlink(tmpbuf);
|
||||
return fd;
|
||||
return decompress_kmodule(dso, name, NULL, 0);
|
||||
}
|
||||
|
||||
int dso__decompress_kmodule_path(struct dso *dso, const char *name,
|
||||
char *pathname, size_t len)
|
||||
{
|
||||
char tmpbuf[] = KMOD_DECOMP_NAME;
|
||||
int fd;
|
||||
int fd = decompress_kmodule(dso, name, pathname, len);
|
||||
|
||||
fd = decompress_kmodule(dso, name, tmpbuf);
|
||||
if (fd < 0) {
|
||||
unlink(tmpbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(pathname, tmpbuf, len);
|
||||
close(fd);
|
||||
return 0;
|
||||
return fd >= 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -332,7 +331,7 @@ int dso__decompress_kmodule_path(struct dso *dso, const char *name,
|
||||
* Returns 0 if there's no strdup error, -ENOMEM otherwise.
|
||||
*/
|
||||
int __kmod_path__parse(struct kmod_path *m, const char *path,
|
||||
bool alloc_name, bool alloc_ext)
|
||||
bool alloc_name)
|
||||
{
|
||||
const char *name = strrchr(path, '/');
|
||||
const char *ext = strrchr(path, '.');
|
||||
@ -372,10 +371,9 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_supported_compression(ext + 1)) {
|
||||
m->comp = true;
|
||||
m->comp = is_supported_compression(ext + 1);
|
||||
if (m->comp > COMP_ID__NONE)
|
||||
ext -= 3;
|
||||
}
|
||||
|
||||
/* Check .ko extension only if there's enough name left. */
|
||||
if (ext > name)
|
||||
@ -393,14 +391,6 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
|
||||
strxfrchar(m->name, '-', '_');
|
||||
}
|
||||
|
||||
if (alloc_ext && m->comp) {
|
||||
m->ext = strdup(ext + 4);
|
||||
if (!m->ext) {
|
||||
free((void *) m->name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -413,8 +403,10 @@ void dso__set_module_info(struct dso *dso, struct kmod_path *m,
|
||||
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
|
||||
|
||||
/* _KMODULE_COMP should be next to _KMODULE */
|
||||
if (m->kmod && m->comp)
|
||||
if (m->kmod && m->comp) {
|
||||
dso->symtab_type++;
|
||||
dso->comp = m->comp;
|
||||
}
|
||||
|
||||
dso__set_short_name(dso, strdup(m->name), true);
|
||||
}
|
||||
@ -468,6 +460,7 @@ static int __open_dso(struct dso *dso, struct machine *machine)
|
||||
int fd = -EINVAL;
|
||||
char *root_dir = (char *)"";
|
||||
char *name = malloc(PATH_MAX);
|
||||
bool decomp = false;
|
||||
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
@ -491,12 +484,13 @@ static int __open_dso(struct dso *dso, struct machine *machine)
|
||||
goto out;
|
||||
}
|
||||
|
||||
decomp = true;
|
||||
strcpy(name, newpath);
|
||||
}
|
||||
|
||||
fd = do_open(name);
|
||||
|
||||
if (dso__needs_decompress(dso))
|
||||
if (decomp)
|
||||
unlink(name);
|
||||
|
||||
out:
|
||||
@ -1218,6 +1212,7 @@ struct dso *dso__new(const char *name)
|
||||
dso->a2l_fails = 1;
|
||||
dso->kernel = DSO_TYPE_USER;
|
||||
dso->needs_swap = DSO_SWAP__UNSET;
|
||||
dso->comp = COMP_ID__NONE;
|
||||
RB_CLEAR_NODE(&dso->rb_node);
|
||||
dso->root = NULL;
|
||||
INIT_LIST_HEAD(&dso->node);
|
||||
|
@ -175,6 +175,7 @@ struct dso {
|
||||
u16 short_name_len;
|
||||
void *dwfl; /* DWARF debug info */
|
||||
struct auxtrace_cache *auxtrace_cache;
|
||||
int comp;
|
||||
|
||||
/* dso data file */
|
||||
struct {
|
||||
@ -250,9 +251,7 @@ int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
|
||||
char dso__symtab_origin(const struct dso *dso);
|
||||
int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
|
||||
char *root_dir, char *filename, size_t size);
|
||||
bool is_supported_compression(const char *ext);
|
||||
bool is_kernel_module(const char *pathname, int cpumode);
|
||||
bool decompress_to_file(const char *ext, const char *filename, int output_fd);
|
||||
bool dso__needs_decompress(struct dso *dso);
|
||||
int dso__decompress_kmodule_fd(struct dso *dso, const char *name);
|
||||
int dso__decompress_kmodule_path(struct dso *dso, const char *name,
|
||||
@ -263,17 +262,15 @@ int dso__decompress_kmodule_path(struct dso *dso, const char *name,
|
||||
|
||||
struct kmod_path {
|
||||
char *name;
|
||||
char *ext;
|
||||
bool comp;
|
||||
int comp;
|
||||
bool kmod;
|
||||
};
|
||||
|
||||
int __kmod_path__parse(struct kmod_path *m, const char *path,
|
||||
bool alloc_name, bool alloc_ext);
|
||||
bool alloc_name);
|
||||
|
||||
#define kmod_path__parse(__m, __p) __kmod_path__parse(__m, __p, false, false)
|
||||
#define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true , false)
|
||||
#define kmod_path__parse_ext(__m, __p) __kmod_path__parse(__m, __p, false, true)
|
||||
#define kmod_path__parse(__m, __p) __kmod_path__parse(__m, __p, false)
|
||||
#define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true)
|
||||
|
||||
void dso__set_module_info(struct dso *dso, struct kmod_path *m,
|
||||
struct machine *machine);
|
||||
|
@ -541,10 +541,17 @@ static int __event__synthesize_thread(union perf_event *comm_event,
|
||||
tgid, process, machine) < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* send mmap only for thread group leader
|
||||
* see thread__init_map_groups
|
||||
*/
|
||||
if (pid == tgid &&
|
||||
perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
|
||||
process, machine, mmap_data,
|
||||
proc_map_timeout))
|
||||
return -1;
|
||||
|
||||
return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
|
||||
process, machine, mmap_data,
|
||||
proc_map_timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (machine__is_default_guest(machine))
|
||||
|
@ -803,7 +803,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
|
||||
if (*output == -1) {
|
||||
*output = fd;
|
||||
|
||||
if (perf_mmap__mmap(&maps[idx], mp, *output) < 0)
|
||||
if (perf_mmap__mmap(&maps[idx], mp, *output, evlist_cpu) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
|
||||
|
@ -2683,7 +2683,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
|
||||
|
||||
struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name)
|
||||
{
|
||||
return pevent_find_field(evsel->tp_format, name);
|
||||
return tep_find_field(evsel->tp_format, name);
|
||||
}
|
||||
|
||||
void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
|
@ -452,11 +452,18 @@ static inline int perf_evsel__group_idx(struct perf_evsel *evsel)
|
||||
return evsel->idx - evsel->leader->idx;
|
||||
}
|
||||
|
||||
/* Iterates group WITHOUT the leader. */
|
||||
#define for_each_group_member(_evsel, _leader) \
|
||||
for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \
|
||||
(_evsel) && (_evsel)->leader == (_leader); \
|
||||
(_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
|
||||
|
||||
/* Iterates group WITH the leader. */
|
||||
#define for_each_group_evsel(_evsel, _leader) \
|
||||
for ((_evsel) = _leader; \
|
||||
(_evsel) && (_evsel)->leader == (_leader); \
|
||||
(_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
|
||||
|
||||
static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evsel)
|
||||
{
|
||||
return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK;
|
||||
|
@ -279,8 +279,6 @@ static int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize)
|
||||
if (!set)
|
||||
return -ENOMEM;
|
||||
|
||||
bitmap_zero(set, size);
|
||||
|
||||
p = (u64 *) set;
|
||||
|
||||
for (i = 0; (u64) i < BITS_TO_U64(size); i++) {
|
||||
@ -1285,7 +1283,6 @@ static int memory_node__read(struct memory_node *n, unsigned long idx)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bitmap_zero(n->set, size);
|
||||
n->node = idx;
|
||||
n->size = size;
|
||||
|
||||
@ -3207,7 +3204,7 @@ static int read_attr(int fd, struct perf_header *ph,
|
||||
}
|
||||
|
||||
static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
|
||||
struct pevent *pevent)
|
||||
struct tep_handle *pevent)
|
||||
{
|
||||
struct event_format *event;
|
||||
char bf[128];
|
||||
@ -3221,7 +3218,7 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
|
||||
return -1;
|
||||
}
|
||||
|
||||
event = pevent_find_event(pevent, evsel->attr.config);
|
||||
event = tep_find_event(pevent, evsel->attr.config);
|
||||
if (event == NULL) {
|
||||
pr_debug("cannot find event format for %d\n", (int)evsel->attr.config);
|
||||
return -1;
|
||||
@ -3239,7 +3236,7 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
|
||||
}
|
||||
|
||||
static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
|
||||
struct pevent *pevent)
|
||||
struct tep_handle *pevent)
|
||||
{
|
||||
struct perf_evsel *pos;
|
||||
|
||||
|
@ -22,12 +22,14 @@
|
||||
"$CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS " \
|
||||
"-Wno-unused-value -Wno-pointer-sign " \
|
||||
"-working-directory $WORKING_DIR " \
|
||||
"-c \"$CLANG_SOURCE\" -target bpf -O2 -o -"
|
||||
"-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
|
||||
|
||||
struct llvm_param llvm_param = {
|
||||
.clang_path = "clang",
|
||||
.llc_path = "llc",
|
||||
.clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE,
|
||||
.clang_opt = NULL,
|
||||
.opts = NULL,
|
||||
.kbuild_dir = NULL,
|
||||
.kbuild_opts = NULL,
|
||||
.user_set_param = false,
|
||||
@ -51,6 +53,8 @@ int perf_llvm_config(const char *var, const char *value)
|
||||
llvm_param.kbuild_opts = strdup(value);
|
||||
else if (!strcmp(var, "dump-obj"))
|
||||
llvm_param.dump_obj = !!perf_config_bool(var, value);
|
||||
else if (!strcmp(var, "opts"))
|
||||
llvm_param.opts = strdup(value);
|
||||
else {
|
||||
pr_debug("Invalid LLVM config option: %s\n", value);
|
||||
return -1;
|
||||
@ -430,11 +434,13 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
|
||||
unsigned int kernel_version;
|
||||
char linux_version_code_str[64];
|
||||
const char *clang_opt = llvm_param.clang_opt;
|
||||
char clang_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
|
||||
char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
|
||||
char serr[STRERR_BUFSIZE];
|
||||
char *kbuild_dir = NULL, *kbuild_include_opts = NULL,
|
||||
*perf_bpf_include_opts = NULL;
|
||||
const char *template = llvm_param.clang_bpf_cmd_template;
|
||||
char *pipe_template = NULL;
|
||||
const char *opts = llvm_param.opts;
|
||||
char *command_echo = NULL, *command_out;
|
||||
char *perf_include_dir = system_path(PERF_INCLUDE_DIR);
|
||||
|
||||
@ -484,6 +490,26 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
|
||||
force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts);
|
||||
force_set_env("WORKING_DIR", kbuild_dir ? : ".");
|
||||
|
||||
if (opts) {
|
||||
err = search_program(llvm_param.llc_path, "llc", llc_path);
|
||||
if (err) {
|
||||
pr_err("ERROR:\tunable to find llc.\n"
|
||||
"Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
|
||||
" \tand 'llc-path' option in [llvm] section of ~/.perfconfig.\n");
|
||||
version_notice();
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -",
|
||||
template, llc_path, opts) < 0) {
|
||||
pr_err("ERROR:\tnot enough memory to setup command line\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
template = pipe_template;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we may reset clang's working dir, path of source file
|
||||
* should be transferred into absolute path, except we want
|
||||
@ -535,6 +561,7 @@ errout:
|
||||
free(obj_buf);
|
||||
free(perf_bpf_include_opts);
|
||||
free(perf_include_dir);
|
||||
free(pipe_template);
|
||||
if (p_obj_buf)
|
||||
*p_obj_buf = NULL;
|
||||
if (p_obj_buf_sz)
|
||||
|
@ -11,6 +11,8 @@
|
||||
struct llvm_param {
|
||||
/* Path of clang executable */
|
||||
const char *clang_path;
|
||||
/* Path of llc executable */
|
||||
const char *llc_path;
|
||||
/*
|
||||
* Template of clang bpf compiling. 5 env variables
|
||||
* can be used:
|
||||
@ -23,6 +25,13 @@ struct llvm_param {
|
||||
const char *clang_bpf_cmd_template;
|
||||
/* Will be filled in $CLANG_OPTIONS */
|
||||
const char *clang_opt;
|
||||
/*
|
||||
* If present it'll add -emit-llvm to $CLANG_OPTIONS to pipe
|
||||
* the clang output to llc, useful for new llvm options not
|
||||
* yet selectable via 'clang -mllvm option', such as -mattr=dwarfris
|
||||
* in clang 6.0/llvm 7
|
||||
*/
|
||||
const char *opts;
|
||||
/* Where to find kbuild system */
|
||||
const char *kbuild_dir;
|
||||
/*
|
||||
|
@ -3,9 +3,13 @@
|
||||
#include <lzma.h>
|
||||
#include <stdio.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "compress.h"
|
||||
#include "util.h"
|
||||
#include "debug.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#define BUFSIZE 8192
|
||||
|
||||
@ -99,3 +103,19 @@ err_fclose:
|
||||
fclose(infile);
|
||||
return err;
|
||||
}
|
||||
|
||||
bool lzma_is_compressed(const char *input)
|
||||
{
|
||||
int fd = open(input, O_RDONLY);
|
||||
const uint8_t magic[6] = { 0xFD, '7', 'z', 'X', 'Z', 0x00 };
|
||||
char buf[6] = { 0 };
|
||||
ssize_t rc;
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
rc = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
return rc == sizeof(buf) ?
|
||||
memcmp(buf, magic, sizeof(buf)) == 0 : false;
|
||||
}
|
||||
|
@ -1212,8 +1212,10 @@ static int map_groups__set_module_path(struct map_groups *mg, const char *path,
|
||||
* Full name could reveal us kmod compression, so
|
||||
* we need to update the symtab_type if needed.
|
||||
*/
|
||||
if (m->comp && is_kmod_dso(map->dso))
|
||||
if (m->comp && is_kmod_dso(map->dso)) {
|
||||
map->dso->symtab_type++;
|
||||
map->dso->comp = m->comp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ pid_t machine__get_current_tid(struct machine *machine, int cpu);
|
||||
int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
|
||||
pid_t tid);
|
||||
/*
|
||||
* For use with libtraceevent's pevent_set_function_resolver()
|
||||
* For use with libtraceevent's tep_set_function_resolver()
|
||||
*/
|
||||
char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp);
|
||||
|
||||
|
@ -381,20 +381,6 @@ struct map *map__clone(struct map *from)
|
||||
return map;
|
||||
}
|
||||
|
||||
int map__overlap(struct map *l, struct map *r)
|
||||
{
|
||||
if (l->start > r->start) {
|
||||
struct map *t = l;
|
||||
l = r;
|
||||
r = t;
|
||||
}
|
||||
|
||||
if (l->end > r->start)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t map__fprintf(struct map *map, FILE *fp)
|
||||
{
|
||||
return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
|
||||
@ -675,20 +661,42 @@ static void __map_groups__insert(struct map_groups *mg, struct map *map)
|
||||
static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
|
||||
{
|
||||
struct rb_root *root;
|
||||
struct rb_node *next;
|
||||
struct rb_node *next, *first;
|
||||
int err = 0;
|
||||
|
||||
down_write(&maps->lock);
|
||||
|
||||
root = &maps->entries;
|
||||
next = rb_first(root);
|
||||
|
||||
/*
|
||||
* Find first map where end > map->start.
|
||||
* Same as find_vma() in kernel.
|
||||
*/
|
||||
next = root->rb_node;
|
||||
first = NULL;
|
||||
while (next) {
|
||||
struct map *pos = rb_entry(next, struct map, rb_node);
|
||||
|
||||
if (pos->end > map->start) {
|
||||
first = next;
|
||||
if (pos->start <= map->start)
|
||||
break;
|
||||
next = next->rb_left;
|
||||
} else
|
||||
next = next->rb_right;
|
||||
}
|
||||
|
||||
next = first;
|
||||
while (next) {
|
||||
struct map *pos = rb_entry(next, struct map, rb_node);
|
||||
next = rb_next(&pos->rb_node);
|
||||
|
||||
if (!map__overlap(pos, map))
|
||||
continue;
|
||||
/*
|
||||
* Stop if current map starts after map->end.
|
||||
* Maps are ordered by start: next will not overlap for sure.
|
||||
*/
|
||||
if (pos->start >= map->end)
|
||||
break;
|
||||
|
||||
if (verbose >= 2) {
|
||||
|
||||
|
@ -166,7 +166,6 @@ static inline void __map__zput(struct map **map)
|
||||
|
||||
#define map__zput(map) __map__zput(&map)
|
||||
|
||||
int map__overlap(struct map *l, struct map *r);
|
||||
size_t map__fprintf(struct map *map, FILE *fp);
|
||||
size_t map__fprintf_dsoname(struct map *map, FILE *fp);
|
||||
char *map__srcline(struct map *map, u64 addr, struct symbol *sym);
|
||||
|
@ -164,7 +164,7 @@ void perf_mmap__munmap(struct perf_mmap *map)
|
||||
auxtrace_mmap__munmap(&map->auxtrace_mmap);
|
||||
}
|
||||
|
||||
int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd)
|
||||
int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu)
|
||||
{
|
||||
/*
|
||||
* The last one will be done at perf_mmap__consume(), so that we
|
||||
@ -191,6 +191,7 @@ int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd)
|
||||
return -1;
|
||||
}
|
||||
map->fd = fd;
|
||||
map->cpu = cpu;
|
||||
|
||||
if (auxtrace_mmap__mmap(&map->auxtrace_mmap,
|
||||
&mp->auxtrace_mp, map->base, fd))
|
||||
|
@ -18,6 +18,7 @@ struct perf_mmap {
|
||||
void *base;
|
||||
int mask;
|
||||
int fd;
|
||||
int cpu;
|
||||
refcount_t refcnt;
|
||||
u64 prev;
|
||||
u64 start;
|
||||
@ -60,7 +61,7 @@ struct mmap_params {
|
||||
struct auxtrace_mmap_params auxtrace_mp;
|
||||
};
|
||||
|
||||
int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd);
|
||||
int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu);
|
||||
void perf_mmap__munmap(struct perf_mmap *map);
|
||||
|
||||
void perf_mmap__get(struct perf_mmap *map);
|
||||
|
@ -139,6 +139,9 @@ struct nsinfo *nsinfo__copy(struct nsinfo *nsi)
|
||||
{
|
||||
struct nsinfo *nnsi;
|
||||
|
||||
if (nsi == NULL)
|
||||
return NULL;
|
||||
|
||||
nnsi = calloc(1, sizeof(*nnsi));
|
||||
if (nnsi != NULL) {
|
||||
nnsi->pid = nsi->pid;
|
||||
|
@ -1991,8 +1991,11 @@ static int set_filter(struct perf_evsel *evsel, const void *arg)
|
||||
int nr_addr_filters = 0;
|
||||
struct perf_pmu *pmu = NULL;
|
||||
|
||||
if (evsel == NULL)
|
||||
goto err;
|
||||
if (evsel == NULL) {
|
||||
fprintf(stderr,
|
||||
"--filter option should follow a -e tracepoint or HW tracer option\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
|
||||
if (perf_evsel__append_tp_filter(evsel, str) < 0) {
|
||||
@ -2014,8 +2017,11 @@ static int set_filter(struct perf_evsel *evsel, const void *arg)
|
||||
perf_pmu__scan_file(pmu, "nr_addr_filters",
|
||||
"%d", &nr_addr_filters);
|
||||
|
||||
if (!nr_addr_filters)
|
||||
goto err;
|
||||
if (!nr_addr_filters) {
|
||||
fprintf(stderr,
|
||||
"This CPU does not support address filtering\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (perf_evsel__append_addr_filter(evsel, str) < 0) {
|
||||
fprintf(stderr,
|
||||
@ -2024,12 +2030,6 @@ static int set_filter(struct perf_evsel *evsel, const void *arg)
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
fprintf(stderr,
|
||||
"--filter option should follow a -e tracepoint or HW tracer option\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int parse_filter(const struct option *opt, const char *str,
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "cpumap.h"
|
||||
#include "print_binary.h"
|
||||
#include "thread_map.h"
|
||||
#include "mmap.h"
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
#define _PyUnicode_FromString(arg) \
|
||||
@ -341,7 +342,7 @@ static bool is_tracepoint(struct pyrf_event *pevent)
|
||||
static PyObject*
|
||||
tracepoint_field(struct pyrf_event *pe, struct format_field *field)
|
||||
{
|
||||
struct pevent *pevent = field->event->pevent;
|
||||
struct tep_handle *pevent = field->event->pevent;
|
||||
void *data = pe->sample.raw_data;
|
||||
PyObject *ret = NULL;
|
||||
unsigned long long val;
|
||||
@ -351,7 +352,7 @@ tracepoint_field(struct pyrf_event *pe, struct format_field *field)
|
||||
offset = field->offset;
|
||||
len = field->size;
|
||||
if (field->flags & FIELD_IS_DYNAMIC) {
|
||||
val = pevent_read_number(pevent, data + offset, len);
|
||||
val = tep_read_number(pevent, data + offset, len);
|
||||
offset = val;
|
||||
len = offset >> 16;
|
||||
offset &= 0xffff;
|
||||
@ -364,8 +365,8 @@ tracepoint_field(struct pyrf_event *pe, struct format_field *field)
|
||||
field->flags &= ~FIELD_IS_STRING;
|
||||
}
|
||||
} else {
|
||||
val = pevent_read_number(pevent, data + field->offset,
|
||||
field->size);
|
||||
val = tep_read_number(pevent, data + field->offset,
|
||||
field->size);
|
||||
if (field->flags & FIELD_IS_POINTER)
|
||||
ret = PyLong_FromUnsignedLong((unsigned long) val);
|
||||
else if (field->flags & FIELD_IS_SIGNED)
|
||||
@ -394,7 +395,7 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name)
|
||||
evsel->tp_format = tp_format;
|
||||
}
|
||||
|
||||
field = pevent_find_any_field(evsel->tp_format, str);
|
||||
field = tep_find_any_field(evsel->tp_format, str);
|
||||
if (!field)
|
||||
return NULL;
|
||||
|
||||
@ -976,6 +977,20 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
|
||||
return Py_BuildValue("i", evlist->nr_entries);
|
||||
}
|
||||
|
||||
static struct perf_mmap *get_md(struct perf_evlist *evlist, int cpu)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < evlist->nr_mmaps; i++) {
|
||||
struct perf_mmap *md = &evlist->mmap[i];
|
||||
|
||||
if (md->cpu == cpu)
|
||||
return md;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
|
||||
PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
@ -990,7 +1005,10 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
|
||||
&cpu, &sample_id_all))
|
||||
return NULL;
|
||||
|
||||
md = &evlist->mmap[cpu];
|
||||
md = get_md(evlist, cpu);
|
||||
if (!md)
|
||||
return NULL;
|
||||
|
||||
if (perf_mmap__read_init(md) < 0)
|
||||
goto end;
|
||||
|
||||
|
71
tools/perf/util/s390-cpumsf-kernel.h
Normal file
71
tools/perf/util/s390-cpumsf-kernel.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Auxtrace support for s390 CPU measurement sampling facility
|
||||
*
|
||||
* Copyright IBM Corp. 2018
|
||||
* Author(s): Hendrik Brueckner <brueckner@linux.ibm.com>
|
||||
* Thomas Richter <tmricht@linux.ibm.com>
|
||||
*/
|
||||
#ifndef S390_CPUMSF_KERNEL_H
|
||||
#define S390_CPUMSF_KERNEL_H
|
||||
|
||||
#define S390_CPUMSF_PAGESZ 4096 /* Size of sample block units */
|
||||
#define S390_CPUMSF_DIAG_DEF_FIRST 0x8001 /* Diagnostic entry lowest id */
|
||||
|
||||
struct hws_basic_entry {
|
||||
unsigned int def:16; /* 0-15 Data Entry Format */
|
||||
unsigned int R:4; /* 16-19 reserved */
|
||||
unsigned int U:4; /* 20-23 Number of unique instruct. */
|
||||
unsigned int z:2; /* zeros */
|
||||
unsigned int T:1; /* 26 PSW DAT mode */
|
||||
unsigned int W:1; /* 27 PSW wait state */
|
||||
unsigned int P:1; /* 28 PSW Problem state */
|
||||
unsigned int AS:2; /* 29-30 PSW address-space control */
|
||||
unsigned int I:1; /* 31 entry valid or invalid */
|
||||
unsigned int CL:2; /* 32-33 Configuration Level */
|
||||
unsigned int:14;
|
||||
unsigned int prim_asn:16; /* primary ASN */
|
||||
unsigned long long ia; /* Instruction Address */
|
||||
unsigned long long gpp; /* Guest Program Parameter */
|
||||
unsigned long long hpp; /* Host Program Parameter */
|
||||
};
|
||||
|
||||
struct hws_diag_entry {
|
||||
unsigned int def:16; /* 0-15 Data Entry Format */
|
||||
unsigned int R:15; /* 16-19 and 20-30 reserved */
|
||||
unsigned int I:1; /* 31 entry valid or invalid */
|
||||
u8 data[]; /* Machine-dependent sample data */
|
||||
};
|
||||
|
||||
struct hws_combined_entry {
|
||||
struct hws_basic_entry basic; /* Basic-sampling data entry */
|
||||
struct hws_diag_entry diag; /* Diagnostic-sampling data entry */
|
||||
};
|
||||
|
||||
struct hws_trailer_entry {
|
||||
union {
|
||||
struct {
|
||||
unsigned int f:1; /* 0 - Block Full Indicator */
|
||||
unsigned int a:1; /* 1 - Alert request control */
|
||||
unsigned int t:1; /* 2 - Timestamp format */
|
||||
unsigned int:29; /* 3 - 31: Reserved */
|
||||
unsigned int bsdes:16; /* 32-47: size of basic SDE */
|
||||
unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */
|
||||
};
|
||||
unsigned long long flags; /* 0 - 64: All indicators */
|
||||
};
|
||||
unsigned long long overflow; /* 64 - sample Overflow count */
|
||||
unsigned char timestamp[16]; /* 16 - 31 timestamp */
|
||||
unsigned long long reserved1; /* 32 -Reserved */
|
||||
unsigned long long reserved2; /* */
|
||||
union { /* 48 - reserved for programming use */
|
||||
struct {
|
||||
unsigned long long clock_base:1; /* in progusage2 */
|
||||
unsigned long long progusage1:63;
|
||||
unsigned long long progusage2;
|
||||
};
|
||||
unsigned long long progusage[2];
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
945
tools/perf/util/s390-cpumsf.c
Normal file
945
tools/perf/util/s390-cpumsf.c
Normal file
@ -0,0 +1,945 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright IBM Corp. 2018
|
||||
* Auxtrace support for s390 CPU-Measurement Sampling Facility
|
||||
*
|
||||
* Author(s): Thomas Richter <tmricht@linux.ibm.com>
|
||||
*
|
||||
* Auxiliary traces are collected during 'perf record' using rbd000 event.
|
||||
* Several PERF_RECORD_XXX are generated during recording:
|
||||
*
|
||||
* PERF_RECORD_AUX:
|
||||
* Records that new data landed in the AUX buffer part.
|
||||
* PERF_RECORD_AUXTRACE:
|
||||
* Defines auxtrace data. Followed by the actual data. The contents of
|
||||
* the auxtrace data is dependent on the event and the CPU.
|
||||
* This record is generated by perf record command. For details
|
||||
* see Documentation/perf.data-file-format.txt.
|
||||
* PERF_RECORD_AUXTRACE_INFO:
|
||||
* Defines a table of contains for PERF_RECORD_AUXTRACE records. This
|
||||
* record is generated during 'perf record' command. Each record contains up
|
||||
* to 256 entries describing offset and size of the AUXTRACE data in the
|
||||
* perf.data file.
|
||||
* PERF_RECORD_AUXTRACE_ERROR:
|
||||
* Indicates an error during AUXTRACE collection such as buffer overflow.
|
||||
* PERF_RECORD_FINISHED_ROUND:
|
||||
* Perf events are not necessarily in time stamp order, as they can be
|
||||
* collected in parallel on different CPUs. If the events should be
|
||||
* processed in time order they need to be sorted first.
|
||||
* Perf report guarantees that there is no reordering over a
|
||||
* PERF_RECORD_FINISHED_ROUND boundary event. All perf records with a
|
||||
* time stamp lower than this record are processed (and displayed) before
|
||||
* the succeeding perf record are processed.
|
||||
*
|
||||
* These records are evaluated during perf report command.
|
||||
*
|
||||
* 1. PERF_RECORD_AUXTRACE_INFO is used to set up the infrastructure for
|
||||
* auxiliary trace data processing. See s390_cpumsf_process_auxtrace_info()
|
||||
* below.
|
||||
* Auxiliary trace data is collected per CPU. To merge the data into the report
|
||||
* an auxtrace_queue is created for each CPU. It is assumed that the auxtrace
|
||||
* data is in ascending order.
|
||||
*
|
||||
* Each queue has a double linked list of auxtrace_buffers. This list contains
|
||||
* the offset and size of a CPU's auxtrace data. During auxtrace processing
|
||||
* the data portion is mmap()'ed.
|
||||
*
|
||||
* To sort the queues in chronological order, all queue access is controlled
|
||||
* by the auxtrace_heap. This is basicly a stack, each stack element has two
|
||||
* entries, the queue number and a time stamp. However the stack is sorted by
|
||||
* the time stamps. The highest time stamp is at the bottom the lowest
|
||||
* (nearest) time stamp is at the top. That sort order is maintained at all
|
||||
* times!
|
||||
*
|
||||
* After the auxtrace infrastructure has been setup, the auxtrace queues are
|
||||
* filled with data (offset/size pairs) and the auxtrace_heap is populated.
|
||||
*
|
||||
* 2. PERF_RECORD_XXX processing triggers access to the auxtrace_queues.
|
||||
* Each record is handled by s390_cpumsf_process_event(). The time stamp of
|
||||
* the perf record is compared with the time stamp located on the auxtrace_heap
|
||||
* top element. If that time stamp is lower than the time stamp from the
|
||||
* record sample, the auxtrace queues will be processed. As auxtrace queues
|
||||
* control many auxtrace_buffers and each buffer can be quite large, the
|
||||
* auxtrace buffer might be processed only partially. In this case the
|
||||
* position in the auxtrace_buffer of that queue is remembered and the time
|
||||
* stamp of the last processed entry of the auxtrace_buffer replaces the
|
||||
* current auxtrace_heap top.
|
||||
*
|
||||
* 3. Auxtrace_queues might run of out data and are feeded by the
|
||||
* PERF_RECORD_AUXTRACE handling, see s390_cpumsf_process_auxtrace_event().
|
||||
*
|
||||
* Event Generation
|
||||
* Each sampling-data entry in the auxilary trace data generates a perf sample.
|
||||
* This sample is filled
|
||||
* with data from the auxtrace such as PID/TID, instruction address, CPU state,
|
||||
* etc. This sample is processed with perf_session__deliver_synth_event() to
|
||||
* be included into the GUI.
|
||||
*
|
||||
* 4. PERF_RECORD_FINISHED_ROUND event is used to process all the remaining
|
||||
* auxiliary traces entries until the time stamp of this record is reached
|
||||
* auxtrace_heap top. This is triggered by ordered_event->deliver().
|
||||
*
|
||||
*
|
||||
* Perf event processing.
|
||||
* Event processing of PERF_RECORD_XXX entries relies on time stamp entries.
|
||||
* This is the function call sequence:
|
||||
*
|
||||
* __cmd_report()
|
||||
* |
|
||||
* perf_session__process_events()
|
||||
* |
|
||||
* __perf_session__process_events()
|
||||
* |
|
||||
* perf_session__process_event()
|
||||
* | This functions splits the PERF_RECORD_XXX records.
|
||||
* | - Those generated by perf record command (type number equal or higher
|
||||
* | than PERF_RECORD_USER_TYPE_START) are handled by
|
||||
* | perf_session__process_user_event(see below)
|
||||
* | - Those generated by the kernel are handled by
|
||||
* | perf_evlist__parse_sample_timestamp()
|
||||
* |
|
||||
* perf_evlist__parse_sample_timestamp()
|
||||
* | Extract time stamp from sample data.
|
||||
* |
|
||||
* perf_session__queue_event()
|
||||
* | If timestamp is positive the sample is entered into an ordered_event
|
||||
* | list, sort order is the timestamp. The event processing is deferred until
|
||||
* | later (see perf_session__process_user_event()).
|
||||
* | Other timestamps (0 or -1) are handled immediately by
|
||||
* | perf_session__deliver_event(). These are events generated at start up
|
||||
* | of command perf record. They create PERF_RECORD_COMM and PERF_RECORD_MMAP*
|
||||
* | records. They are needed to create a list of running processes and its
|
||||
* | memory mappings and layout. They are needed at the beginning to enable
|
||||
* | command perf report to create process trees and memory mappings.
|
||||
* |
|
||||
* perf_session__deliver_event()
|
||||
* | Delivers a PERF_RECORD_XXX entry for handling.
|
||||
* |
|
||||
* auxtrace__process_event()
|
||||
* | The timestamp of the PERF_RECORD_XXX entry is taken to correlate with
|
||||
* | time stamps from the auxiliary trace buffers. This enables
|
||||
* | synchronization between auxiliary trace data and the events on the
|
||||
* | perf.data file.
|
||||
* |
|
||||
* machine__deliver_event()
|
||||
* | Handles the PERF_RECORD_XXX event. This depends on the record type.
|
||||
* It might update the process tree, update a process memory map or enter
|
||||
* a sample with IP and call back chain data into GUI data pool.
|
||||
*
|
||||
*
|
||||
* Deferred processing determined by perf_session__process_user_event() is
|
||||
* finally processed when a PERF_RECORD_FINISHED_ROUND is encountered. These
|
||||
* are generated during command perf record.
|
||||
* The timestamp of PERF_RECORD_FINISHED_ROUND event is taken to process all
|
||||
* PERF_RECORD_XXX entries stored in the ordered_event list. This list was
|
||||
* built up while reading the perf.data file.
|
||||
* Each event is now processed by calling perf_session__deliver_event().
|
||||
* This enables time synchronization between the data in the perf.data file and
|
||||
* the data in the auxiliary trace buffers.
|
||||
*/
|
||||
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <byteswap.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
#include "cpumap.h"
|
||||
#include "color.h"
|
||||
#include "evsel.h"
|
||||
#include "evlist.h"
|
||||
#include "machine.h"
|
||||
#include "session.h"
|
||||
#include "util.h"
|
||||
#include "thread.h"
|
||||
#include "debug.h"
|
||||
#include "auxtrace.h"
|
||||
#include "s390-cpumsf.h"
|
||||
#include "s390-cpumsf-kernel.h"
|
||||
|
||||
struct s390_cpumsf {
|
||||
struct auxtrace auxtrace;
|
||||
struct auxtrace_queues queues;
|
||||
struct auxtrace_heap heap;
|
||||
struct perf_session *session;
|
||||
struct machine *machine;
|
||||
u32 auxtrace_type;
|
||||
u32 pmu_type;
|
||||
u16 machine_type;
|
||||
bool data_queued;
|
||||
};
|
||||
|
||||
struct s390_cpumsf_queue {
|
||||
struct s390_cpumsf *sf;
|
||||
unsigned int queue_nr;
|
||||
struct auxtrace_buffer *buffer;
|
||||
int cpu;
|
||||
};
|
||||
|
||||
/* Display s390 CPU measurement facility basic-sampling data entry */
|
||||
static bool s390_cpumsf_basic_show(const char *color, size_t pos,
|
||||
struct hws_basic_entry *basic)
|
||||
{
|
||||
if (basic->def != 1) {
|
||||
pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos);
|
||||
return false;
|
||||
}
|
||||
color_fprintf(stdout, color, " [%#08zx] Basic Def:%04x Inst:%#04x"
|
||||
" %c%c%c%c AS:%d ASN:%#04x IA:%#018llx\n"
|
||||
"\t\tCL:%d HPP:%#018llx GPP:%#018llx\n",
|
||||
pos, basic->def, basic->U,
|
||||
basic->T ? 'T' : ' ',
|
||||
basic->W ? 'W' : ' ',
|
||||
basic->P ? 'P' : ' ',
|
||||
basic->I ? 'I' : ' ',
|
||||
basic->AS, basic->prim_asn, basic->ia, basic->CL,
|
||||
basic->hpp, basic->gpp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Display s390 CPU measurement facility diagnostic-sampling data entry */
|
||||
static bool s390_cpumsf_diag_show(const char *color, size_t pos,
|
||||
struct hws_diag_entry *diag)
|
||||
{
|
||||
if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) {
|
||||
pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos);
|
||||
return false;
|
||||
}
|
||||
color_fprintf(stdout, color, " [%#08zx] Diag Def:%04x %c\n",
|
||||
pos, diag->def, diag->I ? 'I' : ' ');
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return TOD timestamp contained in an trailer entry */
|
||||
static unsigned long long trailer_timestamp(struct hws_trailer_entry *te)
|
||||
{
|
||||
/* te->t set: TOD in STCKE format, bytes 8-15
|
||||
* to->t not set: TOD in STCK format, bytes 0-7
|
||||
*/
|
||||
unsigned long long ts;
|
||||
|
||||
memcpy(&ts, &te->timestamp[te->t], sizeof(ts));
|
||||
return ts;
|
||||
}
|
||||
|
||||
/* Display s390 CPU measurement facility trailer entry */
|
||||
static bool s390_cpumsf_trailer_show(const char *color, size_t pos,
|
||||
struct hws_trailer_entry *te)
|
||||
{
|
||||
if (te->bsdes != sizeof(struct hws_basic_entry)) {
|
||||
pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos);
|
||||
return false;
|
||||
}
|
||||
color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d"
|
||||
" dsdes:%d Overflow:%lld Time:%#llx\n"
|
||||
"\t\tC:%d TOD:%#lx 1:%#llx 2:%#llx\n",
|
||||
pos,
|
||||
te->f ? 'F' : ' ',
|
||||
te->a ? 'A' : ' ',
|
||||
te->t ? 'T' : ' ',
|
||||
te->bsdes, te->dsdes, te->overflow,
|
||||
trailer_timestamp(te), te->clock_base, te->progusage2,
|
||||
te->progusage[0], te->progusage[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Test a sample data block. It must be 4KB or a multiple thereof in size and
|
||||
* 4KB page aligned. Each sample data page has a trailer entry at the
|
||||
* end which contains the sample entry data sizes.
|
||||
*
|
||||
* Return true if the sample data block passes the checks and set the
|
||||
* basic set entry size and diagnostic set entry size.
|
||||
*
|
||||
* Return false on failure.
|
||||
*
|
||||
* Note: Old hardware does not set the basic or diagnostic entry sizes
|
||||
* in the trailer entry. Use the type number instead.
|
||||
*/
|
||||
static bool s390_cpumsf_validate(int machine_type,
|
||||
unsigned char *buf, size_t len,
|
||||
unsigned short *bsdes,
|
||||
unsigned short *dsdes)
|
||||
{
|
||||
struct hws_basic_entry *basic = (struct hws_basic_entry *)buf;
|
||||
struct hws_trailer_entry *te;
|
||||
|
||||
*dsdes = *bsdes = 0;
|
||||
if (len & (S390_CPUMSF_PAGESZ - 1)) /* Illegal size */
|
||||
return false;
|
||||
if (basic->def != 1) /* No basic set entry, must be first */
|
||||
return false;
|
||||
/* Check for trailer entry at end of SDB */
|
||||
te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
|
||||
- sizeof(*te));
|
||||
*bsdes = te->bsdes;
|
||||
*dsdes = te->dsdes;
|
||||
if (!te->bsdes && !te->dsdes) {
|
||||
/* Very old hardware, use CPUID */
|
||||
switch (machine_type) {
|
||||
case 2097:
|
||||
case 2098:
|
||||
*dsdes = 64;
|
||||
*bsdes = 32;
|
||||
break;
|
||||
case 2817:
|
||||
case 2818:
|
||||
*dsdes = 74;
|
||||
*bsdes = 32;
|
||||
break;
|
||||
case 2827:
|
||||
case 2828:
|
||||
*dsdes = 85;
|
||||
*bsdes = 32;
|
||||
break;
|
||||
default:
|
||||
/* Illegal trailer entry */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return true if there is room for another entry */
|
||||
static bool s390_cpumsf_reached_trailer(size_t entry_sz, size_t pos)
|
||||
{
|
||||
size_t payload = S390_CPUMSF_PAGESZ - sizeof(struct hws_trailer_entry);
|
||||
|
||||
if (payload - (pos & (S390_CPUMSF_PAGESZ - 1)) < entry_sz)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Dump an auxiliary buffer. These buffers are multiple of
|
||||
* 4KB SDB pages.
|
||||
*/
|
||||
static void s390_cpumsf_dump(struct s390_cpumsf *sf,
|
||||
unsigned char *buf, size_t len)
|
||||
{
|
||||
const char *color = PERF_COLOR_BLUE;
|
||||
struct hws_basic_entry *basic;
|
||||
struct hws_diag_entry *diag;
|
||||
unsigned short bsdes, dsdes;
|
||||
size_t pos = 0;
|
||||
|
||||
color_fprintf(stdout, color,
|
||||
". ... s390 AUX data: size %zu bytes\n",
|
||||
len);
|
||||
|
||||
if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes,
|
||||
&dsdes)) {
|
||||
pr_err("Invalid AUX trace data block size:%zu"
|
||||
" (type:%d bsdes:%hd dsdes:%hd)\n",
|
||||
len, sf->machine_type, bsdes, dsdes);
|
||||
return;
|
||||
}
|
||||
|
||||
/* s390 kernel always returns 4KB blocks fully occupied,
|
||||
* no partially filled SDBs.
|
||||
*/
|
||||
while (pos < len) {
|
||||
/* Handle Basic entry */
|
||||
basic = (struct hws_basic_entry *)(buf + pos);
|
||||
if (s390_cpumsf_basic_show(color, pos, basic))
|
||||
pos += bsdes;
|
||||
else
|
||||
return;
|
||||
|
||||
/* Handle Diagnostic entry */
|
||||
diag = (struct hws_diag_entry *)(buf + pos);
|
||||
if (s390_cpumsf_diag_show(color, pos, diag))
|
||||
pos += dsdes;
|
||||
else
|
||||
return;
|
||||
|
||||
/* Check for trailer entry */
|
||||
if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) {
|
||||
/* Show trailer entry */
|
||||
struct hws_trailer_entry te;
|
||||
|
||||
pos = (pos + S390_CPUMSF_PAGESZ)
|
||||
& ~(S390_CPUMSF_PAGESZ - 1);
|
||||
pos -= sizeof(te);
|
||||
memcpy(&te, buf + pos, sizeof(te));
|
||||
/* Set descriptor sizes in case of old hardware
|
||||
* where these values are not set.
|
||||
*/
|
||||
te.bsdes = bsdes;
|
||||
te.dsdes = dsdes;
|
||||
if (s390_cpumsf_trailer_show(color, pos, &te))
|
||||
pos += sizeof(te);
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void s390_cpumsf_dump_event(struct s390_cpumsf *sf, unsigned char *buf,
|
||||
size_t len)
|
||||
{
|
||||
printf(".\n");
|
||||
s390_cpumsf_dump(sf, buf, len);
|
||||
}
|
||||
|
||||
#define S390_LPP_PID_MASK 0xffffffff
|
||||
|
||||
static bool s390_cpumsf_make_event(size_t pos,
|
||||
struct hws_basic_entry *basic,
|
||||
struct s390_cpumsf_queue *sfq)
|
||||
{
|
||||
struct perf_sample sample = {
|
||||
.ip = basic->ia,
|
||||
.pid = basic->hpp & S390_LPP_PID_MASK,
|
||||
.tid = basic->hpp & S390_LPP_PID_MASK,
|
||||
.cpumode = PERF_RECORD_MISC_CPUMODE_UNKNOWN,
|
||||
.cpu = sfq->cpu,
|
||||
.period = 1
|
||||
};
|
||||
union perf_event event;
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
if (basic->CL == 1) /* Native LPAR mode */
|
||||
sample.cpumode = basic->P ? PERF_RECORD_MISC_USER
|
||||
: PERF_RECORD_MISC_KERNEL;
|
||||
else if (basic->CL == 2) /* Guest kernel/user space */
|
||||
sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER
|
||||
: PERF_RECORD_MISC_GUEST_KERNEL;
|
||||
else if (basic->gpp || basic->prim_asn != 0xffff)
|
||||
/* Use heuristics on old hardware */
|
||||
sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER
|
||||
: PERF_RECORD_MISC_GUEST_KERNEL;
|
||||
else
|
||||
sample.cpumode = basic->P ? PERF_RECORD_MISC_USER
|
||||
: PERF_RECORD_MISC_KERNEL;
|
||||
|
||||
event.sample.header.type = PERF_RECORD_SAMPLE;
|
||||
event.sample.header.misc = sample.cpumode;
|
||||
event.sample.header.size = sizeof(struct perf_event_header);
|
||||
|
||||
pr_debug4("%s pos:%#zx ip:%#" PRIx64 " P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
|
||||
__func__, pos, sample.ip, basic->P, basic->CL, sample.pid,
|
||||
sample.tid, sample.cpumode, sample.cpu);
|
||||
if (perf_session__deliver_synth_event(sfq->sf->session, &event,
|
||||
&sample)) {
|
||||
pr_err("s390 Auxiliary Trace: failed to deliver event\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned long long get_trailer_time(const unsigned char *buf)
|
||||
{
|
||||
struct hws_trailer_entry *te;
|
||||
unsigned long long aux_time;
|
||||
|
||||
te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
|
||||
- sizeof(*te));
|
||||
|
||||
if (!te->clock_base) /* TOD_CLOCK_BASE value missing */
|
||||
return 0;
|
||||
|
||||
/* Correct calculation to convert time stamp in trailer entry to
|
||||
* nano seconds (taken from arch/s390 function tod_to_ns()).
|
||||
* TOD_CLOCK_BASE is stored in trailer entry member progusage2.
|
||||
*/
|
||||
aux_time = trailer_timestamp(te) - te->progusage2;
|
||||
aux_time = (aux_time >> 9) * 125 + (((aux_time & 0x1ff) * 125) >> 9);
|
||||
return aux_time;
|
||||
}
|
||||
|
||||
/* Process the data samples of a single queue. The first parameter is a
|
||||
* pointer to the queue, the second parameter is the time stamp. This
|
||||
* is the time stamp:
|
||||
* - of the event that triggered this processing.
|
||||
* - or the time stamp when the last proccesing of this queue stopped.
|
||||
* In this case it stopped at a 4KB page boundary and record the
|
||||
* position on where to continue processing on the next invocation
|
||||
* (see buffer->use_data and buffer->use_size).
|
||||
*
|
||||
* When this function returns the second parameter is updated to
|
||||
* reflect the time stamp of the last processed auxiliary data entry
|
||||
* (taken from the trailer entry of that page). The caller uses this
|
||||
* returned time stamp to record the last processed entry in this
|
||||
* queue.
|
||||
*
|
||||
* The function returns:
|
||||
* 0: Processing successful. The second parameter returns the
|
||||
* time stamp from the trailer entry until which position
|
||||
* processing took place. Subsequent calls resume from this
|
||||
* position.
|
||||
* <0: An error occurred during processing. The second parameter
|
||||
* returns the maximum time stamp.
|
||||
* >0: Done on this queue. The second parameter returns the
|
||||
* maximum time stamp.
|
||||
*/
|
||||
static int s390_cpumsf_samples(struct s390_cpumsf_queue *sfq, u64 *ts)
|
||||
{
|
||||
struct s390_cpumsf *sf = sfq->sf;
|
||||
unsigned char *buf = sfq->buffer->use_data;
|
||||
size_t len = sfq->buffer->use_size;
|
||||
struct hws_basic_entry *basic;
|
||||
unsigned short bsdes, dsdes;
|
||||
size_t pos = 0;
|
||||
int err = 1;
|
||||
u64 aux_ts;
|
||||
|
||||
if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes,
|
||||
&dsdes)) {
|
||||
*ts = ~0ULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get trailer entry time stamp and check if entries in
|
||||
* this auxiliary page are ready for processing. If the
|
||||
* time stamp of the first entry is too high, whole buffer
|
||||
* can be skipped. In this case return time stamp.
|
||||
*/
|
||||
aux_ts = get_trailer_time(buf);
|
||||
if (!aux_ts) {
|
||||
pr_err("[%#08" PRIx64 "] Invalid AUX trailer entry TOD clock base\n",
|
||||
sfq->buffer->data_offset);
|
||||
aux_ts = ~0ULL;
|
||||
goto out;
|
||||
}
|
||||
if (aux_ts > *ts) {
|
||||
*ts = aux_ts;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (pos < len) {
|
||||
/* Handle Basic entry */
|
||||
basic = (struct hws_basic_entry *)(buf + pos);
|
||||
if (s390_cpumsf_make_event(pos, basic, sfq))
|
||||
pos += bsdes;
|
||||
else {
|
||||
err = -EBADF;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pos += dsdes; /* Skip diagnositic entry */
|
||||
|
||||
/* Check for trailer entry */
|
||||
if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) {
|
||||
pos = (pos + S390_CPUMSF_PAGESZ)
|
||||
& ~(S390_CPUMSF_PAGESZ - 1);
|
||||
/* Check existence of next page */
|
||||
if (pos >= len)
|
||||
break;
|
||||
aux_ts = get_trailer_time(buf + pos);
|
||||
if (!aux_ts) {
|
||||
aux_ts = ~0ULL;
|
||||
goto out;
|
||||
}
|
||||
if (aux_ts > *ts) {
|
||||
*ts = aux_ts;
|
||||
sfq->buffer->use_data += pos;
|
||||
sfq->buffer->use_size -= pos;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
*ts = aux_ts;
|
||||
sfq->buffer->use_size = 0;
|
||||
sfq->buffer->use_data = NULL;
|
||||
return err; /* Buffer completely scanned or error */
|
||||
}
|
||||
|
||||
/* Run the s390 auxiliary trace decoder.
|
||||
* Select the queue buffer to operate on, the caller already selected
|
||||
* the proper queue, depending on second parameter 'ts'.
|
||||
* This is the time stamp until which the auxiliary entries should
|
||||
* be processed. This value is updated by called functions and
|
||||
* returned to the caller.
|
||||
*
|
||||
* Resume processing in the current buffer. If there is no buffer
|
||||
* get a new buffer from the queue and setup start position for
|
||||
* processing.
|
||||
* When a buffer is completely processed remove it from the queue
|
||||
* before returning.
|
||||
*
|
||||
* This function returns
|
||||
* 1: When the queue is empty. Second parameter will be set to
|
||||
* maximum time stamp.
|
||||
* 0: Normal processing done.
|
||||
* <0: Error during queue buffer setup. This causes the caller
|
||||
* to stop processing completely.
|
||||
*/
|
||||
static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq,
|
||||
u64 *ts)
|
||||
{
|
||||
|
||||
struct auxtrace_buffer *buffer;
|
||||
struct auxtrace_queue *queue;
|
||||
int err;
|
||||
|
||||
queue = &sfq->sf->queues.queue_array[sfq->queue_nr];
|
||||
|
||||
/* Get buffer and last position in buffer to resume
|
||||
* decoding the auxiliary entries. One buffer might be large
|
||||
* and decoding might stop in between. This depends on the time
|
||||
* stamp of the trailer entry in each page of the auxiliary
|
||||
* data and the time stamp of the event triggering the decoding.
|
||||
*/
|
||||
if (sfq->buffer == NULL) {
|
||||
sfq->buffer = buffer = auxtrace_buffer__next(queue,
|
||||
sfq->buffer);
|
||||
if (!buffer) {
|
||||
*ts = ~0ULL;
|
||||
return 1; /* Processing done on this queue */
|
||||
}
|
||||
/* Start with a new buffer on this queue */
|
||||
if (buffer->data) {
|
||||
buffer->use_size = buffer->size;
|
||||
buffer->use_data = buffer->data;
|
||||
}
|
||||
} else
|
||||
buffer = sfq->buffer;
|
||||
|
||||
if (!buffer->data) {
|
||||
int fd = perf_data__fd(sfq->sf->session->data);
|
||||
|
||||
buffer->data = auxtrace_buffer__get_data(buffer, fd);
|
||||
if (!buffer->data)
|
||||
return -ENOMEM;
|
||||
buffer->use_size = buffer->size;
|
||||
buffer->use_data = buffer->data;
|
||||
}
|
||||
pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n",
|
||||
__func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset,
|
||||
buffer->size, buffer->use_size);
|
||||
err = s390_cpumsf_samples(sfq, ts);
|
||||
|
||||
/* If non-zero, there is either an error (err < 0) or the buffer is
|
||||
* completely done (err > 0). The error is unrecoverable, usually
|
||||
* some descriptors could not be read successfully, so continue with
|
||||
* the next buffer.
|
||||
* In both cases the parameter 'ts' has been updated.
|
||||
*/
|
||||
if (err) {
|
||||
sfq->buffer = NULL;
|
||||
list_del(&buffer->list);
|
||||
auxtrace_buffer__free(buffer);
|
||||
if (err > 0) /* Buffer done, no error */
|
||||
err = 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct s390_cpumsf_queue *
|
||||
s390_cpumsf_alloc_queue(struct s390_cpumsf *sf, unsigned int queue_nr)
|
||||
{
|
||||
struct s390_cpumsf_queue *sfq;
|
||||
|
||||
sfq = zalloc(sizeof(struct s390_cpumsf_queue));
|
||||
if (sfq == NULL)
|
||||
return NULL;
|
||||
|
||||
sfq->sf = sf;
|
||||
sfq->queue_nr = queue_nr;
|
||||
sfq->cpu = -1;
|
||||
return sfq;
|
||||
}
|
||||
|
||||
static int s390_cpumsf_setup_queue(struct s390_cpumsf *sf,
|
||||
struct auxtrace_queue *queue,
|
||||
unsigned int queue_nr, u64 ts)
|
||||
{
|
||||
struct s390_cpumsf_queue *sfq = queue->priv;
|
||||
|
||||
if (list_empty(&queue->head))
|
||||
return 0;
|
||||
|
||||
if (sfq == NULL) {
|
||||
sfq = s390_cpumsf_alloc_queue(sf, queue_nr);
|
||||
if (!sfq)
|
||||
return -ENOMEM;
|
||||
queue->priv = sfq;
|
||||
|
||||
if (queue->cpu != -1)
|
||||
sfq->cpu = queue->cpu;
|
||||
}
|
||||
return auxtrace_heap__add(&sf->heap, queue_nr, ts);
|
||||
}
|
||||
|
||||
static int s390_cpumsf_setup_queues(struct s390_cpumsf *sf, u64 ts)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < sf->queues.nr_queues; i++) {
|
||||
ret = s390_cpumsf_setup_queue(sf, &sf->queues.queue_array[i],
|
||||
i, ts);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s390_cpumsf_update_queues(struct s390_cpumsf *sf, u64 ts)
|
||||
{
|
||||
if (!sf->queues.new_data)
|
||||
return 0;
|
||||
|
||||
sf->queues.new_data = false;
|
||||
return s390_cpumsf_setup_queues(sf, ts);
|
||||
}
|
||||
|
||||
static int s390_cpumsf_process_queues(struct s390_cpumsf *sf, u64 timestamp)
|
||||
{
|
||||
unsigned int queue_nr;
|
||||
u64 ts;
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
struct auxtrace_queue *queue;
|
||||
struct s390_cpumsf_queue *sfq;
|
||||
|
||||
if (!sf->heap.heap_cnt)
|
||||
return 0;
|
||||
|
||||
if (sf->heap.heap_array[0].ordinal >= timestamp)
|
||||
return 0;
|
||||
|
||||
queue_nr = sf->heap.heap_array[0].queue_nr;
|
||||
queue = &sf->queues.queue_array[queue_nr];
|
||||
sfq = queue->priv;
|
||||
|
||||
auxtrace_heap__pop(&sf->heap);
|
||||
if (sf->heap.heap_cnt) {
|
||||
ts = sf->heap.heap_array[0].ordinal + 1;
|
||||
if (ts > timestamp)
|
||||
ts = timestamp;
|
||||
} else {
|
||||
ts = timestamp;
|
||||
}
|
||||
|
||||
ret = s390_cpumsf_run_decoder(sfq, &ts);
|
||||
if (ret < 0) {
|
||||
auxtrace_heap__add(&sf->heap, queue_nr, ts);
|
||||
return ret;
|
||||
}
|
||||
if (!ret) {
|
||||
ret = auxtrace_heap__add(&sf->heap, queue_nr, ts);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s390_cpumsf_synth_error(struct s390_cpumsf *sf, int code, int cpu,
|
||||
pid_t pid, pid_t tid, u64 ip)
|
||||
{
|
||||
char msg[MAX_AUXTRACE_ERROR_MSG];
|
||||
union perf_event event;
|
||||
int err;
|
||||
|
||||
strncpy(msg, "Lost Auxiliary Trace Buffer", sizeof(msg) - 1);
|
||||
auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE,
|
||||
code, cpu, pid, tid, ip, msg);
|
||||
|
||||
err = perf_session__deliver_synth_event(sf->session, &event, NULL);
|
||||
if (err)
|
||||
pr_err("s390 Auxiliary Trace: failed to deliver error event,"
|
||||
"error %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample)
|
||||
{
|
||||
return s390_cpumsf_synth_error(sf, 1, sample->cpu,
|
||||
sample->pid, sample->tid, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_tool *tool)
|
||||
{
|
||||
struct s390_cpumsf *sf = container_of(session->auxtrace,
|
||||
struct s390_cpumsf,
|
||||
auxtrace);
|
||||
u64 timestamp = sample->time;
|
||||
int err = 0;
|
||||
|
||||
if (dump_trace)
|
||||
return 0;
|
||||
|
||||
if (!tool->ordered_events) {
|
||||
pr_err("s390 Auxiliary Trace requires ordered events\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (event->header.type == PERF_RECORD_AUX &&
|
||||
event->aux.flags & PERF_AUX_FLAG_TRUNCATED)
|
||||
return s390_cpumsf_lost(sf, sample);
|
||||
|
||||
if (timestamp) {
|
||||
err = s390_cpumsf_update_queues(sf, timestamp);
|
||||
if (!err)
|
||||
err = s390_cpumsf_process_queues(sf, timestamp);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
struct s390_cpumsf_synth {
|
||||
struct perf_tool cpumsf_tool;
|
||||
struct perf_session *session;
|
||||
};
|
||||
|
||||
static int
|
||||
s390_cpumsf_process_auxtrace_event(struct perf_session *session,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_tool *tool __maybe_unused)
|
||||
{
|
||||
struct s390_cpumsf *sf = container_of(session->auxtrace,
|
||||
struct s390_cpumsf,
|
||||
auxtrace);
|
||||
|
||||
int fd = perf_data__fd(session->data);
|
||||
struct auxtrace_buffer *buffer;
|
||||
off_t data_offset;
|
||||
int err;
|
||||
|
||||
if (sf->data_queued)
|
||||
return 0;
|
||||
|
||||
if (perf_data__is_pipe(session->data)) {
|
||||
data_offset = 0;
|
||||
} else {
|
||||
data_offset = lseek(fd, 0, SEEK_CUR);
|
||||
if (data_offset == -1)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
err = auxtrace_queues__add_event(&sf->queues, session, event,
|
||||
data_offset, &buffer);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Dump here after copying piped trace out of the pipe */
|
||||
if (dump_trace) {
|
||||
if (auxtrace_buffer__get_data(buffer, fd)) {
|
||||
s390_cpumsf_dump_event(sf, buffer->data,
|
||||
buffer->size);
|
||||
auxtrace_buffer__put_data(buffer);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s390_cpumsf_free_events(struct perf_session *session __maybe_unused)
|
||||
{
|
||||
}
|
||||
|
||||
static int s390_cpumsf_flush(struct perf_session *session __maybe_unused,
|
||||
struct perf_tool *tool __maybe_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s390_cpumsf_free_queues(struct perf_session *session)
|
||||
{
|
||||
struct s390_cpumsf *sf = container_of(session->auxtrace,
|
||||
struct s390_cpumsf,
|
||||
auxtrace);
|
||||
struct auxtrace_queues *queues = &sf->queues;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < queues->nr_queues; i++)
|
||||
zfree(&queues->queue_array[i].priv);
|
||||
auxtrace_queues__free(queues);
|
||||
}
|
||||
|
||||
static void s390_cpumsf_free(struct perf_session *session)
|
||||
{
|
||||
struct s390_cpumsf *sf = container_of(session->auxtrace,
|
||||
struct s390_cpumsf,
|
||||
auxtrace);
|
||||
|
||||
auxtrace_heap__free(&sf->heap);
|
||||
s390_cpumsf_free_queues(session);
|
||||
session->auxtrace = NULL;
|
||||
free(sf);
|
||||
}
|
||||
|
||||
static int s390_cpumsf_get_type(const char *cpuid)
|
||||
{
|
||||
int ret, family = 0;
|
||||
|
||||
ret = sscanf(cpuid, "%*[^,],%u", &family);
|
||||
return (ret == 1) ? family : 0;
|
||||
}
|
||||
|
||||
/* Check itrace options set on perf report command.
|
||||
* Return true, if none are set or all options specified can be
|
||||
* handled on s390.
|
||||
* Return false otherwise.
|
||||
*/
|
||||
static bool check_auxtrace_itrace(struct itrace_synth_opts *itops)
|
||||
{
|
||||
if (!itops || !itops->set)
|
||||
return true;
|
||||
pr_err("No --itrace options supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int s390_cpumsf_process_auxtrace_info(union perf_event *event,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
|
||||
struct s390_cpumsf *sf;
|
||||
int err;
|
||||
|
||||
if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event))
|
||||
return -EINVAL;
|
||||
|
||||
sf = zalloc(sizeof(struct s390_cpumsf));
|
||||
if (sf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!check_auxtrace_itrace(session->itrace_synth_opts)) {
|
||||
err = -EINVAL;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = auxtrace_queues__init(&sf->queues);
|
||||
if (err)
|
||||
goto err_free;
|
||||
|
||||
sf->session = session;
|
||||
sf->machine = &session->machines.host; /* No kvm support */
|
||||
sf->auxtrace_type = auxtrace_info->type;
|
||||
sf->pmu_type = PERF_TYPE_RAW;
|
||||
sf->machine_type = s390_cpumsf_get_type(session->evlist->env->cpuid);
|
||||
|
||||
sf->auxtrace.process_event = s390_cpumsf_process_event;
|
||||
sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event;
|
||||
sf->auxtrace.flush_events = s390_cpumsf_flush;
|
||||
sf->auxtrace.free_events = s390_cpumsf_free_events;
|
||||
sf->auxtrace.free = s390_cpumsf_free;
|
||||
session->auxtrace = &sf->auxtrace;
|
||||
|
||||
if (dump_trace)
|
||||
return 0;
|
||||
|
||||
err = auxtrace_queues__process_index(&sf->queues, session);
|
||||
if (err)
|
||||
goto err_free_queues;
|
||||
|
||||
if (sf->queues.populated)
|
||||
sf->data_queued = true;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_queues:
|
||||
auxtrace_queues__free(&sf->queues);
|
||||
session->auxtrace = NULL;
|
||||
err_free:
|
||||
free(sf);
|
||||
return err;
|
||||
}
|
21
tools/perf/util/s390-cpumsf.h
Normal file
21
tools/perf/util/s390-cpumsf.h
Normal file
@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright IBM Corp. 2018
|
||||
* Auxtrace support for s390 CPU-Measurement Sampling Facility
|
||||
*
|
||||
* Author(s): Thomas Richter <tmricht@linux.ibm.com>
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE__PERF_S390_CPUMSF_H
|
||||
#define INCLUDE__PERF_S390_CPUMSF_H
|
||||
|
||||
union perf_event;
|
||||
struct perf_session;
|
||||
struct perf_pmu;
|
||||
|
||||
struct auxtrace_record *
|
||||
s390_cpumsf_recording_init(int *err, struct perf_pmu *s390_cpumsf_pmu);
|
||||
|
||||
int s390_cpumsf_process_auxtrace_info(union perf_event *event,
|
||||
struct perf_session *session);
|
||||
#endif
|
@ -535,7 +535,7 @@ static int perl_stop_script(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perl_generate_script(struct pevent *pevent, const char *outfile)
|
||||
static int perl_generate_script(struct tep_handle *pevent, const char *outfile)
|
||||
{
|
||||
struct event_format *event = NULL;
|
||||
struct format_field *f;
|
||||
|
@ -871,8 +871,8 @@ static void python_process_tracepoint(struct perf_sample *sample,
|
||||
offset = field->offset;
|
||||
len = field->size;
|
||||
if (field->flags & FIELD_IS_DYNAMIC) {
|
||||
val = pevent_read_number(scripting_context->pevent,
|
||||
data + offset, len);
|
||||
val = tep_read_number(scripting_context->pevent,
|
||||
data + offset, len);
|
||||
offset = val;
|
||||
len = offset >> 16;
|
||||
offset &= 0xffff;
|
||||
@ -1588,7 +1588,7 @@ static int python_stop_script(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int python_generate_script(struct pevent *pevent, const char *outfile)
|
||||
static int python_generate_script(struct tep_handle *pevent, const char *outfile)
|
||||
{
|
||||
struct event_format *event = NULL;
|
||||
struct format_field *f;
|
||||
|
@ -1,12 +1,20 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from os import getenv
|
||||
from subprocess import Popen, PIPE
|
||||
from re import sub
|
||||
|
||||
def clang_has_option(option):
|
||||
return [o for o in Popen(['clang', option], stderr=PIPE).stderr.readlines() if "unknown argument" in o] == [ ]
|
||||
|
||||
cc = getenv("CC")
|
||||
if cc == "clang":
|
||||
from _sysconfigdata import build_time_vars
|
||||
from re import sub
|
||||
build_time_vars["CFLAGS"] = sub("-specs=[^ ]+", "", build_time_vars["CFLAGS"])
|
||||
if not clang_has_option("-mcet"):
|
||||
build_time_vars["CFLAGS"] = sub("-mcet", "", build_time_vars["CFLAGS"])
|
||||
if not clang_has_option("-fcf-protection"):
|
||||
build_time_vars["CFLAGS"] = sub("-fcf-protection", "", build_time_vars["CFLAGS"])
|
||||
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
|
@ -601,7 +601,7 @@ static char *get_trace_output(struct hist_entry *he)
|
||||
{
|
||||
struct trace_seq seq;
|
||||
struct perf_evsel *evsel;
|
||||
struct pevent_record rec = {
|
||||
struct tep_record rec = {
|
||||
.data = he->raw_data,
|
||||
.size = he->raw_size,
|
||||
};
|
||||
@ -610,10 +610,10 @@ static char *get_trace_output(struct hist_entry *he)
|
||||
|
||||
trace_seq_init(&seq);
|
||||
if (symbol_conf.raw_trace) {
|
||||
pevent_print_fields(&seq, he->raw_data, he->raw_size,
|
||||
evsel->tp_format);
|
||||
tep_print_fields(&seq, he->raw_data, he->raw_size,
|
||||
evsel->tp_format);
|
||||
} else {
|
||||
pevent_event_info(&seq, evsel->tp_format, &rec);
|
||||
tep_event_info(&seq, evsel->tp_format, &rec);
|
||||
}
|
||||
/*
|
||||
* Trim the buffer, it starts at 4KB and we're not going to
|
||||
@ -2047,7 +2047,7 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
|
||||
struct trace_seq seq;
|
||||
raw_field:
|
||||
trace_seq_init(&seq);
|
||||
pevent_print_field(&seq, he->raw_data, hde->field);
|
||||
tep_print_field(&seq, he->raw_data, hde->field);
|
||||
str = seq.buffer;
|
||||
}
|
||||
|
||||
@ -2074,7 +2074,7 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
|
||||
if (field->flags & FIELD_IS_DYNAMIC) {
|
||||
unsigned long long dyn;
|
||||
|
||||
pevent_read_number_field(field, a->raw_data, &dyn);
|
||||
tep_read_number_field(field, a->raw_data, &dyn);
|
||||
offset = dyn & 0xffff;
|
||||
size = (dyn >> 16) & 0xffff;
|
||||
|
||||
@ -2311,7 +2311,7 @@ static int add_all_matching_fields(struct perf_evlist *evlist,
|
||||
if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
|
||||
continue;
|
||||
|
||||
field = pevent_find_any_field(evsel->tp_format, field_name);
|
||||
field = tep_find_any_field(evsel->tp_format, field_name);
|
||||
if (field == NULL)
|
||||
continue;
|
||||
|
||||
@ -2378,7 +2378,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok,
|
||||
if (!strcmp(field_name, "*")) {
|
||||
ret = add_evsel_fields(evsel, raw_trace, level);
|
||||
} else {
|
||||
field = pevent_find_any_field(evsel->tp_format, field_name);
|
||||
field = tep_find_any_field(evsel->tp_format, field_name);
|
||||
if (field == NULL) {
|
||||
pr_debug("Cannot find event field for %s.%s\n",
|
||||
event_name, field_name);
|
||||
|
@ -276,7 +276,7 @@ extern struct sort_entry sort_thread;
|
||||
extern struct list_head hist_entry__sort_list;
|
||||
|
||||
struct perf_evlist;
|
||||
struct pevent;
|
||||
struct tep_handle;
|
||||
int setup_sorting(struct perf_evlist *evlist);
|
||||
int setup_output_field(void);
|
||||
void reset_output_field(void);
|
||||
|
@ -32,7 +32,7 @@
|
||||
static int get_common_field(struct scripting_context *context,
|
||||
int *offset, int *size, const char *type)
|
||||
{
|
||||
struct pevent *pevent = context->pevent;
|
||||
struct tep_handle *pevent = context->pevent;
|
||||
struct event_format *event;
|
||||
struct format_field *field;
|
||||
|
||||
@ -41,14 +41,14 @@ static int get_common_field(struct scripting_context *context,
|
||||
return 0;
|
||||
|
||||
event = pevent->events[0];
|
||||
field = pevent_find_common_field(event, type);
|
||||
field = tep_find_common_field(event, type);
|
||||
if (!field)
|
||||
return 0;
|
||||
*offset = field->offset;
|
||||
*size = field->size;
|
||||
}
|
||||
|
||||
return pevent_read_number(pevent, context->event_data + *offset, *size);
|
||||
return tep_read_number(pevent, context->event_data + *offset, *size);
|
||||
}
|
||||
|
||||
int common_lock_depth(struct scripting_context *context)
|
||||
@ -99,24 +99,24 @@ raw_field_value(struct event_format *event, const char *name, void *data)
|
||||
struct format_field *field;
|
||||
unsigned long long val;
|
||||
|
||||
field = pevent_find_any_field(event, name);
|
||||
field = tep_find_any_field(event, name);
|
||||
if (!field)
|
||||
return 0ULL;
|
||||
|
||||
pevent_read_number_field(field, data, &val);
|
||||
tep_read_number_field(field, data, &val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
unsigned long long read_size(struct event_format *event, void *ptr, int size)
|
||||
{
|
||||
return pevent_read_number(event->pevent, ptr, size);
|
||||
return tep_read_number(event->pevent, ptr, size);
|
||||
}
|
||||
|
||||
void event_format__fprintf(struct event_format *event,
|
||||
int cpu, void *data, int size, FILE *fp)
|
||||
{
|
||||
struct pevent_record record;
|
||||
struct tep_record record;
|
||||
struct trace_seq s;
|
||||
|
||||
memset(&record, 0, sizeof(record));
|
||||
@ -125,7 +125,7 @@ void event_format__fprintf(struct event_format *event,
|
||||
record.data = data;
|
||||
|
||||
trace_seq_init(&s);
|
||||
pevent_event_info(&s, event, &record);
|
||||
tep_event_info(&s, event, &record);
|
||||
trace_seq_do_fprintf(&s, fp);
|
||||
trace_seq_destroy(&s);
|
||||
}
|
||||
@ -136,7 +136,7 @@ void event_format__print(struct event_format *event,
|
||||
return event_format__fprintf(event, cpu, data, size, stdout);
|
||||
}
|
||||
|
||||
void parse_ftrace_printk(struct pevent *pevent,
|
||||
void parse_ftrace_printk(struct tep_handle *pevent,
|
||||
char *file, unsigned int size __maybe_unused)
|
||||
{
|
||||
unsigned long long addr;
|
||||
@ -157,11 +157,11 @@ void parse_ftrace_printk(struct pevent *pevent,
|
||||
/* fmt still has a space, skip it */
|
||||
printk = strdup(fmt+1);
|
||||
line = strtok_r(NULL, "\n", &next);
|
||||
pevent_register_print_string(pevent, printk, addr);
|
||||
tep_register_print_string(pevent, printk, addr);
|
||||
}
|
||||
}
|
||||
|
||||
void parse_saved_cmdline(struct pevent *pevent,
|
||||
void parse_saved_cmdline(struct tep_handle *pevent,
|
||||
char *file, unsigned int size __maybe_unused)
|
||||
{
|
||||
char *comm;
|
||||
@ -172,24 +172,24 @@ void parse_saved_cmdline(struct pevent *pevent,
|
||||
line = strtok_r(file, "\n", &next);
|
||||
while (line) {
|
||||
sscanf(line, "%d %ms", &pid, &comm);
|
||||
pevent_register_comm(pevent, comm, pid);
|
||||
tep_register_comm(pevent, comm, pid);
|
||||
free(comm);
|
||||
line = strtok_r(NULL, "\n", &next);
|
||||
}
|
||||
}
|
||||
|
||||
int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size)
|
||||
int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size)
|
||||
{
|
||||
return pevent_parse_event(pevent, buf, size, "ftrace");
|
||||
return tep_parse_event(pevent, buf, size, "ftrace");
|
||||
}
|
||||
|
||||
int parse_event_file(struct pevent *pevent,
|
||||
int parse_event_file(struct tep_handle *pevent,
|
||||
char *buf, unsigned long size, char *sys)
|
||||
{
|
||||
return pevent_parse_event(pevent, buf, size, sys);
|
||||
return tep_parse_event(pevent, buf, size, sys);
|
||||
}
|
||||
|
||||
struct event_format *trace_find_next_event(struct pevent *pevent,
|
||||
struct event_format *trace_find_next_event(struct tep_handle *pevent,
|
||||
struct event_format *event)
|
||||
{
|
||||
static int idx;
|
||||
|
@ -96,7 +96,7 @@ static void skip(int size)
|
||||
};
|
||||
}
|
||||
|
||||
static unsigned int read4(struct pevent *pevent)
|
||||
static unsigned int read4(struct tep_handle *pevent)
|
||||
{
|
||||
unsigned int data;
|
||||
|
||||
@ -105,7 +105,7 @@ static unsigned int read4(struct pevent *pevent)
|
||||
return __data2host4(pevent, data);
|
||||
}
|
||||
|
||||
static unsigned long long read8(struct pevent *pevent)
|
||||
static unsigned long long read8(struct tep_handle *pevent)
|
||||
{
|
||||
unsigned long long data;
|
||||
|
||||
@ -158,7 +158,7 @@ out:
|
||||
return str;
|
||||
}
|
||||
|
||||
static int read_proc_kallsyms(struct pevent *pevent)
|
||||
static int read_proc_kallsyms(struct tep_handle *pevent)
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
@ -181,7 +181,7 @@ static int read_proc_kallsyms(struct pevent *pevent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_ftrace_printk(struct pevent *pevent)
|
||||
static int read_ftrace_printk(struct tep_handle *pevent)
|
||||
{
|
||||
unsigned int size;
|
||||
char *buf;
|
||||
@ -208,7 +208,7 @@ static int read_ftrace_printk(struct pevent *pevent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_header_files(struct pevent *pevent)
|
||||
static int read_header_files(struct tep_handle *pevent)
|
||||
{
|
||||
unsigned long long size;
|
||||
char *header_page;
|
||||
@ -235,13 +235,13 @@ static int read_header_files(struct pevent *pevent)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!pevent_parse_header_page(pevent, header_page, size,
|
||||
pevent_get_long_size(pevent))) {
|
||||
if (!tep_parse_header_page(pevent, header_page, size,
|
||||
tep_get_long_size(pevent))) {
|
||||
/*
|
||||
* The commit field in the page is of type long,
|
||||
* use that instead, since it represents the kernel.
|
||||
*/
|
||||
pevent_set_long_size(pevent, pevent->header_page_size_size);
|
||||
tep_set_long_size(pevent, pevent->header_page_size_size);
|
||||
}
|
||||
free(header_page);
|
||||
|
||||
@ -259,7 +259,7 @@ static int read_header_files(struct pevent *pevent)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
|
||||
static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size)
|
||||
{
|
||||
int ret;
|
||||
char *buf;
|
||||
@ -284,8 +284,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_event_file(struct pevent *pevent, char *sys,
|
||||
unsigned long long size)
|
||||
static int read_event_file(struct tep_handle *pevent, char *sys,
|
||||
unsigned long long size)
|
||||
{
|
||||
int ret;
|
||||
char *buf;
|
||||
@ -310,7 +310,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_ftrace_files(struct pevent *pevent)
|
||||
static int read_ftrace_files(struct tep_handle *pevent)
|
||||
{
|
||||
unsigned long long size;
|
||||
int count;
|
||||
@ -328,7 +328,7 @@ static int read_ftrace_files(struct pevent *pevent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_event_files(struct pevent *pevent)
|
||||
static int read_event_files(struct tep_handle *pevent)
|
||||
{
|
||||
unsigned long long size;
|
||||
char *sys;
|
||||
@ -356,7 +356,7 @@ static int read_event_files(struct pevent *pevent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_saved_cmdline(struct pevent *pevent)
|
||||
static int read_saved_cmdline(struct tep_handle *pevent)
|
||||
{
|
||||
unsigned long long size;
|
||||
char *buf;
|
||||
@ -399,7 +399,7 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
|
||||
int host_bigendian;
|
||||
int file_long_size;
|
||||
int file_page_size;
|
||||
struct pevent *pevent = NULL;
|
||||
struct tep_handle *pevent = NULL;
|
||||
int err;
|
||||
|
||||
repipe = __repipe;
|
||||
@ -439,9 +439,9 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
|
||||
|
||||
pevent = tevent->pevent;
|
||||
|
||||
pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
|
||||
pevent_set_file_bigendian(pevent, file_bigendian);
|
||||
pevent_set_host_bigendian(pevent, host_bigendian);
|
||||
tep_set_flag(pevent, TEP_NSEC_OUTPUT);
|
||||
tep_set_file_bigendian(pevent, file_bigendian);
|
||||
tep_set_host_bigendian(pevent, host_bigendian);
|
||||
|
||||
if (do_read(buf, 1) < 0)
|
||||
goto out;
|
||||
@ -451,8 +451,8 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
|
||||
if (!file_page_size)
|
||||
goto out;
|
||||
|
||||
pevent_set_long_size(pevent, file_long_size);
|
||||
pevent_set_page_size(pevent, file_page_size);
|
||||
tep_set_long_size(pevent, file_long_size);
|
||||
tep_set_page_size(pevent, file_page_size);
|
||||
|
||||
err = read_header_files(pevent);
|
||||
if (err)
|
||||
@ -479,9 +479,9 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
|
||||
repipe = false;
|
||||
|
||||
if (show_funcs) {
|
||||
pevent_print_funcs(pevent);
|
||||
tep_print_funcs(pevent);
|
||||
} else if (show_printk) {
|
||||
pevent_print_printk(pevent);
|
||||
tep_print_printk(pevent);
|
||||
}
|
||||
|
||||
pevent = NULL;
|
||||
|
@ -66,7 +66,7 @@ static int python_start_script_unsupported(const char *script __maybe_unused,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int python_generate_script_unsupported(struct pevent *pevent
|
||||
static int python_generate_script_unsupported(struct tep_handle *pevent
|
||||
__maybe_unused,
|
||||
const char *outfile
|
||||
__maybe_unused)
|
||||
@ -130,7 +130,7 @@ static int perl_start_script_unsupported(const char *script __maybe_unused,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int perl_generate_script_unsupported(struct pevent *pevent
|
||||
static int perl_generate_script_unsupported(struct tep_handle *pevent
|
||||
__maybe_unused,
|
||||
const char *outfile __maybe_unused)
|
||||
{
|
||||
|
@ -28,10 +28,10 @@ static bool tevent_initialized;
|
||||
|
||||
int trace_event__init(struct trace_event *t)
|
||||
{
|
||||
struct pevent *pevent = pevent_alloc();
|
||||
struct tep_handle *pevent = tep_alloc();
|
||||
|
||||
if (pevent) {
|
||||
t->plugin_list = traceevent_load_plugins(pevent);
|
||||
t->plugin_list = tep_load_plugins(pevent);
|
||||
t->pevent = pevent;
|
||||
}
|
||||
|
||||
@ -40,33 +40,33 @@ int trace_event__init(struct trace_event *t)
|
||||
|
||||
static int trace_event__init2(void)
|
||||
{
|
||||
int be = traceevent_host_bigendian();
|
||||
struct pevent *pevent;
|
||||
int be = tep_host_bigendian();
|
||||
struct tep_handle *pevent;
|
||||
|
||||
if (trace_event__init(&tevent))
|
||||
return -1;
|
||||
|
||||
pevent = tevent.pevent;
|
||||
pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
|
||||
pevent_set_file_bigendian(pevent, be);
|
||||
pevent_set_host_bigendian(pevent, be);
|
||||
tep_set_flag(pevent, TEP_NSEC_OUTPUT);
|
||||
tep_set_file_bigendian(pevent, be);
|
||||
tep_set_host_bigendian(pevent, be);
|
||||
tevent_initialized = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trace_event__register_resolver(struct machine *machine,
|
||||
pevent_func_resolver_t *func)
|
||||
tep_func_resolver_t *func)
|
||||
{
|
||||
if (!tevent_initialized && trace_event__init2())
|
||||
return -1;
|
||||
|
||||
return pevent_set_function_resolver(tevent.pevent, func, machine);
|
||||
return tep_set_function_resolver(tevent.pevent, func, machine);
|
||||
}
|
||||
|
||||
void trace_event__cleanup(struct trace_event *t)
|
||||
{
|
||||
traceevent_unload_plugins(t->plugin_list, t->pevent);
|
||||
pevent_free(t->pevent);
|
||||
tep_unload_plugins(t->plugin_list, t->pevent);
|
||||
tep_free(t->pevent);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -76,7 +76,7 @@ static struct event_format*
|
||||
tp_format(const char *sys, const char *name)
|
||||
{
|
||||
char *tp_dir = get_events_file(sys);
|
||||
struct pevent *pevent = tevent.pevent;
|
||||
struct tep_handle *pevent = tevent.pevent;
|
||||
struct event_format *event = NULL;
|
||||
char path[PATH_MAX];
|
||||
size_t size;
|
||||
@ -93,7 +93,7 @@ tp_format(const char *sys, const char *name)
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
pevent_parse_format(pevent, &event, data, size, sys);
|
||||
tep_parse_format(pevent, &event, data, size, sys);
|
||||
|
||||
free(data);
|
||||
return event;
|
||||
@ -116,5 +116,5 @@ struct event_format *trace_event__tp_format_id(int id)
|
||||
if (!tevent_initialized && trace_event__init2())
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return pevent_find_event(tevent.pevent, id);
|
||||
return tep_find_event(tevent.pevent, id);
|
||||
}
|
||||
|
@ -13,14 +13,14 @@ struct thread;
|
||||
struct plugin_list;
|
||||
|
||||
struct trace_event {
|
||||
struct pevent *pevent;
|
||||
struct tep_handle *pevent;
|
||||
struct plugin_list *plugin_list;
|
||||
};
|
||||
|
||||
int trace_event__init(struct trace_event *t);
|
||||
void trace_event__cleanup(struct trace_event *t);
|
||||
int trace_event__register_resolver(struct machine *machine,
|
||||
pevent_func_resolver_t *func);
|
||||
tep_func_resolver_t *func);
|
||||
struct event_format*
|
||||
trace_event__tp_format(const char *sys, const char *name);
|
||||
|
||||
@ -34,20 +34,20 @@ void event_format__fprintf(struct event_format *event,
|
||||
void event_format__print(struct event_format *event,
|
||||
int cpu, void *data, int size);
|
||||
|
||||
int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
|
||||
int parse_event_file(struct pevent *pevent,
|
||||
int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size);
|
||||
int parse_event_file(struct tep_handle *pevent,
|
||||
char *buf, unsigned long size, char *sys);
|
||||
|
||||
unsigned long long
|
||||
raw_field_value(struct event_format *event, const char *name, void *data);
|
||||
|
||||
void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
|
||||
void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
|
||||
void parse_saved_cmdline(struct pevent *pevent, char *file, unsigned int size);
|
||||
void parse_proc_kallsyms(struct tep_handle *pevent, char *file, unsigned int size);
|
||||
void parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigned int size);
|
||||
void parse_saved_cmdline(struct tep_handle *pevent, char *file, unsigned int size);
|
||||
|
||||
ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe);
|
||||
|
||||
struct event_format *trace_find_next_event(struct pevent *pevent,
|
||||
struct event_format *trace_find_next_event(struct tep_handle *pevent,
|
||||
struct event_format *event);
|
||||
unsigned long long read_size(struct event_format *event, void *ptr, int size);
|
||||
unsigned long long eval_flag(const char *flag);
|
||||
@ -83,7 +83,7 @@ struct scripting_ops {
|
||||
void (*process_stat)(struct perf_stat_config *config,
|
||||
struct perf_evsel *evsel, u64 tstamp);
|
||||
void (*process_stat_interval)(u64 tstamp);
|
||||
int (*generate_script) (struct pevent *pevent, const char *outfile);
|
||||
int (*generate_script) (struct tep_handle *pevent, const char *outfile);
|
||||
};
|
||||
|
||||
extern unsigned int scripting_max_stack;
|
||||
@ -94,7 +94,7 @@ void setup_perl_scripting(void);
|
||||
void setup_python_scripting(void);
|
||||
|
||||
struct scripting_context {
|
||||
struct pevent *pevent;
|
||||
struct tep_handle *pevent;
|
||||
void *event_data;
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <zlib.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util/compress.h"
|
||||
#include "util/util.h"
|
||||
@ -79,3 +81,19 @@ out_close:
|
||||
|
||||
return ret == Z_STREAM_END ? 0 : -1;
|
||||
}
|
||||
|
||||
bool gzip_is_compressed(const char *input)
|
||||
{
|
||||
int fd = open(input, O_RDONLY);
|
||||
const uint8_t magic[2] = { 0x1f, 0x8b };
|
||||
char buf[2] = { 0 };
|
||||
ssize_t rc;
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
rc = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
return rc == sizeof(buf) ?
|
||||
memcmp(buf, magic, sizeof(buf)) == 0 : false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user