* [PATCH v5 2/3] KernelShark: Add xenomai_cobalt_switch_events plugin for KernelShark
2022-03-09 2:30 [PATCH v5 1/3] build: Add c++ build support Hongzhan Chen
@ 2022-03-09 2:30 ` Hongzhan Chen
2022-03-09 6:16 ` Jan Kiszka
2022-03-09 2:30 ` [PATCH v5 3/3] libtraceevent: Add xenomai_schedparams plugin for libtraceevent Hongzhan Chen
1 sibling, 1 reply; 6+ messages in thread
From: Hongzhan Chen @ 2022-03-09 2:30 UTC (permalink / raw)
To: xenomai, jan.kiszka, florian.bezdeka
For Xenomai-cobalt enabled system, cobalt_switch_context means
that there is schedule and context switch in companion core(realtime
core), which we may need to do special treatment and take correct
action as main kernel sched_switch to visualize out-of-band state
of realtime tasks running in cobalt core. To achive our target,
we implement following:
1. store corresponding cobalt_switch_context events into
container data.
2. modify pid stored in entry to be equal to next_pid to
show correct color in cpu bar when cobalt_switch_context
event happen.
3. show blue hollow box to mark out-of-band state according to
cobalt_switch_context events.
4. clickable cobalt_switch_context plugin shapes.
Signed-off-by: Hongzhan Chen <hongzhan.chen@intel.com>
---
Makefile.am | 4 +
configure.ac | 30 +++
tracing/Makefile.am | 6 +
tracing/kernelshark/CobaltSwitchEvents.cpp | 156 ++++++++++++++++
tracing/kernelshark/Makefile.am | 21 +++
tracing/kernelshark/README | 83 +++++++++
.../xenomai_cobalt_switch_events.c | 174 ++++++++++++++++++
.../xenomai_cobalt_switch_events.h | 58 ++++++
8 files changed, 532 insertions(+)
create mode 100644 tracing/Makefile.am
create mode 100644 tracing/kernelshark/CobaltSwitchEvents.cpp
create mode 100644 tracing/kernelshark/Makefile.am
create mode 100644 tracing/kernelshark/README
create mode 100644 tracing/kernelshark/xenomai_cobalt_switch_events.c
create mode 100644 tracing/kernelshark/xenomai_cobalt_switch_events.h
diff --git a/Makefile.am b/Makefile.am
index 604644277..bd3e4bfb1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,6 +18,9 @@ SUBDIRS += \
testsuite
endif
+SUBDIRS += \
+ tracing
+
EXTRA_DIST = kernel debian
DIST_SUBDIRS = \
@@ -26,6 +29,7 @@ DIST_SUBDIRS = \
doc \
include \
lib \
+ tracing \
scripts \
testsuite \
utils
diff --git a/configure.ac b/configure.ac
index 16cffd8f8..586880a93 100644
--- a/configure.ac
+++ b/configure.ac
@@ -91,6 +91,8 @@ AC_ARG_WITH(cxx,
])
AC_PROG_CXX
+PKG_PROG_PKG_CONFIG
+
# Do not let autoconf set the default value of CFLAGS
if $XENO_EMPTY_CFLAGS; then
CFLAGS=""
@@ -826,6 +828,29 @@ AC_ARG_WITH(demodir,
], [XENO_DEMO_DIR=$demodir])
AC_MSG_RESULT($XENO_DEMO_DIR)
+xeno_build_kernelshark=false
+AC_MSG_CHECKING(build kernelshark plugin)
+AC_ARG_WITH(kernelshark,
+ AS_HELP_STRING([--with-kernelshark],[build kernelshark plugin for xenomai]),
+ [
+ case "$withval" in
+ "" | y | ye | yes) xeno_build_kernelshark=true;;
+ n | no) xeno_build_kernelshark=false;;
+ esac
+ if eval test x$xeno_build_kernelshark = xtrue; then
+ PKG_CHECK_MODULES(kernelshark, libkshark, [xeno_build_kernelshark=true], [xeno_build_kernelshark=false])
+ if eval test x$xeno_build_kernelshark = xtrue; then
+ KS_INCLUDS="$kernelshark_CFLAGS"
+ AC_SUBST([KS_INSTALLDIR], [$(pkg-config --variable=libdir libkshark)])
+ else
+ AC_MSG_ERROR([You must install kernelshark at first before building kernelshark plugin for xenomai])
+ fi
+ fi
+ ], [xeno_build_kernelshark=false])
+AC_MSG_RESULT($xeno_build_kernelshark)
+
+AM_CONDITIONAL([BUILD_KERNELSHARK], [test x$xeno_build_kernelshark = xtrue])
+
AC_MSG_CHECKING([for test source generation])
AC_RUN_IFELSE([AC_LANG_PROGRAM([[ ]], [[ ]])],
[AC_MSG_RESULT(ok)], [AC_MSG_RESULT(failed)], [AC_MSG_RESULT(untestable)])
@@ -936,6 +961,9 @@ AC_SUBST(XENO_DEMO_DIR)
AC_SUBST(XENO_BUILD_COMPILER)
AC_SUBST(XENO_BUILD_ARGS)
AC_SUBST(CORE)
+AC_SUBST(KS_INCLUDS)
+AC_SUBST(KS_INSTALLDIR)
+
AC_CONFIG_FILES([ \
Makefile \
@@ -943,6 +971,8 @@ AC_CONFIG_FILES([ \
scripts/Makefile \
scripts/xeno-config:scripts/xeno-config-$rtcore_type.in \
scripts/xeno \
+ tracing/Makefile \
+ tracing/kernelshark/Makefile \
lib/Makefile \
lib/boilerplate/Makefile \
lib/boilerplate/init/Makefile \
diff --git a/tracing/Makefile.am b/tracing/Makefile.am
new file mode 100644
index 000000000..25c3e033c
--- /dev/null
+++ b/tracing/Makefile.am
@@ -0,0 +1,6 @@
+if BUILD_KERNELSHARK
+SUBDIRS = kernelshark
+endif
+
+DIST_SUBDIRS = \
+ kernelshark
diff --git a/tracing/kernelshark/CobaltSwitchEvents.cpp b/tracing/kernelshark/CobaltSwitchEvents.cpp
new file mode 100644
index 000000000..3a521bdfc
--- /dev/null
+++ b/tracing/kernelshark/CobaltSwitchEvents.cpp
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2021 Intel Inc, Hongzhan Chen <hongzhan.chen@intel.com>
+ */
+
+/**
+ * @file CobaltSwitchEvents.cpp
+ * @brief Defines a callback function for Xenomai Cobalt context switch
+ * events used to plot in cobalt blue the out-of-band state of
+ * the task
+ */
+
+// KernelShark
+#include "libkshark.h"
+#include "libkshark-plugin.h"
+#include "xenomai_cobalt_switch_events.h"
+#include "KsPlotTools.hpp"
+#include "KsPlugins.hpp"
+#include "KsPluginsGUI.hpp"
+
+static void *ks4xenomai_ptr;
+
+/**
+ * @brief Provide the plugin with a pointer to the KsMainWindow object (the GUI
+ * itself) such that the plugin can manipulate the GUI.
+ */
+__hidden void *plugin_set_gui_ptr(void *gui_ptr)
+{
+ ks4xenomai_ptr = gui_ptr;
+ return nullptr;
+}
+
+/**
+ * This class represents the graphical element visualizing OOB state between
+ * two cobalt_switch_context events.
+ */
+class XenomaiSwitchBox : public LatencyBox
+{
+ /** On double click do. */
+ void _doubleClick() const override
+ {
+ markEntryB(ks4xenomai_ptr, _data[1]->entry);
+ markEntryA(ks4xenomai_ptr, _data[0]->entry);
+ }
+};
+
+/*
+ * Ideally, the cobalt_switch_context has to be the last trace event recorded before
+ * the task is preempted. Because of this, when the data is loaded (the first pass),
+ * the "pid" field of the cobalt_switch_context entries gets edited by this plugin
+ * to be equal to the "next pid" of the cobalt_switch_context event. However, in
+ * reality the cobalt_switch_context event may be followed by some trailing events
+ * from the same task (printk events for example). This has the effect of extending
+ * the graph of the task outside of the actual duration of the task. The "second
+ * pass" over the data is used to fix this problem. It takes advantage of the
+ * "next" field of the entry (this field is set during the first pass) to search
+ * for trailing events after the "cobalt_switch_context". In addition, when
+ * we find that it try to switch in-band because next-pid is zero, we prefer to
+ * skip this event because it try to leave oob not enterring.
+ */
+static void secondPass(plugin_cobalt_context *plugin_ctx)
+{
+ kshark_data_container *cSS;
+ kshark_entry *e;
+ int pid_rec, switch_inband;
+
+ cSS = plugin_ctx->cs_data;
+ for (ssize_t i = 0; i < cSS->size; ++i) {
+ switch_inband = plugin_cobalt_check_switch_inband(
+ cSS->data[i]->field);
+
+ /* we skip cobalt_switch_context that try to
+ * switch into in-band state because we just handle
+ * out-of-band
+ */
+ if (switch_inband)
+ continue;
+ 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;
+
+ e = e->next;
+ /* Find all trailing events. */
+ for (; e->next; e = e->next) {
+ if (e->pid == plugin_sched_get_pid(
+ cSS->data[i]->field)) {
+ /*
+ * Change the "pid" to be equal to the "next
+ * pid" of the cobalt_switch_context event
+ * and leave a sign that you edited this
+ * entry.
+ */
+ e->pid = cSS->data[i]->entry->pid;
+ e->visible &= ~KS_PLUGIN_UNTOUCHED_MASK;
+
+ /* This is the last trailing event, we finish
+ * this round.
+ */
+ if (e->next->pid != plugin_sched_get_pid(
+ cSS->data[i]->field))
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * @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.
+ */
+__hidden void plugin_cobalt_draw(kshark_cpp_argv *argv_c,
+ int sd, int pid, int draw_action)
+{
+ plugin_cobalt_context *plugin_ctx;
+
+ if (!(draw_action & KSHARK_TASK_DRAW) || pid == 0)
+ return;
+
+ plugin_ctx = __get_context(sd);
+ if (!plugin_ctx)
+ return;
+
+ KsCppArgV *argvCpp = KS_ARGV_TO_CPP(argv_c);
+
+ if (!plugin_ctx->second_pass_done) {
+ /* The second pass is not done yet. */
+ secondPass(plugin_ctx);
+ plugin_ctx->second_pass_done = true;
+ }
+
+ IsApplicableFunc checkFieldCS = [=] (kshark_data_container *d,
+ ssize_t i) {
+ return !(plugin_cobalt_check_switch_inband(d->data[i]->field)) &&
+ d->data[i]->entry->pid == pid;
+ };
+
+ IsApplicableFunc checkEntryPid = [=] (kshark_data_container *d,
+ ssize_t i) {
+ return plugin_sched_get_pid(d->data[i]->field) == pid;
+ };
+
+ eventFieldIntervalPlot(argvCpp,
+ plugin_ctx->cs_data, checkFieldCS,
+ plugin_ctx->cs_data, checkEntryPid,
+ makeLatencyBox<XenomaiSwitchBox>,
+ {0, 71, 171}, // Cobalt Blue
+ -1); // Default size
+}
diff --git a/tracing/kernelshark/Makefile.am b/tracing/kernelshark/Makefile.am
new file mode 100644
index 000000000..195fdcdd5
--- /dev/null
+++ b/tracing/kernelshark/Makefile.am
@@ -0,0 +1,21 @@
+
+lib_LTLIBRARIES = libplugin_xenomai_cobalt_switch_events.la
+
+libplugin_xenomai_cobalt_switch_events_la_SOURCES = \
+ CobaltSwitchEvents.cpp \
+ xenomai_cobalt_switch_events.c \
+ xenomai_cobalt_switch_events.h
+
+libplugin_xenomai_cobalt_switch_events_la_CPPFLAGS = \
+ $(KS_INCLUDS)
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ echo "$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install \
+ $(INSTALL_DATA) $(lib_LTLIBRARIES) '$(KS_INSTALLDIR)/kernelshark/plugins/'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install \
+ $(INSTALL_DATA) $(lib_LTLIBRARIES) "$(KS_INSTALLDIR)/kernelshark/plugins/"
+
+uninstall-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ echo "$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall $(RM) '$(KS_INSTALLDIR)/kernelshark/plugins/$(lib_LTLIBRARIES)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall $(RM) "$(KS_INSTALLDIR)/kernelshark/plugins/$(lib_LTLIBRARIES)"
+
diff --git a/tracing/kernelshark/README b/tracing/kernelshark/README
new file mode 100644
index 000000000..a180aa787
--- /dev/null
+++ b/tracing/kernelshark/README
@@ -0,0 +1,83 @@
+
+What is it?
+=============
+
+ It is Xenomai plugin for KernelShark to visualize out-of-band state
+ of realtime thread running in companion core with making use of
+ cobalt_switch_context events in trace log.
+
+ For more introductions about KernelShark , please refer to [1].
+
+How to build?
+================================
+
+Preparation:
+
+ - compile and install third party softwares that KernelShark depends on:
+ please refer to "Third Party Software" in [2].
+
+ - GIT clone:
+ git clone https://git.kernel.org/pub/scm/utils/trace-cmd/kernel-shark.git
+
+ - build kernel-shark and install both the GUI and libkshark-devel:
+
+ cd kernel-shark/build
+ cmake ../
+ make
+ sudo make install
+
+ Note:
+ Building standlone xenomai plugin based on kernel-shark
+ depends on following patchset after kernelshark-v2.1.0:
+ kernel-shark: Install missing headers (commit 5419186f4bbad68aa16849882a8f12fa9adb22c5)
+ kernel-shark: Add KsPluginsGUI.hpp/.cpp (commit 59b5763c7c52b703e3b8e05be801f7c85365c9d3)
+ kernel-shark: Load 'ctrl' interface for user plugins (commit e35970770b71f0cc849870512a806dff96bf19e1)
+
+Building & installing plugin:
+
+ goto your xenomai folder
+ ./scripts/bootstrap
+ ./configure --with-kernelshark
+ make
+ sudo make -C tracing/kernelshark install
+
+How to use the plugin with KernelShark?
+====================================
+
+ kernelshark -p your_path_of_libplugin_xenomai_cobalt_switch_events.so your_path_of_trace.dat
+
+What the difference is after Xenomai plug works?
+===============================================
+
+ 1. For those trace log which does not include cobalt_switch_context event, you may
+ not expect that there is any difference after Xenomai plugin is loaded.
+
+ 2. But when there is cobalt_switch_context event in trace log, the plugin would
+ try to analysis cobalt_switch_context event and visualize the OOB state
+ with cobalt blue hollow box in the corresponding task bar.
+
+How to check OOB state with cobalt blue hollow box?
+==================================================
+
+ 1. Please check if there is cobalt_switch_context events existing in the log using
+ search boxes in the list area of kernelshark GUI.
+
+ 2. When there is cobalt_switch_context events existing in the log, please goto
+ task plots dialog to choose tasks that you may want to check its OOB state by
+ clicking menu Plots->Tasks and then hit "Apply".
+
+ 3. Selected tasks would be added to the bottom of the graph area as task plots.
+ You may zoom in to check if there is cobalt blue hollow box showing in
+ the corresponding task bar/plot if the time span is really large and
+ there is too much events.
+
+ 4. When you double click the hollow box, there is two vertical lines
+ that marked as "Mark A" and "Mark B" which you may use to measure time of
+ running in OOB state between two cobalt_switch_context events.
+
+ Note:
+ Please refer to [1] about introduction of search boxes or task plot or "Mark A" &
+ "Mark B" on Graph Control Area for more detailed info.
+
+[1]: https://kernelshark.org/Documentation.html
+[2]: https://git.kernel.org/pub/scm/utils/trace-cmd/kernel-shark.git/tree/README
diff --git a/tracing/kernelshark/xenomai_cobalt_switch_events.c b/tracing/kernelshark/xenomai_cobalt_switch_events.c
new file mode 100644
index 000000000..758966df7
--- /dev/null
+++ b/tracing/kernelshark/xenomai_cobalt_switch_events.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2021 Intel Inc, Hongzhan Chen <hongzhan.chen@intel.com>
+ */
+
+/**
+ * @file xenomai_cobalt_switch_events.c
+ * @brief handle xenomai cobalt switch context event
+ */
+
+// C
+#include <stdlib.h>
+#include <stdio.h>
+
+// trace-cmd
+#include <trace-cmd.h>
+
+// KernelShark
+#include "xenomai_cobalt_switch_events.h"
+#include "libkshark-tepdata.h"
+
+/** Plugin context instance. */
+
+//! @cond Doxygen_Suppress
+
+#define SWITCH_INBAND_SHIFT PREV_STATE_SHIFT
+
+#define SWITCH_INBAND_MASK PREV_STATE_MASK
+
+//! @endcond
+
+static void cobalt_free_context(struct plugin_cobalt_context *plugin_ctx)
+{
+ if (!plugin_ctx)
+ return;
+
+ kshark_free_data_container(plugin_ctx->cs_data);
+}
+
+/* Use the most significant byte to store state marking switch in-band. */
+static void plugin_cobalt_set_switch_inband_state(ks_num_field_t *field,
+ ks_num_field_t inband_state)
+{
+ unsigned long long mask = SWITCH_INBAND_MASK << SWITCH_INBAND_SHIFT;
+ *field &= ~mask;
+ *field |= (inband_state & SWITCH_INBAND_MASK) << SWITCH_INBAND_SHIFT;
+}
+
+/**
+ * @brief Retrieve the state of switch-in-band from the data field stored in
+ * the kshark_data_container object.
+ *
+ * @param field: Input location for the data field.
+ */
+__hidden int plugin_cobalt_check_switch_inband(ks_num_field_t field)
+{
+ unsigned long long mask = SWITCH_INBAND_MASK << SWITCH_INBAND_SHIFT;
+
+ return (field & mask) >> SWITCH_INBAND_SHIFT;
+}
+
+/** A general purpose macro is used to define plugin context. */
+KS_DEFINE_PLUGIN_CONTEXT(struct plugin_cobalt_context, cobalt_free_context);
+
+static bool plugin_cobalt_init_context(struct kshark_data_stream *stream,
+ struct plugin_cobalt_context *plugin_ctx)
+{
+ struct tep_event *event;
+
+ if (!kshark_is_tep(stream))
+ return false;
+
+ plugin_ctx->tep = kshark_get_tep(stream);
+
+ event = tep_find_event_by_name(plugin_ctx->tep,
+ "cobalt_core", "cobalt_switch_context");
+ if (!event)
+ return false;
+
+ plugin_ctx->cobalt_switch_event = event;
+ plugin_ctx->cobalt_switch_next_field =
+ tep_find_any_field(event, "next_pid");
+
+ plugin_ctx->second_pass_done = false;
+
+ plugin_ctx->cs_data = kshark_init_data_container();
+ if (!plugin_ctx->cs_data)
+ return false;
+
+ return true;
+}
+
+static void plugin_cobalt_switch_action(struct kshark_data_stream *stream,
+ void *rec, struct kshark_entry *entry)
+{
+ struct tep_record *record = (struct tep_record *) rec;
+ struct plugin_cobalt_context *plugin_ctx;
+ unsigned long long next_pid;
+ ks_num_field_t ks_field = 0;
+ int ret;
+
+ plugin_ctx = __get_context(stream->stream_id);
+ if (!plugin_ctx)
+ return;
+
+ ret = tep_read_number_field(plugin_ctx->cobalt_switch_next_field,
+ record->data, &next_pid);
+
+ if (ret == 0 && next_pid >= 0) {
+ plugin_sched_set_pid(&ks_field, entry->pid);
+ if (next_pid == 0) {
+ plugin_cobalt_set_switch_inband_state(&ks_field,
+ SWITCH_INBAND_STATE);
+ }
+
+ kshark_data_container_append(plugin_ctx->cs_data,
+ entry, ks_field);
+
+ if (next_pid > 0)
+ entry->pid = next_pid;
+ }
+}
+
+/** Load this plugin. */
+int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream)
+{
+ struct plugin_cobalt_context *plugin_ctx;
+
+ plugin_ctx = __init(stream->stream_id);
+ if (!plugin_ctx || !plugin_cobalt_init_context(stream, plugin_ctx)) {
+ __close(stream->stream_id);
+ return 0;
+ }
+
+ if (plugin_ctx->cobalt_switch_event) {
+ kshark_register_event_handler(stream,
+ plugin_ctx->cobalt_switch_event->id,
+ plugin_cobalt_switch_action);
+ }
+
+ kshark_register_draw_handler(stream, plugin_cobalt_draw);
+
+ return 1;
+}
+
+/** Unload this plugin. */
+int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream)
+{
+ struct plugin_cobalt_context *plugin_ctx = __get_context(stream->stream_id);
+ int ret = 0;
+
+ if (plugin_ctx) {
+ if (plugin_ctx->cobalt_switch_event) {
+ kshark_unregister_event_handler(stream,
+ plugin_ctx->cobalt_switch_event->id,
+ plugin_cobalt_switch_action);
+ }
+
+ kshark_unregister_draw_handler(stream, plugin_cobalt_draw);
+
+ ret = 1;
+ }
+
+ __close(stream->stream_id);
+
+ return ret;
+}
+
+/** Initialize the control interface of the plugin. */
+void *KSHARK_MENU_PLUGIN_INITIALIZER(void *gui_ptr)
+{
+ return plugin_set_gui_ptr(gui_ptr);
+}
diff --git a/tracing/kernelshark/xenomai_cobalt_switch_events.h b/tracing/kernelshark/xenomai_cobalt_switch_events.h
new file mode 100644
index 000000000..f7f4593ff
--- /dev/null
+++ b/tracing/kernelshark/xenomai_cobalt_switch_events.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2021 Intel Inc, Hongzhan Chen<hongzhan.chen@intel.com>
+ */
+
+/**
+ * @file xenomai_cobalt_switch_events.h
+ * @brief Plugin for xenomai cobalt switch context event
+ */
+
+#ifndef _KS_PLUGIN_COBALT_SWITCH_H
+#define _KS_PLUGIN_COBALT_SWITCH_H
+
+// KernelShark
+#include "libkshark.h"
+#include "plugins/common_sched.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** cobalt_switch_context is trying to switch in-band. */
+#define SWITCH_INBAND_STATE 1
+
+/** Structure representing a plugin-specific context. */
+struct plugin_cobalt_context {
+ /** Page event used to parse the page. */
+ struct tep_handle *tep;
+
+ /** Pointer to the cobalt_switch_event object. */
+ struct tep_event *cobalt_switch_event;
+
+ /** Pointer to the cobalt_switch_next_field format descriptor. */
+ struct tep_format_field *cobalt_switch_next_field;
+
+ /** True if the second pass is already done. */
+ bool second_pass_done;
+
+ /** Data container for cobalt_switch_context data. */
+ struct kshark_data_container *cs_data;
+
+};
+
+KS_DECLARE_PLUGIN_CONTEXT_METHODS(struct plugin_cobalt_context)
+
+int plugin_cobalt_check_switch_inband(ks_num_field_t field);
+
+void plugin_cobalt_draw(struct kshark_cpp_argv *argv, int sd, int pid,
+ int draw_action);
+
+void *plugin_set_gui_ptr(void *gui_ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v5 3/3] libtraceevent: Add xenomai_schedparams plugin for libtraceevent
2022-03-09 2:30 [PATCH v5 1/3] build: Add c++ build support Hongzhan Chen
2022-03-09 2:30 ` [PATCH v5 2/3] KernelShark: Add xenomai_cobalt_switch_events plugin for KernelShark Hongzhan Chen
@ 2022-03-09 2:30 ` Hongzhan Chen
1 sibling, 0 replies; 6+ messages in thread
From: Hongzhan Chen @ 2022-03-09 2:30 UTC (permalink / raw)
To: xenomai, jan.kiszka, florian.bezdeka
For cobalt thread, there is special struct param_ex data stored in
data record, we need to parse and print its content out correctly
to hint user.
Signed-off-by: Hongzhan Chen <hongzhan.chen@intel.com>
---
configure.ac | 26 +++
tracing/Makefile.am | 15 +-
tracing/libtraceevent/Makefile.am | 19 +++
tracing/libtraceevent/README | 35 ++++
.../plugin_xenomai_schedparams.c | 158 ++++++++++++++++++
5 files changed, 252 insertions(+), 1 deletion(-)
create mode 100644 tracing/libtraceevent/Makefile.am
create mode 100644 tracing/libtraceevent/README
create mode 100644 tracing/libtraceevent/plugin_xenomai_schedparams.c
diff --git a/configure.ac b/configure.ac
index 586880a93..e855b7f3c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -851,6 +851,29 @@ AC_MSG_RESULT($xeno_build_kernelshark)
AM_CONDITIONAL([BUILD_KERNELSHARK], [test x$xeno_build_kernelshark = xtrue])
+xeno_build_libtraceevent=false
+AC_MSG_CHECKING(build libtraceevent plugin)
+AC_ARG_WITH(libtraceevent,
+ AS_HELP_STRING([--with-libtraceevent],[build libtraceevent plugin]),
+ [
+ case "$withval" in
+ "" | y | ye | yes) xeno_build_libtraceevent=true;;
+ n | no) xeno_build_libtraceevent=false;;
+ esac
+ if eval test x$xeno_build_libtraceevent = xtrue; then
+ PKG_CHECK_MODULES(libtraceevent, libtraceevent, [xeno_build_libtraceevent=true], [xeno_build_libtraceevent=false])
+ if eval test x$xeno_build_libtraceevent = xtrue; then
+ TRACEEVENT_INCLUDS="$libtraceevent_CFLAGS"
+ AC_SUBST([TRACEEVENT_INSTALLDIR], [$(pkg-config --variable=libdir libtraceevent)])
+ else
+ AC_MSG_ERROR([You must install libtraceevent at first before building libtraceevent plugin for xenomai])
+ fi
+ fi
+ ], [xeno_build_libtraceevent=false])
+AC_MSG_RESULT($xeno_build_libtraceevent)
+
+AM_CONDITIONAL([BUILD_LIBTRACEEVENT], [test x$xeno_build_libtraceevent = xtrue])
+
AC_MSG_CHECKING([for test source generation])
AC_RUN_IFELSE([AC_LANG_PROGRAM([[ ]], [[ ]])],
[AC_MSG_RESULT(ok)], [AC_MSG_RESULT(failed)], [AC_MSG_RESULT(untestable)])
@@ -963,6 +986,8 @@ AC_SUBST(XENO_BUILD_ARGS)
AC_SUBST(CORE)
AC_SUBST(KS_INCLUDS)
AC_SUBST(KS_INSTALLDIR)
+AC_SUBST(TRACEEVENT_INCLUDS)
+AC_SUBST(TRACEEVENT_INSTALLDIR)
AC_CONFIG_FILES([ \
@@ -973,6 +998,7 @@ AC_CONFIG_FILES([ \
scripts/xeno \
tracing/Makefile \
tracing/kernelshark/Makefile \
+ tracing/libtraceevent/Makefile \
lib/Makefile \
lib/boilerplate/Makefile \
lib/boilerplate/init/Makefile \
diff --git a/tracing/Makefile.am b/tracing/Makefile.am
index 25c3e033c..8f3d20adf 100644
--- a/tracing/Makefile.am
+++ b/tracing/Makefile.am
@@ -1,6 +1,19 @@
if BUILD_KERNELSHARK
SUBDIRS = kernelshark
+
+if BUILD_LIBTRACEEVENT
+SUBDIRS += \
+ libtraceevent
+endif
+
+else
+
+if BUILD_LIBTRACEEVENT
+SUBDIRS = libtraceevent
+endif
+
endif
DIST_SUBDIRS = \
- kernelshark
+ kernelshark \
+ libtraceevent
diff --git a/tracing/libtraceevent/Makefile.am b/tracing/libtraceevent/Makefile.am
new file mode 100644
index 000000000..9c6ab505b
--- /dev/null
+++ b/tracing/libtraceevent/Makefile.am
@@ -0,0 +1,19 @@
+
+lib_LTLIBRARIES = libplugin_xenomai_schedparams.la
+
+libplugin_xenomai_schedparams_la_SOURCES = \
+ plugin_xenomai_schedparams.c
+
+libplugin_xenomai_schedparams_la_CPPFLAGS = \
+ $(TRACEEVENT_INCLUDS) \
+ -I$(top_srcdir)/include
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ echo "$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install \
+ $(INSTALL_DATA) $(lib_LTLIBRARIES) '$(TRACEEVENT_INSTALLDIR)/traceevent/plugins/'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install \
+ $(INSTALL_DATA) $(lib_LTLIBRARIES) "$(TRACEEVENT_INSTALLDIR)/traceevent/plugins/"
+
+uninstall-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ echo "$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall $(RM) '$(TRACEEVENT_INSTALLDIR)/traceevent/plugins/$(lib_LTLIBRARIES)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall $(RM) "$(TRACEEVENT_INSTALLDIR)/traceevent/plugins/$(lib_LTLIBRARIES)"
diff --git a/tracing/libtraceevent/README b/tracing/libtraceevent/README
new file mode 100644
index 000000000..984f17dee
--- /dev/null
+++ b/tracing/libtraceevent/README
@@ -0,0 +1,35 @@
+
+What is it?
+=============
+
+ It is Xenomai plugin on libtracevent to parse struct param_ex
+ out correctly for trace log.
+
+How to compile?
+================================
+
+Preparation:
+
+ - GIT clone:
+
+ https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git
+
+ - build and install libtraceevent:
+
+ make;
+ sudo make install
+
+Building & Install plugin
+
+ goto your xenomai folder
+ ./scripts/bootstrap
+ ./configure --with-libtraceevent
+ make
+ sudo make -C tracing/libtraceevent install
+
+How to use built lib?
+===============================
+
+ While libtracevent and its plugins is installed correctly, the plugins
+ would be loaded automatically by other module such as libtracecmd after
+ corresponding tracing tool such as kernelshark or tracecmd run.
diff --git a/tracing/libtraceevent/plugin_xenomai_schedparams.c b/tracing/libtraceevent/plugin_xenomai_schedparams.c
new file mode 100644
index 000000000..01234fe5f
--- /dev/null
+++ b/tracing/libtraceevent/plugin_xenomai_schedparams.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * Copyright (C) 2021 Intel Inc, Hongzhan Chen <hongzhan.chen@intel.com>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/sched.h>
+#include <cobalt/uapi/sched.h>
+#include <sched.h>
+#include "event-parse.h"
+#include "trace-seq.h"
+
+static void write_policy(struct trace_seq *p, int policy)
+{
+ trace_seq_printf(p, "policy=");
+
+ switch (policy) {
+ case SCHED_QUOTA:
+ trace_seq_printf(p, "quota ");
+ break;
+ case SCHED_TP:
+ trace_seq_printf(p, "tp ");
+ break;
+ case SCHED_NORMAL:
+ trace_seq_printf(p, "normal ");
+ break;
+ case SCHED_SPORADIC:
+ trace_seq_printf(p, "sporadic ");
+ break;
+ case SCHED_RR:
+ trace_seq_printf(p, "rr ");
+ break;
+ case SCHED_FIFO:
+ trace_seq_printf(p, "fifo ");
+ break;
+ case SCHED_COBALT:
+ trace_seq_printf(p, "cobalt ");
+ break;
+ case SCHED_WEAK:
+ trace_seq_printf(p, "weak ");
+ break;
+ default:
+ trace_seq_printf(p, "unknown ");
+ break;
+ }
+}
+
+/* save param */
+static void write_param(struct tep_format_field *field,
+ struct tep_record *record,
+ struct trace_seq *p, int policy)
+{
+ int offset;
+ struct sched_param_ex *params;
+
+ offset = field->offset;
+
+ if (!strncmp(field->type, "__data_loc", 10)) {
+ unsigned long long v;
+
+ if (tep_read_number_field(field, record->data, &v)) {
+ trace_seq_printf(p, "invalid_data_loc");
+ return;
+ }
+ offset = v & 0xffff;
+
+ }
+
+ params = (struct sched_param_ex *)((char *)record->data + offset);
+
+ trace_seq_printf(p, "param: { ");
+
+ switch (policy) {
+ case SCHED_QUOTA:
+ trace_seq_printf(p, "priority=%d, group=%d",
+ params->sched_priority,
+ params->sched_quota_group);
+ break;
+ case SCHED_TP:
+ trace_seq_printf(p, "priority=%d, partition=%d",
+ params->sched_priority,
+ params->sched_tp_partition);
+ break;
+ case SCHED_NORMAL:
+ break;
+ case SCHED_SPORADIC:
+ trace_seq_printf(p, "priority=%d, low_priority=%d, ",
+ params->sched_priority,
+ params->sched_ss_low_priority);
+
+ trace_seq_printf(p, "budget=(%ld.%09ld), period=(%ld.%09ld), ",
+ params->sched_ss_init_budget.tv_sec,
+ params->sched_ss_init_budget.tv_nsec);
+
+ trace_seq_printf(p, "maxrepl=%d",
+ params->sched_ss_max_repl);
+ break;
+ case SCHED_RR:
+ case SCHED_FIFO:
+ case SCHED_COBALT:
+ case SCHED_WEAK:
+ default:
+ trace_seq_printf(p, "priority=%d", params->sched_priority);
+ break;
+ }
+ trace_seq_printf(p, " }");
+ trace_seq_putc(p, '\0');
+
+}
+
+static int cobalt_schedparam_handler(struct trace_seq *s,
+ struct tep_record *record,
+ struct tep_event *event, void *context)
+{
+ struct tep_format_field *field;
+ unsigned long long val;
+
+ if (tep_get_field_val(s, event, "pth", record, &val, 1))
+ return trace_seq_putc(s, '!');
+ trace_seq_puts(s, "pth: ");
+ trace_seq_printf(s, "0x%08llx ", val);
+
+ if (tep_get_field_val(s, event, "policy", record, &val, 1) == 0)
+ write_policy(s, val);
+
+ field = tep_find_field(event, "param_ex");
+ if (field)
+ write_param(field, record, s, val);
+
+ return 0;
+}
+
+int TEP_PLUGIN_LOADER(struct tep_handle *tep)
+{
+ tep_register_event_handler(tep, -1, "cobalt_posix", "cobalt_pthread_setschedparam",
+ cobalt_schedparam_handler, NULL);
+
+ tep_register_event_handler(tep, -1, "cobalt_posix", "cobalt_pthread_getschedparam",
+ cobalt_schedparam_handler, NULL);
+
+ tep_register_event_handler(tep, -1, "cobalt_posix", "cobalt_pthread_create",
+ cobalt_schedparam_handler, NULL);
+
+ return 0;
+}
+
+void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
+{
+ tep_unregister_event_handler(tep, -1, "cobalt_posix", "cobalt_pthread_setschedparam",
+ cobalt_schedparam_handler, NULL);
+
+ tep_unregister_event_handler(tep, -1, "cobalt_posix", "cobalt_pthread_getschedparam",
+ cobalt_schedparam_handler, NULL);
+
+ tep_unregister_event_handler(tep, -1, "cobalt_posix", "cobalt_pthread_create",
+ cobalt_schedparam_handler, NULL);
+}
--
2.17.1
^ permalink raw reply related [flat|nested] 6+ messages in thread