All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/8]  Add infrastructure for plugins.
@ 2018-09-20 16:55 Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 1/8] kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset KS Yordan Karadzhov (VMware)
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-09-20 16:55 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

The infrastructure for plugins used by the Qt-based version of KernelShark
is introduced in this series of patches. This is the last major component
of the C API. The last patch adds a plugin for dealing with "sched" events.

This is version 5 of this series of patches. In this version I address the
final comments made by Steven Rostedt in his review of v4. The criteria for
deciding when to start plotting latencies ([PATCH v5 8/8]) will stay as a
TODO action item.

Yordan Karadzhov (VMware) (8):
  kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset
    KS.
  kernel-shark-qt: Add Plugin event handlers to session.
  kernel-shark-qt: Add C++/C conversion for args of a plugin draw
    function.
  kernel-shark-qt: Make kshark_read_at() non-static.
  kernel-shark-qt: Remove the TODO action in kshark_read_at()
  kernel-shark-qt: Add src/plugins dir. to hold the source code of the
    plugins
  kernel-shark-qt: Tell Doxygen to enter ../src/plugins/
  kernel-shark-qt: Add a plugin for sched events.

 kernel-shark-qt/doc/dox_config              |   2 +-
 kernel-shark-qt/src/CMakeLists.txt          |   3 +
 kernel-shark-qt/src/KsPlugins.hpp           |  51 ++++
 kernel-shark-qt/src/libkshark-plugin.c      | 290 +++++++++++++++++++
 kernel-shark-qt/src/libkshark-plugin.h      | 179 ++++++++++++
 kernel-shark-qt/src/libkshark.c             |  38 ++-
 kernel-shark-qt/src/libkshark.h             |  20 ++
 kernel-shark-qt/src/plugins/CMakeLists.txt  |  27 ++
 kernel-shark-qt/src/plugins/SchedEvents.cpp | 263 +++++++++++++++++
 kernel-shark-qt/src/plugins/sched_events.c  | 305 ++++++++++++++++++++
 kernel-shark-qt/src/plugins/sched_events.h  |  76 +++++
 11 files changed, 1248 insertions(+), 6 deletions(-)
 create mode 100644 kernel-shark-qt/src/KsPlugins.hpp
 create mode 100644 kernel-shark-qt/src/libkshark-plugin.c
 create mode 100644 kernel-shark-qt/src/libkshark-plugin.h
 create mode 100644 kernel-shark-qt/src/plugins/CMakeLists.txt
 create mode 100644 kernel-shark-qt/src/plugins/SchedEvents.cpp
 create mode 100644 kernel-shark-qt/src/plugins/sched_events.c
 create mode 100644 kernel-shark-qt/src/plugins/sched_events.h

-- 
2.17.1

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v5 1/8] kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset KS.
  2018-09-20 16:55 [PATCH v5 0/8] Add infrastructure for plugins Yordan Karadzhov (VMware)
@ 2018-09-20 16:55 ` Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 2/8] kernel-shark-qt: Add Plugin event handlers to session Yordan Karadzhov (VMware)
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-09-20 16:55 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

This patch adds infrastructure for loading/unloading of plugins. Each
plugin is coupled to a specific type of trace event and is allowed to
perform two types of actions.

The first action is executed once for each kshark_entry only at the time
when the data is loaded. This action can modify (even completely rewrite)
the content of the kshark_entrys generated from the trace events having
the type of the plugin.

The second action can add graphical elements on top of the existing graphs
generated by the Visualization model. This will become clear in the
following patches. This action is executed once for each graph and this is
happening every time when the Visualization model changes its state. It is
very powerful and can be used not only for drawing, but also for performing
arbitrary modifications on the data. The pointer to the model descriptor
object can access the entire array of kshark_entries, which, in turn, could
be used to modify those entries.

The plugin infrastructure of the Qt-baset KernelShark reuses the system
of macros for loading/unloading, implemented for the original GTK version.

This version of the patch contains number of improvements suggested by
Steven Rostedt. Thanks Steven!

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/src/CMakeLists.txt     |   1 +
 kernel-shark-qt/src/libkshark-plugin.c | 290 +++++++++++++++++++++++++
 kernel-shark-qt/src/libkshark-plugin.h | 179 +++++++++++++++
 kernel-shark-qt/src/libkshark.h        |   3 +
 4 files changed, 473 insertions(+)
 create mode 100644 kernel-shark-qt/src/libkshark-plugin.c
 create mode 100644 kernel-shark-qt/src/libkshark-plugin.h

diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt
index ac2847a..cdc28c4 100644
--- a/kernel-shark-qt/src/CMakeLists.txt
+++ b/kernel-shark-qt/src/CMakeLists.txt
@@ -3,6 +3,7 @@ message("\n src ...")
 message(STATUS "libkshark")
 add_library(kshark SHARED libkshark.c
                           libkshark-model.c
+                          libkshark-plugin.c
                           libkshark-configio.c
                           libkshark-collection.c)
 
diff --git a/kernel-shark-qt/src/libkshark-plugin.c b/kernel-shark-qt/src/libkshark-plugin.c
new file mode 100644
index 0000000..10e4647
--- /dev/null
+++ b/kernel-shark-qt/src/libkshark-plugin.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+ /**
+  *  @file    libkshark-plugin.c
+  *  @brief   KernelShark plugins.
+  */
+
+// C
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <errno.h>
+
+// KernelShark
+#include "libkshark-plugin.h"
+#include "libkshark.h"
+
+static struct kshark_event_handler *
+gui_event_handler_alloc(int event_id,
+			kshark_plugin_event_handler_func evt_func,
+			kshark_plugin_draw_handler_func dw_func)
+{
+	struct kshark_event_handler *handler = malloc(sizeof(*handler));
+
+	if (!handler) {
+		fprintf(stderr,
+			"failed to allocate memory for gui eventhandler");
+		return NULL;
+	}
+
+	handler->next = NULL;
+	handler->id = event_id;
+	handler->event_func = evt_func;
+	handler->draw_func = dw_func;
+
+	return handler;
+}
+
+/**
+ * @brief Search the list of event handlers for a handle associated with a
+ *	  given event type.
+ *
+ * @param handlers: Input location for the Event handler list.
+ * @param event_id: Event Id to search for.
+ */
+struct kshark_event_handler *
+kshark_find_event_handler(struct kshark_event_handler *handlers, int event_id)
+{
+	for (; handlers; handlers = handlers->next)
+		if (handlers->id == event_id)
+			return handlers;
+
+	return NULL;
+}
+
+/**
+ * @brief Add new event handler to an existing list of handlers.
+ *
+ * @param handlers: Input location for the Event handler list.
+ * @param event_id: Event Id.
+ * @param evt_func: Input location for an Event action provided by the plugin.
+ * @param dw_func: Input location for a Draw action provided by the plugin.
+ *
+ * @returns Zero on success, or a negative error code on failure.
+ */
+int kshark_register_event_handler(struct kshark_event_handler **handlers,
+				  int event_id,
+				  kshark_plugin_event_handler_func evt_func,
+				  kshark_plugin_draw_handler_func dw_func)
+{
+	struct kshark_event_handler *handler =
+		gui_event_handler_alloc(event_id, evt_func, dw_func);
+
+	if(!handler)
+		return -ENOMEM;
+
+	handler->next = *handlers;
+	*handlers = handler;
+	return 0;
+}
+
+/**
+ * @brief Search the list for a specific plugin handle. If such a plugin handle
+ *	  exists, unregister (remove and free) this handle from the list.
+ *
+ * @param handlers: Input location for the Event handler list.
+ * @param event_id: Event Id of the plugin handler to be unregistered.
+ * @param evt_func: Event action function of the handler to be unregistered.
+ * @param dw_func: Draw action function of the handler to be unregistered.
+ */
+void kshark_unregister_event_handler(struct kshark_event_handler **handlers,
+				     int event_id,
+				     kshark_plugin_event_handler_func evt_func,
+				     kshark_plugin_draw_handler_func dw_func)
+{
+	struct kshark_event_handler **last;
+
+	for (last = handlers; *last; last = &(*last)->next) {
+		if ((*last)->id == event_id &&
+		    (*last)->event_func == evt_func &&
+		    (*last)->draw_func == dw_func) {
+			struct kshark_event_handler *this_handler;
+			this_handler = *last;
+			*last = this_handler->next;
+			free(this_handler);
+
+			return;
+		}
+	}
+}
+
+/**
+ * @brief Free all Event handlers in a given list.
+ *
+ * @param handlers: Input location for the Event handler list.
+ */
+void kshark_free_event_handler_list(struct kshark_event_handler *handlers)
+{
+	struct kshark_event_handler *last;
+
+	while (handlers) {
+		last = handlers;
+		handlers = handlers->next;
+		free(last);
+	}
+}
+
+/**
+ * @brief Allocate memory for a new plugin. Add this plugin to the list of
+ *	  plugins used by the session.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param file: The plugin object file to load.
+ *
+ * @returns Zero on success, or a negative error code on failure.
+ */
+int kshark_register_plugin(struct kshark_context *kshark_ctx,
+			   const char *file)
+{
+	struct kshark_plugin_list *plugin = kshark_ctx->plugins;
+	struct stat st;
+	int ret;
+
+	while (plugin) {
+		if (strcmp(plugin->file, file) == 0)
+			return -EEXIST;
+
+		plugin = plugin->next;
+	}
+
+	ret = stat(file, &st);
+	if (ret < 0) {
+		fprintf(stderr, "plugin %s not found\n", file);
+		return -ENODEV;
+	}
+
+	plugin = calloc(sizeof(struct kshark_plugin_list), 1);
+	if (!plugin) {
+		fprintf(stderr, "failed to allocate memory for plugin\n");
+		return -ENOMEM;
+	}
+
+	if (asprintf(&plugin->file, "%s", file) <= 0) {
+		fprintf(stderr,
+			"failed to allocate memory for plugin file name");
+		return -ENOMEM;
+	}
+
+	plugin->handle = dlopen(plugin->file, RTLD_NOW | RTLD_GLOBAL);
+	if (!plugin->handle)
+		goto fail;
+
+	plugin->init = dlsym(plugin->handle,
+			     KSHARK_PLUGIN_INITIALIZER_NAME);
+
+	plugin->close = dlsym(plugin->handle,
+			      KSHARK_PLUGIN_DEINITIALIZER_NAME);
+
+	if (!plugin->init || !plugin->close)
+		goto fail;
+
+	plugin->next = kshark_ctx->plugins;
+	kshark_ctx->plugins = plugin;
+
+	return 0;
+
+ fail:
+	fprintf(stderr, "cannot load plugin '%s'\n%s\n",
+		plugin->file, dlerror());
+
+	if (plugin->handle) {
+		dlclose(plugin->handle);
+		plugin->handle = NULL;
+	}
+
+	free(plugin);
+
+	return EFAULT;
+}
+
+/**
+ * @brief Unrgister a plugin.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ * @param file: The plugin object file to unregister.
+ */
+void kshark_unregister_plugin(struct kshark_context *kshark_ctx,
+			      const char *file)
+{
+	struct kshark_plugin_list **last;
+
+	for (last = &kshark_ctx->plugins; *last; last = &(*last)->next) {
+		if (strcmp((*last)->file, file) == 0) {
+			struct kshark_plugin_list *this_plugin;
+			this_plugin = *last;
+			*last = this_plugin->next;
+
+			dlclose(this_plugin->handle);
+			free(this_plugin);
+
+			return;
+		}
+	}
+}
+
+/**
+ * @brief Free all plugins in a given list.
+ *
+ * @param plugins: Input location for the plugins list.
+ */
+void kshark_free_plugin_list(struct kshark_plugin_list *plugins)
+{
+	struct kshark_plugin_list *last;
+
+	while (plugins) {
+		last = plugins;
+		plugins = plugins->next;
+
+		free(last->file);
+		dlclose(last->handle);
+
+		free(last);
+	}
+}
+
+/**
+ * @brief Use this function to initialize/update/deinitialize all registered
+ *	  plugins.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ * @param task_id: Action identifier specifying the action to be executed.
+ *
+ * @returns The number of successful added/removed plugin handlers on success,
+ *	    or a negative error code on failure.
+ */
+int kshark_handle_plugins(struct kshark_context *kshark_ctx,
+			  enum kshark_plugin_actions task_id)
+{
+	struct kshark_plugin_list *plugin;
+	int handler_count = 0;
+
+	for (plugin = kshark_ctx->plugins; plugin; plugin = plugin->next) {
+		switch (task_id) {
+		case KSHARK_PLUGIN_INIT:
+			handler_count += plugin->init(kshark_ctx);
+			break;
+
+		case KSHARK_PLUGIN_UPDATE:
+			plugin->close(kshark_ctx);
+			handler_count += plugin->init(kshark_ctx);
+			break;
+
+		case KSHARK_PLUGIN_CLOSE:
+			handler_count += plugin->close(kshark_ctx);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return handler_count;
+}
diff --git a/kernel-shark-qt/src/libkshark-plugin.h b/kernel-shark-qt/src/libkshark-plugin.h
new file mode 100644
index 0000000..0cb677a
--- /dev/null
+++ b/kernel-shark-qt/src/libkshark-plugin.h
@@ -0,0 +1,179 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2016 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ */
+
+ /**
+  *  @file    libkshark-plugin.h
+  *  @brief   KernelShark plugins.
+  */
+
+#ifndef _KSHARK_PLUGIN_H
+#define _KSHARK_PLUGIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// trace-cmd
+#include "event-parse.h"
+
+/* Quiet warnings over documenting simple structures */
+//! @cond Doxygen_Suppress
+
+#define KSHARK_PLUGIN_INITIALIZER kshark_plugin_initializer
+
+#define KSHARK_PLUGIN_DEINITIALIZER kshark_plugin_deinitializer
+
+#define _MAKE_STR(x)	#x
+#define MAKE_STR(x)	_MAKE_STR(x)
+
+#define KSHARK_PLUGIN_INITIALIZER_NAME MAKE_STR(KSHARK_PLUGIN_INITIALIZER)
+
+#define KSHARK_PLUGIN_DEINITIALIZER_NAME MAKE_STR(KSHARK_PLUGIN_DEINITIALIZER)
+
+struct kshark_context;
+
+struct kshark_entry;
+
+//! @endcond
+
+/**
+ * A function type to be used when defining load/reload/unload plugin
+ * functions.
+ */
+typedef int (*kshark_plugin_load_func)(struct kshark_context *);
+
+struct kshark_trace_histo;
+
+/**
+ * Structure representing the C arguments of the drawing function of
+ * a plugin.
+ */
+struct kshark_cpp_argv {
+	/** Pointer to the model descriptor object. */
+	struct kshark_trace_histo	*histo;
+};
+
+/** A function type to be used when defining plugin functions for drawing. */
+typedef void
+(*kshark_plugin_draw_handler_func)(struct kshark_cpp_argv *argv,
+				   int val, int draw_action);
+
+/**
+ * A function type to be used when defining plugin functions for data
+ * manipulation.
+ */
+typedef void
+(*kshark_plugin_event_handler_func)(struct kshark_context *kshark_ctx,
+				    struct tep_record *rec,
+				    struct kshark_entry *e);
+
+/** Plugin action identifier. */
+enum kshark_plugin_actions {
+	/**
+	 * Load plugins action. This action identifier is used when handling
+	 * plugins.
+	 */
+	KSHARK_PLUGIN_INIT,
+
+	/**
+	 * Reload plugins action. This action identifier is used when handling
+	 * plugins.
+	 */
+	KSHARK_PLUGIN_UPDATE,
+
+	/**
+	 * Unload plugins action. This action identifier is used when handling
+	 * plugins.
+	 */
+	KSHARK_PLUGIN_CLOSE,
+
+	/**
+	 * Task draw action. This action identifier is used by the plugin draw
+	 * function.
+	 */
+	KSHARK_PLUGIN_TASK_DRAW,
+
+	/**
+	 * CPU draw action. This action identifier is used by the plugin draw
+	 * function.
+	 */
+	KSHARK_PLUGIN_CPU_DRAW,
+};
+
+/**
+ * Plugin Event handler structure, defining the properties of the required
+ * kshark_entry.
+ */
+struct kshark_event_handler {
+	/** Pointer to the next Plugin Event handler. */
+	struct kshark_event_handler		*next;
+
+	/** Unique Id ot the trace event type. */
+	int					id;
+
+	/**
+	 * Event action function. This action can be used to modify the content
+	 * of all kshark_entries having Event Ids equal to "id".
+	 */
+	kshark_plugin_event_handler_func	event_func;
+
+	/**
+	 * Draw action function. This action can be used to draw additional
+	 * graphical elements (shapes) for all kshark_entries having Event Ids
+	 * equal to "id".
+	 */
+	kshark_plugin_draw_handler_func		draw_func;
+};
+
+struct kshark_event_handler *
+kshark_find_event_handler(struct kshark_event_handler *handlers, int event_id);
+
+int kshark_register_event_handler(struct kshark_event_handler **handlers,
+				  int event_id,
+				  kshark_plugin_event_handler_func evt_func,
+				  kshark_plugin_draw_handler_func dw_func);
+
+void kshark_unregister_event_handler(struct kshark_event_handler **handlers,
+				     int event_id,
+				     kshark_plugin_event_handler_func evt_func,
+				     kshark_plugin_draw_handler_func dw_func);
+
+void kshark_free_event_handler_list(struct kshark_event_handler *handlers);
+
+/** Linked list of plugins. */
+struct kshark_plugin_list {
+	/** Pointer to the next Plugin. */
+	struct kshark_plugin_list	*next;
+
+	/** The plugin object file to load. */
+	char				*file;
+
+	/** Plugin Event handler. */
+	void				*handle;
+
+	/** Callback function for initialization of the plugin. */
+	kshark_plugin_load_func		init;
+
+	/** Callback function for deinitialization of the plugin. */
+	kshark_plugin_load_func		close;
+};
+
+int kshark_register_plugin(struct kshark_context *kshark_ctx,
+			   const char *file);
+
+void kshark_unregister_plugin(struct kshark_context *kshark_ctx,
+			      const char *file);
+
+void kshark_free_plugin_list(struct kshark_plugin_list *plugins);
+
+int kshark_handle_plugins(struct kshark_context *kshark_ctx,
+			  enum kshark_plugin_actions  task_id);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _KSHARK_PLUGIN_H
diff --git a/kernel-shark-qt/src/libkshark.h b/kernel-shark-qt/src/libkshark.h
index 2580449..fda133c 100644
--- a/kernel-shark-qt/src/libkshark.h
+++ b/kernel-shark-qt/src/libkshark.h
@@ -121,6 +121,9 @@ struct kshark_context {
 
 	/** List of Data collections. */
 	struct kshark_entry_collection *collections;
+
+	/** List of Plugins. */
+	struct kshark_plugin_list	*plugins;
 };
 
 bool kshark_instance(struct kshark_context **kshark_ctx);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 2/8] kernel-shark-qt: Add Plugin event handlers to session.
  2018-09-20 16:55 [PATCH v5 0/8] Add infrastructure for plugins Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 1/8] kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset KS Yordan Karadzhov (VMware)
@ 2018-09-20 16:55 ` Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 3/8] kernel-shark-qt: Add C++/C conversion for args of a plugin draw function Yordan Karadzhov (VMware)
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-09-20 16:55 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

Plugin event handlers are added to the Session context descriptor.
The handlers are used to execute plugin-specific action (callback
function) during the processing of the trace data.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/src/libkshark.c | 21 +++++++++++++++++++++
 kernel-shark-qt/src/libkshark.h | 14 ++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/kernel-shark-qt/src/libkshark.c b/kernel-shark-qt/src/libkshark.c
index b4a76ae..38d4c3f 100644
--- a/kernel-shark-qt/src/libkshark.c
+++ b/kernel-shark-qt/src/libkshark.c
@@ -33,6 +33,9 @@ static bool kshark_default_context(struct kshark_context **context)
 	if (!kshark_ctx)
 		return false;
 
+	kshark_ctx->event_handlers = NULL;
+	kshark_ctx->plugins = NULL;
+
 	kshark_ctx->show_task_filter = tracecmd_filter_id_hash_alloc();
 	kshark_ctx->hide_task_filter = tracecmd_filter_id_hash_alloc();
 
@@ -217,6 +220,12 @@ void kshark_free(struct kshark_context *kshark_ctx)
 	tracecmd_filter_id_hash_free(kshark_ctx->show_event_filter);
 	tracecmd_filter_id_hash_free(kshark_ctx->hide_event_filter);
 
+	if (kshark_ctx->plugins) {
+		kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_CLOSE);
+		kshark_free_plugin_list(kshark_ctx->plugins);
+		kshark_free_event_handler_list(kshark_ctx->event_handlers);
+	}
+
 	kshark_free_task_list(kshark_ctx);
 
 	if (seq.buffer)
@@ -564,6 +573,7 @@ static void free_rec_list(struct rec_list **rec_list, int n_cpus,
 static size_t get_records(struct kshark_context *kshark_ctx,
 			  struct rec_list ***rec_list, enum rec_type type)
 {
+	struct kshark_event_handler *evt_handler;
 	struct event_filter *adv_filter;
 	struct kshark_task_list *task;
 	struct tep_record *rec;
@@ -608,6 +618,17 @@ static size_t get_records(struct kshark_context *kshark_ctx,
 
 				entry = &temp_rec->entry;
 				kshark_set_entry_values(kshark_ctx, rec, entry);
+
+				/* Execute all plugin-provided actions (if any). */
+				evt_handler = kshark_ctx->event_handlers;
+				while ((evt_handler = kshark_find_event_handler(evt_handler,
+										entry->event_id))) {
+					evt_handler->event_func(kshark_ctx, rec, entry);
+					evt_handler = evt_handler->next;
+					if (!evt_handler)
+						entry->visible &= ~KS_PLUGIN_UNTOUCHED_MASK;
+				}
+
 				pid = entry->pid;
 				/* Apply event filtering. */
 				ret = FILTER_MATCH;
diff --git a/kernel-shark-qt/src/libkshark.h b/kernel-shark-qt/src/libkshark.h
index fda133c..1165bb1 100644
--- a/kernel-shark-qt/src/libkshark.h
+++ b/kernel-shark-qt/src/libkshark.h
@@ -29,6 +29,9 @@ extern "C" {
 #include "event-parse.h"
 #include "trace-filter-hash.h"
 
+// KernelShark
+#include "libkshark-plugin.h"
+
 /**
  * Kernel Shark entry contains all information from one trace record needed
  * in order to  visualize the time-series of trace records. The part of the
@@ -124,6 +127,9 @@ struct kshark_context {
 
 	/** List of Plugins. */
 	struct kshark_plugin_list	*plugins;
+
+	/** List of Plugin Event handlers. */
+	struct kshark_event_handler	*event_handlers;
 };
 
 bool kshark_instance(struct kshark_context **kshark_ctx);
@@ -160,6 +166,14 @@ enum kshark_filter_masks {
 
 	/** Special mask used whene filtering events. */
 	KS_EVENT_VIEW_FILTER_MASK	= 1 << 2,
+
+	/* The next 4 bits are reserved for more KS_X_VIEW_FILTER_MASKs. */
+
+	/**
+	 * Use this mask to check if the content of the entry has been accessed
+	 * by a plugin-defined function.
+	 */
+	KS_PLUGIN_UNTOUCHED_MASK	= 1 << 7
 };
 
 /** Filter type identifier. */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 3/8] kernel-shark-qt: Add C++/C conversion for args of a plugin draw function.
  2018-09-20 16:55 [PATCH v5 0/8] Add infrastructure for plugins Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 1/8] kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset KS Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 2/8] kernel-shark-qt: Add Plugin event handlers to session Yordan Karadzhov (VMware)
@ 2018-09-20 16:55 ` Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 4/8] kernel-shark-qt: Make kshark_read_at() non-static Yordan Karadzhov (VMware)
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-09-20 16:55 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

The draw function of a plugin has a type declared in C. However, the
function needs to access some high level objects, defined in the C++
libraries. This patch adds instruments for converting the arguments
of the plugin's draw function from C++ to C and from C to C++.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/src/KsPlugins.hpp | 51 +++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 kernel-shark-qt/src/KsPlugins.hpp

diff --git a/kernel-shark-qt/src/KsPlugins.hpp b/kernel-shark-qt/src/KsPlugins.hpp
new file mode 100644
index 0000000..3955cdf
--- /dev/null
+++ b/kernel-shark-qt/src/KsPlugins.hpp
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+/**
+  *  @file    KsPlugins.hpp
+  *  @brief   KernelShark C++ plugin declarations.
+  */
+
+#ifndef _KS_PLUGINS_H
+#define _KS_PLUGINS_H
+
+// KernelShark
+#include "libkshark-model.h"
+#include "KsPlotTools.hpp"
+
+/**
+ * Structure representing the vector of C++ arguments of the drawing function
+ * of a plugin.
+ */
+struct KsCppArgV {
+	/** Pointer to the model descriptor object. */
+	kshark_trace_histo	*_histo;
+
+	/** Pointer to the graph object. */
+	KsPlot::Graph		*_graph;
+
+	/**
+	 * Pointer to the list of shapes. All shapes created by the plugin
+	 * will be added to this list.
+	 */
+	KsPlot::PlotObjList	*_shapes;
+
+	/**
+	 * Convert the "this" pointer of the C++ argument vector into a
+	 * C pointer.
+	 */
+	kshark_cpp_argv *toC()
+	{
+		return reinterpret_cast<kshark_cpp_argv *>(this);
+	}
+};
+
+/**
+ * Macro used to convert a C pointer into a pointer to KsCppArgV (C++ struct).
+ */
+#define KS_ARGV_TO_CPP(a) (reinterpret_cast<KsCppArgV *>(a))
+
+#endif
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 4/8] kernel-shark-qt: Make kshark_read_at() non-static.
  2018-09-20 16:55 [PATCH v5 0/8] Add infrastructure for plugins Yordan Karadzhov (VMware)
                   ` (2 preceding siblings ...)
  2018-09-20 16:55 ` [PATCH v5 3/8] kernel-shark-qt: Add C++/C conversion for args of a plugin draw function Yordan Karadzhov (VMware)
@ 2018-09-20 16:55 ` Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 5/8] kernel-shark-qt: Remove the TODO action in kshark_read_at() Yordan Karadzhov (VMware)
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-09-20 16:55 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

kshark_read_at() function provides a thread-safe read of a record from
a specific offset inside the trace.dat file. So far this function was
used only in libkshark.c and was defined static. This patch makes the
function non-static in order to make possible to use it from a plugin.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/src/libkshark.c | 12 ++++++++++--
 kernel-shark-qt/src/libkshark.h |  3 +++
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/kernel-shark-qt/src/libkshark.c b/kernel-shark-qt/src/libkshark.c
index 38d4c3f..3635b48 100644
--- a/kernel-shark-qt/src/libkshark.c
+++ b/kernel-shark-qt/src/libkshark.c
@@ -830,8 +830,16 @@ ssize_t kshark_load_data_records(struct kshark_context *kshark_ctx,
 	return -ENOMEM;
 }
 
-static struct tep_record *kshark_read_at(struct kshark_context *kshark_ctx,
-					 uint64_t offset)
+/**
+ * @brief A thread-safe read of a record from a specific offset.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param offset: the offset into the file to find the record.
+ *
+ * @returns The returned pevent_record must be freed.
+ */
+struct tep_record *kshark_read_at(struct kshark_context *kshark_ctx,
+				  uint64_t offset)
 {
 	/*
 	 * It turns that tracecmd_read_at() is not thread-safe.
diff --git a/kernel-shark-qt/src/libkshark.h b/kernel-shark-qt/src/libkshark.h
index 1165bb1..e846c85 100644
--- a/kernel-shark-qt/src/libkshark.h
+++ b/kernel-shark-qt/src/libkshark.h
@@ -150,6 +150,9 @@ void kshark_free(struct kshark_context *kshark_ctx);
 
 char* kshark_dump_entry(const struct kshark_entry *entry);
 
+struct tep_record *kshark_read_at(struct kshark_context *kshark_ctx,
+				  uint64_t offset);
+
 /** Bit masks used to control the visibility of the entry after filtering. */
 enum kshark_filter_masks {
 	/**
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 5/8] kernel-shark-qt: Remove the TODO action in kshark_read_at()
  2018-09-20 16:55 [PATCH v5 0/8] Add infrastructure for plugins Yordan Karadzhov (VMware)
                   ` (3 preceding siblings ...)
  2018-09-20 16:55 ` [PATCH v5 4/8] kernel-shark-qt: Make kshark_read_at() non-static Yordan Karadzhov (VMware)
@ 2018-09-20 16:55 ` Yordan Karadzhov (VMware)
  2018-09-20 22:05   ` Steven Rostedt
  2018-09-20 16:55 ` [PATCH v5 6/8] kernel-shark-qt: Add src/plugins dir. to hold the source code of the plugins Yordan Karadzhov (VMware)
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 10+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-09-20 16:55 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

The TODO message states that we have to understand why racecmd_read_at()
is not thread-safe and see if this can be fixed. We now know why and we
know that this cannot be fixed.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/src/libkshark.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/kernel-shark-qt/src/libkshark.c b/kernel-shark-qt/src/libkshark.c
index 3635b48..506511d 100644
--- a/kernel-shark-qt/src/libkshark.c
+++ b/kernel-shark-qt/src/libkshark.c
@@ -842,9 +842,8 @@ struct tep_record *kshark_read_at(struct kshark_context *kshark_ctx,
 				  uint64_t offset)
 {
 	/*
-	 * It turns that tracecmd_read_at() is not thread-safe.
-	 * TODO: Understand why and see if this can be fixed.
-	 * For the time being use a mutex to protect the access.
+	 * Calling tracecmd_read_at() is not thread-safe. Use a mutex to
+	 * protect the access.
 	 */
 	pthread_mutex_lock(&kshark_ctx->input_mutex);
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 6/8] kernel-shark-qt: Add src/plugins dir. to hold the source code of the plugins
  2018-09-20 16:55 [PATCH v5 0/8] Add infrastructure for plugins Yordan Karadzhov (VMware)
                   ` (4 preceding siblings ...)
  2018-09-20 16:55 ` [PATCH v5 5/8] kernel-shark-qt: Remove the TODO action in kshark_read_at() Yordan Karadzhov (VMware)
@ 2018-09-20 16:55 ` Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 7/8] kernel-shark-qt: Tell Doxygen to enter ../src/plugins/ Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 8/8] kernel-shark-qt: Add a plugin for sched events Yordan Karadzhov (VMware)
  7 siblings, 0 replies; 10+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-09-20 16:55 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

Tell Cmake to enter src/plugins. Add a Cmake function for building plugin
libraries.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/src/CMakeLists.txt         |  2 ++
 kernel-shark-qt/src/plugins/CMakeLists.txt | 22 ++++++++++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 kernel-shark-qt/src/plugins/CMakeLists.txt

diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt
index cdc28c4..3365413 100644
--- a/kernel-shark-qt/src/CMakeLists.txt
+++ b/kernel-shark-qt/src/CMakeLists.txt
@@ -28,5 +28,7 @@ if (OPENGL_FOUND AND GLUT_FOUND)
 
 endif (OPENGL_FOUND AND GLUT_FOUND)
 
+add_subdirectory(plugins)
+
 configure_file( ${KS_DIR}/build/deff.h.cmake
                 ${KS_DIR}/src/KsDeff.h)
diff --git a/kernel-shark-qt/src/plugins/CMakeLists.txt b/kernel-shark-qt/src/plugins/CMakeLists.txt
new file mode 100644
index 0000000..565f1cb
--- /dev/null
+++ b/kernel-shark-qt/src/plugins/CMakeLists.txt
@@ -0,0 +1,22 @@
+message("\n src/plugins ...")
+
+function(BUILD_PLUGIN)
+    set(options )
+    set(oneValueArgs NAME)
+    set(multiValueArgs SOURCE)
+    cmake_parse_arguments(ADD_PLUGIN "${options}"
+                                     ${oneValueArgs}
+                                     ${multiValueArgs}
+                                     ${ARGN})
+
+    message(STATUS ${ADD_PLUGIN_NAME})
+
+    add_library(${ADD_PLUGIN_NAME} SHARED ${ADD_PLUGIN_SOURCE})
+    set_target_properties(${ADD_PLUGIN_NAME} PROPERTIES PREFIX "plugin-")
+    target_link_libraries(${ADD_PLUGIN_NAME} kshark)
+
+endfunction()
+
+set(PLUGIN_LIST "")
+
+set(PLUGINS ${PLUGIN_LIST} PARENT_SCOPE)
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 7/8] kernel-shark-qt: Tell Doxygen to enter ../src/plugins/
  2018-09-20 16:55 [PATCH v5 0/8] Add infrastructure for plugins Yordan Karadzhov (VMware)
                   ` (5 preceding siblings ...)
  2018-09-20 16:55 ` [PATCH v5 6/8] kernel-shark-qt: Add src/plugins dir. to hold the source code of the plugins Yordan Karadzhov (VMware)
@ 2018-09-20 16:55 ` Yordan Karadzhov (VMware)
  2018-09-20 16:55 ` [PATCH v5 8/8] kernel-shark-qt: Add a plugin for sched events Yordan Karadzhov (VMware)
  7 siblings, 0 replies; 10+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-09-20 16:55 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

This Patch adds ../src/plugins/ to the list of input locations used by
Doxygen to search for documented source files.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/doc/dox_config | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel-shark-qt/doc/dox_config b/kernel-shark-qt/doc/dox_config
index b982baa..acc9083 100644
--- a/kernel-shark-qt/doc/dox_config
+++ b/kernel-shark-qt/doc/dox_config
@@ -4,7 +4,7 @@
 DOXYFILE_ENCODING      = UTF-8
 PROJECT_NAME           = "kernel-shark-qt"
 PROJECT_BRIEF = "Kernel Shark is a front-end reader of the Linux kernel tracing data."
-INPUT                  = "../src/"
+INPUT                  = ../src/ ../src/plugins/
 SOURCE_BROWSER         = YES
 QT_AUTOBRIEF           = YES
 TAB_SIZE               = 8
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v5 8/8] kernel-shark-qt: Add a plugin for sched events.
  2018-09-20 16:55 [PATCH v5 0/8] Add infrastructure for plugins Yordan Karadzhov (VMware)
                   ` (6 preceding siblings ...)
  2018-09-20 16:55 ` [PATCH v5 7/8] kernel-shark-qt: Tell Doxygen to enter ../src/plugins/ Yordan Karadzhov (VMware)
@ 2018-09-20 16:55 ` Yordan Karadzhov (VMware)
  7 siblings, 0 replies; 10+ messages in thread
From: Yordan Karadzhov (VMware) @ 2018-09-20 16:55 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

The plugin is responsible for the following actions, specific for
"sched" events:

1. Changes the value of the "pid" field of the "sched_switch" entries.
   This alows the sched_switch entry to be plotted as part of the "next"
   task.

2. On "sched_switch" event, the plugin registers the "next" task (if not
   registered already).

3. Plots in green the wake up latency of the task and in red the time
   the task was preempted by another task.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/src/plugins/CMakeLists.txt  |   5 +
 kernel-shark-qt/src/plugins/SchedEvents.cpp | 263 +++++++++++++++++
 kernel-shark-qt/src/plugins/sched_events.c  | 305 ++++++++++++++++++++
 kernel-shark-qt/src/plugins/sched_events.h  |  76 +++++
 4 files changed, 649 insertions(+)
 create mode 100644 kernel-shark-qt/src/plugins/SchedEvents.cpp
 create mode 100644 kernel-shark-qt/src/plugins/sched_events.c
 create mode 100644 kernel-shark-qt/src/plugins/sched_events.h

diff --git a/kernel-shark-qt/src/plugins/CMakeLists.txt b/kernel-shark-qt/src/plugins/CMakeLists.txt
index 565f1cb..88fd93c 100644
--- a/kernel-shark-qt/src/plugins/CMakeLists.txt
+++ b/kernel-shark-qt/src/plugins/CMakeLists.txt
@@ -19,4 +19,9 @@ endfunction()
 
 set(PLUGIN_LIST "")
 
+BUILD_PLUGIN(NAME sched_events
+             SOURCE sched_events.c SchedEvents.cpp)
+list(APPEND PLUGIN_LIST "sched_events default") # This plugin will be loaded by default
+# list(APPEND PLUGIN_LIST "sched_events") # This plugin isn't loaded by default
+
 set(PLUGINS ${PLUGIN_LIST} PARENT_SCOPE)
diff --git a/kernel-shark-qt/src/plugins/SchedEvents.cpp b/kernel-shark-qt/src/plugins/SchedEvents.cpp
new file mode 100644
index 0000000..713feb4
--- /dev/null
+++ b/kernel-shark-qt/src/plugins/SchedEvents.cpp
@@ -0,0 +1,263 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+/**
+ *  @file    SchedEvents.cpp
+ *  @brief   Defines a callback function for Sched events used to plot in green
+ *	     the wake up latency of the task and in red the time the task was
+ *	     preempted by another task.
+ */
+
+// C++
+#include<iostream>
+
+// C++ 11
+#include<functional>
+
+// KernelShark
+#include "libkshark.h"
+#include "plugins/sched_events.h"
+#include "KsPlotTools.hpp"
+#include "KsPlugins.hpp"
+
+//! @cond Doxygen_Suppress
+
+#define PLUGIN_MIN_BOX_SIZE 4
+
+#define PLUGIN_MAX_ENTRIES_PER_BIN 500
+
+//! @endcond
+
+extern struct plugin_sched_context *plugin_sched_context_handler;
+
+static int plugin_get_wakeup_pid(kshark_context *kshark_ctx,
+				 plugin_sched_context *plugin_ctx,
+				 const struct kshark_entry *e)
+{
+	struct tep_record *record;
+	unsigned long long val;
+
+	record = kshark_read_at(kshark_ctx, e->offset);
+	tep_read_number_field(plugin_ctx->sched_wakeup_pid_field,
+			      record->data, &val);
+	free_record(record);
+
+	return val;
+}
+
+/** Sched Event identifier. */
+enum class SchedEvent {
+	/** Sched Switch Event. */
+	Switch,
+
+	/** Sched Wakeup Event. */
+	Wakeup,
+};
+
+static void pluginDraw(plugin_sched_context *plugin_ctx,
+		       kshark_context *kshark_ctx,
+		       kshark_trace_histo *histo,
+		       kshark_entry_collection *col,
+		       SchedEvent e,
+		       int pid,
+		       KsPlot::Graph *graph,
+		       KsPlot::PlotObjList *shapes)
+{
+	std::function<void(int)> ifSchedBack;
+	KsPlot::Rectangle *rec = nullptr;
+	int height = graph->getHeight() * .3;
+
+	auto openBox = [&] (const KsPlot::Point &p)
+	{
+		/*
+		 * First check if we already have an open box. If we don't
+		 * have, open a new one.
+		 */
+		if (!rec)
+			rec = new KsPlot::Rectangle;
+
+		rec->setFill(false);
+		rec->setPoint(0, p.x() - 1, p.y() - height);
+		rec->setPoint(1, p.x() - 1, p.y() - 1);
+	};
+
+	auto closeBox = [&] (const KsPlot::Point &p)
+	{
+		if (rec == nullptr)
+			return;
+
+		int boxSize = rec->getPoint(0)->x;
+		if (boxSize < PLUGIN_MIN_BOX_SIZE) {
+			/* This box is too small. Don't try to plot it. */
+			delete rec;
+			rec = nullptr;
+			return;
+		}
+
+		rec->setPoint(3, p.x() - 1, p.y() - height);
+		rec->setPoint(2, p.x() - 1, p.y() - 1);
+
+		shapes->push_front(rec);
+		rec = nullptr;
+	};
+
+	auto lamIfSchSwitchFront = [&] (int bin)
+	{
+		/*
+		 * Starting from the first element in this bin, go forward
+		 * in time until you find a trace entry that satisfies the
+		 * condition defined by kshark_match_pid.
+		 */
+		const kshark_entry *entryF =
+			ksmodel_get_entry_front(histo, bin, false,
+						kshark_match_pid, pid,
+						col, nullptr);
+
+		if (entryF &&
+		    entryF->pid == pid &&
+		    plugin_ctx->sched_switch_event &&
+		    entryF->event_id == plugin_ctx->sched_switch_event->id) {
+			/*
+			 * entryF is sched_switch_event. Close the box and add
+			 * it to the list of shapes to be ploted.
+			 */
+			closeBox(graph->getBin(bin)._base);
+		}
+	};
+
+	auto lamIfSchWakeupBack = [&] (int bin)
+	{
+		/*
+		 * Starting from the last element in this bin, go backward
+		 * in time until you find a trace entry that satisfies the
+		 * condition defined by plugin_wakeup_match_pid.
+		 */
+		const kshark_entry *entryB =
+			ksmodel_get_entry_back(histo, bin, false,
+					       plugin_wakeup_match_pid, pid,
+					       col, nullptr);
+		int wakeup_pid;
+
+		if (entryB &&
+		    plugin_ctx->sched_wakeup_event &&
+		    entryB->event_id == plugin_ctx->sched_wakeup_event->id) {
+			wakeup_pid =
+				plugin_get_wakeup_pid(kshark_ctx, plugin_ctx, entryB);
+			if (wakeup_pid == pid) {
+				/*
+				 * entryB is a sched_wakeup_event. Open a
+				 * green box here.
+				 */
+				openBox(graph->getBin(bin)._base);
+
+				 /* Green */
+				rec->_color = KsPlot::Color(0, 255, 0);
+			}
+		}
+	};
+
+	auto lamIfSchSwitchBack = [&] (int bin)
+	{
+		/*
+		 * Starting from the last element in this bin, go backward
+		 * in time until you find a trace entry that satisfies the
+		 * condition defined by plugin_switch_match_pid.
+		 */
+		const kshark_entry *entryB =
+			ksmodel_get_entry_back(histo, bin, false,
+					       plugin_switch_match_pid, pid,
+					       col, nullptr);
+
+		if (entryB &&
+		    entryB->pid != pid &&
+		    plugin_ctx->sched_switch_event &&
+		    entryB->event_id == plugin_ctx->sched_switch_event->id) {
+			/*
+			 * entryB is a sched_switch_event. Open a
+			 * red box here.
+			 */
+			openBox(graph->getBin(bin)._base);
+
+			/* Red */
+			rec->_color = KsPlot::Color(255, 0, 0);
+		}
+	};
+
+	if (e == SchedEvent::Switch)
+		ifSchedBack = lamIfSchSwitchBack;
+	else
+		ifSchedBack = lamIfSchWakeupBack;
+
+	for (int bin = 0; bin < graph->size(); ++bin) {
+		/**
+		 * Plotting the latencies makes sense only in the case of a
+		 * deep zoom. Here we set a naive threshold based on the number
+		 * of entries inside the current bin. This cut seems to work
+		 * well in all cases I tested so far, but it may result in
+		 * unexpected behavior with some unusual trace data-sets.
+		 * TODO: find a better criteria for deciding when to start
+		 * plotting latencies.
+		 */
+		if (ksmodel_bin_count(histo, bin) > PLUGIN_MAX_ENTRIES_PER_BIN)
+			continue;
+
+		lamIfSchSwitchFront(bin);
+
+		ifSchedBack(bin);
+	}
+
+	if (rec)
+		delete rec;
+
+	return;
+}
+
+/**
+ * @brief Plugin's draw function.
+ *
+ * @param argv_c: A C pointer to be converted to KsCppArgV (C++ struct).
+ * @param pid: Process Id.
+ * @param draw_action: Draw action identifier.
+ *
+ * @returns True if the Pid of the entry matches the value of "pid".
+ *	    Otherwise false.
+ */
+void plugin_draw(kshark_cpp_argv *argv_c, int pid, int draw_action)
+{
+	plugin_sched_context *plugin_ctx;
+	kshark_context *kshark_ctx(NULL);
+	kshark_entry_collection *col;
+
+	if (draw_action != KSHARK_PLUGIN_TASK_DRAW || pid == 0)
+		return;
+
+	plugin_ctx = plugin_sched_context_handler;
+	if (!plugin_ctx || !kshark_instance(&kshark_ctx))
+		return;
+
+	KsCppArgV *argvCpp = KS_ARGV_TO_CPP(argv_c);
+
+	/*
+	 * Try to find a collections for this task. It is OK if
+	 * coll = NULL.
+	 */
+	col = kshark_find_data_collection(kshark_ctx->collections,
+					  kshark_match_pid, pid);
+
+	try {
+		pluginDraw(plugin_ctx, kshark_ctx,
+			   argvCpp->_histo, col,
+			   SchedEvent::Switch, pid,
+			   argvCpp->_graph, argvCpp->_shapes);
+
+		pluginDraw(plugin_ctx, kshark_ctx,
+			   argvCpp->_histo, col,
+			   SchedEvent::Wakeup, pid,
+			   argvCpp->_graph, argvCpp->_shapes);
+	} catch (const std::exception &exc) {
+		std::cerr << "Exception in SchedEvents\n" << exc.what();
+	}
+}
diff --git a/kernel-shark-qt/src/plugins/sched_events.c b/kernel-shark-qt/src/plugins/sched_events.c
new file mode 100644
index 0000000..ffc8333
--- /dev/null
+++ b/kernel-shark-qt/src/plugins/sched_events.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+/**
+ *  @file    sched_events.c
+ *  @brief   Defines a callback function for Sched events used to registers the
+ *	     "next" task (if not registered already) and to changes the value
+ *	     of the "pid" field of the "sched_switch" entries such that, it
+ *	     will be ploted as part of the "next" task.
+ */
+
+// C
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+// KernelShark
+#include "plugins/sched_events.h"
+
+/** Plugin context instance. */
+struct plugin_sched_context *plugin_sched_context_handler = NULL;
+
+static bool plugin_sched_init_context(struct kshark_context *kshark_ctx)
+{
+	struct plugin_sched_context *plugin_ctx;
+	struct event_format *event;
+
+	/* No context should exist when we initialize the plugin. */
+	assert(plugin_sched_context_handler == NULL);
+
+	plugin_sched_context_handler =
+		malloc(sizeof(*plugin_sched_context_handler));
+	if (!plugin_sched_context_handler) {
+		fprintf(stderr,
+			"Failed to allocate memory for plugin_sched_context.\n");
+		return false;
+	}
+
+	plugin_ctx = plugin_sched_context_handler;
+	plugin_ctx->handle = kshark_ctx->handle;
+	plugin_ctx->pevent = kshark_ctx->pevent;
+
+	event = tep_find_event_by_name(plugin_ctx->pevent,
+				       "sched", "sched_switch");
+	if (!event)
+		return false;
+
+	plugin_ctx->sched_switch_event = event;
+	plugin_ctx->sched_switch_next_field =
+		tep_find_any_field(event, "next_pid");
+
+	plugin_ctx->sched_switch_comm_field =
+		tep_find_field(event, "next_comm");
+
+	event = tep_find_event_by_name(plugin_ctx->pevent,
+				      "sched", "sched_wakeup");
+	if (!event)
+		return false;
+
+	plugin_ctx->sched_wakeup_event = event;
+	plugin_ctx->sched_wakeup_pid_field =
+		tep_find_any_field(event, "pid");
+
+	plugin_ctx->sched_wakeup_success_field =
+		tep_find_field(event, "success");
+
+	event = tep_find_event_by_name(plugin_ctx->pevent,
+				       "sched", "sched_wakeup_new");
+	if (!event)
+		return false;
+
+	plugin_ctx->sched_wakeup_new_event = event;
+	plugin_ctx->sched_wakeup_new_pid_field =
+		tep_find_any_field(event, "pid");
+
+	plugin_ctx->sched_wakeup_new_success_field =
+		tep_find_field(event, "success");
+
+	return true;
+}
+
+/**
+ * @brief Get the Process Id of the next scheduled task.
+ *
+ * @param record: Input location for a sched_switch record.
+ */
+int plugin_get_next_pid(struct tep_record *record)
+{
+	struct plugin_sched_context *plugin_ctx =
+		plugin_sched_context_handler;
+	unsigned long long val;
+
+	tep_read_number_field(plugin_ctx->sched_switch_next_field,
+			      record->data, &val);
+	return val;
+}
+
+/**
+ * @brief Get the Process Id of the task being woke up.
+ *
+ * @param record: Input location for a sched_wakeup record.
+ */
+int plugin_get_wakeup_pid(struct tep_record *record)
+{
+	struct plugin_sched_context *plugin_ctx =
+		plugin_sched_context_handler;
+	unsigned long long val;
+
+	tep_read_number_field(plugin_ctx->sched_wakeup_pid_field,
+			      record->data, &val);
+	return val;
+}
+
+static void plugin_register_command(struct kshark_context *kshark_ctx,
+				    struct tep_record *record,
+				    int pid)
+{
+	struct plugin_sched_context *plugin_ctx =
+		plugin_sched_context_handler;
+	const char *comm;
+
+	if (!plugin_ctx->sched_switch_comm_field)
+		return;
+
+	comm = record->data + plugin_ctx->sched_switch_comm_field->offset;
+	/*
+	 * TODO: The retrieve of the name of the command above needs to be
+	 * implemented as a wrapper function in libtracevent.
+	 */
+
+	if (!tep_pid_is_registered(kshark_ctx->pevent, pid))
+			tep_register_comm(kshark_ctx->pevent, comm, pid);
+}
+
+static int plugin_get_wakeup_new_pid(struct tep_record *record)
+{
+	struct plugin_sched_context *plugin_ctx =
+		plugin_sched_context_handler;
+	unsigned long long val;
+
+	tep_read_number_field(plugin_ctx->sched_wakeup_new_pid_field,
+				 record->data, &val);
+
+	return val;
+}
+
+/**
+ * @brief Process Id matching function adapted for sched_wakeup and
+ *	  sched_wakeup_new events.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param e: kshark_entry to be checked.
+ * @param pid: Matching condition value.
+ *
+ * @returns True if the Pid of the entry matches the value of "pid".
+ *	    Otherwise false.
+ */
+bool plugin_wakeup_match_pid(struct kshark_context *kshark_ctx,
+			     struct kshark_entry *e,
+			     int pid)
+{
+	struct plugin_sched_context *plugin_ctx;
+	struct tep_record *record = NULL;
+	unsigned long long val;
+	int wakeup_pid = -1;
+
+	if (e->pid == pid)
+		return true;
+
+	plugin_ctx = plugin_sched_context_handler;
+	if (!plugin_ctx)
+		return false;
+
+	if (plugin_ctx->sched_wakeup_event &&
+	    e->event_id == plugin_ctx->sched_wakeup_event->id) {
+		record = kshark_read_at(kshark_ctx, e->offset);
+
+		/* We only want those that actually woke up the task. */
+		tep_read_number_field(plugin_ctx->sched_wakeup_success_field,
+				      record->data, &val);
+
+		if (val)
+			wakeup_pid = plugin_get_wakeup_pid(record);
+	}
+
+	if (plugin_ctx->sched_wakeup_new_event &&
+	    e->event_id == plugin_ctx->sched_wakeup_new_event->id) {
+		record = kshark_read_at(kshark_ctx, e->offset);
+
+		/* We only want those that actually woke up the task. */
+		tep_read_number_field(plugin_ctx->sched_wakeup_new_success_field,
+				      record->data, &val);
+
+		if (val)
+			wakeup_pid = plugin_get_wakeup_new_pid(record);
+	}
+
+	free_record(record);
+
+	if (wakeup_pid >= 0 && wakeup_pid == pid)
+		return true;
+
+	return false;
+}
+
+/**
+ * @brief Process Id matching function adapted for sched_switch events.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param e: kshark_entry to be checked.
+ * @param pid: Matching condition value.
+ *
+ * @returns True if the Pid of the entry matches the value of "pid".
+ *	    Otherwise false.
+ */
+bool plugin_switch_match_pid(struct kshark_context *kshark_ctx,
+			     struct kshark_entry *e,
+			     int pid)
+{
+	struct plugin_sched_context *plugin_ctx;
+	struct tep_record *record = NULL;
+	int switch_pid = -1;
+
+	if (e->pid == pid)
+		return true;
+
+	plugin_ctx = plugin_sched_context_handler;
+
+	if (plugin_ctx->sched_switch_event &&
+	    e->event_id == plugin_ctx->sched_switch_event->id) {
+		record = kshark_read_at(kshark_ctx, e->offset);
+
+		switch_pid = tep_data_pid(plugin_ctx->pevent, record);
+	}
+
+	free_record(record);
+
+	if (switch_pid >= 0 && switch_pid == pid)
+		return true;
+
+	return false;
+}
+
+static void plugin_sched_action(struct kshark_context *kshark_ctx,
+				struct tep_record *rec,
+				struct kshark_entry *entry)
+{
+	entry->pid = plugin_get_next_pid(rec);
+	plugin_register_command(kshark_ctx, rec, entry->pid);
+}
+
+static int plugin_sched_init(struct kshark_context *kshark_ctx)
+{
+	struct plugin_sched_context *plugin_ctx;
+
+	if (!plugin_sched_init_context(kshark_ctx)) {
+		free(plugin_sched_context_handler);
+		plugin_sched_context_handler = NULL;
+		return 0;
+	}
+
+	plugin_ctx = plugin_sched_context_handler;
+
+	kshark_register_event_handler(&kshark_ctx->event_handlers,
+				      plugin_ctx->sched_switch_event->id,
+				      plugin_sched_action,
+				      plugin_draw);
+
+	return 1;
+}
+
+static int plugin_sched_close(struct kshark_context *kshark_ctx)
+{
+	struct plugin_sched_context *plugin_ctx;
+
+	if (!plugin_sched_context_handler)
+		return 0;
+
+	plugin_ctx = plugin_sched_context_handler;
+
+	kshark_unregister_event_handler(&kshark_ctx->event_handlers,
+					plugin_ctx->sched_switch_event->id,
+					plugin_sched_action,
+					plugin_draw);
+
+	free(plugin_ctx);
+	plugin_sched_context_handler = NULL;
+
+	return 1;
+}
+
+/** Load this plugin. */
+int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx)
+{
+	return plugin_sched_init(kshark_ctx);
+}
+
+/** Unload this plugin. */
+int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx)
+{
+	return plugin_sched_close(kshark_ctx);
+}
diff --git a/kernel-shark-qt/src/plugins/sched_events.h b/kernel-shark-qt/src/plugins/sched_events.h
new file mode 100644
index 0000000..673f5cf
--- /dev/null
+++ b/kernel-shark-qt/src/plugins/sched_events.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+/**
+ *  @file    sched_events.h
+ *  @brief   Plugin for Sched events.
+ */
+
+#ifndef _KS_PLUGIN_SHED_H
+#define _KS_PLUGIN_SHED_H
+
+// KernelShark
+#include "libkshark.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Structure representing a plugin-specific context. */
+struct plugin_sched_context {
+	/** Input handle for the trace data file. */
+	struct tracecmd_input	*handle;
+
+	/** Page event used to parse the page. */
+	struct tep_handle	*pevent;
+
+	/** Pointer to the sched_switch_event object. */
+	struct event_format	*sched_switch_event;
+
+	/** Pointer to the sched_switch_next_field format descriptor. */
+	struct format_field	*sched_switch_next_field;
+
+	/** Pointer to the sched_switch_comm_field format descriptor. */
+	struct format_field	*sched_switch_comm_field;
+
+	/** Pointer to the sched_wakeup_event object. */
+	struct event_format	*sched_wakeup_event;
+
+	/** Pointer to the sched_wakeup_pid_field format descriptor. */
+	struct format_field	*sched_wakeup_pid_field;
+
+	/** Pointer to the sched_wakeup_success_field format descriptor. */
+	struct format_field	*sched_wakeup_success_field;
+
+	/** Pointer to the sched_wakeup_new_event object. */
+	struct event_format	*sched_wakeup_new_event;
+
+	/** Pointer to the sched_wakeup_new_pid_field format descriptor. */
+	struct format_field	*sched_wakeup_new_pid_field;
+
+	/**
+	 * Pointer to the sched_wakeup_new_success_field format descriptor.
+	 */
+	struct format_field	*sched_wakeup_new_success_field;
+};
+
+int plugin_get_next_pid(struct tep_record *record);
+
+int plugin_get_wakeup_pid(struct tep_record *record);
+
+bool plugin_wakeup_match_pid(struct kshark_context *kshark_ctx,
+			     struct kshark_entry *e, int pid);
+
+bool plugin_switch_match_pid(struct kshark_context *kshark_ctx,
+			     struct kshark_entry *e, int pid);
+
+void plugin_draw(struct kshark_cpp_argv *argv, int pid, int draw_action);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v5 5/8] kernel-shark-qt: Remove the TODO action in kshark_read_at()
  2018-09-20 16:55 ` [PATCH v5 5/8] kernel-shark-qt: Remove the TODO action in kshark_read_at() Yordan Karadzhov (VMware)
@ 2018-09-20 22:05   ` Steven Rostedt
  0 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2018-09-20 22:05 UTC (permalink / raw)
  To: Yordan Karadzhov (VMware); +Cc: linux-trace-devel

On Thu, 20 Sep 2018 19:55:41 +0300
"Yordan Karadzhov (VMware)" <y.karadz@gmail.com> wrote:

> The TODO message states that we have to understand why racecmd_read_at()
> is not thread-safe and see if this can be fixed. We now know why and we
> know that this cannot be fixed.

I wouldn't say that it can not be fixed, but that it's hard to fix.

I'll update the change log.

Thanks!

-- Steve

> 
> Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
> ---
>  kernel-shark-qt/src/libkshark.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/kernel-shark-qt/src/libkshark.c b/kernel-shark-qt/src/libkshark.c
> index 3635b48..506511d 100644
> --- a/kernel-shark-qt/src/libkshark.c
> +++ b/kernel-shark-qt/src/libkshark.c
> @@ -842,9 +842,8 @@ struct tep_record *kshark_read_at(struct kshark_context *kshark_ctx,
>  				  uint64_t offset)
>  {
>  	/*
> -	 * It turns that tracecmd_read_at() is not thread-safe.
> -	 * TODO: Understand why and see if this can be fixed.
> -	 * For the time being use a mutex to protect the access.
> +	 * Calling tracecmd_read_at() is not thread-safe. Use a mutex to
> +	 * protect the access.
>  	 */
>  	pthread_mutex_lock(&kshark_ctx->input_mutex);
>  

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-09-21  3:51 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-20 16:55 [PATCH v5 0/8] Add infrastructure for plugins Yordan Karadzhov (VMware)
2018-09-20 16:55 ` [PATCH v5 1/8] kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset KS Yordan Karadzhov (VMware)
2018-09-20 16:55 ` [PATCH v5 2/8] kernel-shark-qt: Add Plugin event handlers to session Yordan Karadzhov (VMware)
2018-09-20 16:55 ` [PATCH v5 3/8] kernel-shark-qt: Add C++/C conversion for args of a plugin draw function Yordan Karadzhov (VMware)
2018-09-20 16:55 ` [PATCH v5 4/8] kernel-shark-qt: Make kshark_read_at() non-static Yordan Karadzhov (VMware)
2018-09-20 16:55 ` [PATCH v5 5/8] kernel-shark-qt: Remove the TODO action in kshark_read_at() Yordan Karadzhov (VMware)
2018-09-20 22:05   ` Steven Rostedt
2018-09-20 16:55 ` [PATCH v5 6/8] kernel-shark-qt: Add src/plugins dir. to hold the source code of the plugins Yordan Karadzhov (VMware)
2018-09-20 16:55 ` [PATCH v5 7/8] kernel-shark-qt: Tell Doxygen to enter ../src/plugins/ Yordan Karadzhov (VMware)
2018-09-20 16:55 ` [PATCH v5 8/8] kernel-shark-qt: Add a plugin for sched events Yordan Karadzhov (VMware)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.