perf sched: Make it easier to plug in new sub profilers
authorFrederic Weisbecker <fweisbec@gmail.com>
Sat, 12 Sep 2009 01:59:01 +0000 (03:59 +0200)
committerIngo Molnar <mingo@elte.hu>
Sun, 13 Sep 2009 08:22:42 +0000 (10:22 +0200)
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 <fweisbec@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
tools/perf/builtin-sched.c

index 0215936..756fe62 100644 (file)
@@ -14,6 +14,9 @@
 #include "util/trace-event.h"
 #include <sys/types.h>
 
+
+#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, "<unknown>");
-       wakee = register_pid(wakeup_event.pid, wakeup_event.comm);
+       waker = register_pid(wakeup_event->common_pid, "<unknown>");
+       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();