Commit 419ab0d6 authored by Frederic Weisbecker's avatar Frederic Weisbecker Committed by Ingo Molnar

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: default avatarFrederic 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: default avatarIngo Molnar <mingo@elte.hu>
parent 46538818
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
#include "util/trace-event.h" #include "util/trace-event.h"
#include <sys/types.h> #include <sys/types.h>
#define MAX_CPUS 4096
static char const *input_name = "perf.data"; static char const *input_name = "perf.data";
static int input; static int input;
static unsigned long page_size; static unsigned long page_size;
...@@ -27,6 +30,8 @@ static struct thread *last_match; ...@@ -27,6 +30,8 @@ static struct thread *last_match;
static struct perf_header *header; static struct perf_header *header;
static u64 sample_type; static u64 sample_type;
static int replay_mode;
/* /*
* Scheduler benchmarks * Scheduler benchmarks
...@@ -677,6 +682,27 @@ do { \ ...@@ -677,6 +682,27 @@ do { \
FILL_FIELD(ptr, common_tgid, event, data); \ FILL_FIELD(ptr, common_tgid, event, data); \
} while (0) } 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 { struct trace_wakeup_event {
u32 size; u32 size;
...@@ -694,78 +720,79 @@ struct trace_wakeup_event { ...@@ -694,78 +720,79 @@ struct trace_wakeup_event {
u32 cpu; u32 cpu;
}; };
static void struct trace_fork_event {
process_sched_wakeup_event(struct raw_event_sample *raw, struct event *event, u32 size;
int cpu __used, u64 timestamp __used, struct thread *thread __used)
{
struct task_desc *waker, *wakee;
struct trace_wakeup_event wakeup_event;
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) { if (verbose) {
printf("sched_wakeup event %p\n", event); printf("sched_wakeup event %p\n", event);
printf(" ... pid %d woke up %s/%d\n", printf(" ... pid %d woke up %s/%d\n",
wakeup_event.common_pid, wakeup_event->common_pid,
wakeup_event.comm, wakeup_event->comm,
wakeup_event.pid); wakeup_event->pid);
} }
waker = register_pid(wakeup_event.common_pid, "<unknown>"); waker = register_pid(wakeup_event->common_pid, "<unknown>");
wakee = register_pid(wakeup_event.pid, wakeup_event.comm); wakee = register_pid(wakeup_event->pid, wakeup_event->comm);
add_sched_event_wakeup(waker, timestamp, wakee); add_sched_event_wakeup(waker, timestamp, wakee);
} }
struct trace_switch_event { static unsigned long cpu_last_switched[MAX_CPUS];
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 void static void
process_sched_switch_event(struct raw_event_sample *raw, struct event *event, replay_switch_event(struct trace_switch_event *switch_event,
int cpu __used, u64 timestamp __used, struct thread *thread __used) struct event *event,
int cpu,
u64 timestamp,
struct thread *thread __used)
{ {
struct trace_switch_event switch_event;
struct task_desc *prev, *next; struct task_desc *prev, *next;
u64 timestamp0; u64 timestamp0;
s64 delta; 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) if (verbose)
printf("sched_switch event %p\n", event); printf("sched_switch event %p\n", event);
...@@ -783,38 +810,94 @@ process_sched_switch_event(struct raw_event_sample *raw, struct event *event, ...@@ -783,38 +810,94 @@ process_sched_switch_event(struct raw_event_sample *raw, struct event *event,
if (verbose) { if (verbose) {
printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n", printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n",
switch_event.prev_comm, switch_event.prev_pid, switch_event->prev_comm, switch_event->prev_pid,
switch_event.next_comm, switch_event.next_pid, switch_event->next_comm, switch_event->next_pid,
delta); delta);
} }
prev = register_pid(switch_event.prev_pid, switch_event.prev_comm); prev = register_pid(switch_event->prev_pid, switch_event->prev_comm);
next = register_pid(switch_event.next_pid, switch_event.next_comm); next = register_pid(switch_event->next_pid, switch_event->next_comm);
cpu_last_switched[cpu] = timestamp; cpu_last_switched[cpu] = timestamp;
add_sched_event_run(prev, timestamp, delta); 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; static void
u8 common_flags; replay_fork_event(struct trace_fork_event *fork_event,
u8 common_preempt_count; struct event *event,
u32 common_pid; int cpu __used,
u32 common_tgid; 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]; static struct trace_sched_handler replay_ops = {
u32 parent_pid; .wakeup_event = replay_wakeup_event,
char child_comm[16]; .switch_event = replay_switch_event,
u32 child_pid; .fork_event = replay_fork_event,
}; };
static struct trace_sched_handler *trace_handler;
static void static void
process_sched_fork_event(struct raw_event_sample *raw, struct event *event, process_sched_wakeup_event(struct raw_event_sample *raw,
int cpu __used, u64 timestamp __used, struct thread *thread __used) 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; struct trace_fork_event fork_event;
...@@ -825,17 +908,14 @@ process_sched_fork_event(struct raw_event_sample *raw, struct event *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_ARRAY(fork_event, child_comm, event, raw->data);
FILL_FIELD(fork_event, child_pid, event, raw->data); FILL_FIELD(fork_event, child_pid, event, raw->data);
if (verbose) { trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread);
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);
} }
static void process_sched_exit_event(struct event *event, static void
int cpu __used, u64 timestamp __used, struct thread *thread __used) process_sched_exit_event(struct event *event,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
{ {
if (verbose) if (verbose)
printf("sched_exit event %p\n", event); printf("sched_exit event %p\n", event);
...@@ -1072,6 +1152,8 @@ static const char * const annotate_usage[] = { ...@@ -1072,6 +1152,8 @@ static const char * const annotate_usage[] = {
static const struct option options[] = { static const struct option options[] = {
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
"dump raw trace in ASCII"), "dump raw trace in ASCII"),
OPT_BOOLEAN('r', "replay", &replay_mode,
"replay sched behaviour from traces"),
OPT_BOOLEAN('v', "verbose", &verbose, OPT_BOOLEAN('v', "verbose", &verbose,
"be more verbose (show symbol address, etc)"), "be more verbose (show symbol address, etc)"),
OPT_END() OPT_END()
...@@ -1096,6 +1178,11 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used) ...@@ -1096,6 +1178,11 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
// setup_pager(); // 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_run_measurement_overhead();
calibrate_sleep_measurement_overhead(); calibrate_sleep_measurement_overhead();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment