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 unsigned int nr_skipped_cpu; 206 }; 207 208 struct perf_kwork { 209 /* 210 * metadata 211 */ 212 struct perf_tool tool; 213 struct list_head class_list; 214 struct list_head atom_page_list; 215 struct list_head sort_list, cmp_id; 216 struct rb_root_cached sorted_work_root; 217 const struct trace_kwork_handler *tp_handler; 218 219 /* 220 * profile filters 221 */ 222 const char *profile_name; 223 224 const char *cpu_list; 225 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 226 227 const char *time_str; 228 struct perf_time_interval ptime; 229 230 /* 231 * options for command 232 */ 233 bool force; 234 const char *event_list_str; 235 enum kwork_report_type report; 236 237 /* 238 * options for subcommand 239 */ 240 bool summary; 241 const char *sort_order; 242 bool show_callchain; 243 unsigned int max_stack; 244 bool use_bpf; 245 246 /* 247 * statistics 248 */ 249 u64 timestart; 250 u64 timeend; 251 252 unsigned long nr_events; 253 unsigned long nr_lost_chunks; 254 unsigned long nr_lost_events; 255 256 u64 all_runtime; 257 u64 all_count; 258 u64 nr_skipped_events[KWORK_TRACE_MAX + 1]; 259 260 /* 261 * perf kwork top data 262 */ 263 struct kwork_top_stat top_stat; 264 265 /* Add work callback. */ 266 struct kwork_work *(*add_work)(struct perf_kwork *kwork, 267 struct kwork_class *class, 268 struct kwork_work *key); 269 270 }; 271 272 #ifdef HAVE_BPF_SKEL 273 274 int perf_kwork__trace_prepare_bpf(struct perf_kwork *kwork); 275 int perf_kwork__report_read_bpf(struct perf_kwork *kwork); 276 void perf_kwork__report_cleanup_bpf(void); 277 278 void perf_kwork__trace_start(void); 279 void perf_kwork__trace_finish(void); 280 281 int perf_kwork__top_prepare_bpf(struct perf_kwork *kwork); 282 int perf_kwork__top_read_bpf(struct perf_kwork *kwork); 283 void perf_kwork__top_cleanup_bpf(void); 284 285 void perf_kwork__top_start(void); 286 void perf_kwork__top_finish(void); 287 288 #else /* !HAVE_BPF_SKEL */ 289 290 static inline int 291 perf_kwork__trace_prepare_bpf(struct perf_kwork *kwork __maybe_unused) 292 { 293 return -1; 294 } 295 296 static inline int 297 perf_kwork__report_read_bpf(struct perf_kwork *kwork __maybe_unused) 298 { 299 return -1; 300 } 301 302 static inline void perf_kwork__report_cleanup_bpf(void) {} 303 304 static inline void perf_kwork__trace_start(void) {} 305 static inline void perf_kwork__trace_finish(void) {} 306 307 static inline int 308 perf_kwork__top_prepare_bpf(struct perf_kwork *kwork __maybe_unused) 309 { 310 return -1; 311 } 312 313 static inline int 314 perf_kwork__top_read_bpf(struct perf_kwork *kwork __maybe_unused) 315 { 316 return -1; 317 } 318 319 static inline void perf_kwork__top_cleanup_bpf(void) {} 320 321 static inline void perf_kwork__top_start(void) {} 322 static inline void perf_kwork__top_finish(void) {} 323 324 #endif /* HAVE_BPF_SKEL */ 325 326 #endif /* PERF_UTIL_KWORK_H */ 327