From 8bcd73ddae5d74fb9b2b8aaedd3aa6a39ef3f75d Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 5 Mar 2012 14:22:27 -0500 Subject: rt-graph: Litmus events and tasks loaded on startup --- Makefile | 8 +++-- kernel-shark.c | 44 ++++++++++++++++++++++++-- rt-graph.c | 78 ++++++++++++++++++++++++++++++++++++---------- rt-graph.h | 31 +++++++++++++++++-- trace-graph-main.c | 2 +- trace-graph.c | 91 +++--------------------------------------------------- trace-graph.h | 7 ++--- trace-plot-cpu.c | 20 ++++++++++++ 8 files changed, 164 insertions(+), 117 deletions(-) diff --git a/Makefile b/Makefile index c97cab7..dc7100e 100644 --- a/Makefile +++ b/Makefile @@ -299,12 +299,14 @@ TRACE_GUI_OBJS = trace-filter.o trace-compat.o trace-hash.o trace-dialog.o \ TRACE_CMD_OBJS = trace-cmd.o trace-record.o trace-read.o trace-split.o trace-listen.o \ trace-stack.o trace-options.o TRACE_VIEW_OBJS = trace-view.o trace-view-store.o -TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o -RT_GRAPH_OBJS = rt-graph.o +RT_GRAPH_OBJS = rt-graph.o rt-plot-task.o +TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o \ + trace-plot-cpu.o trace-plot-task.o \ + $(RT_GRAPH_OBJS) task-list.o TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) $(TRACE_GUI_OBJS) TRACE_GRAPH_MAIN_OBJS = trace-graph-main.o $(TRACE_GRAPH_OBJS) $(TRACE_GUI_OBJS) KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) $(TRACE_GUI_OBJS) \ - $(RT_GRAPH_OBJS) trace-capture.o kernel-shark.o + trace-capture.o kernel-shark.o PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o parse-utils.o TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \ diff --git a/kernel-shark.c b/kernel-shark.c index 0c89e00..e0c123a 100644 --- a/kernel-shark.c +++ b/kernel-shark.c @@ -969,7 +969,7 @@ __list_tasks_clicked (struct shark_info *info, store = TRACE_VIEW_STORE(model); - tasks = trace_graph_task_list(ginfo); + tasks = task_list_pids(ginfo->tasks); selected = filter_task_pids(task_filter); trace_task_dialog(info->handle, tasks, selected, func, info); @@ -1068,7 +1068,7 @@ __graph_tasks_clicked (struct shark_info *info, if (!ginfo->handle) return; - tasks = trace_graph_task_list(ginfo); + tasks = task_list_pids(ginfo->tasks); selected = filter_task_pids(task_filter); trace_task_dialog(ginfo->handle, tasks, selected, func, info); @@ -1268,7 +1268,7 @@ plot_tasks_clicked (gpointer data) if (!ginfo->handle) return; - tasks = trace_graph_task_list(ginfo); + tasks = task_list_pids(ginfo->tasks); graph_plot_task_plotted(ginfo, &selected); trace_task_dialog(ginfo->handle, tasks, selected, @@ -1277,6 +1277,29 @@ plot_tasks_clicked (gpointer data) free(selected); } +/* Callback for the clicked signal of the plot real-time tasks button */ +static void +plot_rt_tasks_clicked (gpointer data) +{ + struct shark_info *info = data; + struct graph_info *ginfo = info->ginfo; + struct rt_graph_info *rtinfo; + gint *selected; + gint *tasks; + + if (!ginfo->handle) + return; + + rtinfo = &ginfo->rtinfo; + tasks = task_list_pids(rtinfo->tasks); + rt_plot_task_plotted(rtinfo, &selected); + + trace_task_dialog(ginfo->handle, tasks, selected, + rt_plot_task_update_callback, rtinfo); + free(tasks); + free(selected); +} + /* Callback for the clicked signal of the help contents button */ static void help_content_clicked (gpointer data) @@ -2184,6 +2207,21 @@ void kernel_shark(int argc, char **argv) /* We do need to show menu items */ gtk_widget_show(sub_item); + /* --- Plot - RT Tasks Option --- */ + + sub_item = gtk_menu_item_new_with_label("Real-Time Tasks"); + + /* Add them to the menu */ + gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); + + /* We can attach the Quit menu item to our exit function */ + g_signal_connect_swapped (G_OBJECT (sub_item), "activate", + G_CALLBACK (plot_rt_tasks_clicked), + (gpointer) info); + + /* We do need to show menu items */ + gtk_widget_show(sub_item); + /* --- End Plot Options --- */ gtk_menu_item_set_submenu(GTK_MENU_ITEM (menu_item), menu); diff --git a/rt-graph.c b/rt-graph.c index 6eab52f..71f2033 100644 --- a/rt-graph.c +++ b/rt-graph.c @@ -1,5 +1,16 @@ #include "rt-graph.h" +#include "trace-hash.h" +#define DEBUG_LEVEL 1 +#if DEBUG_LEVEL > 0 +#define dprintf(l, x...) \ + do { \ + if (l <= DEBUG_LEVEL) \ + printf(x); \ + } while (0) +#else +#define dprintf(l, x...) do { if (0) printf(x); } while (0) +#endif /** * rt_graph_check_task_param - check for litmus_task_param record * Return 1 and @pid, @wcet, and @period if the record matches @@ -22,8 +33,9 @@ int rt_graph_check_task_param(struct rt_graph_info *rtinfo, event = pevent_find_event_by_name(pevent, "litmus", "litmus_task_param"); if (!event) - return 0; + goto out; rtinfo->task_param_id = event->id; + dprintf(2, "Found task_param id %d\n", event->id); rtinfo->param_pid_field = pevent_find_field(event, "pid"); rtinfo->param_wcet_field = pevent_find_field(event, "wcet"); rtinfo->param_period_field = pevent_find_field(event, "period"); @@ -39,8 +51,13 @@ int rt_graph_check_task_param(struct rt_graph_info *rtinfo, pevent_read_number_field(rtinfo->param_period_field, record->data, period); ret = 1; - } + dprintf(3, "Read task_param (%d) record for task %d " + "(%llu, %llu)\n", id, *pid, *wcet, *period); + /* Only of these per task, so we can safely add new tasks now */ + add_task_hash(rtinfo->tasks, *pid); + } + out: return ret; } @@ -50,7 +67,7 @@ int rt_graph_check_task_param(struct rt_graph_info *rtinfo, */ int rt_graph_check_task_release(struct rt_graph_info *rtinfo, struct pevent *pevent, struct record *record, - gint *pid, gint *job, + gint *pid, gint *job, unsigned long long *release, unsigned long long *deadline) { struct event_format *event; @@ -62,10 +79,12 @@ int rt_graph_check_task_release(struct rt_graph_info *rtinfo, event = pevent_find_event_by_name(pevent, "litmus", "litmus_task_release"); if (!event) - return 0; + goto out; rtinfo->task_release_id = event->id; + dprintf(2, "Found task_release id %d\n", event->id); rtinfo->release_pid_field = pevent_find_field(event, "pid"); rtinfo->release_job_field = pevent_find_field(event, "job"); + rtinfo->release_release_field = pevent_find_field(event, "release"); rtinfo->release_deadline_field = pevent_find_field(event, "deadline"); } @@ -77,11 +96,15 @@ int rt_graph_check_task_release(struct rt_graph_info *rtinfo, pevent_read_number_field(rtinfo->release_job_field, record->data, &val); *job = val; + pevent_read_number_field(rtinfo->release_release_field, + record->data, release); pevent_read_number_field(rtinfo->release_deadline_field, record->data, deadline); ret = 1; + dprintf(3, "Read task_release (%d) record for job %d:%d, " + "dead: %llu\n", id, *pid, *job, *deadline); } - + out: return ret; } @@ -91,21 +114,23 @@ int rt_graph_check_task_release(struct rt_graph_info *rtinfo, */ int rt_graph_check_task_completion(struct rt_graph_info *rtinfo, struct pevent *pevent, struct record *record, - gint *pid, gint *job) + gint *pid, gint *job, unsigned long long *when) { struct event_format *event; unsigned long long val; gint id; int ret = 0; - if (rtinfo->task_param_id < 0) { + if (rtinfo->task_completion_id < 0) { event = pevent_find_event_by_name(pevent, "litmus", "litmus_task_completion"); if (!event) - return 0; + goto out; rtinfo->task_completion_id = event->id; + dprintf(2, "Found task_completion id %d\n", event->id); rtinfo->completion_pid_field = pevent_find_field(event, "pid"); rtinfo->completion_job_field = pevent_find_field(event, "job"); + rtinfo->completion_when_field = pevent_find_field(event, "when"); } id = pevent_data_type(pevent, record); @@ -116,9 +141,13 @@ int rt_graph_check_task_completion(struct rt_graph_info *rtinfo, pevent_read_number_field(rtinfo->completion_job_field, record->data, &val); *job = val; + pevent_read_number_field(rtinfo->completion_when_field, + record->data, when); ret = 1; + dprintf(3, "Read task_completion (%d) record for job %d:%d\n", + id, *pid, *job); } - + out: return ret; } @@ -128,7 +157,7 @@ int rt_graph_check_task_completion(struct rt_graph_info *rtinfo, */ int rt_graph_check_task_block(struct rt_graph_info *rtinfo, struct pevent *pevent, struct record *record, - gint *pid) + gint *pid, unsigned long long *when) { struct event_format *event; unsigned long long val; @@ -139,9 +168,11 @@ int rt_graph_check_task_block(struct rt_graph_info *rtinfo, event = pevent_find_event_by_name(pevent, "litmus", "litmus_task_block"); if (!event) - return 0; + goto out; + dprintf(2, "Found task_block id %d\n", event->id); rtinfo->task_block_id = event->id; rtinfo->block_pid_field = pevent_find_field(event, "pid"); + rtinfo->block_when_field = pevent_find_field(event, "when"); } id = pevent_data_type(pevent, record); @@ -149,9 +180,13 @@ int rt_graph_check_task_block(struct rt_graph_info *rtinfo, pevent_read_number_field(rtinfo->block_pid_field, record->data, &val); *pid = val; + pevent_read_number_field(rtinfo->block_when_field, + record->data, when); ret = 1; + dprintf(3, "Read task_block (%d) record for task %d\n", + id, *pid); } - + out: return ret; } @@ -161,7 +196,7 @@ int rt_graph_check_task_block(struct rt_graph_info *rtinfo, */ int rt_graph_check_task_resume(struct rt_graph_info *rtinfo, struct pevent *pevent, struct record *record, - gint *pid) + gint *pid, unsigned long long *when) { struct event_format *event; unsigned long long val; @@ -172,9 +207,11 @@ int rt_graph_check_task_resume(struct rt_graph_info *rtinfo, event = pevent_find_event_by_name(pevent, "litmus", "litmus_task_resume"); if (!event) - return 0; + goto out; + dprintf(2, "Found task_resume id %d\n", event->id); rtinfo->task_resume_id = event->id; rtinfo->resume_pid_field = pevent_find_field(event, "pid"); + rtinfo->resume_when_field = pevent_find_field(event, "when"); } id = pevent_data_type(pevent, record); @@ -182,9 +219,13 @@ int rt_graph_check_task_resume(struct rt_graph_info *rtinfo, pevent_read_number_field(rtinfo->resume_pid_field, record->data, &val); *pid = val; + pevent_read_number_field(rtinfo->resume_when_field, + record->data, when); ret = 1; + dprintf(3, "Read task_resume (%d) record for task %d\n", + id, *pid); } - + out: return ret; } @@ -193,7 +234,7 @@ int rt_graph_check_task_resume(struct rt_graph_info *rtinfo, */ void init_rt_event_cache(struct rt_graph_info *rtinfo) { - print("hello"); + dprintf(1, "Initializing RT event cache\n"); rtinfo->task_param_id = -1; rtinfo->task_release_id = -1; rtinfo->task_completion_id = -1; @@ -206,11 +247,16 @@ void init_rt_event_cache(struct rt_graph_info *rtinfo) rtinfo->release_pid_field = NULL; rtinfo->release_job_field = NULL; + rtinfo->release_release_field = NULL; rtinfo->release_deadline_field = NULL; rtinfo->completion_pid_field = NULL; rtinfo->completion_job_field = NULL; + rtinfo->completion_when_field = NULL; rtinfo->block_pid_field = NULL; + rtinfo->block_when_field = NULL; + rtinfo->resume_pid_field = NULL; + rtinfo->resume_when_field = NULL; } diff --git a/rt-graph.h b/rt-graph.h index 0ea921a..3037301 100644 --- a/rt-graph.h +++ b/rt-graph.h @@ -3,9 +3,13 @@ #include #include "trace-cmd.h" +#include "task-list.h" struct rt_graph_info { + /* List of all tasks */ + struct task_list *tasks[TASK_HASH_SIZE]; + /* Cache of event fields so that they don't need to be located * during each access. */ @@ -13,33 +17,54 @@ struct rt_graph_info { struct format_field *param_pid_field; struct format_field *param_wcet_field; struct format_field *param_period_field; + gint task_release_id; struct format_field *release_pid_field; struct format_field *release_job_field; + struct format_field *release_release_field; struct format_field *release_deadline_field; + gint task_completion_id; struct format_field *completion_pid_field; struct format_field *completion_job_field; + struct format_field *completion_when_field; + gint task_block_id; struct format_field *block_pid_field; + struct format_field *block_when_field; + gint task_resume_id; struct format_field *resume_pid_field; + struct format_field *resume_when_field; }; +/* Event parsers */ int rt_graph_check_task_param(struct rt_graph_info *rtinfo, struct pevent *pevent, struct record *record, gint *pid, unsigned long long *wcet, unsigned long long *period); int rt_graph_check_task_release(struct rt_graph_info *rtinfo, struct pevent *pevent, struct record *record, gint *pid, gint *job, + unsigned long long *release, unsigned long long *deadline); int rt_graph_check_task_completion(struct rt_graph_info *rtinfo, struct pevent *pevent, - struct record *record, gint *pid, gint *job); + struct record *record, gint *pid, gint *job, + unsigned long long *when); int rt_graph_check_task_block(struct rt_graph_info *rtinfo, struct pevent *pevent, - struct record *record, gint *pid); + struct record *record, gint *pid, + unsigned long long *when); int rt_graph_check_task_resume(struct rt_graph_info *rtinfo, struct pevent *pevent, - struct record *record, gint *pid); + struct record *record, gint *pid, + unsigned long long *when); void init_rt_event_cache(struct rt_graph_info *rtinfo); +/* Metadata */ +void rt_plot_task_plotted(struct rt_graph_info *rt_info, gint **plotted); + +/* Callbacks for managing task list */ +void rt_plot_task_update_callback(gboolean accept, gint *selected, + gint *non_select, gpointer data); +void rt_plot_task_plotted(struct rt_graph_info *rtinfo, gint **plotted); + #endif diff --git a/trace-graph-main.c b/trace-graph-main.c index f2c8e54..b296994 100644 --- a/trace-graph-main.c +++ b/trace-graph-main.c @@ -145,7 +145,7 @@ plot_tasks_clicked (gpointer data) if (!ginfo->handle) return; - tasks = trace_graph_task_list(ginfo); + tasks = task_list_pids(ginfo->tasks); graph_plot_task_plotted(ginfo, &selected); trace_task_dialog(ginfo->handle, tasks, selected, diff --git a/trace-graph.c b/trace-graph.c index 6dafadf..819482e 100644 --- a/trace-graph.c +++ b/trace-graph.c @@ -70,91 +70,6 @@ static GdkGC *red; static void redraw_pixmap_backend(struct graph_info *ginfo); static void update_label_window(struct graph_info *ginfo); -struct task_list { - struct task_list *next; - gint pid; -}; - -static guint get_task_hash_key(gint pid) -{ - return trace_hash(pid) % TASK_HASH_SIZE; -} - -static struct task_list *find_task_hash(struct graph_info *ginfo, - gint key, gint pid) -{ - struct task_list *list; - - for (list = ginfo->tasks[key]; list; list = list->next) { - if (list->pid == pid) - return list; - } - - return NULL; -} - -static struct task_list *add_task_hash(struct graph_info *ginfo, - int pid) -{ - struct task_list *list; - guint key = get_task_hash_key(pid); - - list = find_task_hash(ginfo, key, pid); - if (list) - return list; - - list = malloc_or_die(sizeof(*list)); - list->pid = pid; - list->next = ginfo->tasks[key]; - ginfo->tasks[key] = list; - - return list; -} - -static void free_task_hash(struct graph_info *ginfo) -{ - struct task_list *list; - int i; - - for (i = 0; i < TASK_HASH_SIZE; i++) { - while (ginfo->tasks[i]) { - list = ginfo->tasks[i]; - ginfo->tasks[i] = list->next; - free(list); - } - } -} - -/** - * trace_graph_task_list - return an allocated list of all found tasks - * @ginfo: The graph info structure - * - * Returns an allocated list of pids found in the graph, ending - * with a -1. This array must be freed with free(). - */ -gint *trace_graph_task_list(struct graph_info *ginfo) -{ - struct task_list *list; - gint *pids; - gint count = 0; - gint i; - - for (i = 0; i < TASK_HASH_SIZE; i++) { - list = ginfo->tasks[i]; - while (list) { - if (count) - pids = realloc(pids, sizeof(*pids) * (count + 2)); - else - pids = malloc(sizeof(*pids) * 2); - pids[count++] = list->pid; - pids[count] = -1; - list = list->next; - } - } - - return pids; -} - static void convert_nano(unsigned long long time, unsigned long *sec, unsigned long *usec) { @@ -210,6 +125,8 @@ static void init_event_cache(struct graph_info *ginfo) * it into the pevent command line list. */ ginfo->read_comms = TRUE; + + init_rt_event_cache(&ginfo->rtinfo); } struct filter_task_item * @@ -1082,7 +999,7 @@ int trace_graph_check_sched_switch(struct graph_info *ginfo, if (ginfo->read_comms) { /* record all pids, for task plots */ this_pid = pevent_data_pid(ginfo->pevent, record); - add_task_hash(ginfo, this_pid); + add_task_hash(ginfo->tasks, this_pid); } if (ginfo->event_sched_switch_id < 0) { @@ -2385,7 +2302,7 @@ void trace_graph_free_info(struct graph_info *ginfo) pevent_filter_free(ginfo->event_filter); trace_graph_plot_free(ginfo); tracecmd_close(ginfo->handle); - free_task_hash(ginfo); + free_task_hash(ginfo->tasks); ginfo->cursor = 0; } diff --git a/trace-graph.h b/trace-graph.h index c3ae5a3..92d9883 100644 --- a/trace-graph.h +++ b/trace-graph.h @@ -25,6 +25,7 @@ #include "trace-cmd.h" #include "trace-hash.h" #include "trace-xml.h" +#include "task-list.h" #include "rt-graph.h" struct graph_info; @@ -146,8 +147,6 @@ struct plot_hash { }; #define PLOT_HASH_SIZE 1024 -#define TASK_HASH_SIZE 1024 -struct task_list; struct graph_info { struct tracecmd_input *handle; @@ -230,7 +229,7 @@ struct graph_info { struct format_field *wakeup_new_pid_field; struct format_field *wakeup_new_success_field; - struct rt_graph_info rt_info; + struct rt_graph_info rtinfo; gboolean read_comms; /* Read all comms on first load */ @@ -308,7 +307,6 @@ gboolean trace_graph_filter_on_event(struct graph_info *ginfo, struct record *re void trace_graph_copy_filter(struct graph_info *ginfo, gboolean all_events, struct event_filter *event_filter); -gint *trace_graph_task_list(struct graph_info *ginfo); int trace_graph_load_filters(struct graph_info *ginfo, struct tracecmd_xml_handle *handle); @@ -400,4 +398,5 @@ void graph_plot_task_update_callback(gboolean accept, void graph_plot_task_plotted(struct graph_info *ginfo, gint **plotted); + #endif /* _TRACE_GRAPH_H */ diff --git a/trace-plot-cpu.c b/trace-plot-cpu.c index 7514b34..5dea225 100644 --- a/trace-plot-cpu.c +++ b/trace-plot-cpu.c @@ -95,11 +95,31 @@ static int filter_record(struct graph_info *ginfo, const char *comm; int wake_pid; int filter; + gint rpid; + gint job; + unsigned long long release; + unsigned long long deadline; + unsigned long long period; + unsigned long long wcet; + unsigned long long when; *orig_pid = pevent_data_pid(ginfo->pevent, record); filter = trace_graph_filter_on_task(ginfo, *orig_pid); + + /* Load real-time records */ + rt_graph_check_task_param(&ginfo->rtinfo, ginfo->pevent, record, + &rpid, &wcet, &period); + rt_graph_check_task_release(&ginfo->rtinfo, ginfo->pevent, record, + &rpid, &job, &release, &deadline); + rt_graph_check_task_completion(&ginfo->rtinfo, ginfo->pevent, record, + &rpid, &job, &when); + rt_graph_check_task_block(&ginfo->rtinfo, ginfo->pevent, record, + &rpid, &when); + rt_graph_check_task_resume(&ginfo->rtinfo, ginfo->pevent, record, + &rpid, &when); + if (trace_graph_check_sched_switch(ginfo, record, sched_pid, &comm)) { is_sched_switch = TRUE; -- cgit v1.2.2