linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] kernel-shark: Visualization plugin tools
@ 2021-01-06 16:11 Yordan Karadzhov (VMware)
  2021-01-06 16:11 ` [PATCH 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro Yordan Karadzhov (VMware)
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-01-06 16:11 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

We implement a general purpose instruments, that can be used to
implement efficient (fast) visualization plugins. We also use
the new instrumentation to optimize the sched_events plugin.

Yordan Karadzhov (VMware) (6):
  kernel-shark: Add KS_DOUBLE_SIZE macro
  kernel-shark: Add kshark_data_container to libkshark
  kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro
  kernel-shark: Start using C++17
  kernel-shark: Add plotting methods to KsPlugins
  kernel-shark: Speed-up the sched_events plugin

 CMakeLists.txt              |   8 +-
 src/CMakeLists.txt          |   5 +-
 src/KsPlugins.cpp           | 416 ++++++++++++++++++++++++++++++++++++
 src/KsPlugins.hpp           |  48 +++++
 src/libkshark-plugin.h      |  58 +++++
 src/libkshark-tepdata.c     |  34 +++
 src/libkshark-tepdata.h     |   7 +
 src/libkshark.c             | 162 +++++++++++++-
 src/libkshark.h             |  43 ++++
 src/plugins/CMakeLists.txt  |  11 +-
 src/plugins/SchedEvents.cpp | 310 +++++++--------------------
 src/plugins/sched_events.c  | 393 +++++++++++-----------------------
 src/plugins/sched_events.h  |  50 ++---
 tests/libkshark-tests.cpp   |  66 ++++++
 14 files changed, 1052 insertions(+), 559 deletions(-)
 create mode 100644 src/KsPlugins.cpp

-- 
2.25.1


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

* [PATCH 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro
  2021-01-06 16:11 [PATCH 0/6] kernel-shark: Visualization plugin tools Yordan Karadzhov (VMware)
@ 2021-01-06 16:11 ` Yordan Karadzhov (VMware)
  2021-01-06 17:02   ` Steven Rostedt
  2021-01-06 16:11 ` [PATCH 2/6] kernel-shark: Add kshark_data_container to libkshark Yordan Karadzhov (VMware)
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-01-06 16:11 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

The macro is useful for resizing of dynamic arrays. It is currently
used to resize the Data stream descriptor array, owned by the session
context. We will later use the macro with the arrays of data fields and
plugin contexts.

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

diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h
index 1a642ad..f3c724f 100644
--- a/src/libkshark-plugin.h
+++ b/src/libkshark-plugin.h
@@ -346,6 +346,20 @@ int kshark_handle_dpi(struct kshark_data_stream *stream,
 int kshark_handle_all_dpis(struct kshark_data_stream *stream,
 			   enum kshark_plugin_actions  task_id);
 
+/** General purpose macro for resizing dynamic arrays. */
+#define KS_DOUBLE_SIZE(type, array, size, ok)				\
+{									\
+	ssize_t n = *size;						\
+	*ok = false;							\
+	type *tmp = (type *) realloc(array, 2 * n * sizeof(*tmp));	\
+	if (tmp) {							\
+		memset(tmp + n, 0, n * sizeof(*tmp));			\
+		*size = 2 * n;						\
+		array = tmp;						\
+		*ok = true;						\
+	}								\
+}									\
+
 #ifdef __cplusplus
 }
 #endif // __cplusplus
diff --git a/src/libkshark.c b/src/libkshark.c
index 315c24f..3aa3fa2 100644
--- a/src/libkshark.c
+++ b/src/libkshark.c
@@ -234,16 +234,15 @@ int kshark_add_stream(struct kshark_context *kshark_ctx)
 
 	if (kshark_ctx->stream_info.next_free_stream_id ==
 	    kshark_ctx->stream_info.array_size) {
-		size_t new_size = 2 * kshark_ctx->stream_info.array_size;
-		struct kshark_data_stream **streams_tmp;
+		bool ok;
 
-		streams_tmp = realloc(kshark_ctx->stream,
-				      new_size * sizeof(*kshark_ctx->stream));
-		if (!streams_tmp)
-			return -ENOMEM;
+		KS_DOUBLE_SIZE(struct kshark_data_stream *,
+			       kshark_ctx->stream,
+			       &kshark_ctx->stream_info.array_size,
+			       &ok);
 
-		kshark_ctx->stream = streams_tmp;
-		kshark_ctx->stream_info.array_size = new_size;
+		if (!ok)
+			return -ENOMEM;
 	}
 
 	stream = kshark_stream_alloc();
-- 
2.25.1


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

* [PATCH 2/6] kernel-shark: Add kshark_data_container to libkshark
  2021-01-06 16:11 [PATCH 0/6] kernel-shark: Visualization plugin tools Yordan Karadzhov (VMware)
  2021-01-06 16:11 ` [PATCH 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro Yordan Karadzhov (VMware)
@ 2021-01-06 16:11 ` Yordan Karadzhov (VMware)
  2021-01-06 17:38   ` Steven Rostedt
  2021-01-06 16:11 ` [PATCH 3/6] kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro Yordan Karadzhov (VMware)
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-01-06 16:11 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

We add an infrastructure for recording the data from a particular trace
event field during data loading. The goal is to avoid the use of the
expensive "read_event_field" operation in the case when the value of the
field is needed during the visualization processing (in a plugins for
example).

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/libkshark.c           | 147 ++++++++++++++++++++++++++++++++++++++
 src/libkshark.h           |  43 +++++++++++
 tests/libkshark-tests.cpp |  34 +++++++++
 3 files changed, 224 insertions(+)

diff --git a/src/libkshark.c b/src/libkshark.c
index 3aa3fa2..8722794 100644
--- a/src/libkshark.c
+++ b/src/libkshark.c
@@ -2116,3 +2116,150 @@ kshark_merge_data_matrices(struct kshark_matrix_data_set *buffers, int n_buffers
  end:
 	return merged_data;
 }
+
+/** @brief Allocate memory for kshark_data_container. */
+struct kshark_data_container *kshark_init_data_container()
+{
+	struct kshark_data_container *container;
+
+	container = calloc(1, sizeof(*container));
+	if (!container)
+		goto fail;
+
+	container->data = calloc(KS_CONTAINER_DEFAULT_SIZE,
+				  sizeof(*container->data));
+
+	if (!container->data)
+		goto fail;
+
+	container->capacity = KS_CONTAINER_DEFAULT_SIZE;
+	container->sorted = false;
+
+	return container;
+
+ fail:
+	fprintf(stderr, "Failed to allocate memory for data container.\n");
+	kshark_free_data_container(container);
+	return NULL;
+}
+
+/**
+ * @brief Free the memory allocated for a kshark_data_container
+ * @param container: Intput location for the kshark_data_container object.
+ */
+void kshark_free_data_container(struct kshark_data_container *container)
+{
+	for (ssize_t i = 0; i < container->size; ++i)
+		free(container->data[i]);
+
+	free(container->data);
+	free(container);
+}
+
+/**
+ * @brief Append data field value to a kshark_data_container
+ * @param container: Intput location for the kshark_data_container object.
+ * @param entry: The entry that needs addition data field value.
+ * @param field: The value of data field to be added.
+ *
+ * @returns The size of the container after the addition.
+ */
+ssize_t kshark_data_container_append(struct kshark_data_container *container,
+				     struct kshark_entry *entry, int64_t field)
+{
+	if (container->capacity == container->size) {
+		bool ok;
+
+		KS_DOUBLE_SIZE(struct kshark_data_field_int64 *,
+			       container->data,
+			       &container->capacity,
+			       &ok);
+
+		if (!ok)
+			return -ENOMEM;
+	}
+
+	container->data[container->size] = malloc(sizeof(container->data));
+	container->data[container->size]->entry = entry;
+	container->data[container->size++]->field = field;
+
+	return container->size;
+}
+
+static int compare_time_dc(const void* a, const void* b)
+{
+	const struct kshark_data_field_int64 *field_a, *field_b;
+
+	field_a = *(const struct kshark_data_field_int64 **) a;
+	field_b = *(const struct kshark_data_field_int64 **) b;
+
+	if (field_a->entry->ts > field_b->entry->ts)
+		return 1;
+
+	if (field_a->entry->ts < field_b->entry->ts)
+		return -1;
+
+	return 0;
+}
+
+/**
+ * @brief Sort in time the records in kshark_data_container. The container is
+ *	  resized in order to free the unused memory capacity.
+ *
+ * @param container: Intput location for the kshark_data_container object.
+ */
+void kshark_data_container_sort(struct kshark_data_container *container)
+{
+	struct kshark_data_field_int64	**data_tmp;
+
+	qsort(container->data, container->size,
+	      sizeof(struct kshark_data_field_int64 *),
+	      compare_time_dc);
+
+	container->sorted = true;
+
+	data_tmp = realloc(container->data,
+			   container->size * sizeof(*container->data));
+
+	if (!data_tmp)
+		return;
+
+	container->data = data_tmp;
+	container->capacity = container->size;
+}
+
+/**
+ * @brief Binary search inside a time-sorted array of kshark_data_field_int64.
+ *
+ * @param time: The value of time to search for.
+ * @param data: Input location for the data.
+ * @param l: Array index specifying the lower edge of the range to search in.
+ * @param h: Array index specifying the upper edge of the range to search in.
+ *
+ * @returns On success, the index of the first kshark_data_field_int64 inside
+ *	    the range, having a timestamp equal or bigger than "time".
+ *	    If all fields inside the range have timestamps greater than "time"
+ *	    the function returns BSEARCH_ALL_GREATER (negative value).
+ *	    If all fields inside the range have timestamps smaller than "time"
+ *	    the function returns BSEARCH_ALL_SMALLER (negative value).
+ */
+ssize_t kshark_find_entry_field_by_time(int64_t time,
+					struct kshark_data_field_int64 **data,
+					size_t l, size_t h)
+{
+	size_t mid;
+
+	if (data[l]->entry->ts > time)
+		return BSEARCH_ALL_GREATER;
+
+	if (data[h]->entry->ts < time)
+		return BSEARCH_ALL_SMALLER;
+
+	/*
+	 * After executing the BSEARCH macro, "l" will be the index of the last
+	 * entry having timestamp < time and "h" will be the index of the first
+	 * entry having timestamp >= time.
+	 */
+	BSEARCH(h, l, data[mid]->entry->ts < time);
+	return h;
+}
diff --git a/src/libkshark.h b/src/libkshark.h
index dd4f2b7..aa4b3ca 100644
--- a/src/libkshark.h
+++ b/src/libkshark.h
@@ -1105,6 +1105,49 @@ struct kshark_matrix_data_set
 kshark_merge_data_matrices(struct kshark_matrix_data_set *buffers,
 			   int n_buffers);
 
+/**
+ * Structure used to store the data of a kshark_entry plus one additional
+ * 64 bit integer data field.
+ */
+struct kshark_data_field_int64 {
+	/** The entry object holding the basic data of the trace record. */
+	struct kshark_entry	*entry;
+
+	/** Additional 64 bit integer data field. */
+	int64_t			field;
+};
+
+/** The capacity of the kshark_data_container object after initialization. */
+#define KS_CONTAINER_DEFAULT_SIZE	1024
+
+/** Structure used to store an array of entries and data fields. */
+struct kshark_data_container {
+	/** An array of kshark_data_field_int64 objects. */
+	struct kshark_data_field_int64	**data;
+
+	/** The total number of kshark_data_field_int64 objects stored. */
+	ssize_t		size;
+
+	/** The memory capacity of the container. */
+	ssize_t		capacity;
+
+	/** Is sorted in time. */
+	bool		sorted;
+};
+
+struct kshark_data_container *kshark_init_data_container();
+
+void kshark_free_data_container(struct kshark_data_container *container);
+
+ssize_t kshark_data_container_append(struct kshark_data_container *container,
+				     struct kshark_entry *entry, int64_t field);
+
+void kshark_data_container_sort(struct kshark_data_container *container);
+
+ssize_t kshark_find_entry_field_by_time(int64_t time,
+					struct kshark_data_field_int64 **data,
+					size_t l, size_t h);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/tests/libkshark-tests.cpp b/tests/libkshark-tests.cpp
index 27c1171..06fdf62 100644
--- a/tests/libkshark-tests.cpp
+++ b/tests/libkshark-tests.cpp
@@ -46,3 +46,37 @@ BOOST_AUTO_TEST_CASE(add_remove_streams)
 
 	kshark_close_all(kshark_ctx);
 }
+
+#define N_VALUES	2 * KS_CONTAINER_DEFAULT_SIZE + 1
+#define MAX_TS		100000
+BOOST_AUTO_TEST_CASE(fill_data_container)
+{
+	struct kshark_data_container *data = kshark_init_data_container();
+	struct kshark_entry entries[N_VALUES];
+	int64_t i, ts_last(0);
+
+	BOOST_CHECK_EQUAL(data->capacity, KS_CONTAINER_DEFAULT_SIZE);
+
+	for (i = 0; i < N_VALUES; ++i) {
+		entries[i].ts = rand() % MAX_TS;
+		kshark_data_container_append(data, &entries[i], i);
+	}
+
+	BOOST_CHECK_EQUAL(data->size, N_VALUES);
+	BOOST_CHECK_EQUAL(data->capacity, 4 * KS_CONTAINER_DEFAULT_SIZE);
+
+	kshark_data_container_sort(data);
+	BOOST_CHECK_EQUAL(data->capacity, N_VALUES);
+	for (i = 0; i < N_VALUES; ++i) {
+		BOOST_REQUIRE(data->data[i]->entry->ts >= ts_last);
+		ts_last = data->data[i]->entry->ts;
+	}
+
+	i = kshark_find_entry_field_by_time(MAX_TS / 2, data->data,
+					    0, N_VALUES -1);
+
+	BOOST_REQUIRE(data->data[i - 1]->entry->ts < MAX_TS / 2);
+	BOOST_REQUIRE(data->data[i]->entry->ts >= MAX_TS / 2);
+
+	kshark_free_data_container(data);
+}
-- 
2.25.1


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

* [PATCH 3/6] kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro
  2021-01-06 16:11 [PATCH 0/6] kernel-shark: Visualization plugin tools Yordan Karadzhov (VMware)
  2021-01-06 16:11 ` [PATCH 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro Yordan Karadzhov (VMware)
  2021-01-06 16:11 ` [PATCH 2/6] kernel-shark: Add kshark_data_container to libkshark Yordan Karadzhov (VMware)
@ 2021-01-06 16:11 ` Yordan Karadzhov (VMware)
  2021-01-06 17:45   ` Steven Rostedt
  2021-01-06 16:11 ` [PATCH 4/6] kernel-shark: Start using C++17 Yordan Karadzhov (VMware)
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-01-06 16:11 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

When we implement a KernelShark plugins, we often need a way to define
a structure that can hold context data that is visible only inside the
plugin and that has specific values for each data stream. The tricky
part here is that the total number of data streams and the IDs of the
active streams are dynamic quantities that can change as the user adds
or removes data streams. The macro defines an interface of functions
that will be useful for the plugin developer, helping to directly use
context objects, without caring for the complications due to the dynamic
configuration of active data streams.
---
 src/libkshark-plugin.h    | 43 +++++++++++++++++++++++++++++++++++++++
 tests/libkshark-tests.cpp | 32 +++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h
index f3c724f..e58d658 100644
--- a/src/libkshark-plugin.h
+++ b/src/libkshark-plugin.h
@@ -360,6 +360,49 @@ int kshark_handle_all_dpis(struct kshark_data_stream *stream,
 	}								\
 }									\
 
+/** General purpose macro defining methods for adding plugin context. */
+#define KS_DEFINE_PLUGIN_CONTEXT(type)					\
+static type **__context_handler;					\
+static ssize_t __n_streams = -1;					\
+static bool ok;								\
+static inline type *__init(int sd)					\
+{									\
+	type *obj;							\
+	if (__n_streams < 0 && sd < KS_DEFAULT_NUM_STREAMS) {		\
+		__context_handler =					\
+			(type **) calloc(KS_DEFAULT_NUM_STREAMS,	\
+					 sizeof(*__context_handler));	\
+		if (!__context_handler)					\
+			return NULL;					\
+		__n_streams = KS_DEFAULT_NUM_STREAMS;			\
+	} else if (sd >= __n_streams) {					\
+		KS_DOUBLE_SIZE(type *, __context_handler,		\
+			       &__n_streams, &ok)			\
+		if (!ok)						\
+			return NULL;					\
+	}								\
+	assert(__context_handler[sd] == NULL);				\
+	obj = (type *) calloc(1, sizeof(*obj));				\
+	__context_handler[sd] = obj;					\
+	return obj;							\
+}									\
+static inline void __close(int sd)					\
+{									\
+	if (sd < 0) {							\
+		free(__context_handler);				\
+		__n_streams = -1;					\
+		return;							\
+	}								\
+	free(__context_handler[sd]);					\
+	__context_handler[sd] = NULL;					\
+}									\
+static inline type *__get_context(int sd)				\
+{									\
+	if (sd < 0 || sd >= __n_streams)				\
+		return NULL;						\
+	return __context_handler[sd];					\
+}									\
+
 #ifdef __cplusplus
 }
 #endif // __cplusplus
diff --git a/tests/libkshark-tests.cpp b/tests/libkshark-tests.cpp
index 06fdf62..4990cdb 100644
--- a/tests/libkshark-tests.cpp
+++ b/tests/libkshark-tests.cpp
@@ -10,6 +10,7 @@
 
 // KernelShark
 #include "libkshark.h"
+#include "libkshark-plugin.h"
 
 #define N_TEST_STREAMS	1000
 
@@ -80,3 +81,34 @@ BOOST_AUTO_TEST_CASE(fill_data_container)
 
 	kshark_free_data_container(data);
 }
+
+struct test_context {
+	int a;
+	char b;
+};
+
+KS_DEFINE_PLUGIN_CONTEXT(struct test_context);
+
+BOOST_AUTO_TEST_CASE(init_close_plugin)
+{
+	struct test_context *ctx;
+	int i;
+
+	for (i = 0; i < N_TEST_STREAMS; ++i) {
+		ctx = __init(i);
+		ctx->a = i * 10;
+		ctx->b = 'z';
+	}
+
+	for (i = 0; i < N_TEST_STREAMS; ++i) {
+		ctx = __get_context(i);
+		BOOST_REQUIRE(ctx != NULL);
+		BOOST_CHECK_EQUAL(ctx->a, i * 10);
+		BOOST_CHECK_EQUAL(ctx->b, 'z');
+
+		__close(i);
+		BOOST_REQUIRE(__get_context(i) == NULL);
+	}
+
+	__close(-1);
+}
-- 
2.25.1


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

* [PATCH 4/6] kernel-shark: Start using C++17
  2021-01-06 16:11 [PATCH 0/6] kernel-shark: Visualization plugin tools Yordan Karadzhov (VMware)
                   ` (2 preceding siblings ...)
  2021-01-06 16:11 ` [PATCH 3/6] kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro Yordan Karadzhov (VMware)
@ 2021-01-06 16:11 ` Yordan Karadzhov (VMware)
  2021-01-06 16:11 ` [PATCH 5/6] kernel-shark: Add plotting methods to KsPlugins Yordan Karadzhov (VMware)
  2021-01-06 16:11 ` [PATCH 6/6] kernel-shark: Speed-up the sched_events plugin Yordan Karadzhov (VMware)
  5 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-01-06 16:11 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

Update to a more recent version of the C++ standard. The particular
motivation to do this change now is because, we would like to use
"auto" as a function parameter type for lambda functions.

Signen-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 CMakeLists.txt | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9abacd0..dd62091 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -62,8 +62,12 @@ find_package (Boost COMPONENTS unit_test_framework)
 set(LIBRARY_OUTPUT_PATH    "${KS_DIR}/lib")
 set(EXECUTABLE_OUTPUT_PATH "${KS_DIR}/bin")
 
-set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} -Wall -pthread -fPIC")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11 -pthread -fPIC")
+set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} -Wall -pthread -fPIC -fno-common")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pthread -fPIC -fno-common")
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
 
 if (NOT CMAKE_BUILD_TYPE)
     set(CMAKE_BUILD_TYPE RelWithDebInfo)
-- 
2.25.1


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

* [PATCH 5/6] kernel-shark: Add plotting methods to KsPlugins
  2021-01-06 16:11 [PATCH 0/6] kernel-shark: Visualization plugin tools Yordan Karadzhov (VMware)
                   ` (3 preceding siblings ...)
  2021-01-06 16:11 ` [PATCH 4/6] kernel-shark: Start using C++17 Yordan Karadzhov (VMware)
@ 2021-01-06 16:11 ` Yordan Karadzhov (VMware)
  2021-01-06 16:11 ` [PATCH 6/6] kernel-shark: Speed-up the sched_events plugin Yordan Karadzhov (VMware)
  5 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-01-06 16:11 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

We add generic methods for visualizing the value of a given trace
event field or the relation between two given trace event field.
Those methods are taking advantage of the stored values of the event
fields in kshark_data_container objects and allow the visualization
plugin to process the data orders of magnitude faster.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/CMakeLists.txt |   3 +-
 src/KsPlugins.cpp  | 416 +++++++++++++++++++++++++++++++++++++++++++++
 src/KsPlugins.hpp  |  48 ++++++
 3 files changed, 466 insertions(+), 1 deletion(-)
 create mode 100644 src/KsPlugins.cpp

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e35b436..588cccd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -41,7 +41,8 @@ if (OPENGL_FOUND)
 
     message(STATUS "libkshark-plot")
     add_library(kshark-plot  SHARED  libkshark-plot.c
-                                     KsPlotTools.cpp)
+                                     KsPlotTools.cpp
+                                     KsPlugins.cpp)
 
     target_link_libraries(kshark-plot  kshark
                                        ${GLUT_LIBRARY}
diff --git a/src/KsPlugins.cpp b/src/KsPlugins.cpp
new file mode 100644
index 0000000..ad9f478
--- /dev/null
+++ b/src/KsPlugins.cpp
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2019 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
+ */
+
+/**
+  *  @file    KsPlugins.cpp
+  *  @brief   KernelShark C++ plugin declarations.
+  */
+
+// C++
+#include<iostream>
+
+// KernelShark
+#include "KsPlugins.hpp"
+
+using namespace KsPlot;
+
+/**
+ * A pair of Bin Id and a trace event data field in this bin, that needs to be
+ * plotted.
+ */
+typedef std::forward_list<std::pair<int, kshark_data_field_int64 *>> PlotPointList;
+
+//! @cond Doxygen_Suppress
+
+typedef std::function<void(int, kshark_data_container *, ssize_t,
+			   PlotPointList *)> pushFunc;
+
+typedef std::function<void(kshark_data_container *, ssize_t,
+			   PlotPointList *)> resolveFunc;
+
+//! @endcond
+
+static void pointPlot(KsCppArgV *argvCpp, IsApplicableFunc isApplicable,
+		      pluginShapeFunc makeShape, Color col, float size)
+{
+	int nBins = argvCpp->_graph->size();
+
+	for (int bin = 0; bin < nBins; ++bin)
+		if (isApplicable(nullptr, bin))
+			argvCpp->_shapes->push_front(makeShape({argvCpp->_graph},
+							       {bin}, {},
+							       col, size));
+}
+
+static std::pair<ssize_t, ssize_t>
+getRange(kshark_trace_histo *histo, kshark_data_container *data)
+{
+	ssize_t firstEntry, lastEntry;
+	std::pair<ssize_t, ssize_t> err(-1, -2);
+
+	firstEntry = kshark_find_entry_field_by_time(histo->min,
+						     data->data,
+						     0,
+						     data->size - 1);
+
+	if (firstEntry == BSEARCH_ALL_SMALLER)
+		return err;
+
+	if (firstEntry == BSEARCH_ALL_GREATER)
+		firstEntry = 0;
+
+	lastEntry = kshark_find_entry_field_by_time(histo->max,
+						    data->data,
+						    firstEntry,
+						    data->size - 1);
+
+	if (lastEntry == BSEARCH_ALL_GREATER)
+		return err;
+
+	if (lastEntry == BSEARCH_ALL_SMALLER)
+		lastEntry = data->size - 1;
+
+	return {firstEntry, lastEntry};
+}
+
+static PlotPointList
+getInBinEvents(kshark_trace_histo *histo,
+	       kshark_data_container *data,
+	       IsApplicableFunc isApplicable,
+	       pushFunc push,
+	       resolveFunc resolve)
+{
+	int bin, lastBin(-1);
+	PlotPointList buffer;
+
+	auto lamIsOverflow = [] (int bin) {
+		return (bin == UPPER_OVERFLOW_BIN ||
+			bin == LOWER_OVERFLOW_BIN) ? true : false;
+	};
+
+	auto range = getRange(histo, data);
+
+	for (ssize_t i = range.second; i >= range.first; --i) {
+		if (isApplicable(data, i)) {
+			bin = ksmodel_get_bin(histo, data->data[i]->entry);
+			if (lamIsOverflow(bin))
+				continue;
+
+			if (bin != lastBin) {
+				push(bin, data, i, &buffer);
+				lastBin = bin;
+			} else {
+				resolve(data, i, &buffer);
+			}
+		}
+	}
+
+	return buffer;
+}
+
+static PlotPointList
+getLastInBinEvents(kshark_trace_histo *histo, kshark_data_container *data,
+		   IsApplicableFunc isApplicable)
+{
+	pushFunc push = [] (int bin, kshark_data_container *data, ssize_t i,
+			    PlotPointList *list) {
+		list->push_front({bin, data->data[i]});
+	};
+
+	/*
+	 * Do not resolve. This means that only the very last (in time)
+	 * appearance of the event in the bin will be visualized.
+	 */
+	resolveFunc resolve = [] (kshark_data_container *data, ssize_t i,
+				  PlotPointList *list) {};
+
+	return getInBinEvents(histo, data, isApplicable, push, resolve);
+}
+
+static PlotPointList
+getMaxInBinEvents(kshark_trace_histo *histo, kshark_data_container *data,
+		 IsApplicableFunc isApplicable)
+{
+	pushFunc push = [] (int bin, kshark_data_container *data, ssize_t i,
+			    PlotPointList *list) {
+		list->push_front({bin, data->data[i]});
+	};
+
+	/* Overwrite if bigger. */
+	resolveFunc resolve = [] (kshark_data_container *data, ssize_t i,
+				  PlotPointList *list) {
+		if (list->front().second < data->data[i])
+			list->front().second = data->data[i];
+	};
+
+	return getInBinEvents(histo, data, isApplicable, push, resolve);
+}
+
+
+static PlotPointList
+getMinInBinEvents(kshark_trace_histo *histo, kshark_data_container *data,
+		 IsApplicableFunc isApplicable)
+{
+	pushFunc push = [] (int bin, kshark_data_container *data, ssize_t i,
+			    PlotPointList *list) {
+		list->push_front({bin, data->data[i]});
+	};
+
+	/* Overwrite if smaller. */
+	resolveFunc resolve = [] (kshark_data_container *data, ssize_t i,
+				  PlotPointList *list) {
+		if (list->front().second > data->data[i])
+			list->front().second = data->data[i];
+	};
+
+	return getInBinEvents(histo, data, isApplicable, push, resolve);
+}
+
+//! @cond Doxygen_Suppress
+
+#define PLUGIN_MIN_BOX_SIZE 4
+
+//! @endcond
+
+static void intervalPlot(kshark_trace_histo *histo,
+			 kshark_data_container *dataEvtA,
+			 IsApplicableFunc checkFieldA,
+			 kshark_data_container *dataEvtB,
+			 IsApplicableFunc checkFieldB,
+			 Graph *graph,
+			 PlotObjList *shapes,
+			 pluginShapeFunc makeShape,
+			 Color col,
+			 float size)
+{
+	kshark_data_field_int64 *dataA, *dataB;
+	PlotPointList bufferA, bufferB;
+	int binA, binB;
+	int64_t tsB;
+
+	auto lamGetBin = [] (auto it) {return (*it).first;};
+
+	auto lamGetTime = [] (auto it) {return (*it).second->entry->ts;};
+
+	auto lamGetData = [] (auto it) {return (*it).second;};
+
+	bufferA = getLastInBinEvents(histo,
+				     dataEvtA,
+				     checkFieldA);
+
+	bufferB = getLastInBinEvents(histo,
+				     dataEvtB,
+				     checkFieldB);
+
+	if (bufferA.empty() || bufferB.empty())
+		return;
+
+	auto itA = bufferA.cbegin();
+	auto itB = bufferB.cbegin();
+	while (itA != bufferA.cend() && itB != bufferB.cend()) {
+		binA = lamGetBin(itA);
+		dataA = lamGetData(itA);
+
+		/*
+		 * We will draw a shape between "Event A" and "Event B".
+		 * Because the shape starts with "Event A", we will skip all
+		 * "Event B" entries before the "Event A" entry.
+		 */
+		do {
+			dataB = lamGetData(itB);
+			tsB = lamGetTime(itB);
+			binB = lamGetBin(itB);
+			itB++;
+		} while (itB != bufferB.cend() && tsB < lamGetTime(itA));
+
+		/*
+		 * The shape ends with "Event B" and we already have this
+		 * event. However, we have to make sure that we will start the
+		 * shape from the very last "Event A" entry, which is rigth
+		 * before the "Event B" entry, which we already selected.
+		 */
+		while (itA != bufferA.cend() && lamGetTime(itA) < tsB) {
+			dataA = lamGetData(itA);
+			binA = lamGetBin(itA);
+			itA++;
+		}
+
+		if (binB - binA >= PLUGIN_MIN_BOX_SIZE)
+			shapes->push_front(makeShape({graph},
+						     {binA, binB},
+						     {dataA, dataB},
+						     col, size));
+	}
+}
+
+/**
+ * @brief Generic plotting method for plugins. To be used for visualizing
+ *	  a trace events.
+ *
+ * @param argvCpp: The C++ arguments of the drawing function of the plugin.
+ * @param isApplicable: Check function used to select events from data
+ *		       container A.
+ * @param makeShape: Input location for a function pointer used to generate
+ *		     the shape to be plotted.
+ * @param col: The color of the shape to be plotted.
+ * @param size: The size of the shape to be plotted.
+ */
+void eventPlot(KsCppArgV *argvCpp,
+	       IsApplicableFunc isApplicable,
+	       pluginShapeFunc makeShape,
+	       Color col,
+	       float size)
+{
+	try {
+		pointPlot(argvCpp, isApplicable, makeShape, col, size);
+	} catch (const std::exception &exc) {
+		std::cerr << "Exception in eventPlot\n"
+			  << exc.what() << std::endl;
+	}
+}
+
+//! @cond Doxygen_Suppress
+
+enum class PlotWath {
+	Maximum,
+	Minimum,
+};
+
+//! @endcond
+
+static void eventFieldPlot(KsCppArgV *argvCpp,
+		    kshark_data_container *dataEvt,
+		    IsApplicableFunc checkField,
+		    PlotWath s,
+		    pluginShapeFunc makeShape,
+		    KsPlot::Color col,
+		    float size)
+{
+	PlotPointList buffer;
+
+	if (dataEvt->size == 0)
+		return;
+
+	if (!dataEvt->sorted)
+		kshark_data_container_sort(dataEvt);
+
+	try {
+		if (s == PlotWath::Maximum)
+			buffer = getMaxInBinEvents(argvCpp->_histo,
+						   dataEvt, checkField);
+
+		if  (s == PlotWath::Minimum)
+			buffer = getMinInBinEvents(argvCpp->_histo,
+						   dataEvt, checkField);
+
+		for (auto const &i: buffer) {
+			argvCpp->_shapes->push_front(makeShape({argvCpp->_graph},
+							       {i.first},
+							       {i.second},
+							       col, size));
+		}
+	} catch (const std::exception &exc) {
+		std::cerr << "Exception in eventFieldPlot\n"
+			  << exc.what() << std::endl;
+	}
+}
+
+/**
+ * @brief Generic plotting method for plugins. To be used for visualizing
+ *	  the value of a data fiels trace events.
+ *
+ * @param argvCpp: The C++ arguments of the drawing function of the plugin.
+ * @param dataEvt: Input location for the container of the Evant's data.
+ * @param checkField: Check function used to select events from data
+ *		       container.
+ * @param makeShape: Input location for a function pointer used to generate
+ *		     the shape to be plotted.
+ * @param col: The color of the shape to be plotted.
+ * @param size: The size of the shape to be plotted.
+ */
+void eventFieldPlotMax(KsCppArgV *argvCpp,
+		       kshark_data_container *dataEvt,
+		       IsApplicableFunc checkField,
+		       pluginShapeFunc makeShape,
+		       KsPlot::Color col,
+		       float size)
+{
+	eventFieldPlot(argvCpp, dataEvt, checkField,
+		       PlotWath::Maximum,
+		       makeShape, col, size);
+}
+
+/**
+ * @brief Generic plotting method for plugins. To be used for visualizing
+ *	  the value of a data fiels trace events.
+ *
+ * @param argvCpp: The C++ arguments of the drawing function of the plugin.
+ * @param dataEvt: Input location for the container of the Evant's data.
+ * @param checkField: check function used to select events from data
+ *		       container.
+ * @param makeShape: Input location for a function pointer used to generate
+ *		     the shape to be plotted.
+ * @param col: The color of the shape to be plotted.
+ * @param size: The size of the shape to be plotted.
+ */
+void eventFieldPlotMin(KsCppArgV *argvCpp,
+		       kshark_data_container *dataEvt,
+		       IsApplicableFunc checkField,
+		       pluginShapeFunc makeShape,
+		       KsPlot::Color col,
+		       float size)
+{
+	eventFieldPlot(argvCpp, dataEvt, checkField,
+		       PlotWath::Minimum,
+		       makeShape, col, size);
+}
+
+/**
+ * @brief Generic plotting method for plugins. To be used for visualizing
+ *	  the correlation between two trace events.
+ *
+ * @param argvCpp: The C++ arguments of the drawing function of the plugin.
+ * @param dataEvtA: Input location for the container of the Evant A data.
+ * @param checkFieldA: Check function used to select events from data
+ *		       container A.
+ * @param dataEvtB: Input location for the container of the Evant B data.
+ * @param checkFieldB: Check function used to select events from data
+ *		       container B.
+ * @param makeShape: Input location for a function pointer used to generate
+ *		     the shape to be plotted.
+ * @param col: The color of the shape to be plotted.
+ * @param size: The size of the shape to be plotted.
+ */
+void eventFieldIntervalPlot(KsCppArgV *argvCpp,
+			    kshark_data_container *dataEvtA,
+			    IsApplicableFunc checkFieldA,
+			    kshark_data_container *dataEvtB,
+			    IsApplicableFunc checkFieldB,
+			    pluginShapeFunc makeShape,
+			    KsPlot::Color col,
+			    float size)
+{
+	if (dataEvtA->size == 0 || dataEvtB->size == 0)
+		return;
+
+	if (!dataEvtA->sorted)
+		kshark_data_container_sort(dataEvtA);
+
+	if (!dataEvtB->sorted)
+		kshark_data_container_sort(dataEvtB);
+
+	try {
+		intervalPlot(argvCpp->_histo,
+			     dataEvtA, checkFieldA,
+			     dataEvtB, checkFieldB,
+			     argvCpp->_graph,
+			     argvCpp->_shapes,
+			     makeShape, col, size);
+	} catch (const std::exception &exc) {
+		std::cerr << "Exception in eventFieldIntervalPlot\n"
+			  << exc.what() << std::endl;
+	}
+}
diff --git a/src/KsPlugins.hpp b/src/KsPlugins.hpp
index 3955cdf..a19bb9d 100644
--- a/src/KsPlugins.hpp
+++ b/src/KsPlugins.hpp
@@ -12,6 +12,9 @@
 #ifndef _KS_PLUGINS_H
 #define _KS_PLUGINS_H
 
+// C++
+#include <functional>
+
 // KernelShark
 #include "libkshark-model.h"
 #include "KsPlotTools.hpp"
@@ -48,4 +51,49 @@ struct KsCppArgV {
  */
 #define KS_ARGV_TO_CPP(a) (reinterpret_cast<KsCppArgV *>(a))
 
+/**
+ * Function of this type has to be implemented by the user in order to use
+ * some of the Generic plotting method. The returned shape will be plotted
+ * by KernelShark on top of the existing Graph generated by the model.
+ */
+typedef std::function<KsPlot::PlotObject *(std::vector<const KsPlot::Graph *> graph,
+					   std::vector<int> bin,
+					   std::vector<kshark_data_field_int64 *> data,
+					   KsPlot::Color col,
+					   float size)> pluginShapeFunc;
+
+/**
+ * Function of this type has to be implemented by the user in order to use
+ * some of the Generic plotting method. The user must implement a logic
+ * deciding if the record, having a given index inside the data container has
+ * to be visualized.
+ */
+typedef std::function<bool(kshark_data_container *, ssize_t)> IsApplicableFunc;
+
+void eventPlot(KsCppArgV *argvCpp, IsApplicableFunc isApplicable,
+	       pluginShapeFunc makeShape, KsPlot::Color col, float size);
+
+void eventFieldPlotMax(KsCppArgV *argvCpp,
+		       kshark_data_container *dataEvt,
+		       IsApplicableFunc checkField,
+		       pluginShapeFunc makeShape,
+		       KsPlot::Color col,
+		       float size);
+
+void eventFieldPlotMin(KsCppArgV *argvCpp,
+		       kshark_data_container *dataEvt,
+		       IsApplicableFunc checkField,
+		       pluginShapeFunc makeShape,
+		       KsPlot::Color col,
+		       float size);
+
+void eventFieldIntervalPlot(KsCppArgV *argvCpp,
+			    kshark_data_container *dataEvtA,
+			    IsApplicableFunc checkFieldA,
+			    kshark_data_container *dataEvtB,
+			    IsApplicableFunc checkFieldB,
+			    pluginShapeFunc makeShape,
+			    KsPlot::Color col,
+			    float size);
+
 #endif
-- 
2.25.1


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

* [PATCH 6/6] kernel-shark: Speed-up the sched_events plugin
  2021-01-06 16:11 [PATCH 0/6] kernel-shark: Visualization plugin tools Yordan Karadzhov (VMware)
                   ` (4 preceding siblings ...)
  2021-01-06 16:11 ` [PATCH 5/6] kernel-shark: Add plotting methods to KsPlugins Yordan Karadzhov (VMware)
@ 2021-01-06 16:11 ` Yordan Karadzhov (VMware)
  5 siblings, 0 replies; 11+ messages in thread
From: Yordan Karadzhov (VMware) @ 2021-01-06 16:11 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov (VMware)

General revision of the sched_events plugin that achieves much faster
processing of the wake-up latency, by using the new generic methods
for visualization of event's data field.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 src/CMakeLists.txt          |   2 +-
 src/libkshark-plugin.h      |   1 +
 src/libkshark-tepdata.c     |  34 ++++
 src/libkshark-tepdata.h     |   7 +
 src/plugins/CMakeLists.txt  |  11 +-
 src/plugins/SchedEvents.cpp | 310 +++++++---------------------
 src/plugins/sched_events.c  | 393 +++++++++++-------------------------
 src/plugins/sched_events.h  |  50 ++---
 8 files changed, 260 insertions(+), 548 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 588cccd..980e802 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -135,7 +135,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
 
 endif (Qt5Widgets_FOUND AND Qt5Network_FOUND)
 
-# add_subdirectory(plugins)
+add_subdirectory(plugins)
 
 find_program(DO_AS_ROOT pkexec)
 
diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h
index e58d658..77887e5 100644
--- a/src/libkshark-plugin.h
+++ b/src/libkshark-plugin.h
@@ -19,6 +19,7 @@ extern "C" {
 // C
 #include <stdint.h>
 #include <stdbool.h>
+#include <assert.h>
 
 /* Quiet warnings over documenting simple structures */
 //! @cond Doxygen_Suppress
diff --git a/src/libkshark-tepdata.c b/src/libkshark-tepdata.c
index 724cff2..d4be052 100644
--- a/src/libkshark-tepdata.c
+++ b/src/libkshark-tepdata.c
@@ -1912,3 +1912,37 @@ int kshark_tep_find_top_stream(struct kshark_context *kshark_ctx,
 
 	return top_stream->stream_id;
 }
+
+static bool find_wakeup_event(struct tep_handle *tep, const char *wakeup_name,
+			      struct tep_event **waking_event_ptr)
+{
+	*waking_event_ptr = tep_find_event_by_name(tep, "sched", wakeup_name);
+
+	return (*waking_event_ptr)? true : false;
+}
+
+/**
+ * @brief Search the available trace events and retrieve a definition of
+ *	  a waking_event.
+ *
+ * @param tep: Input location for the the Page event object.
+ * @param waking_event_ptr: Output location for the the waking_event object.
+ *
+ * @returns True on success, otherwise False.
+ */
+bool define_wakeup_event(struct tep_handle *tep,
+			 struct tep_event **waking_event_ptr)
+{
+	bool wakeup_found;
+
+	wakeup_found = find_wakeup_event(tep, "sched_wakeup",
+					 waking_event_ptr);
+
+	wakeup_found |= find_wakeup_event(tep, "sched_wakeup_new",
+					  waking_event_ptr);
+
+	wakeup_found |= find_wakeup_event(tep, "sched_waking",
+					  waking_event_ptr);
+
+	return wakeup_found;
+}
diff --git a/src/libkshark-tepdata.h b/src/libkshark-tepdata.h
index 46b18c8..1b955be 100644
--- a/src/libkshark-tepdata.h
+++ b/src/libkshark-tepdata.h
@@ -105,6 +105,13 @@ int kshark_tep_find_top_stream(struct kshark_context *kshark_ctx,
 
 bool kshark_tep_is_top_stream(struct kshark_data_stream *stream);
 
+struct tep_event;
+
+struct tep_format_field;
+
+bool define_wakeup_event(struct tep_handle *tep,
+			 struct tep_event **wakeup_event);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index 2da73f8..108bc5f 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -20,14 +20,13 @@ 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
+list(APPEND PLUGIN_LIST "sched_events")
 
-BUILD_PLUGIN(NAME missed_events
-             SOURCE missed_events.c MissedEvents.cpp)
-list(APPEND PLUGIN_LIST "missed_events default") # This plugin will be loaded by default
+# BUILD_PLUGIN(NAME missed_events
+#              SOURCE missed_events.c MissedEvents.cpp)
+# list(APPEND PLUGIN_LIST "missed_events")
 
-install(TARGETS sched_events missed_events
+install(TARGETS ${PLUGIN_LIST}
         LIBRARY DESTINATION ${KS_PLUGIN_INSTALL_PREFIX}
         COMPONENT kernelshark)
 
diff --git a/src/plugins/SchedEvents.cpp b/src/plugins/SchedEvents.cpp
index 8408657..c85a059 100644
--- a/src/plugins/SchedEvents.cpp
+++ b/src/plugins/SchedEvents.cpp
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: LGPL-2.1
 
 /*
- * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ * Copyright (C) 2018 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
  */
 
 /**
@@ -12,180 +12,39 @@
  */
 
 // C++
-#include<iostream>
-
-// C++ 11
-#include<functional>
-#include<unordered_set>
+#include <vector>
 
 // KernelShark
 #include "libkshark.h"
+#include "libkshark-plugin.h"
 #include "plugins/sched_events.h"
 #include "KsPlotTools.hpp"
 #include "KsPlugins.hpp"
 
-//! @cond Doxygen_Suppress
-
-#define PLUGIN_MIN_BOX_SIZE 4
-
-#define KS_TASK_COLLECTION_MARGIN 25
-
-//! @endcond
-
-extern struct plugin_sched_context *plugin_sched_context_handler;
-
-/** Sched Event identifier. */
-enum class SchedEvent {
-	/** Sched Switch Event. */
-	Switch,
+using namespace KsPlot;
 
-	/** 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)
+static PlotObject *makeShape(std::vector<const Graph *> graph,
+			     std::vector<int> bins,
+			     std::vector<kshark_data_field_int64 *>,
+			     Color col, float size)
 {
-	const kshark_entry *entryClose, *entryOpen, *entryME;
-	ssize_t indexClose(0), indexOpen(0), indexME(0);
-	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;
-
-		if (e == SchedEvent::Switch) {
-			/* Red box. */
-			rec->_color = KsPlot::Color(255, 0, 0);
-		} else {
-			/* Green box. */
-			rec->_color = KsPlot::Color(0, 255, 0);
-		}
-
-		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 = p.x() - 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;
-	};
-
-	for (int bin = 0; bin < graph->size(); ++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.
-		 */
-		entryClose = ksmodel_get_entry_back(histo, bin, false,
-						 plugin_switch_match_entry_pid,
-						 pid, col, &indexClose);
-
-		entryME = ksmodel_get_task_missed_events(histo,
-							 bin, pid,
-							 col,
-							 &indexME);
-
-		if (e == SchedEvent::Switch) {
-			/*
-			 * 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_rec_pid.
-			 */
-			entryOpen =
-				ksmodel_get_entry_back(histo, bin, false,
-						       plugin_switch_match_rec_pid,
-						       pid, col, &indexOpen);
+	Rectangle *rec = new KsPlot::Rectangle;
+	Point p0 = graph[0]->bin(bins[0])._base;
+	Point p1 = graph[0]->bin(bins[1])._base;
+	int height = graph[0]->height() * .3;
 
-		} else {
-			/*
-			 * 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_rec_pid.
-			 */
-			entryOpen =
-				ksmodel_get_entry_back(histo, bin, false,
-						       plugin_wakeup_match_rec_pid,
-						       pid,
-						       col,
-						       &indexOpen);
+	rec->setFill(false);
+	rec->setPoint(0, p0.x() - 1, p0.y() - height);
+	rec->setPoint(1, p0.x() - 1, p0.y() - 1);
 
-			if (entryOpen) {
-				int cpu = ksmodel_get_cpu_back(histo, bin,
-								      pid,
-								      false,
-								      col,
-								      nullptr);
-				if (cpu >= 0) {
-					/*
-					 * The task is already running. Ignore
-					 * this wakeup event.
-					 */
-					entryOpen = nullptr;
-				}
-			}
-		}
-
-		if (rec) {
-			if (entryME || entryClose) {
-				/* Close the box in this bin. */
-				closeBox(graph->getBin(bin)._base);
-				if (entryOpen &&
-				    indexME < indexOpen &&
-				    indexClose < indexOpen) {
-					/*
-					 * We have a Sched switch entry that
-					 * comes after (in time) the closure of
-					 * the previous box. We have to open a
-					 * new box in this bin.
-					 */
-					openBox(graph->getBin(bin)._base);
-				}
-			}
-		} else {
-			if (entryOpen &&
-			    (!entryClose || indexClose < indexOpen)) {
-				/* Open a new box in this bin. */
-				openBox(graph->getBin(bin)._base);
-			}
-		}
-	}
+	rec->setPoint(3, p1.x() - 1, p1.y() - height);
+	rec->setPoint(2, p1.x() - 1, p1.y() - 1);
 
-	if (rec)
-		delete rec;
+	rec->_size = size;
+	rec->_color = col;
 
-	return;
-}
+	return rec;
+};
 
 /*
  * Ideally, the sched_switch has to be the last trace event recorded before the
@@ -199,49 +58,32 @@ static void pluginDraw(plugin_sched_context *plugin_ctx,
  * of the entry (this field is set during the first pass) to search for trailing
  * events after the "sched_switch".
  */
-static void secondPass(kshark_entry **data,
-		       kshark_entry_collection *col,
-		       int pid)
+static void secondPass(plugin_sched_context *plugin_ctx)
 {
-	if (!col)
-		return;
-
-	const kshark_entry *e;
-	kshark_entry *last;
-	int first, n;
-	ssize_t index;
-
-	/* Loop over the intervals of the data collection. */
-	for (size_t i = 0; i < col->size; ++i) {
-		first = col->break_points[i];
-		n = first - col->resume_points[i];
-
-		kshark_entry_request *req =
-			kshark_entry_request_alloc(first, n,
-						   plugin_switch_match_rec_pid,
-						   pid,
-						   false,
-						   KS_GRAPH_VIEW_FILTER_MASK);
-
-		e = kshark_get_entry_back(req, data, &index);
-		free(req);
-
-		if (!e || index < 0) {
-			/* No sched_switch event in this interval. */
+	kshark_data_container *cSS;
+	kshark_entry *e;
+	int pid_rec;
+
+	cSS = plugin_ctx->ss_data;
+	for (ssize_t i = 0; i < cSS->size; ++i) {
+		pid_rec = plugin_sched_get_pid(cSS->data[i]->field);
+		e = cSS->data[i]->entry;
+		if (!e->next || e->pid == 0 ||
+		    e->event_id == e->next->event_id ||
+		    pid_rec != e->next->pid)
 			continue;
-		}
 
 		/* Find the very last trailing event. */
-		for (last = data[index]; last->next; last = last->next) {
-			if (last->next->pid != pid) {
+		for (; e->next; e = e->next) {
+			if (e->next->pid != plugin_sched_get_pid(cSS->data[i]->field)) {
 				/*
 				 * This is the last trailing event. Change the
 				 * "pid" to be equal to the "next pid" of the
 				 * sched_switch event and leave a sign that you
 				 * edited this entry.
 				 */
-				last->pid = data[index]->pid;
-				last->visible &= ~KS_PLUGIN_UNTOUCHED_MASK;
+				e->pid = cSS->data[i]->entry->pid;
+				e->visible &= ~KS_PLUGIN_UNTOUCHED_MASK;
 				break;
 			}
 		}
@@ -252,62 +94,56 @@ static void secondPass(kshark_entry **data,
  * @brief Plugin's draw function.
  *
  * @param argv_c: A C pointer to be converted to KsCppArgV (C++ struct).
+ * @param sd: Data stream identifier.
  * @param pid: Process Id.
  * @param draw_action: Draw action identifier.
  */
-void plugin_draw(kshark_cpp_argv *argv_c, int pid, int draw_action)
+void plugin_draw(kshark_cpp_argv *argv_c, int sd, 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)
+	if (!(draw_action & KSHARK_TASK_DRAW) || pid == 0)
 		return;
 
-	plugin_ctx = plugin_sched_context_handler;
-	if (!plugin_ctx || !kshark_instance(&kshark_ctx))
+	plugin_ctx = __get_context(sd);
+	if (!plugin_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(plugin_ctx->collections,
-					  plugin_match_pid, pid);
-	if (!col) {
-		/*
-		 * If a data collection for this task does not exist,
-		 * register a new one.
-		 */
-		kshark_entry **data = argvCpp->_histo->data;
-		int size = argvCpp->_histo->data_size;
-
-		col = kshark_add_collection_to_list(kshark_ctx,
-						    &plugin_ctx->collections,
-						    data, size,
-						    plugin_match_pid, pid,
-						    KS_TASK_COLLECTION_MARGIN);
+	if (!plugin_ctx->second_pass_done) {
+		/* The second pass is not done yet. */
+		secondPass(plugin_ctx);
+		plugin_ctx->second_pass_done = true;
 	}
 
-	if (!tracecmd_filter_id_find(plugin_ctx->second_pass_hash, pid)) {
-		/* The second pass for this task is not done yet. */
-		secondPass(argvCpp->_histo->data, col, pid);
-		tracecmd_filter_id_add(plugin_ctx->second_pass_hash, pid);
-	}
+	IsApplicableFunc checkFieldSW = [=] (kshark_data_container *d,
+					     ssize_t i) {
+		return d->data[i]->field == pid;
+	};
 
-	try {
-		pluginDraw(plugin_ctx, kshark_ctx,
-			   argvCpp->_histo, col,
-			   SchedEvent::Wakeup, pid,
-			   argvCpp->_graph, argvCpp->_shapes);
+	IsApplicableFunc checkFieldSS = [=] (kshark_data_container *d,
+					     ssize_t i) {
+		return !(plugin_sched_get_prev_state(d->data[i]->field) & 0x7f) &&
+		       plugin_sched_get_pid(d->data[i]->field) == pid;
+	};
 
-		pluginDraw(plugin_ctx, kshark_ctx,
-			   argvCpp->_histo, col,
-			   SchedEvent::Switch, pid,
-			   argvCpp->_graph, argvCpp->_shapes);
-	} catch (const std::exception &exc) {
-		std::cerr << "Exception in SchedEvents\n" << exc.what();
-	}
+	IsApplicableFunc checkEntryPid = [=] (kshark_data_container *d,
+					      ssize_t i) {
+		return d->data[i]->entry->pid == pid;
+	};
+
+	eventFieldIntervalPlot(argvCpp,
+			       plugin_ctx->sw_data, checkFieldSW,
+			       plugin_ctx->ss_data, checkEntryPid,
+			       makeShape,
+			       {0, 255, 0}, // Green
+			       -1);         // Default size
+
+	eventFieldIntervalPlot(argvCpp,
+			       plugin_ctx->ss_data, checkFieldSS,
+			       plugin_ctx->ss_data, checkEntryPid,
+			       makeShape,
+			       {255, 0, 0}, // Red
+			       -1);         // Default size
 }
diff --git a/src/plugins/sched_events.c b/src/plugins/sched_events.c
index d0fd15e..1596880 100644
--- a/src/plugins/sched_events.c
+++ b/src/plugins/sched_events.c
@@ -1,85 +1,92 @@
 // SPDX-License-Identifier: LGPL-2.1
 
 /*
- * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ * Copyright (C) 2018 VMware Inc, Yordan Karadzhov (VMware) <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.
+ *  @brief
  */
 
 // C
 #include <stdlib.h>
 #include <stdio.h>
-#include <assert.h>
+
+// trace-cmd
+#include "trace-cmd/trace-cmd.h"
 
 // KernelShark
 #include "plugins/sched_events.h"
+#include "libkshark-tepdata.h"
 
 /** Plugin context instance. */
-struct plugin_sched_context *plugin_sched_context_handler = NULL;
 
-static bool define_wakeup_event(struct tep_handle *tep, const char *wakeup_name,
-				struct tep_event **wakeup_event,
-				struct tep_format_field **pid_field)
-{
-	struct tep_event *event;
+//! @cond Doxygen_Suppress
 
-	event = tep_find_event_by_name(tep, "sched", wakeup_name);
-	if (!event)
-		return false;
+typedef unsigned long long tep_num_field_t;
 
-	*wakeup_event = event;
-	*pid_field = tep_find_any_field(event, "pid");
+#define PREV_STATE_SHIFT	((int) ((sizeof(ks_num_field_t) - 1) * 8))
 
-	return true;
+#define PREV_STATE_MASK		(((ks_num_field_t) 1 << 8) - 1)
+
+#define PID_MASK		(((ks_num_field_t) 1 << PREV_STATE_SHIFT) - 1)
+
+//! @endcond
+
+static void plugin_sched_set_pid(ks_num_field_t *field,
+				 tep_num_field_t pid)
+{
+	*field &= ~PID_MASK;
+	*field = pid & PID_MASK;
 }
 
-static void plugin_free_context(struct plugin_sched_context *plugin_ctx)
+/**
+ * @brief Retrieve the PID value from the data field stored in the
+ *	  kshark_data_container object.
+ *
+ * @param field: Input location for the data field.
+ */
+int plugin_sched_get_pid(ks_num_field_t field)
 {
-	if (!plugin_ctx)
-		return;
+	return field & PID_MASK;
+}
 
-	tracecmd_filter_id_hash_free(plugin_ctx->second_pass_hash);
-	kshark_free_collection_list(plugin_ctx->collections);
+/* Use the most significant byte to store the value of "prev_state". */
+static void plugin_sched_set_prev_state(ks_num_field_t *field,
+					tep_num_field_t prev_state)
+{
+	tep_num_field_t mask = PREV_STATE_MASK << PREV_STATE_SHIFT;
+	*field &= ~mask;
+	*field |= (prev_state & PREV_STATE_MASK) << PREV_STATE_SHIFT;
+}
 
-	free(plugin_ctx);
+/**
+ * @brief Retrieve the "prev_state" value from the data field stored in the
+ *	  kshark_data_container object.
+ *
+ * @param field: Input location for the data field.
+ */
+int plugin_sched_get_prev_state(ks_num_field_t field)
+{
+	tep_num_field_t mask = PREV_STATE_MASK << PREV_STATE_SHIFT;
+	return (field & mask) >> PREV_STATE_SHIFT;
 }
 
-static bool plugin_sched_init_context(struct kshark_context *kshark_ctx)
+static bool plugin_sched_init_context(struct kshark_data_stream *stream,
+				      struct plugin_sched_context *plugin_ctx)
 {
-	struct plugin_sched_context *plugin_ctx;
 	struct tep_event *event;
 	bool wakeup_found;
 
-	/* No context should exist when we initialize the plugin. */
-	assert(plugin_sched_context_handler == NULL);
-
-	plugin_sched_context_handler =
-		calloc(1, sizeof(*plugin_sched_context_handler));
-	if (!plugin_sched_context_handler) {
-		fprintf(stderr,
-			"Failed to allocate memory for plugin_sched_context.\n");
+	if (!kshark_is_tep(stream))
 		return false;
-	}
 
-	plugin_ctx = plugin_sched_context_handler;
-	plugin_ctx->handle = kshark_ctx->handle;
-	plugin_ctx->pevent = kshark_ctx->pevent;
-	plugin_ctx->collections = NULL;
-
-	event = tep_find_event_by_name(plugin_ctx->pevent,
+	plugin_ctx->tep = kshark_get_tep(stream);
+	event = tep_find_event_by_name(plugin_ctx->tep,
 				       "sched", "sched_switch");
-	if (!event) {
-		plugin_free_context(plugin_ctx);
-		plugin_sched_context_handler = NULL;
-
+	if (!event)
 		return false;
-	}
 
 	plugin_ctx->sched_switch_event = event;
 	plugin_ctx->sched_switch_next_field =
@@ -91,277 +98,121 @@ static bool plugin_sched_init_context(struct kshark_context *kshark_ctx)
 	plugin_ctx->sched_switch_prev_state_field =
 		tep_find_field(event, "prev_state");
 
+	wakeup_found = define_wakeup_event(plugin_ctx->tep,
+					   &plugin_ctx->sched_waking_event);
 
-	wakeup_found = define_wakeup_event(kshark_ctx->pevent, "sched_wakeup",
-					   &plugin_ctx->sched_wakeup_event,
-					   &plugin_ctx->sched_wakeup_pid_field);
-
-	wakeup_found |= define_wakeup_event(kshark_ctx->pevent, "sched_wakeup_new",
-					   &plugin_ctx->sched_wakeup_new_event,
-					   &plugin_ctx->sched_wakeup_new_pid_field);
+	if (wakeup_found) {
+		plugin_ctx->sched_waking_pid_field =
+			tep_find_any_field(plugin_ctx->sched_waking_event, "pid");
+	}
 
-	wakeup_found |= define_wakeup_event(kshark_ctx->pevent, "sched_waking",
-					   &plugin_ctx->sched_waking_event,
-					   &plugin_ctx->sched_waking_pid_field);
+	plugin_ctx->second_pass_done = false;
 
-	plugin_ctx->second_pass_hash = tracecmd_filter_id_hash_alloc();
+	plugin_ctx->ss_data = kshark_init_data_container();
+	plugin_ctx->sw_data = kshark_init_data_container();
+	if (!plugin_ctx->ss_data ||
+	    !plugin_ctx->sw_data)
+		return false;
 
 	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)
+static void plugin_sched_swith_action(struct kshark_data_stream *stream,
+				      void *rec, struct kshark_entry *entry)
 {
-	struct plugin_sched_context *plugin_ctx =
-		plugin_sched_context_handler;
-	unsigned long long val;
+	struct tep_record *record = (struct tep_record *) rec;
+	struct plugin_sched_context *plugin_ctx;
+	unsigned long long next_pid, prev_state;
+	ks_num_field_t ks_field;
 	int ret;
 
-	ret = tep_read_number_field(plugin_ctx->sched_switch_next_field,
-				    record->data, &val);
-
-	return ret ? : 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)
+	plugin_ctx = __get_context(stream->stream_id);
+	if (!plugin_ctx)
 		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_is_pid_registered(kshark_ctx->pevent, pid))
-			tep_register_comm(kshark_ctx->pevent, comm, pid);
-}
-
-static int find_wakeup_pid(struct kshark_context *kshark_ctx, struct kshark_entry *e,
-		    struct tep_event *wakeup_event, struct tep_format_field *pid_field)
-{
-	struct tep_record *record;
-	unsigned long long val;
-	int ret;
-
-	if (!wakeup_event || e->event_id != wakeup_event->id)
-		return -1;
+	ret = tep_read_number_field(plugin_ctx->sched_switch_next_field,
+				    record->data, &next_pid);
 
-	record = tracecmd_read_at(kshark_ctx->handle, e->offset, NULL);
-	ret = tep_read_number_field(pid_field, record->data, &val);
-	free_record(record);
+	if (ret == 0 && next_pid >= 0) {
+		plugin_sched_set_pid(&ks_field, entry->pid);
 
-	if (ret)
-		return -1;
+		ret = tep_read_number_field(plugin_ctx->sched_switch_prev_state_field,
+					    record->data, &prev_state);
 
-	return val;
-}
+		if (ret == 0)
+			plugin_sched_set_prev_state(&ks_field, prev_state);
 
-static bool wakeup_match_rec_pid(struct plugin_sched_context *plugin_ctx,
-				 struct kshark_context *kshark_ctx,
-				 struct kshark_entry *e,
-				 int pid)
-{
-	struct tep_event *wakeup_events[] = {
-		plugin_ctx->sched_waking_event,
-		plugin_ctx->sched_wakeup_event,
-		plugin_ctx->sched_wakeup_new_event,
-	};
-	struct tep_format_field *wakeup_fields[] = {
-		plugin_ctx->sched_waking_pid_field,
-		plugin_ctx->sched_wakeup_pid_field,
-		plugin_ctx->sched_wakeup_new_pid_field,
-	};
-	int i, wakeup_pid = -1;
-
-	for (i = 0; i < sizeof(wakeup_events) / sizeof(wakeup_events[0]); i++) {
-		wakeup_pid = find_wakeup_pid(kshark_ctx, e, wakeup_events[i], wakeup_fields[i]);
-		if (wakeup_pid >= 0)
-			break;
+		kshark_data_container_append(plugin_ctx->ss_data, entry, ks_field);
+		entry->pid = next_pid;
 	}
-
-	if (wakeup_pid >= 0 && wakeup_pid == pid)
-		return true;
-
-	return false;
-}
-
-/**
- * @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 record matches the value of "pid".
- *	    Otherwise false.
- */
-bool plugin_wakeup_match_rec_pid(struct kshark_context *kshark_ctx,
-				 struct kshark_entry *e,
-				 int pid)
-{
-	struct plugin_sched_context *plugin_ctx;
-
-	plugin_ctx = plugin_sched_context_handler;
-	if (!plugin_ctx)
-		return false;
-
-	return wakeup_match_rec_pid(plugin_ctx, kshark_ctx, e, pid);
 }
 
-/**
- * @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 record matches the value of "pid".
- *	    Otherwise false.
- */
-bool plugin_switch_match_rec_pid(struct kshark_context *kshark_ctx,
-				 struct kshark_entry *e,
-				 int pid)
+static void plugin_sched_wakeup_action(struct kshark_data_stream *stream,
+				       void *rec, struct kshark_entry *entry)
 {
+	struct tep_record *record = (struct tep_record *) rec;
 	struct plugin_sched_context *plugin_ctx;
 	unsigned long long val;
-	int ret, switch_pid = -1;
-
-	plugin_ctx = plugin_sched_context_handler;
-
-	if (plugin_ctx->sched_switch_event &&
-	    e->event_id == plugin_ctx->sched_switch_event->id) {
-		struct tep_record *record;
-
-		record = tracecmd_read_at(kshark_ctx->handle, e->offset, NULL);
-		ret = tep_read_number_field(plugin_ctx->sched_switch_prev_state_field,
-					    record->data, &val);
-
-		if (ret == 0 && !(val & 0x7f))
-			switch_pid = tep_data_pid(plugin_ctx->pevent, record);
+	int ret;
 
-		free_record(record);
-	}
+	plugin_ctx = __get_context(stream->stream_id);
+	if (!plugin_ctx)
+		return;
 
-	if (switch_pid >= 0 && switch_pid == pid)
-		return true;
+	ret = tep_read_number_field(plugin_ctx->sched_waking_pid_field,
+				    record->data, &val);
 
-	return false;
+	if (ret == 0)
+		kshark_data_container_append(plugin_ctx->sw_data, entry, val);
 }
 
-/**
- * @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_entry_pid(struct kshark_context *kshark_ctx,
-				   struct kshark_entry *e,
-				   int pid)
+/** Load this plugin. */
+int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream)
 {
+	printf("--> sched init %i\n", stream->stream_id);
 	struct plugin_sched_context *plugin_ctx;
 
-	plugin_ctx = plugin_sched_context_handler;
-
-	if (plugin_ctx->sched_switch_event &&
-	    e->event_id == plugin_ctx->sched_switch_event->id &&
-	    e->pid == pid)
-		return true;
-
-	return false;
-}
-
-/**
- * @brief A match function to be used to process a data collections for
- *	  the Sched events plugin.
- *
- * @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 entry is relevant for the Sched events plugin.
- *	    Otherwise false.
- */
-bool plugin_match_pid(struct kshark_context *kshark_ctx,
-		      struct kshark_entry *e, int pid)
-{
-	return plugin_switch_match_entry_pid(kshark_ctx, e, pid) ||
-	       plugin_switch_match_rec_pid(kshark_ctx, e, pid) ||
-	       plugin_wakeup_match_rec_pid(kshark_ctx, e, pid);
-}
-
-static void plugin_sched_action(struct kshark_context *kshark_ctx,
-				struct tep_record *rec,
-				struct kshark_entry *entry)
-{
-	int pid = plugin_get_next_pid(rec);
-	if (pid >= 0) {
-		entry->pid = pid;
-		plugin_register_command(kshark_ctx, rec, entry->pid);
+	plugin_ctx = __init(stream->stream_id);
+	if (!plugin_ctx || !plugin_sched_init_context(stream, plugin_ctx)) {
+		__close(stream->stream_id);
+		return 0;
 	}
-}
-
-static int plugin_sched_init(struct kshark_context *kshark_ctx)
-{
-	struct plugin_sched_context *plugin_ctx;
 
-	if (!plugin_sched_init_context(kshark_ctx))
-		return 0;
+	kshark_register_event_handler(stream,
+				      plugin_ctx->sched_switch_event->id,
+				      plugin_sched_swith_action);
 
-	plugin_ctx = plugin_sched_context_handler;
+	kshark_register_event_handler(stream,
+				      plugin_ctx->sched_waking_event->id,
+				      plugin_sched_wakeup_action);
 
-	kshark_register_event_handler(&kshark_ctx->event_handlers,
-				      plugin_ctx->sched_switch_event->id,
-				      plugin_sched_action,
-				      plugin_draw);
+	kshark_register_draw_handler(stream, plugin_draw);
 
 	return 1;
 }
 
-static int plugin_sched_close(struct kshark_context *kshark_ctx)
+/** Unload this plugin. */
+int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream)
 {
+	printf("<-- sched close %i\n", stream->stream_id);
 	struct plugin_sched_context *plugin_ctx;
+	int sd = stream->stream_id;
 
-	if (!plugin_sched_context_handler)
+	plugin_ctx = __get_context(sd);
+	if (!plugin_ctx)
 		return 0;
 
-	plugin_ctx = plugin_sched_context_handler;
-
-	kshark_unregister_event_handler(&kshark_ctx->event_handlers,
+	kshark_unregister_event_handler(stream,
 					plugin_ctx->sched_switch_event->id,
-					plugin_sched_action,
-					plugin_draw);
+					plugin_sched_swith_action);
 
-	plugin_free_context(plugin_ctx);
-	plugin_sched_context_handler = NULL;
+	kshark_unregister_event_handler(stream,
+					plugin_ctx->sched_waking_event->id,
+					plugin_sched_wakeup_action);
 
-	return 1;
-}
+	kshark_unregister_draw_handler(stream, plugin_draw);
 
-/** Load this plugin. */
-int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx)
-{
-	return plugin_sched_init(kshark_ctx);
-}
+	__close(sd);
 
-/** Unload this plugin. */
-int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx)
-{
-	return plugin_sched_close(kshark_ctx);
+	return 1;
 }
diff --git a/src/plugins/sched_events.h b/src/plugins/sched_events.h
index dbc9963..4c57606 100644
--- a/src/plugins/sched_events.h
+++ b/src/plugins/sched_events.h
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1 */
 
 /*
- * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
  */
 
 /**
@@ -14,6 +14,7 @@
 
 // KernelShark
 #include "libkshark.h"
+#include "libkshark-plugin.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -21,11 +22,8 @@ extern "C" {
 
 /** 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;
+	struct tep_handle	*tep;
 
 	/** Pointer to the sched_switch_event object. */
 	struct tep_event	*sched_switch_event;
@@ -39,47 +37,33 @@ struct plugin_sched_context {
 	/** Pointer to the sched_switch_prev_state_field format descriptor. */
 	struct tep_format_field	*sched_switch_prev_state_field;
 
-	/** Pointer to the sched_wakeup_event object. */
-	struct tep_event	*sched_wakeup_event;
-
-	/** Pointer to the sched_wakeup_pid_field format descriptor. */
-	struct tep_format_field	*sched_wakeup_pid_field;
-
-	/** Pointer to the sched_wakeup_new_event object. */
-	struct tep_event	*sched_wakeup_new_event;
-
-	/** Pointer to the sched_wakeup_new_pid_field format descriptor. */
-	struct tep_format_field	*sched_wakeup_new_pid_field;
-
 	/** Pointer to the sched_waking_event object. */
 	struct tep_event        *sched_waking_event;
 
 	/** Pointer to the sched_waking_pid_field format descriptor. */
 	struct tep_format_field *sched_waking_pid_field;
 
-	/** List of Data collections used by this plugin. */
-	struct kshark_entry_collection	*collections;
+	/** True if the second pass is already done. */
+	bool	second_pass_done;
 
-	/** Hash of the tasks for which the second pass is already done. */
-	struct tracecmd_filter_id	*second_pass_hash;
-};
+	/** Data container for sched_switch data. */
+	struct kshark_data_container	*ss_data;
 
-int plugin_get_next_pid(struct tep_record *record);
+	/** Data container for sched_waking data. */
+	struct kshark_data_container	*sw_data;
+};
 
-bool plugin_wakeup_match_rec_pid(struct kshark_context *kshark_ctx,
-				 struct kshark_entry *e, int pid);
+KS_DEFINE_PLUGIN_CONTEXT(struct plugin_sched_context);
 
-bool plugin_switch_match_rec_pid(struct kshark_context *kshark_ctx,
-				 struct kshark_entry *e, int pid);
+/** The type of the data field stored in the kshark_data_container object. */
+typedef int64_t ks_num_field_t;
 
-bool plugin_switch_match_entry_pid(struct kshark_context *kshark_ctx,
-				   struct kshark_entry *e,
-				   int pid);
+int plugin_sched_get_pid(ks_num_field_t field);
 
-bool plugin_match_pid(struct kshark_context *kshark_ctx,
-		      struct kshark_entry *e, int pid);
+int plugin_sched_get_prev_state(ks_num_field_t field);
 
-void plugin_draw(struct kshark_cpp_argv *argv, int pid, int draw_action);
+void plugin_draw(struct kshark_cpp_argv *argv, int sd, int pid,
+		 int draw_action);
 
 #ifdef __cplusplus
 }
-- 
2.25.1


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

* Re: [PATCH 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro
  2021-01-06 16:11 ` [PATCH 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro Yordan Karadzhov (VMware)
@ 2021-01-06 17:02   ` Steven Rostedt
  2021-01-06 17:28     ` Steven Rostedt
  0 siblings, 1 reply; 11+ messages in thread
From: Steven Rostedt @ 2021-01-06 17:02 UTC (permalink / raw)
  To: Yordan Karadzhov (VMware); +Cc: linux-trace-devel

On Wed,  6 Jan 2021 18:11:15 +0200
"Yordan Karadzhov (VMware)" <y.karadz@gmail.com> wrote:

> The macro is useful for resizing of dynamic arrays. It is currently
> used to resize the Data stream descriptor array, owned by the session
> context. We will later use the macro with the arrays of data fields and
> plugin contexts.
> 
> Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
> ---
>  src/libkshark-plugin.h | 14 ++++++++++++++
>  src/libkshark.c        | 15 +++++++--------
>  2 files changed, 21 insertions(+), 8 deletions(-)
> 
> diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h
> index 1a642ad..f3c724f 100644
> --- a/src/libkshark-plugin.h
> +++ b/src/libkshark-plugin.h
> @@ -346,6 +346,20 @@ int kshark_handle_dpi(struct kshark_data_stream *stream,
>  int kshark_handle_all_dpis(struct kshark_data_stream *stream,
>  			   enum kshark_plugin_actions  task_id);
>  
> +/** General purpose macro for resizing dynamic arrays. */

Perhaps make this into a static inline function?

> +#define KS_DOUBLE_SIZE(type, array, size, ok)				\
> +{									\
> +	ssize_t n = *size;						\
> +	*ok = false;							\

As a macro, ok does not need to be passed in as an address.

> +	type *tmp = (type *) realloc(array, 2 * n * sizeof(*tmp));	\
> +	if (tmp) {							\
> +		memset(tmp + n, 0, n * sizeof(*tmp));			\
> +		*size = 2 * n;						\

as a macro you do not need to pass in the address. If you are going to do
that, then please make this into a static inline function.

> +		array = tmp;						\
> +		*ok = true;						\

I would get rid of the ok, and just have this return true or false.

FYI, as a macro, to return a value you have:

#define foo() ({ return true; })

Which would then return a true value.

-- Steve

> +	}								\
> +}									\
> +
>  #ifdef __cplusplus
>  }
>  #endif // __cplusplus
> diff --git a/src/libkshark.c b/src/libkshark.c
> index 315c24f..3aa3fa2 100644
> --- a/src/libkshark.c
> +++ b/src/libkshark.c
> @@ -234,16 +234,15 @@ int kshark_add_stream(struct kshark_context *kshark_ctx)
>  
>  	if (kshark_ctx->stream_info.next_free_stream_id ==
>  	    kshark_ctx->stream_info.array_size) {
> -		size_t new_size = 2 * kshark_ctx->stream_info.array_size;
> -		struct kshark_data_stream **streams_tmp;
> +		bool ok;
>  
> -		streams_tmp = realloc(kshark_ctx->stream,
> -				      new_size * sizeof(*kshark_ctx->stream));
> -		if (!streams_tmp)
> -			return -ENOMEM;
> +		KS_DOUBLE_SIZE(struct kshark_data_stream *,
> +			       kshark_ctx->stream,
> +			       &kshark_ctx->stream_info.array_size,
> +			       &ok);
>  
> -		kshark_ctx->stream = streams_tmp;
> -		kshark_ctx->stream_info.array_size = new_size;
> +		if (!ok)
> +			return -ENOMEM;
>  	}
>  
>  	stream = kshark_stream_alloc();


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

* Re: [PATCH 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro
  2021-01-06 17:02   ` Steven Rostedt
@ 2021-01-06 17:28     ` Steven Rostedt
  0 siblings, 0 replies; 11+ messages in thread
From: Steven Rostedt @ 2021-01-06 17:28 UTC (permalink / raw)
  To: Yordan Karadzhov (VMware); +Cc: linux-trace-devel

On Wed, 6 Jan 2021 12:02:08 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Wed,  6 Jan 2021 18:11:15 +0200
> "Yordan Karadzhov (VMware)" <y.karadz@gmail.com> wrote:
> 
> > The macro is useful for resizing of dynamic arrays. It is currently
> > used to resize the Data stream descriptor array, owned by the session
> > context. We will later use the macro with the arrays of data fields and
> > plugin contexts.
> > 
> > Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
> > ---
> >  src/libkshark-plugin.h | 14 ++++++++++++++
> >  src/libkshark.c        | 15 +++++++--------
> >  2 files changed, 21 insertions(+), 8 deletions(-)
> > 
> > diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h
> > index 1a642ad..f3c724f 100644
> > --- a/src/libkshark-plugin.h
> > +++ b/src/libkshark-plugin.h
> > @@ -346,6 +346,20 @@ int kshark_handle_dpi(struct kshark_data_stream *stream,
> >  int kshark_handle_all_dpis(struct kshark_data_stream *stream,
> >  			   enum kshark_plugin_actions  task_id);
> >  
> > +/** General purpose macro for resizing dynamic arrays. */  
> 
> Perhaps make this into a static inline function?

Never mind, I see you need the macro due to the "type" field. But we can
shorten this with:

   #define KS_DOUBLE_SIZE(array, size)				\
   ({								\
	ssize_t n = size;					\
	typeof(array) _tmp_ = (typeof(array)) realloc(array, 2 * n * \
                               sizeof(*_tmp_));			\
	if (_tmp_) {						\
		memset(_tmp_ + n, 0, n * sizeof(*_tmp_));	\
		size = 2 * n;					\
		array = _tmp_;					\
		true;						\
	}							\
	false;							\
   })

> FYI, as a macro, to return a value you have:
> 
> #define foo() ({ return true; })

The above is wrong, it should have been:

  #define foo() ({ true; })

-- Steve

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

* Re: [PATCH 2/6] kernel-shark: Add kshark_data_container to libkshark
  2021-01-06 16:11 ` [PATCH 2/6] kernel-shark: Add kshark_data_container to libkshark Yordan Karadzhov (VMware)
@ 2021-01-06 17:38   ` Steven Rostedt
  0 siblings, 0 replies; 11+ messages in thread
From: Steven Rostedt @ 2021-01-06 17:38 UTC (permalink / raw)
  To: Yordan Karadzhov (VMware); +Cc: linux-trace-devel

On Wed,  6 Jan 2021 18:11:16 +0200
"Yordan Karadzhov (VMware)" <y.karadz@gmail.com> wrote:

> We add an infrastructure for recording the data from a particular trace
> event field during data loading. The goal is to avoid the use of the
> expensive "read_event_field" operation in the case when the value of the
> field is needed during the visualization processing (in a plugins for

			"in plugins for example"

> example).
> 
> Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
> ---
>  src/libkshark.c           | 147 ++++++++++++++++++++++++++++++++++++++
>  src/libkshark.h           |  43 +++++++++++
>  tests/libkshark-tests.cpp |  34 +++++++++
>  3 files changed, 224 insertions(+)
> 
> diff --git a/src/libkshark.c b/src/libkshark.c
> index 3aa3fa2..8722794 100644
> --- a/src/libkshark.c
> +++ b/src/libkshark.c
> @@ -2116,3 +2116,150 @@ kshark_merge_data_matrices(struct kshark_matrix_data_set *buffers, int n_buffers
>   end:
>  	return merged_data;
>  }
> +
> +/** @brief Allocate memory for kshark_data_container. */
> +struct kshark_data_container *kshark_init_data_container()
> +{
> +	struct kshark_data_container *container;
> +
> +	container = calloc(1, sizeof(*container));
> +	if (!container)
> +		goto fail;

Note, we goto fail on failed allocation.

> +
> +	container->data = calloc(KS_CONTAINER_DEFAULT_SIZE,
> +				  sizeof(*container->data));
> +
> +	if (!container->data)
> +		goto fail;
> +
> +	container->capacity = KS_CONTAINER_DEFAULT_SIZE;
> +	container->sorted = false;
> +
> +	return container;
> +
> + fail:
> +	fprintf(stderr, "Failed to allocate memory for data container.\n");
> +	kshark_free_data_container(container);

We call kshark_free_data_container(container) where container could equal
NULL.

> +	return NULL;
> +}
> +
> +/**
> + * @brief Free the memory allocated for a kshark_data_container
> + * @param container: Intput location for the kshark_data_container object.
> + */
> +void kshark_free_data_container(struct kshark_data_container *container)
> +{

Need a check here of:

	if (!container)
		return;

> +	for (ssize_t i = 0; i < container->size; ++i)

Otherwise, the above will crash.

> +		free(container->data[i]);
> +
> +	free(container->data);
> +	free(container);
> +}
> +
> +/**
> + * @brief Append data field value to a kshark_data_container
> + * @param container: Intput location for the kshark_data_container object.

                        "Input"

> + * @param entry: The entry that needs addition data field value.
> + * @param field: The value of data field to be added.
> + *
> + * @returns The size of the container after the addition.
> + */
> +ssize_t kshark_data_container_append(struct kshark_data_container *container,
> +				     struct kshark_entry *entry, int64_t field)
> +{
> +	if (container->capacity == container->size) {
> +		bool ok;
> +
> +		KS_DOUBLE_SIZE(struct kshark_data_field_int64 *,
> +			       container->data,
> +			       &container->capacity,
> +			       &ok);
> +
> +		if (!ok)
> +			return -ENOMEM;

By changing the KS_DOUBLE_SIZE to what I recommended, you could shorten the
above to just:

		if (!KS_DOUBLE_SIZE(container->data, container->capacity)
			return -ENOMEM;

> +	}
> +
> +	container->data[container->size] = malloc(sizeof(container->data));

			sizeof(container->data[0]) ?

> +	container->data[container->size]->entry = entry;
> +	container->data[container->size++]->field = field;
> +
> +	return container->size;
> +}
> +
> +static int compare_time_dc(const void* a, const void* b)
> +{
> +	const struct kshark_data_field_int64 *field_a, *field_b;
> +
> +	field_a = *(const struct kshark_data_field_int64 **) a;
> +	field_b = *(const struct kshark_data_field_int64 **) b;
> +
> +	if (field_a->entry->ts > field_b->entry->ts)
> +		return 1;
> +
> +	if (field_a->entry->ts < field_b->entry->ts)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +/**
> + * @brief Sort in time the records in kshark_data_container. The container is
> + *	  resized in order to free the unused memory capacity.
> + *
> + * @param container: Intput location for the kshark_data_container object.
> + */
> +void kshark_data_container_sort(struct kshark_data_container *container)
> +{
> +	struct kshark_data_field_int64	**data_tmp;
> +
> +	qsort(container->data, container->size,
> +	      sizeof(struct kshark_data_field_int64 *),

I always like using the variable in sizeof, just in case things change:
		sizeof(*container->data)

-- Steve

> +	      compare_time_dc);
> +
> +	container->sorted = true;
> +
> +	data_tmp = realloc(container->data,
> +			   container->size * sizeof(*container->data));
> +
> +	if (!data_tmp)
> +		return;
> +
> +	container->data = data_tmp;
> +	container->capacity = container->size;
> +}
> +
> +/**
> + * @brief Binary search inside a time-sorted array of kshark_data_field_int64.
> + *
> + * @param time: The value of time to search for.
> + * @param data: Input location for the data.
> + * @param l: Array index specifying the lower edge of the range to search in.
> + * @param h: Array index specifying the upper edge of the range to search in.
> + *
> + * @returns On success, the index of the first kshark_data_field_int64 inside
> + *	    the range, having a timestamp equal or bigger than "time".
> + *	    If all fields inside the range have timestamps greater than "time"
> + *	    the function returns BSEARCH_ALL_GREATER (negative value).
> + *	    If all fields inside the range have timestamps smaller than "time"
> + *	    the function returns BSEARCH_ALL_SMALLER (negative value).
> + */
> +ssize_t kshark_find_entry_field_by_time(int64_t time,
> +					struct kshark_data_field_int64 **data,
> +					size_t l, size_t h)
> +{
> +	size_t mid;
> +
> +	if (data[l]->entry->ts > time)
> +		return BSEARCH_ALL_GREATER;
> +
> +	if (data[h]->entry->ts < time)
> +		return BSEARCH_ALL_SMALLER;
> +
> +	/*
> +	 * After executing the BSEARCH macro, "l" will be the index of the last
> +	 * entry having timestamp < time and "h" will be the index of the first
> +	 * entry having timestamp >= time.
> +	 */
> +	BSEARCH(h, l, data[mid]->entry->ts < time);
> +	return h;
> +}

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

* Re: [PATCH 3/6] kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro
  2021-01-06 16:11 ` [PATCH 3/6] kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro Yordan Karadzhov (VMware)
@ 2021-01-06 17:45   ` Steven Rostedt
  0 siblings, 0 replies; 11+ messages in thread
From: Steven Rostedt @ 2021-01-06 17:45 UTC (permalink / raw)
  To: Yordan Karadzhov (VMware); +Cc: linux-trace-devel

On Wed,  6 Jan 2021 18:11:17 +0200
"Yordan Karadzhov (VMware)" <y.karadz@gmail.com> wrote:

> When we implement a KernelShark plugins, we often need a way to define
> a structure that can hold context data that is visible only inside the
> plugin and that has specific values for each data stream. The tricky
> part here is that the total number of data streams and the IDs of the
> active streams are dynamic quantities that can change as the user adds
> or removes data streams. The macro defines an interface of functions
> that will be useful for the plugin developer, helping to directly use
> context objects, without caring for the complications due to the dynamic
> configuration of active data streams.
> ---
>  src/libkshark-plugin.h    | 43 +++++++++++++++++++++++++++++++++++++++
>  tests/libkshark-tests.cpp | 32 +++++++++++++++++++++++++++++
>  2 files changed, 75 insertions(+)
> 
> diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h
> index f3c724f..e58d658 100644
> --- a/src/libkshark-plugin.h
> +++ b/src/libkshark-plugin.h
> @@ -360,6 +360,49 @@ int kshark_handle_all_dpis(struct kshark_data_stream *stream,
>  	}								\
>  }									\
>  
> +/** General purpose macro defining methods for adding plugin context. */
> +#define KS_DEFINE_PLUGIN_CONTEXT(type)					\

When macros like this are done in Linux, it is common to add a "prefix"
argument, and name all the variables and functions created by it with that
prefix.

#define KS_DEFINE_PLUGIN_CONTEXT(prefix, type) \
 static type **prefix##_context_handler; \
 [..]
 static inline type *prefix##_init(int sd) \
 [..]

This would allow this macro to be used more than once in a file.

It's up to you if you want to do it that way.

-- Steve

> +static type **__context_handler;					\
> +static ssize_t __n_streams = -1;					\
> +static bool ok;								\
> +static inline type *__init(int sd)					\
> +{									\
> +	type *obj;							\
> +	if (__n_streams < 0 && sd < KS_DEFAULT_NUM_STREAMS) {		\
> +		__context_handler =					\
> +			(type **) calloc(KS_DEFAULT_NUM_STREAMS,	\
> +					 sizeof(*__context_handler));	\
> +		if (!__context_handler)					\
> +			return NULL;					\
> +		__n_streams = KS_DEFAULT_NUM_STREAMS;			\
> +	} else if (sd >= __n_streams) {					\
> +		KS_DOUBLE_SIZE(type *, __context_handler,		\
> +			       &__n_streams, &ok)			\
> +		if (!ok)						\
> +			return NULL;					\
> +	}								\
> +	assert(__context_handler[sd] == NULL);				\
> +	obj = (type *) calloc(1, sizeof(*obj));				\
> +	__context_handler[sd] = obj;					\
> +	return obj;							\
> +}									\
> +static inline void __close(int sd)					\
> +{									\
> +	if (sd < 0) {							\
> +		free(__context_handler);				\
> +		__n_streams = -1;					\
> +		return;							\
> +	}								\
> +	free(__context_handler[sd]);					\
> +	__context_handler[sd] = NULL;					\
> +}									\
> +static inline type *__get_context(int sd)				\
> +{									\
> +	if (sd < 0 || sd >= __n_streams)				\
> +		return NULL;						\
> +	return __context_handler[sd];					\
> +}									\
> +
>  #ifdef __cplusplus
>  }
>  #endif // __cplusplus

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

end of thread, other threads:[~2021-01-06 17:45 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-06 16:11 [PATCH 0/6] kernel-shark: Visualization plugin tools Yordan Karadzhov (VMware)
2021-01-06 16:11 ` [PATCH 1/6] kernel-shark: Add KS_DOUBLE_SIZE macro Yordan Karadzhov (VMware)
2021-01-06 17:02   ` Steven Rostedt
2021-01-06 17:28     ` Steven Rostedt
2021-01-06 16:11 ` [PATCH 2/6] kernel-shark: Add kshark_data_container to libkshark Yordan Karadzhov (VMware)
2021-01-06 17:38   ` Steven Rostedt
2021-01-06 16:11 ` [PATCH 3/6] kernel-shark: Add KS_DEFINE_PLUGIN_CONTEXT macro Yordan Karadzhov (VMware)
2021-01-06 17:45   ` Steven Rostedt
2021-01-06 16:11 ` [PATCH 4/6] kernel-shark: Start using C++17 Yordan Karadzhov (VMware)
2021-01-06 16:11 ` [PATCH 5/6] kernel-shark: Add plotting methods to KsPlugins Yordan Karadzhov (VMware)
2021-01-06 16:11 ` [PATCH 6/6] kernel-shark: Speed-up the sched_events plugin Yordan Karadzhov (VMware)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).