From 419ab0d6a959f41ec7fde807fe311aaafb05c3be Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 12 Sep 2009 03:59:01 +0200 Subject: [PATCH] perf sched: Make it easier to plug in new sub profilers Create a sched event structure of handlers in which various sched events reader can plug their own callbacks. This makes easier the addition of new perf sched sub commands. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Signed-off-by: Ingo Molnar --- tools/perf/builtin-sched.c | 243 ++++++++++++++++++++++++++++++--------------- 1 file changed, 165 insertions(+), 78 deletions(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 0215936..756fe62 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -14,6 +14,9 @@ #include "util/trace-event.h" #include + +#define MAX_CPUS 4096 + static char const *input_name = "perf.data"; static int input; static unsigned long page_size; @@ -27,6 +30,8 @@ static struct thread *last_match; static struct perf_header *header; static u64 sample_type; +static int replay_mode; + /* * Scheduler benchmarks @@ -677,6 +682,27 @@ do { \ FILL_FIELD(ptr, common_tgid, event, data); \ } while (0) + + +struct trace_switch_event { + u32 size; + + u16 common_type; + u8 common_flags; + u8 common_preempt_count; + u32 common_pid; + u32 common_tgid; + + char prev_comm[16]; + u32 prev_pid; + u32 prev_prio; + u64 prev_state; + char next_comm[16]; + u32 next_pid; + u32 next_prio; +}; + + struct trace_wakeup_event { u32 size; @@ -694,78 +720,79 @@ struct trace_wakeup_event { u32 cpu; }; -static void -process_sched_wakeup_event(struct raw_event_sample *raw, struct event *event, - int cpu __used, u64 timestamp __used, struct thread *thread __used) -{ - struct task_desc *waker, *wakee; - struct trace_wakeup_event wakeup_event; +struct trace_fork_event { + u32 size; - FILL_COMMON_FIELDS(wakeup_event, event, raw->data); + u16 common_type; + u8 common_flags; + u8 common_preempt_count; + u32 common_pid; + u32 common_tgid; + + char parent_comm[16]; + u32 parent_pid; + char child_comm[16]; + u32 child_pid; +}; + +struct trace_sched_handler { + void (*switch_event)(struct trace_switch_event *, + struct event *, + int cpu, + u64 timestamp, + struct thread *thread); + + void (*wakeup_event)(struct trace_wakeup_event *, + struct event *, + int cpu, + u64 timestamp, + struct thread *thread); + + void (*fork_event)(struct trace_fork_event *, + struct event *, + int cpu, + u64 timestamp, + struct thread *thread); +}; - FILL_ARRAY(wakeup_event, comm, event, raw->data); - FILL_FIELD(wakeup_event, pid, event, raw->data); - FILL_FIELD(wakeup_event, prio, event, raw->data); - FILL_FIELD(wakeup_event, success, event, raw->data); - FILL_FIELD(wakeup_event, cpu, event, raw->data); +static void +replay_wakeup_event(struct trace_wakeup_event *wakeup_event, + struct event *event, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) +{ + struct task_desc *waker, *wakee; if (verbose) { printf("sched_wakeup event %p\n", event); printf(" ... pid %d woke up %s/%d\n", - wakeup_event.common_pid, - wakeup_event.comm, - wakeup_event.pid); + wakeup_event->common_pid, + wakeup_event->comm, + wakeup_event->pid); } - waker = register_pid(wakeup_event.common_pid, ""); - wakee = register_pid(wakeup_event.pid, wakeup_event.comm); + waker = register_pid(wakeup_event->common_pid, ""); + wakee = register_pid(wakeup_event->pid, wakeup_event->comm); add_sched_event_wakeup(waker, timestamp, wakee); } -struct trace_switch_event { - u32 size; - - u16 common_type; - u8 common_flags; - u8 common_preempt_count; - u32 common_pid; - u32 common_tgid; - - char prev_comm[16]; - u32 prev_pid; - u32 prev_prio; - u64 prev_state; - char next_comm[16]; - u32 next_pid; - u32 next_prio; -}; - -#define MAX_CPUS 4096 - -unsigned long cpu_last_switched[MAX_CPUS]; +static unsigned long cpu_last_switched[MAX_CPUS]; static void -process_sched_switch_event(struct raw_event_sample *raw, struct event *event, - int cpu __used, u64 timestamp __used, struct thread *thread __used) +replay_switch_event(struct trace_switch_event *switch_event, + struct event *event, + int cpu, + u64 timestamp, + struct thread *thread __used) { - struct trace_switch_event switch_event; struct task_desc *prev, *next; u64 timestamp0; s64 delta; - FILL_COMMON_FIELDS(switch_event, event, raw->data); - - FILL_ARRAY(switch_event, prev_comm, event, raw->data); - FILL_FIELD(switch_event, prev_pid, event, raw->data); - FILL_FIELD(switch_event, prev_prio, event, raw->data); - FILL_FIELD(switch_event, prev_state, event, raw->data); - FILL_ARRAY(switch_event, next_comm, event, raw->data); - FILL_FIELD(switch_event, next_pid, event, raw->data); - FILL_FIELD(switch_event, next_prio, event, raw->data); - if (verbose) printf("sched_switch event %p\n", event); @@ -783,38 +810,94 @@ process_sched_switch_event(struct raw_event_sample *raw, struct event *event, if (verbose) { printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n", - switch_event.prev_comm, switch_event.prev_pid, - switch_event.next_comm, switch_event.next_pid, + switch_event->prev_comm, switch_event->prev_pid, + switch_event->next_comm, switch_event->next_pid, delta); } - prev = register_pid(switch_event.prev_pid, switch_event.prev_comm); - next = register_pid(switch_event.next_pid, switch_event.next_comm); + prev = register_pid(switch_event->prev_pid, switch_event->prev_comm); + next = register_pid(switch_event->next_pid, switch_event->next_comm); cpu_last_switched[cpu] = timestamp; add_sched_event_run(prev, timestamp, delta); - add_sched_event_sleep(prev, timestamp, switch_event.prev_state); + add_sched_event_sleep(prev, timestamp, switch_event->prev_state); } -struct trace_fork_event { - u32 size; - u16 common_type; - u8 common_flags; - u8 common_preempt_count; - u32 common_pid; - u32 common_tgid; +static void +replay_fork_event(struct trace_fork_event *fork_event, + struct event *event, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) +{ + if (verbose) { + printf("sched_fork event %p\n", event); + printf("... parent: %s/%d\n", fork_event->parent_comm, fork_event->parent_pid); + printf("... child: %s/%d\n", fork_event->child_comm, fork_event->child_pid); + } + register_pid(fork_event->parent_pid, fork_event->parent_comm); + register_pid(fork_event->child_pid, fork_event->child_comm); +} - char parent_comm[16]; - u32 parent_pid; - char child_comm[16]; - u32 child_pid; +static struct trace_sched_handler replay_ops = { + .wakeup_event = replay_wakeup_event, + .switch_event = replay_switch_event, + .fork_event = replay_fork_event, }; + +static struct trace_sched_handler *trace_handler; + static void -process_sched_fork_event(struct raw_event_sample *raw, struct event *event, - int cpu __used, u64 timestamp __used, struct thread *thread __used) +process_sched_wakeup_event(struct raw_event_sample *raw, + struct event *event, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) +{ + struct trace_wakeup_event wakeup_event; + + FILL_COMMON_FIELDS(wakeup_event, event, raw->data); + + FILL_ARRAY(wakeup_event, comm, event, raw->data); + FILL_FIELD(wakeup_event, pid, event, raw->data); + FILL_FIELD(wakeup_event, prio, event, raw->data); + FILL_FIELD(wakeup_event, success, event, raw->data); + FILL_FIELD(wakeup_event, cpu, event, raw->data); + + trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); +} + +static void +process_sched_switch_event(struct raw_event_sample *raw, + struct event *event, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) +{ + struct trace_switch_event switch_event; + + FILL_COMMON_FIELDS(switch_event, event, raw->data); + + FILL_ARRAY(switch_event, prev_comm, event, raw->data); + FILL_FIELD(switch_event, prev_pid, event, raw->data); + FILL_FIELD(switch_event, prev_prio, event, raw->data); + FILL_FIELD(switch_event, prev_state, event, raw->data); + FILL_ARRAY(switch_event, next_comm, event, raw->data); + FILL_FIELD(switch_event, next_pid, event, raw->data); + FILL_FIELD(switch_event, next_prio, event, raw->data); + + trace_handler->switch_event(&switch_event, event, cpu, timestamp, thread); +} + +static void +process_sched_fork_event(struct raw_event_sample *raw, + struct event *event, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) { struct trace_fork_event fork_event; @@ -825,17 +908,14 @@ process_sched_fork_event(struct raw_event_sample *raw, struct event *event, FILL_ARRAY(fork_event, child_comm, event, raw->data); FILL_FIELD(fork_event, child_pid, event, raw->data); - if (verbose) { - printf("sched_fork event %p\n", event); - printf("... parent: %s/%d\n", fork_event.parent_comm, fork_event.parent_pid); - printf("... child: %s/%d\n", fork_event.child_comm, fork_event.child_pid); - } - register_pid(fork_event.parent_pid, fork_event.parent_comm); - register_pid(fork_event.child_pid, fork_event.child_comm); + trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); } -static void process_sched_exit_event(struct event *event, - int cpu __used, u64 timestamp __used, struct thread *thread __used) +static void +process_sched_exit_event(struct event *event, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) { if (verbose) printf("sched_exit event %p\n", event); @@ -1072,6 +1152,8 @@ static const char * const annotate_usage[] = { static const struct option options[] = { OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), + OPT_BOOLEAN('r', "replay", &replay_mode, + "replay sched behaviour from traces"), OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_END() @@ -1096,6 +1178,11 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used) // setup_pager(); + if (replay_mode) + trace_handler = &replay_ops; + else /* We may need a default subcommand */ + die("Please select a sub command (-r)\n"); + calibrate_run_measurement_overhead(); calibrate_sleep_measurement_overhead(); -- 1.8.2.3