1 #ifndef PERF_UTIL_KWORK_H 2 #define PERF_UTIL_KWORK_H 3 4 #include "perf.h" 5 #include "util/tool.h" 6 #include "util/time-utils.h" 7 8 #include <stdlib.h> 9 #include <linux/bitmap.h> 10 #include <linux/list.h> 11 #include <linux/rbtree.h> 12 #include <linux/types.h> 13 14 struct perf_sample; 15 struct perf_session; 16 17 enum kwork_class_type { 18 KWORK_CLASS_IRQ, 19 KWORK_CLASS_SOFTIRQ, 20 KWORK_CLASS_WORKQUEUE, 21 KWORK_CLASS_SCHED, 22 KWORK_CLASS_MAX, 23 }; 24 25 enum kwork_report_type { 26 KWORK_REPORT_RUNTIME, 27 KWORK_REPORT_LATENCY, 28 KWORK_REPORT_TIMEHIST, 29 KWORK_REPORT_TOP, 30 }; 31 32 enum kwork_trace_type { 33 KWORK_TRACE_RAISE, 34 KWORK_TRACE_ENTRY, 35 KWORK_TRACE_EXIT, 36 KWORK_TRACE_MAX, 37 }; 38 39 /* 40 * data structure: 41 * 42 * +==================+ +============+ +======================+ 43 * | class | | work | | atom | 44 * +==================+ +============+ +======================+ 45 * +------------+ | +-----+ | | +------+ | | +-------+ +-----+ | 46 * | perf_kwork | +-> | irq | --------|+-> | eth0 | --+-> | raise | - | ... | --+ +-----------+ 47 * +-----+------+ || +-----+ ||| +------+ ||| +-------+ +-----+ | | | | 48 * | || ||| ||| | +-> | atom_page | 49 * | || ||| ||| +-------+ +-----+ | | | 50 * | class_list ||| |+-> | entry | - | ... | ----> | | 51 * | || ||| ||| +-------+ +-----+ | | | 52 * | || ||| ||| | +-> | | 53 * | || ||| ||| +-------+ +-----+ | | | | 54 * | || ||| |+-> | exit | - | ... | --+ +-----+-----+ 55 * | || ||| | | +-------+ +-----+ | | 56 * | || ||| | | | | 57 * | || ||| +-----+ | | | | 58 * | || |+-> | ... | | | | | 59 * | || | | +-----+ | | | | 60 * | || | | | | | | 61 * | || +---------+ | | +-----+ | | +-------+ +-----+ | | 62 * | +-> | softirq | -------> | RCU | ---+-> | raise | - | ... | --+ +-----+-----+ 63 * | || +---------+ | | +-----+ ||| +-------+ +-----+ | | | | 64 * | || | | ||| | +-> | atom_page | 65 * | || | | ||| +-------+ +-----+ | | | 66 * | || | | |+-> | entry | - | ... | ----> | | 67 * | || | | ||| +-------+ +-----+ | | | 68 * | || | | ||| | +-> | | 69 * | || | | ||| +-------+ +-----+ | | | | 70 * | || | | |+-> | exit | - | ... | --+ +-----+-----+ 71 * | || | | | | +-------+ +-----+ | | 72 * | || | | | | | | 73 * | || +-----------+ | | +-----+ | | | | 74 * | +-> | workqueue | -----> | ... | | | | | 75 * | | +-----------+ | | +-----+ | | | | 76 * | +==================+ +============+ +======================+ | 77 * | | 78 * +----> atom_page_list ---------------------------------------------------------+ 79 * 80 */ 81 82 struct kwork_atom { 83 struct list_head list; 84 u64 time; 85 struct kwork_atom *prev; 86 87 void *page_addr; 88 unsigned long bit_inpage; 89 }; 90 91 #define NR_ATOM_PER_PAGE 128 92 struct kwork_atom_page { 93 struct list_head list; 94 struct kwork_atom atoms[NR_ATOM_PER_PAGE]; 95 DECLARE_BITMAP(bitmap, NR_ATOM_PER_PAGE); 96 }; 97 98 struct perf_kwork; 99 struct kwork_class; 100 struct kwork_work { 101 /* 102 * class field 103 */ 104 struct rb_node node; 105 struct kwork_class *class; 106 107 /* 108 * work field 109 */ 110 u64 id; 111 int cpu; 112 char *name; 113 114 /* 115 * atom field 116 */ 117 u64 nr_atoms; 118 struct list_head atom_list[KWORK_TRACE_MAX]; 119 120 /* 121 * runtime report 122 */ 123 u64 max_runtime; 124 u64 max_runtime_start; 125 u64 max_runtime_end; 126 u64 total_runtime; 127 128 /* 129 * latency report 130 */ 131 u64 max_latency; 132 u64 max_latency_start; 133 u64 max_latency_end; 134 u64 total_latency; 135 136 /* 137 * top report 138 */ 139 u32 cpu_usage; 140 u32 tgid; 141 bool is_kthread; 142 }; 143 144 struct kwork_class { 145 struct list_head list; 146 const char *name; 147 enum kwork_class_type type; 148 149 unsigned int nr_tracepoints; 150 const struct evsel_str_handler *tp_handlers; 151 152 struct rb_root_cached work_root; 153 154 int (*class_init)(struct kwork_class *class, 155 struct perf_session *session); 156 157 void (*work_init)(struct perf_kwork *kwork, 158 struct kwork_class *class, 159 struct kwork_work *work, 160 enum kwork_trace_type src_type, 161 struct perf_sample *sample, 162 struct machine *machine); 163 164 void (*work_name)(struct kwork_work *work, 165 char *buf, int len); 166 }; 167 168 static inline void work_exit(struct kwork_work *work) 169 { 170 if (work) { 171 free(work->name); 172 work->name = NULL; 173 } 174 } 175 176 struct trace_kwork_handler { 177 int (*raise_event)(struct perf_kwork *kwork, 178 struct kwork_class *class, 179 struct perf_sample *sample, struct machine *machine); 180 181 int (*entry_event)(struct perf_kwork *kwork, 182 struct kwork_class *class, 183 struct perf_sample *sample, struct machine *machine); 184 185 int (*exit_event)(struct perf_kwork *kwork, 186 struct kwork_class *class, 187 struct perf_sample *sample, struct machine *machine); 188 189 int (*sched_switch_event)(struct perf_kwork *kwork, 190 struct kwork_class *class, 191 struct perf_sample *sample, struct machine *machine); 192 }; 193 194 struct __top_cpus_runtime { 195 u64 load; 196 u64 idle; 197 u64 irq; 198 u64 softirq; 199 u64 total; 200 }; 201 202 struct kwork_top_stat { 203 DECLARE_BITMAP(all_cpus_bitmap, MAX_NR_CPUS); 204 struct __top_cpus_runtime *cpus_runtime; 205 }; 206 207 struct perf_kwork { 208 /* 209 * metadata 210 */ 211 struct perf_tool tool; 212 struct list_head class_list; 213 struct list_head atom_page_list; 214 struct list_head sort_list, cmp_id; 215 struct rb_root_cached sorted_work_root; 216 const struct trace_kwork_handler *tp_handler; 217 218 /* 219 * profile filters 220 */ 221 const char *profile_name; 222 223 const char *cpu_list; 224 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 225 226 const char *time_str; 227 struct perf_time_interval ptime; 228 229 /* 230 * options for command 231 */ 232 bool force; 233 const char *event_list_str; 234 enum kwork_report_type report; 235 236 /* 237 * options for subcommand 238 */ 239 bool summary; 240 const char *sort_order; 241 bool show_callchain; 242 unsigned int max_stack; 243 bool use_bpf; 244 245 /* 246 * statistics 247 */ 248 u64 timestart; 249 u64 timeend; 250 251 unsigned long nr_events; 252 unsigned long nr_lost_chunks; 253 unsigned long nr_lost_events; 254 255 u64 all_runtime; 256 u64 all_count; 257 u64 nr_skipped_events[KWORK_TRACE_MAX + 1]; 258 259 /* 260 * perf kwork top data 261 */ 262 struct kwork_top_stat top_stat; 263 264 /* Add work callback. */ 265 struct kwork_work *(*add_work)(struct perf_kwork *kwork, 266 struct kwork_class *class, 267 struct kwork_work *key); 268 269 }; 270 271 #ifdef HAVE_BPF_SKEL 272 273 int perf_kwork__trace_prepare_bpf(struct perf_kwork *kwork); 274 int perf_kwork__report_read_bpf(struct perf_kwork *kwork); 275 void perf_kwork__report_cleanup_bpf(void); 276 277 void perf_kwork__trace_start(void); 278 void perf_kwork__trace_finish(void); 279 280 int perf_kwork__top_prepare_bpf(struct perf_kwork *kwork); 281 int perf_kwork__top_read_bpf(struct perf_kwork *kwork); 282 void perf_kwork__top_cleanup_bpf(void); 283 284 void perf_kwork__top_start(void); 285 void perf_kwork__top_finish(void); 286 287 #else /* !HAVE_BPF_SKEL */ 288 289 static inline int 290 perf_kwork__trace_prepare_bpf(struct perf_kwork *kwork __maybe_unused) 291 { 292 return -1; 293 } 294 295 static inline int 296 perf_kwork__report_read_bpf(struct perf_kwork *kwork __maybe_unused) 297 { 298 return -1; 299 } 300 301 static inline void perf_kwork__report_cleanup_bpf(void) {} 302 303 static inline void perf_kwork__trace_start(void) {} 304 static inline void perf_kwork__trace_finish(void) {} 305 306 static inline int 307 perf_kwork__top_prepare_bpf(struct perf_kwork *kwork __maybe_unused) 308 { 309 return -1; 310 } 311 312 static inline int 313 perf_kwork__top_read_bpf(struct perf_kwork *kwork __maybe_unused) 314 { 315 return -1; 316 } 317 318 static inline void perf_kwork__top_cleanup_bpf(void) {} 319 320 static inline void perf_kwork__top_start(void) {} 321 static inline void perf_kwork__top_finish(void) {} 322 323 #endif /* HAVE_BPF_SKEL */ 324 325 #endif /* PERF_UTIL_KWORK_H */ 326