[PATCH v2 4/4] kernelshark: Adding a GUI plugin for xenomai events

From: Yordan Karadzhov (VMware)
Date: Fri Nov 10 2017 - 07:31:36 EST


A plugin for processing xenomai events "cobalt_switch_context"
and "cobalt_thread_resume" is added.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@xxxxxxxxx>
---
Makefile | 1 +
kshark-plugin.h | 10 ++
plugin_xenomai_gui.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 311 insertions(+)
create mode 100644 plugin_xenomai_gui.c

diff --git a/Makefile b/Makefile
index 992e6b0..e4d280b 100644
--- a/Makefile
+++ b/Makefile
@@ -384,6 +384,7 @@ PLUGIN_OBJS += plugin_tlb.o
PLUGINS := $(PLUGIN_OBJS:.o=.so)

GUI_PLUGIN_OBJS =
+GUI_PLUGIN_OBJS += plugin_xenomai_gui.o

GUI_PLUGINS := $(GUI_PLUGIN_OBJS:.o=.so)

diff --git a/kshark-plugin.h b/kshark-plugin.h
index 42fb40c..1166781 100644
--- a/kshark-plugin.h
+++ b/kshark-plugin.h
@@ -53,6 +53,16 @@ enum gui_plugin_actions {
KSHARK_PLUGIN_GET_COMMAND,
};

+enum gui_plugin_ctx_updates {
+ KSHARK_PLUGIN_UPDATE_SWITCH_EVENT = (1 << 0),
+ KSHARK_PLUGIN_UPDATE_WAKEUP_EVENT = (1 << 1),
+ KSHARK_PLUGIN_UPDATE_WAKEUP_PID = (1 << 2),
+ KSHARK_PLUGIN_UPDATE_SWITCH_PID = (1 << 3),
+ KSHARK_PLUGIN_UPDATE_PREV_STATE = (1 << 4),
+ KSHARK_PLUGIN_UPDATE_NEXT_NAME = (1 << 5),
+ KSHARK_PLUGIN_UPDATE_ALL = INT_MAX
+};
+
enum gui_event_types {
KSHARK_PLUGIN_SWITCH_EVENT,
KSHARK_PLUGIN_WAKEUP_EVENT,
diff --git a/plugin_xenomai_gui.c b/plugin_xenomai_gui.c
new file mode 100644
index 0000000..c786cc8
--- /dev/null
+++ b/plugin_xenomai_gui.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@xxxxxxxxx>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "event-parse.h"
+#include "kernel-shark.h"
+#include "kshark-plugin.h"
+
+struct xenomai_context {
+ struct pevent *pevent;
+
+ struct event_format *cobalt_switch_event;
+ struct format_field *cobalt_switch_next_pid_field;
+ struct format_field *cobalt_switch_prev_state_field;
+ struct format_field *cobalt_switch_next_name_field;
+
+ struct event_format *cobalt_wakeup_event;
+ struct format_field *cobalt_wakeup_pid_field;
+};
+
+struct xenomai_context *xenomai_context_handler = NULL;
+struct gui_event_handler *switch_handler = NULL;
+struct gui_event_handler *wakeup_handler = NULL;
+
+#define COBALT_PREV_STATE_BIT (1 << 3)
+#define COBALT_COMM_OFFSET_MASK 0xFFFF
+
+static gboolean xenomai_update_context(struct pevent *pevent, int task_id)
+{
+ struct event_format *event;
+ struct xenomai_context *ctx = xenomai_context_handler;
+
+ if (!ctx)
+ return FALSE;
+
+ if (task_id & KSHARK_PLUGIN_UPDATE_SWITCH_EVENT) {
+ event = pevent_find_event_by_name(pevent,
+ "cobalt_core",
+ "cobalt_switch_context");
+ if (!event)
+ return FALSE;
+
+ ctx->cobalt_switch_event = event;
+ }
+
+ if (task_id & KSHARK_PLUGIN_UPDATE_WAKEUP_EVENT) {
+ event = pevent_find_event_by_name(pevent,
+ "cobalt_core",
+ "cobalt_thread_resume");
+ if (!event)
+ return FALSE;
+
+ ctx->cobalt_wakeup_event = event;
+ }
+
+ if (task_id & KSHARK_PLUGIN_UPDATE_SWITCH_PID) {
+ ctx->cobalt_switch_next_pid_field =
+ pevent_find_field(ctx->cobalt_switch_event, "next_pid");
+ }
+
+ if (task_id & KSHARK_PLUGIN_UPDATE_PREV_STATE) {
+ ctx->cobalt_switch_prev_state_field =
+ pevent_find_field(ctx->cobalt_switch_event, "prev_state");
+ }
+
+ if (task_id & KSHARK_PLUGIN_UPDATE_NEXT_NAME) {
+ ctx->cobalt_switch_next_name_field =
+ pevent_find_field(ctx->cobalt_switch_event, "next_name");
+ }
+
+ if (task_id & KSHARK_PLUGIN_UPDATE_WAKEUP_PID) {
+ ctx->cobalt_wakeup_pid_field =
+ pevent_find_field(ctx->cobalt_wakeup_event, "pid");
+ }
+
+ return TRUE;
+}
+
+static void xenomai_context_new(struct shark_info *info, struct trace_view_store *store)
+{
+ if (!xenomai_context_handler) {
+ xenomai_context_handler =
+ (struct xenomai_context*) malloc(sizeof(struct xenomai_context));
+ }
+
+ xenomai_context_handler->pevent = tracecmd_get_pevent(info->handle);
+
+ int status = xenomai_update_context(xenomai_context_handler->pevent,
+ KSHARK_PLUGIN_UPDATE_ALL);
+ if (status == FALSE) {
+ free(xenomai_context_handler);
+ xenomai_context_handler = NULL;
+ }
+}
+
+static int cobalt_get_next_pid(struct xenomai_context *ctx,
+ struct pevent_record *record,
+ int *pid)
+{
+ long long unsigned int val;
+ int status = pevent_read_number_field(ctx->cobalt_switch_next_pid_field,
+ record->data, &val);
+ if (pid)
+ *pid = val;
+
+ return status;
+}
+
+static int cobalt_get_prev_state(struct xenomai_context *ctx,
+ struct pevent_record *record,
+ int *state)
+{
+ long long unsigned int val;
+ pevent_read_number_field(ctx->cobalt_switch_prev_state_field,
+ record->data, &val);
+
+ if (state)
+ *state = val;
+
+ return (val & COBALT_PREV_STATE_BIT) ? 1 : 0;
+}
+
+static void cobalt_get_command(struct xenomai_context *ctx,
+ struct pevent_record *record,
+ const char **comm)
+{
+ int offset =
+ data2host4(ctx->pevent, record->data + ctx->cobalt_switch_next_name_field->offset);
+
+ offset &= COBALT_COMM_OFFSET_MASK;
+ *comm = record->data + offset;
+}
+
+static gboolean xenomai_switch_handler(struct pevent_record *record,
+ int task_id,
+ void *output)
+{
+ struct xenomai_context *ctx = xenomai_context_handler;
+
+ if (!ctx)
+ return FALSE;
+
+ switch (task_id) {
+ case KSHARK_PLUGIN_GET_PID:
+ cobalt_get_next_pid(ctx, record, output);
+ return TRUE;
+
+ case KSHARK_PLUGIN_GET_PREV_STATE:
+ return cobalt_get_prev_state(ctx, record, output);
+
+ case KSHARK_PLUGIN_GET_COMMAND:
+ cobalt_get_command(ctx, record, (const char**) output);
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+static int cobalt_get_wakeup_pid(struct xenomai_context *ctx,
+ struct pevent_record *record,
+ int *pid)
+{
+ long long unsigned int val;
+ int status = pevent_read_number_field(ctx->cobalt_wakeup_pid_field,
+ record->data, &val);
+
+ if (pid)
+ *pid = val;
+
+ return status;
+}
+
+static gboolean xenomai_wakeup_handler(struct pevent_record *record,
+ int task_id,
+ void *output)
+{
+ struct xenomai_context *ctx = xenomai_context_handler;
+
+ if (!ctx)
+ return FALSE;
+
+ switch (task_id) {
+ case KSHARK_PLUGIN_GET_PID:
+ cobalt_get_wakeup_pid(ctx, record, output);
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+void KSHARK_PLUGIN_LOADER(void *info, void *store)
+{
+ struct shark_info *ks_info = info;
+ struct trace_view_store *ks_store = store;
+
+ xenomai_context_new(ks_info, ks_store);
+
+ if (!xenomai_context_handler)
+ return;
+
+ struct xenomai_context *ctx = xenomai_context_handler;
+
+ switch_handler = make_gui_event_handler(ctx->cobalt_switch_event->id,
+ KSHARK_PLUGIN_SWITCH_EVENT,
+ xenomai_switch_handler,
+ xenomai_update_context);
+
+ wakeup_handler = make_gui_event_handler(ctx->cobalt_wakeup_event->id,
+ KSHARK_PLUGIN_WAKEUP_EVENT,
+ xenomai_wakeup_handler,
+ xenomai_update_context);
+
+ if (switch_handler && wakeup_handler) {
+ trace_view_store_register_gui_handler(ks_store, switch_handler);
+ trace_view_store_register_gui_handler(ks_store, wakeup_handler);
+
+ trace_graph_register_gui_handler(ks_info->ginfo, switch_handler);
+ trace_graph_register_gui_handler(ks_info->ginfo, wakeup_handler);
+ }
+}
+
+void KSHARK_PLUGIN_RELOADER(void *info, void *store)
+{
+ struct shark_info *ks_info = info;
+ struct trace_view_store *ks_store = store;
+
+ if (!xenomai_context_handler) {
+ xenomai_context_new(ks_info, ks_store);
+
+ if (!xenomai_context_handler)
+ return;
+ } else {
+ int status = xenomai_update_context(tracecmd_get_pevent(ks_info->handle),
+ KSHARK_PLUGIN_UPDATE_ALL);
+
+ if (status == FALSE)
+ return;
+ }
+
+ if (switch_handler && wakeup_handler) {
+ trace_view_store_register_gui_handler(ks_store, switch_handler);
+ trace_view_store_register_gui_handler(ks_store, wakeup_handler);
+ }
+}
+
+void KSHARK_PLUGIN_UNLOADER(void *info, void *store)
+{
+ struct shark_info *ks_info = info;
+ struct trace_view_store *ks_store = store;
+ struct xenomai_context *ctx = xenomai_context_handler;
+
+ if (!ctx)
+ return;
+
+ if (switch_handler) {
+ unregister_gui_event_handler(&ks_store->event_handlers,
+ ctx->cobalt_switch_event->id);
+
+ unregister_gui_event_handler(&ks_info->ginfo->event_handlers,
+ ctx->cobalt_switch_event->id);
+
+ free(switch_handler);
+ switch_handler = NULL;
+ }
+
+ if (wakeup_handler) {
+ unregister_gui_event_handler(&ks_store->event_handlers,
+ ctx->cobalt_wakeup_event->id);
+
+ unregister_gui_event_handler(&ks_info->ginfo->event_handlers,
+ ctx->cobalt_wakeup_event->id);
+
+ free(wakeup_handler);
+ wakeup_handler = NULL;
+ }
+
+ free(ctx);
+ xenomai_context_handler = NULL;
+}
--
2.15.0.rc0