| #ifndef PERF_UTIL_KWORK_H | |
| #define PERF_UTIL_KWORK_H | |
| #include "perf.h" | |
| #include "util/tool.h" | |
| #include "util/time-utils.h" | |
| #include <stdlib.h> | |
| #include <linux/bitmap.h> | |
| #include <linux/list.h> | |
| #include <linux/rbtree.h> | |
| #include <linux/types.h> | |
| struct perf_sample; | |
| struct perf_session; | |
| enum kwork_class_type { | |
| KWORK_CLASS_IRQ, | |
| KWORK_CLASS_SOFTIRQ, | |
| KWORK_CLASS_WORKQUEUE, | |
| KWORK_CLASS_SCHED, | |
| KWORK_CLASS_MAX, | |
| }; | |
| enum kwork_report_type { | |
| KWORK_REPORT_RUNTIME, | |
| KWORK_REPORT_LATENCY, | |
| KWORK_REPORT_TIMEHIST, | |
| KWORK_REPORT_TOP, | |
| }; | |
| enum kwork_trace_type { | |
| KWORK_TRACE_RAISE, | |
| KWORK_TRACE_ENTRY, | |
| KWORK_TRACE_EXIT, | |
| KWORK_TRACE_MAX, | |
| }; | |
| /* | |
| * data structure: | |
| * | |
| * +==================+ +============+ +======================+ | |
| * | class | | work | | atom | | |
| * +==================+ +============+ +======================+ | |
| * +------------+ | +-----+ | | +------+ | | +-------+ +-----+ | | |
| * | perf_kwork | +-> | irq | --------|+-> | eth0 | --+-> | raise | - | ... | --+ +-----------+ | |
| * +-----+------+ || +-----+ ||| +------+ ||| +-------+ +-----+ | | | | | |
| * | || ||| ||| | +-> | atom_page | | |
| * | || ||| ||| +-------+ +-----+ | | | | |
| * | class_list ||| |+-> | entry | - | ... | ----> | | | |
| * | || ||| ||| +-------+ +-----+ | | | | |
| * | || ||| ||| | +-> | | | |
| * | || ||| ||| +-------+ +-----+ | | | | | |
| * | || ||| |+-> | exit | - | ... | --+ +-----+-----+ | |
| * | || ||| | | +-------+ +-----+ | | | |
| * | || ||| | | | | | |
| * | || ||| +-----+ | | | | | |
| * | || |+-> | ... | | | | | | |
| * | || | | +-----+ | | | | | |
| * | || | | | | | | | |
| * | || +---------+ | | +-----+ | | +-------+ +-----+ | | | |
| * | +-> | softirq | -------> | RCU | ---+-> | raise | - | ... | --+ +-----+-----+ | |
| * | || +---------+ | | +-----+ ||| +-------+ +-----+ | | | | | |
| * | || | | ||| | +-> | atom_page | | |
| * | || | | ||| +-------+ +-----+ | | | | |
| * | || | | |+-> | entry | - | ... | ----> | | | |
| * | || | | ||| +-------+ +-----+ | | | | |
| * | || | | ||| | +-> | | | |
| * | || | | ||| +-------+ +-----+ | | | | | |
| * | || | | |+-> | exit | - | ... | --+ +-----+-----+ | |
| * | || | | | | +-------+ +-----+ | | | |
| * | || | | | | | | | |
| * | || +-----------+ | | +-----+ | | | | | |
| * | +-> | workqueue | -----> | ... | | | | | | |
| * | | +-----------+ | | +-----+ | | | | | |
| * | +==================+ +============+ +======================+ | | |
| * | | | |
| * +----> atom_page_list ---------------------------------------------------------+ | |
| * | |
| */ | |
| struct kwork_atom { | |
| struct list_head list; | |
| u64 time; | |
| struct kwork_atom *prev; | |
| void *page_addr; | |
| unsigned long bit_inpage; | |
| }; | |
| #define NR_ATOM_PER_PAGE 128 | |
| struct kwork_atom_page { | |
| struct list_head list; | |
| struct kwork_atom atoms[NR_ATOM_PER_PAGE]; | |
| DECLARE_BITMAP(bitmap, NR_ATOM_PER_PAGE); | |
| }; | |
| struct perf_kwork; | |
| struct kwork_class; | |
| struct kwork_work { | |
| /* | |
| * class field | |
| */ | |
| struct rb_node node; | |
| struct kwork_class *class; | |
| /* | |
| * work field | |
| */ | |
| u64 id; | |
| int cpu; | |
| char *name; | |
| /* | |
| * atom field | |
| */ | |
| u64 nr_atoms; | |
| struct list_head atom_list[KWORK_TRACE_MAX]; | |
| /* | |
| * runtime report | |
| */ | |
| u64 max_runtime; | |
| u64 max_runtime_start; | |
| u64 max_runtime_end; | |
| u64 total_runtime; | |
| /* | |
| * latency report | |
| */ | |
| u64 max_latency; | |
| u64 max_latency_start; | |
| u64 max_latency_end; | |
| u64 total_latency; | |
| /* | |
| * top report | |
| */ | |
| u32 cpu_usage; | |
| u32 tgid; | |
| bool is_kthread; | |
| }; | |
| struct kwork_class { | |
| struct list_head list; | |
| const char *name; | |
| enum kwork_class_type type; | |
| unsigned int nr_tracepoints; | |
| const struct evsel_str_handler *tp_handlers; | |
| struct rb_root_cached work_root; | |
| int (*class_init)(struct kwork_class *class, | |
| struct perf_session *session); | |
| void (*work_init)(struct perf_kwork *kwork, | |
| struct kwork_class *class, | |
| struct kwork_work *work, | |
| enum kwork_trace_type src_type, | |
| struct perf_sample *sample, | |
| struct machine *machine); | |
| void (*work_name)(struct kwork_work *work, | |
| char *buf, int len); | |
| }; | |
| static inline void work_exit(struct kwork_work *work) | |
| { | |
| if (work) { | |
| free(work->name); | |
| work->name = NULL; | |
| } | |
| } | |
| struct trace_kwork_handler { | |
| int (*raise_event)(struct perf_kwork *kwork, | |
| struct kwork_class *class, | |
| struct perf_sample *sample, struct machine *machine); | |
| int (*entry_event)(struct perf_kwork *kwork, | |
| struct kwork_class *class, | |
| struct perf_sample *sample, struct machine *machine); | |
| int (*exit_event)(struct perf_kwork *kwork, | |
| struct kwork_class *class, | |
| struct perf_sample *sample, struct machine *machine); | |
| int (*sched_switch_event)(struct perf_kwork *kwork, | |
| struct kwork_class *class, | |
| struct perf_sample *sample, struct machine *machine); | |
| }; | |
| struct __top_cpus_runtime { | |
| u64 load; | |
| u64 idle; | |
| u64 irq; | |
| u64 softirq; | |
| u64 total; | |
| }; | |
| struct kwork_top_stat { | |
| DECLARE_BITMAP(all_cpus_bitmap, MAX_NR_CPUS); | |
| struct __top_cpus_runtime *cpus_runtime; | |
| unsigned int nr_skipped_cpu; | |
| }; | |
| struct perf_kwork { | |
| /* | |
| * metadata | |
| */ | |
| struct perf_tool tool; | |
| struct list_head class_list; | |
| struct list_head atom_page_list; | |
| struct list_head sort_list, cmp_id; | |
| struct rb_root_cached sorted_work_root; | |
| const struct trace_kwork_handler *tp_handler; | |
| /* | |
| * profile filters | |
| */ | |
| const char *profile_name; | |
| const char *cpu_list; | |
| DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | |
| const char *time_str; | |
| struct perf_time_interval ptime; | |
| /* | |
| * options for command | |
| */ | |
| bool force; | |
| const char *event_list_str; | |
| enum kwork_report_type report; | |
| /* | |
| * options for subcommand | |
| */ | |
| bool summary; | |
| const char *sort_order; | |
| bool show_callchain; | |
| unsigned int max_stack; | |
| bool use_bpf; | |
| /* | |
| * statistics | |
| */ | |
| u64 timestart; | |
| u64 timeend; | |
| unsigned long nr_events; | |
| unsigned long nr_lost_chunks; | |
| unsigned long nr_lost_events; | |
| u64 all_runtime; | |
| u64 all_count; | |
| u64 nr_skipped_events[KWORK_TRACE_MAX + 1]; | |
| /* | |
| * perf kwork top data | |
| */ | |
| struct kwork_top_stat top_stat; | |
| /* Add work callback. */ | |
| struct kwork_work *(*add_work)(struct perf_kwork *kwork, | |
| struct kwork_class *class, | |
| struct kwork_work *key); | |
| }; | |
| #ifdef HAVE_BPF_SKEL | |
| int perf_kwork__trace_prepare_bpf(struct perf_kwork *kwork); | |
| int perf_kwork__report_read_bpf(struct perf_kwork *kwork); | |
| void perf_kwork__report_cleanup_bpf(void); | |
| void perf_kwork__trace_start(void); | |
| void perf_kwork__trace_finish(void); | |
| int perf_kwork__top_prepare_bpf(struct perf_kwork *kwork); | |
| int perf_kwork__top_read_bpf(struct perf_kwork *kwork); | |
| void perf_kwork__top_cleanup_bpf(void); | |
| void perf_kwork__top_start(void); | |
| void perf_kwork__top_finish(void); | |
| #else /* !HAVE_BPF_SKEL */ | |
| static inline int | |
| perf_kwork__trace_prepare_bpf(struct perf_kwork *kwork __maybe_unused) | |
| { | |
| return -1; | |
| } | |
| static inline int | |
| perf_kwork__report_read_bpf(struct perf_kwork *kwork __maybe_unused) | |
| { | |
| return -1; | |
| } | |
| static inline void perf_kwork__report_cleanup_bpf(void) {} | |
| static inline void perf_kwork__trace_start(void) {} | |
| static inline void perf_kwork__trace_finish(void) {} | |
| static inline int | |
| perf_kwork__top_prepare_bpf(struct perf_kwork *kwork __maybe_unused) | |
| { | |
| return -1; | |
| } | |
| static inline int | |
| perf_kwork__top_read_bpf(struct perf_kwork *kwork __maybe_unused) | |
| { | |
| return -1; | |
| } | |
| static inline void perf_kwork__top_cleanup_bpf(void) {} | |
| static inline void perf_kwork__top_start(void) {} | |
| static inline void perf_kwork__top_finish(void) {} | |
| #endif /* HAVE_BPF_SKEL */ | |
| #endif /* PERF_UTIL_KWORK_H */ |