All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] Add basic components to be used by the Qt GUI
@ 2018-10-08 15:16 Yordan Karadzhov
  2018-10-08 15:16 ` [PATCH 1/4] kernel-shark-qt: Add Qt as a third party dependency Yordan Karadzhov
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Yordan Karadzhov @ 2018-10-08 15:16 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov

This series of patches introduces the first components of the Qt-based
KernelShark GUI. It includes some basic utils, as well as various small
widgets and dialogues used by the GUI. The GUI itself will be introdused
in the following series.

Yordan Karadzhov (VMware) (4):
  kernel-shark-qt: Add Qt as a third party dependency.
  kernel-shark-qt: Add KernalShark Utils
  kernel-shark-qt: Add Widgets Lib
  kernel-shark-qt: Add widget demo example.

 kernel-shark-qt/CMakeLists.txt          |   8 +
 kernel-shark-qt/README                  |   6 +-
 kernel-shark-qt/build/deff.h.cmake      |  16 +
 kernel-shark-qt/examples/CMakeLists.txt |   4 +
 kernel-shark-qt/examples/widgetdemo.cpp | 159 +++++
 kernel-shark-qt/src/CMakeLists.txt      |  22 +
 kernel-shark-qt/src/KsUtils.cpp         | 584 ++++++++++++++++
 kernel-shark-qt/src/KsUtils.hpp         | 231 +++++++
 kernel-shark-qt/src/KsWidgetsLib.cpp    | 873 ++++++++++++++++++++++++
 kernel-shark-qt/src/KsWidgetsLib.hpp    | 370 ++++++++++
 10 files changed, 2272 insertions(+), 1 deletion(-)
 create mode 100644 kernel-shark-qt/examples/widgetdemo.cpp
 create mode 100644 kernel-shark-qt/src/KsUtils.cpp
 create mode 100644 kernel-shark-qt/src/KsUtils.hpp
 create mode 100644 kernel-shark-qt/src/KsWidgetsLib.cpp
 create mode 100644 kernel-shark-qt/src/KsWidgetsLib.hpp

-- 
2.17.1

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

* [PATCH 1/4] kernel-shark-qt: Add Qt as a third party dependency.
  2018-10-08 15:16 [PATCH 0/4] Add basic components to be used by the Qt GUI Yordan Karadzhov
@ 2018-10-08 15:16 ` Yordan Karadzhov
  2018-10-08 15:16 ` [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils Yordan Karadzhov
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 15+ messages in thread
From: Yordan Karadzhov @ 2018-10-08 15:16 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov

From: Yordan Karadzhov <ykaradzhov@vmware.com>

This patch prepares the Cmake build infrastructure for the
introduction of a KernelShark GUI, baset on Qt.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/CMakeLists.txt | 8 ++++++++
 kernel-shark-qt/README         | 6 +++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/kernel-shark-qt/CMakeLists.txt b/kernel-shark-qt/CMakeLists.txt
index 4a40b11..71a021e 100644
--- a/kernel-shark-qt/CMakeLists.txt
+++ b/kernel-shark-qt/CMakeLists.txt
@@ -20,6 +20,14 @@ find_package(Doxygen)
 find_package(OpenGL)
 find_package(GLUT)
 
+find_package(Qt5Widgets 5.7.1)
+find_package(Qt5Network)
+if (Qt5Widgets_FOUND)
+
+    message(STATUS "Found Qt5Widgets:  (version ${Qt5Widgets_VERSION})")
+
+endif (Qt5Widgets_FOUND)
+
 set(LIBRARY_OUTPUT_PATH    "${KS_DIR}/lib")
 set(EXECUTABLE_OUTPUT_PATH "${KS_DIR}/bin")
 
diff --git a/kernel-shark-qt/README b/kernel-shark-qt/README
index 84708bd..14bcb77 100644
--- a/kernel-shark-qt/README
+++ b/kernel-shark-qt/README
@@ -4,10 +4,13 @@ This directory contains the new Qt-based version of the KernelShark GUI.
 
 Third Party Software:
 ------------------------------------------------------------
-The external dependencies:
+KernelShark has the following external dependencies:
+  Cmake, Json-C, OpenGL/Glut, Qt5Base.
+
 1. In order to install the packages on Ubuntu do the following:
     sudo apt-get install build-essential git cmake libjson-c-dev -y
     sudo apt-get install freeglut3-dev libxmu-dev libxi-dev -y
+    sudo apt-get install qtbase5-dev -y
 
 1.1 I you want to be able to generate Doxygen documentation:
     sudo apt-get install graphviz doxygen-gui -y
@@ -16,6 +19,7 @@ The external dependencies:
 2. In order to install the packages on Fedora, as root do the following:
     dnf install gcc gcc-c++ git cmake json-c-devel -y
     dnf install freeglut-devel redhat-rpm-config -y
+    dnf install qt5-qtbase-devel -y
 
 2.1 I you want to be able to generate Doxygen documentation:
     dnf install graphviz doxygen -y
-- 
2.17.1

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

* [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils
  2018-10-08 15:16 [PATCH 0/4] Add basic components to be used by the Qt GUI Yordan Karadzhov
  2018-10-08 15:16 ` [PATCH 1/4] kernel-shark-qt: Add Qt as a third party dependency Yordan Karadzhov
@ 2018-10-08 15:16 ` Yordan Karadzhov
  2018-10-09 16:34   ` Steven Rostedt
  2018-10-08 15:16 ` [PATCH 3/4] kernel-shark-qt: Add Widgets Lib Yordan Karadzhov
  2018-10-08 15:16 ` [PATCH 4/4] kernel-shark-qt: Add widget demo example Yordan Karadzhov
  3 siblings, 1 reply; 15+ messages in thread
From: Yordan Karadzhov @ 2018-10-08 15:16 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov, Yordan Karadzhov

From: Yordan Karadzhov <ykaradzhov@vmware.com>

This patch introduces the kshark-gui library and defines some basic
components, like Data Store and Plugin Manager, used under the hood
of the KernelShark GUI.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/build/deff.h.cmake |  16 +
 kernel-shark-qt/src/CMakeLists.txt |  20 +
 kernel-shark-qt/src/KsUtils.cpp    | 584 +++++++++++++++++++++++++++++
 kernel-shark-qt/src/KsUtils.hpp    | 231 ++++++++++++
 4 files changed, 851 insertions(+)
 create mode 100644 kernel-shark-qt/src/KsUtils.cpp
 create mode 100644 kernel-shark-qt/src/KsUtils.hpp

diff --git a/kernel-shark-qt/build/deff.h.cmake b/kernel-shark-qt/build/deff.h.cmake
index 44ea08b..d1a1bb7 100644
--- a/kernel-shark-qt/build/deff.h.cmake
+++ b/kernel-shark-qt/build/deff.h.cmake
@@ -14,7 +14,23 @@
 /** KernelShark source code path. */
 #cmakedefine KS_DIR "@KS_DIR@"
 
+/** KernelShark configuration directory path. */
+#cmakedefine KS_CONF_DIR "@KS_CONF_DIR@"
+
 /** Location of the trace-cmd executable. */
 #cmakedefine TRACECMD_BIN_DIR "@TRACECMD_BIN_DIR@"
 
+#ifdef __cplusplus
+
+	#include <QString>
+
+	/**
+	 * String containing semicolon-separated list of plugin names.
+	 * The plugins to be loaded when KernelShark starts are tagged
+	 * with "default".
+	 */
+	const QString plugins = "@PLUGINS@";
+
+#endif /* __cplusplus */
+
 #endif // _KS_CONFIG_H
diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt
index 305cea7..e897e9a 100644
--- a/kernel-shark-qt/src/CMakeLists.txt
+++ b/kernel-shark-qt/src/CMakeLists.txt
@@ -28,6 +28,26 @@ if (OPENGL_FOUND AND GLUT_FOUND)
 
 endif (OPENGL_FOUND AND GLUT_FOUND)
 
+if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
+
+    message(STATUS "libkshark-gui")
+    set (ks-guiLib_hdr  KsUtils.hpp)
+
+    QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr})
+
+    add_library(kshark-gui  SHARED  ${ks-guiLib_hdr_moc}    KsUtils.cpp)
+
+    target_link_libraries(kshark-gui kshark-plot
+                                     ${CMAKE_DL_LIBS}
+                                     ${TRACEEVENT_LIBRARY}
+                                     ${TRACECMD_LIBRARY}
+                                     Qt5::Widgets
+                                     Qt5::Network)
+
+    set_target_properties(kshark-gui PROPERTIES  SUFFIX ".so.${KS_VERSION_STRING}")
+
+endif (Qt5Widgets_FOUND AND Qt5Network_FOUND)
+
 add_subdirectory(plugins)
 
 configure_file( ${KS_DIR}/build/deff.h.cmake
diff --git a/kernel-shark-qt/src/KsUtils.cpp b/kernel-shark-qt/src/KsUtils.cpp
new file mode 100644
index 0000000..2c4cecc
--- /dev/null
+++ b/kernel-shark-qt/src/KsUtils.cpp
@@ -0,0 +1,584 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+/**
+ *  @file    KsUtils.cpp
+ *  @brief   KernelShark Utils.
+ */
+
+// KernelShark
+#include "KsUtils.hpp"
+
+namespace KsUtils {
+
+/** @brief Geat a sorteg vector of Task's Pids.  */
+QVector<int> getPidList()
+{
+	kshark_context *kshark_ctx(nullptr);
+	int nTasks, *tempPids;
+	QVector<int> pids;
+
+	if (!kshark_instance(&kshark_ctx))
+		return pids;
+
+	nTasks = kshark_get_task_pids(kshark_ctx, &tempPids);
+	for (int r = 0; r < nTasks; ++r) {
+		pids.append(tempPids[r]);
+	}
+
+	free(tempPids);
+
+	qSort(pids);
+
+	return pids;
+}
+
+/**
+ * Set the bit of the filter mask of the kshark session context responsible
+ * for the visibility of the events in the Table View.
+ */
+void listFilterSync(bool state)
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	if (state) {
+		kshark_ctx->filter_mask |= KS_TEXT_VIEW_FILTER_MASK;
+	} else {
+		kshark_ctx->filter_mask &= ~KS_TEXT_VIEW_FILTER_MASK;
+	}
+}
+
+/**
+ * Set the bit of the filter mask of the kshark session context responsible
+ * for the visibility of the events in the Graph View.
+ */
+void graphFilterSync(bool state)
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	if (state) {
+		kshark_ctx->filter_mask |= KS_GRAPH_VIEW_FILTER_MASK;
+	} else {
+		kshark_ctx->filter_mask &= ~KS_GRAPH_VIEW_FILTER_MASK;
+	}
+}
+
+/**
+ * @brief Simple CPU matching function to be user for data collections.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param e: kshark_entry to be checked.
+ * @param cpu: Matching condition value.
+ *
+ * @returns True if the CPU of the entry matches the value of "cpu" and
+ * 	    the entry is visibility in Graph. Otherwise false.
+ */
+bool matchCPUVisible(struct kshark_context *kshark_ctx,
+		     struct kshark_entry *e, int cpu)
+{
+	if (e->cpu == cpu && (e->visible & KS_GRAPH_VIEW_FILTER_MASK))
+		return true;
+
+	return false;
+}
+
+}; // KsUtils
+
+/** A stream operator for converting QColor into KsPlot::Color. */
+KsPlot::Color& operator <<(KsPlot::Color &thisColor, const QColor &c)
+{
+	thisColor.set(c.red(), c.green(), c.blue());
+
+	return thisColor;
+}
+
+/** Create a default (empty) KsDataStore. */
+KsDataStore::KsDataStore(QWidget *parent)
+: QObject(parent),
+  _pevent(nullptr),
+  _rows(nullptr),
+  _dataSize(0)
+{}
+
+/** Destroy the KsDataStore object. */
+KsDataStore::~KsDataStore()
+{}
+
+/** Load trace data for file. */
+void KsDataStore::loadDataFile(const QString &file)
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	clear();
+
+	if (!kshark_open(kshark_ctx, file.toStdString().c_str()) ||
+	    !kshark_ctx->handle ||
+	    !kshark_ctx->pevent) {
+		qCritical() << "ERROR Loading file " << file;
+		return;
+	}
+
+	_pevent = kshark_ctx->pevent;
+
+	if (kshark_ctx->event_handlers == nullptr)
+		kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT);
+	else
+		kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_UPDATE);
+
+	_dataSize = kshark_load_data_entries(kshark_ctx, &_rows);
+}
+
+void KsDataStore::_freeData()
+{
+	if (_dataSize) {
+		for (size_t r = 0; r < _dataSize; ++r)
+			free(_rows[r]);
+
+		free(_rows);
+		_rows = nullptr;
+	}
+}
+
+/** Reload the trace data. */
+void KsDataStore::reload()
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	_freeData();
+
+	_dataSize = kshark_load_data_entries(kshark_ctx, &_rows);
+	_pevent = kshark_ctx->pevent;
+
+	emit updateWidgets(this);
+}
+
+/** Free the loaded trace data and close the file. */
+void KsDataStore::clear()
+{
+	kshark_context *kshark_ctx(nullptr);
+
+	_freeData();
+
+	_pevent = nullptr;
+
+	if (kshark_instance(&kshark_ctx) &&
+	    kshark_ctx->handle)
+		kshark_close(kshark_ctx);
+}
+
+/** Update the visibility of the entries (filter). */
+void KsDataStore::update()
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	if (kshark_filter_is_set(kshark_ctx)) {
+		kshark_filter_entries(kshark_ctx, _rows, _dataSize);
+		emit updateWidgets(this);
+	}
+}
+
+/** Register a collection of visible entries for each CPU. */
+void KsDataStore::registerCPUCollections()
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx) ||
+	    !kshark_filter_is_set(kshark_ctx))
+		return;
+
+	int nCPUs = _pevent->cpus;
+	for (int cpu = 0; cpu < nCPUs; ++cpu) {
+		kshark_register_data_collection(kshark_ctx,
+						_rows, _dataSize,
+						KsUtils::matchCPUVisible,
+						cpu,
+						0);
+	}
+}
+
+void KsDataStore::_unregisterCPUCollections()
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	int nCPUs = _pevent->cpus;
+	for (int cpu = 0; cpu < nCPUs; ++cpu) {
+		kshark_unregister_data_collection(&kshark_ctx->collections,
+						  KsUtils::matchCPUVisible,
+						  cpu);
+	}
+}
+
+void KsDataStore::_applyIdFilter(int filterId, QVector<int> vec)
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	switch (filterId) {
+		case KS_SHOW_EVENT_FILTER:
+		case KS_HIDE_EVENT_FILTER:
+			kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER);
+			kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER);
+			break;
+		case KS_SHOW_TASK_FILTER:
+		case KS_HIDE_TASK_FILTER:
+			kshark_filter_clear(kshark_ctx, KS_SHOW_TASK_FILTER);
+			kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER);
+			break;
+		default:
+			return;
+	}
+
+	for (auto &&pid: vec)
+		kshark_filter_add_id(kshark_ctx, filterId, pid);
+
+	if (!_pevent)
+		return;
+
+	_unregisterCPUCollections();
+
+	/*
+	 * If the advanced event filter is set the data has to be reloaded,
+	 * because the advanced filter uses tep_records.
+	 */
+	if (kshark_ctx->advanced_event_filter->filters)
+		reload();
+	else
+		kshark_filter_entries(kshark_ctx, _rows, _dataSize);
+
+	registerCPUCollections();
+
+	emit updateWidgets(this);
+}
+
+/** Apply Show Task filter. */
+void KsDataStore::applyPosTaskFilter(QVector<int> vec)
+{
+	_applyIdFilter(KS_SHOW_TASK_FILTER, vec);
+}
+
+/** Apply Hide Task filter. */
+void KsDataStore::applyNegTaskFilter(QVector<int> vec)
+{
+	_applyIdFilter(KS_HIDE_TASK_FILTER, vec);
+}
+
+/** Apply Show Event filter. */
+void KsDataStore::applyPosEventFilter(QVector<int> vec)
+{
+	_applyIdFilter(KS_SHOW_EVENT_FILTER, vec);
+}
+
+/** Apply Hide Event filter. */
+void KsDataStore::applyNegEventFilter(QVector<int> vec)
+{
+	_applyIdFilter(KS_HIDE_EVENT_FILTER, vec);
+}
+
+/** Disable all filters. */
+void KsDataStore::clearAllFilters()
+{
+	kshark_context *kshark_ctx(nullptr);
+	kshark_instance(&kshark_ctx);
+
+	if (!_pevent)
+		return;
+
+	_unregisterCPUCollections();
+
+	kshark_filter_clear(kshark_ctx, KS_SHOW_TASK_FILTER);
+	kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER);
+	kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER);
+	kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER);
+
+	tep_filter_reset(kshark_ctx->advanced_event_filter);
+	kshark_clear_all_filters(kshark_ctx, _rows, _dataSize);
+
+	emit updateWidgets(this);
+}
+
+/**
+ * @brief Create Plugin Manager. Use list of plugins declared in the
+ *	  CMake-generated header file.
+ */
+KsPluginManager::KsPluginManager(QWidget *parent)
+: QObject(parent)
+{
+	kshark_context *kshark_ctx(nullptr);
+	_parsePluginList();
+
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	registerFromList(kshark_ctx);
+}
+
+/** Parse the plugin list declared in the CMake-generated header file. */
+void KsPluginManager::_parsePluginList()
+{
+	_ksPluginList = KsUtils::getPluginList();
+	int nPlugins = _ksPluginList.count();
+
+	_registeredKsPlugins.resize(nPlugins);
+	for (int i = 0; i < nPlugins; ++i) {
+		if (_ksPluginList[i].contains(" default", Qt::CaseInsensitive)) {
+			_ksPluginList[i].remove(" default", Qt::CaseInsensitive);
+			_registeredKsPlugins[i] = true;
+		} else {
+			_registeredKsPlugins[i] = false;
+		}
+	}
+}
+
+/**
+ * Register the plugins by using the information in "_ksPluginList" and
+ * "_registeredKsPlugins".
+ */
+void KsPluginManager::registerFromList(kshark_context *kshark_ctx)
+{
+	auto lamRegBuiltIn = [&kshark_ctx](const QString &plugin)
+	{
+		char *lib;
+		int n;
+		n = asprintf(&lib, "%s/lib/plugin-%s.so",
+			     KS_DIR, plugin.toStdString().c_str());
+		if (n > 0) {
+			kshark_register_plugin(kshark_ctx, lib);
+			free(lib);
+		}
+	};
+
+	auto lamRegUser = [&kshark_ctx](const QString &plugin)
+	{
+		const char *lib = plugin.toStdString().c_str();
+		kshark_register_plugin(kshark_ctx, lib);
+	};
+
+	_forEachInList(_ksPluginList,
+		       _registeredKsPlugins,
+		       lamRegBuiltIn);
+
+	_forEachInList(_userPluginList,
+		       _registeredUserPlugins,
+		       lamRegUser);
+}
+
+/**
+ * Unegister the plugins by using the information in "_ksPluginList" and
+ * "_registeredKsPlugins".
+ */
+void KsPluginManager::unregisterFromList(kshark_context *kshark_ctx)
+{
+	auto lamUregBuiltIn = [&kshark_ctx] (const QString &plugin)
+	{
+		char *lib;
+		int n;
+		n = asprintf(&lib, "%s/lib/plugin-%s.so",
+			     KS_DIR, plugin.toStdString().c_str());
+		if (n > 0) {
+			kshark_unregister_plugin(kshark_ctx, lib);
+			free(lib);
+		}
+	};
+
+	auto lamUregUser = [&kshark_ctx] (const QString &plugin)
+	{
+		const char *lib = plugin.toStdString().c_str();
+		kshark_unregister_plugin(kshark_ctx, lib);
+	};
+
+	_forEachInList(_ksPluginList,
+		       _registeredKsPlugins,
+			lamUregBuiltIn);
+
+	_forEachInList(_userPluginList,
+		       _registeredUserPlugins,
+			lamUregUser);
+}
+
+/**
+ * @brief Register a Plugin.
+ *
+ * @param plugin: provide here the name of the plugin (as in the CMake-generated
+ *		  header file) of a name of the plugin's library file (.so).
+ */
+void KsPluginManager::registerPlugin(const QString &plugin)
+{
+	kshark_context *kshark_ctx(nullptr);
+	char *lib;
+	int n;
+
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	for (int i = 0; i < _ksPluginList.count(); ++i) {
+		if (_ksPluginList[i] == plugin) {
+			/*
+			 * The argument is the name of the plugin. From the
+			 * name get the library .so file.
+			 */
+			n = asprintf(&lib, "%s/lib/plugin-%s.so",
+					KS_DIR, plugin.toStdString().c_str());
+			if (n > 0) {
+				kshark_register_plugin(kshark_ctx, lib);
+				_registeredKsPlugins[i] = true;
+				free(lib);
+			}
+
+			return;
+		} else if (plugin.contains("/lib/plugin-" + _ksPluginList[i],
+					   Qt::CaseInsensitive)) {
+			/*
+			 * The argument is the name of the library .so file.
+			 */
+			n = asprintf(&lib, "%s", plugin.toStdString().c_str());
+			if (n > 0) {
+				kshark_register_plugin(kshark_ctx, lib);
+				_registeredKsPlugins[i] = true;
+				free(lib);
+			}
+
+			return;
+		}
+	}
+
+	/* No plugin with this name in the list. Try to add it anyway. */
+	if (plugin.endsWith(".so") && QFileInfo::exists(plugin)) {
+		kshark_register_plugin(kshark_ctx,
+				       plugin.toStdString().c_str());
+
+		_userPluginList.append(plugin);
+		_registeredUserPlugins.append(true);
+	} else {
+		qCritical() << "ERROR: " << plugin << "cannot be registered!";
+	}
+}
+
+/** @brief Unregister a Plugin.
+ *<br> WARNING: Do not use this function to unregister User plugins.
+ * @param plugin: provide here the name of the plugin (as in the CMake-generated
+ *		  header file) of a name of the plugin's library file (.so).
+ *
+ */
+void KsPluginManager::unregisterPlugin(const QString &plugin)
+{
+	kshark_context *kshark_ctx(nullptr);
+	char *lib;
+	int n;
+
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	for (int i = 0; i < _ksPluginList.count(); ++i) {
+		if (_ksPluginList[i] == plugin) {
+			/*
+			 * The argument is the name of the plugin. From the
+			 * name get the library .so file.
+			 */
+			n = asprintf(&lib, "%s/lib/plugin-%s.so", KS_DIR,
+				     plugin.toStdString().c_str());
+			if (n > 0) {
+				kshark_unregister_plugin(kshark_ctx, lib);
+				_registeredKsPlugins[i] = false;
+				free(lib);
+			}
+
+			return;
+		} else if  (plugin.contains("/lib/plugin-" +
+			                   _ksPluginList[i], Qt::CaseInsensitive)) {
+			/*
+			 * The argument is the name of the library .so file.
+			 */
+			n = asprintf(&lib, "%s", plugin.toStdString().c_str());
+			if (n > 0) {
+				kshark_unregister_plugin(kshark_ctx, lib);
+				_registeredKsPlugins[i] = false;
+				free(lib);
+			}
+
+			return;
+		}
+	}
+}
+
+/** Unload all plugins. */
+void KsPluginManager::unloadAll()
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_CLOSE);
+	kshark_free_plugin_list(kshark_ctx->plugins);
+	kshark_ctx->plugins = nullptr;
+	kshark_free_event_handler_list(kshark_ctx->event_handlers);
+
+	unregisterFromList(kshark_ctx);
+}
+
+/** @brief Update (change) the Plugins.
+ *
+ * @param pluginIds: The indexes of the plugins to be loaded.
+ */
+void KsPluginManager::updatePlugins(QVector<int> pluginIds)
+{
+	kshark_context *kshark_ctx(nullptr);
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	auto register_plugins = [&] (QVector<int> ids)
+	{
+		int nKsPlugins = _registeredKsPlugins.count();
+
+		/* First clear all registered plugins. */
+		for (auto &p: _registeredKsPlugins)
+			p = false;
+		for (auto &p: _registeredUserPlugins)
+			p = false;
+
+		/* The vector contains the indexes of those to register. */
+		for (auto const &p: ids) {
+			if (p < nKsPlugins)
+				_registeredKsPlugins[p] = true;
+			else
+				_registeredUserPlugins[p - nKsPlugins] = true;
+		}
+		registerFromList(kshark_ctx);
+	};
+
+	if (!kshark_ctx->pevent) {
+		kshark_free_plugin_list(kshark_ctx->plugins);
+		kshark_ctx->plugins = nullptr;
+
+		/*
+		 * No data is loaded. For the moment, just register the
+		 * plugins. Handling of the plugins will be done after
+		 * we load a data file.
+		 */
+		register_plugins(pluginIds);
+		return;
+	}
+
+	/* Clean up all old plugins first. */
+	unloadAll();
+
+	/* Now load. */
+	register_plugins(pluginIds);
+	kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT);
+
+	emit dataReload();
+}
diff --git a/kernel-shark-qt/src/KsUtils.hpp b/kernel-shark-qt/src/KsUtils.hpp
new file mode 100644
index 0000000..40142ca
--- /dev/null
+++ b/kernel-shark-qt/src/KsUtils.hpp
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+/**
+ *  @file    KsUtils.hpp
+ *  @brief   KernelShark Utils.
+ */
+
+#ifndef _KS_UTILS_H
+#define _KS_UTILS_H
+
+// C++ 11
+#include <chrono>
+
+// Qt
+#include <QtWidgets>
+
+// KernelShark
+#include "libkshark.h"
+#include "libkshark-model.h"
+#include "KsCmakeDef.hpp"
+#include "KsPlotTools.hpp"
+
+/** Macro providing the height of the screen in pixels. */
+#define SCREEN_HEIGHT  QApplication::desktop()->screenGeometry().height()
+
+/** Macro providing the width of the screen in pixels. */
+#define SCREEN_WIDTH   QApplication::desktop()->screenGeometry().width()
+
+//! @cond Doxygen_Suppress
+
+auto fontHeight = [] ()
+{
+	QFont font;
+	QFontMetrics fm(font);
+	return fm.height();
+};
+
+auto stringWidth = [](QString s)
+{
+	QFont font;
+	QFontMetrics fm(font);
+	return fm.width(s);
+};
+
+//! @endcond
+
+/** Macro providing the height of the font in pixels. */
+#define FONT_HEIGHT		fontHeight()
+
+/** Macro providing the width of the font in pixels. */
+#define FONT_WIDTH 		stringWidth("4")
+
+/** Macro providing the width of a string in pixels. */
+#define STRING_WIDTH(s)		stringWidth(s)
+
+/** Macro providing the height of the KernelShark graphs in pixels. */
+#define KS_GRAPH_HEIGHT	(FONT_HEIGHT*2)
+
+//! @cond Doxygen_Suppress
+
+#define KS_JSON_CAST(doc) \
+reinterpret_cast<json_object *>(doc)
+
+#define KS_C_STR_CAST(doc) \
+reinterpret_cast<const char *>(doc)
+
+typedef std::chrono::high_resolution_clock::time_point  hd_time;
+
+#define GET_TIME std::chrono::high_resolution_clock::now()
+
+#define GET_DURATION(t0) \
+std::chrono::duration_cast<std::chrono::duration<double>>( \
+std::chrono::high_resolution_clock::now() - t0).count()
+
+//! @endcond
+
+namespace KsUtils {
+
+QVector<int> getPidList();
+
+/** @brief Geat the list of plugins. */
+inline QStringList getPluginList() {return plugins.split(";");}
+
+void listFilterSync(bool state);
+
+void graphFilterSync(bool state);
+
+/** @brief Convert the timestamp of the trace record into a string showing
+ *	   the time in seconds.
+ *
+ * @param ts: Input location for the timestamp.
+ * @param prec: the number of digits after the decimal point in the return
+ *		string.
+ *
+ * @returns String showing the time in seconds.
+ */
+inline QString Ts2String(int64_t ts, int prec)
+{
+	return QString::number(ts * 1e-9, 'f', prec);
+}
+
+bool matchCPUVisible(struct kshark_context *kshark_ctx,
+			      struct kshark_entry *e, int cpu);
+}; // KsUtils
+
+/** Identifier of the Dual Marker active state. */
+enum class DualMarkerState {
+	A,
+	B
+};
+
+/**
+ * The KsDataStore class provides the access to trace data for all KernelShark
+ * widgets.
+ */
+class KsDataStore : public QObject
+{
+	Q_OBJECT
+public:
+	explicit KsDataStore(QWidget *parent = nullptr);
+
+	~KsDataStore();
+
+	void loadDataFile(const QString &file);
+
+	void clear();
+
+	/** Get the page event used to parse the page.. */
+	tep_handle *pevent() const {return _pevent;}
+
+	/** Get the trace data array.. */
+	struct kshark_entry **rows() const {return _rows;}
+
+	/** Get the size of the data array. */
+	size_t size() const {return _dataSize;}
+
+	void reload();
+
+	void update();
+
+	void registerCPUCollections();
+
+	void applyPosTaskFilter(QVector<int>);
+
+	void applyNegTaskFilter(QVector<int>);
+
+	void applyPosEventFilter(QVector<int>);
+
+	void applyNegEventFilter(QVector<int>);
+
+	void clearAllFilters();
+
+signals:
+	/**
+	 * This signal is emitted when the data has changed and the View
+	 * widgets have to update.
+	 */
+	void updateWidgets(KsDataStore *);
+
+private:
+	/** Page event used to parse the page. */
+	tep_handle		*_pevent;
+
+	/** Trace data array. */
+	struct kshark_entry	**_rows;
+
+	/** The size of the data array. */
+	size_t			_dataSize;
+
+	void _freeData();
+	void _unregisterCPUCollections();
+	void _applyIdFilter(int filterId, QVector<int> vec);
+};
+
+/** A Plugin Manage class. */
+class KsPluginManager : public QObject
+{
+	Q_OBJECT
+public:
+	explicit KsPluginManager(QWidget *parent = nullptr);
+
+	/** A list of available built-in plugins. */
+	QStringList	_ksPluginList;
+
+	/** A list of registered built-in plugins. */
+	QVector<bool>	_registeredKsPlugins;
+
+	/** A list of available user plugins. */
+	QStringList	_userPluginList;
+
+	/** A list of registered user plugins. */
+	QVector<bool>	_registeredUserPlugins;
+
+	void registerFromList(kshark_context *kshark_ctx);
+	void unregisterFromList(kshark_context *kshark_ctx);
+
+	void registerPlugin(const QString &plugin);
+	void unregisterPlugin(const QString &plugin);
+	void unloadAll();
+
+	void updatePlugins(QVector<int> pluginId);
+
+signals:
+	/** This signal is emitted when a plugin is loaded or unloaded. */
+	void dataReload();
+
+private:
+	void _parsePluginList();
+
+	template <class T>
+	void _forEachInList(const QStringList &pl,
+			    const QVector<bool> &reg,
+			    T action)
+	{
+		int nPlugins;
+		nPlugins = pl.count();
+		for (int i = 0; i < nPlugins; ++i) {
+			if (reg[i]) {
+				action(pl[i]);
+			}
+		}
+	}
+};
+
+KsPlot::Color& operator <<(KsPlot::Color &thisColor, const QColor &c);
+
+#endif
-- 
2.17.1

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

* [PATCH 3/4] kernel-shark-qt: Add Widgets Lib
  2018-10-08 15:16 [PATCH 0/4] Add basic components to be used by the Qt GUI Yordan Karadzhov
  2018-10-08 15:16 ` [PATCH 1/4] kernel-shark-qt: Add Qt as a third party dependency Yordan Karadzhov
  2018-10-08 15:16 ` [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils Yordan Karadzhov
@ 2018-10-08 15:16 ` Yordan Karadzhov
  2018-10-09 16:42   ` Steven Rostedt
  2018-10-08 15:16 ` [PATCH 4/4] kernel-shark-qt: Add widget demo example Yordan Karadzhov
  3 siblings, 1 reply; 15+ messages in thread
From: Yordan Karadzhov @ 2018-10-08 15:16 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov, Yordan Karadzhov

From: Yordan Karadzhov <ykaradzhov@vmware.com>

This patch defines various small widgets and dialogues to be used by
the KernelShark GUI.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/src/CMakeLists.txt   |   6 +-
 kernel-shark-qt/src/KsWidgetsLib.cpp | 873 +++++++++++++++++++++++++++
 kernel-shark-qt/src/KsWidgetsLib.hpp | 370 ++++++++++++
 3 files changed, 1247 insertions(+), 2 deletions(-)
 create mode 100644 kernel-shark-qt/src/KsWidgetsLib.cpp
 create mode 100644 kernel-shark-qt/src/KsWidgetsLib.hpp

diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt
index e897e9a..2ac79ca 100644
--- a/kernel-shark-qt/src/CMakeLists.txt
+++ b/kernel-shark-qt/src/CMakeLists.txt
@@ -31,11 +31,13 @@ endif (OPENGL_FOUND AND GLUT_FOUND)
 if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
 
     message(STATUS "libkshark-gui")
-    set (ks-guiLib_hdr  KsUtils.hpp)
+    set (ks-guiLib_hdr  KsUtils.hpp
+                        KsWidgetsLib.hpp)
 
     QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr})
 
-    add_library(kshark-gui  SHARED  ${ks-guiLib_hdr_moc}    KsUtils.cpp)
+    add_library(kshark-gui  SHARED  ${ks-guiLib_hdr_moc}    KsUtils.cpp
+                                                            KsWidgetsLib.cpp)
 
     target_link_libraries(kshark-gui kshark-plot
                                      ${CMAKE_DL_LIBS}
diff --git a/kernel-shark-qt/src/KsWidgetsLib.cpp b/kernel-shark-qt/src/KsWidgetsLib.cpp
new file mode 100644
index 0000000..c6ae266
--- /dev/null
+++ b/kernel-shark-qt/src/KsWidgetsLib.cpp
@@ -0,0 +1,873 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+/**
+ *  @file    KsWidgetsLib.cpp
+ *  @brief   Defines small widgets and dialogues used by the KernelShark GUI.
+ */
+
+// KernelShark
+#include "libkshark.h"
+#include "KsUtils.hpp"
+#include "KsCmakeDef.hpp"
+#include "KsPlotTools.hpp"
+#include "KsWidgetsLib.hpp"
+
+/**
+ * @brief Create KsProgressBar.
+ *
+ * @param message: Text to be shown.
+ * @param parent: The parent of this widget.
+ */
+KsProgressBar::KsProgressBar(QString message, QWidget *parent)
+: QWidget(parent),
+  _sb(this),
+  _pb(&_sb) {
+	resize(FONT_WIDTH * 50, FONT_HEIGHT * 5);
+	setWindowTitle("KernelShark");
+	setLayout(new QVBoxLayout);
+
+	_pb.setOrientation(Qt::Horizontal);
+	_pb.setTextVisible(false);
+	_pb.setRange(0, KS_PROGRESS_BAR_MAX);
+	_pb.setValue(1);
+
+	_sb.addPermanentWidget(&_pb, 1);
+
+	layout()->addWidget(new QLabel(message));
+	layout()->addWidget(&_sb);
+
+	setWindowFlags(Qt::WindowStaysOnTopHint);
+
+	show();
+}
+
+/** @brief Set the state of the progressbar.
+ *
+ * @param i: A value ranging from 0 to KS_PROGRESS_BAR_MAX.
+ */
+void KsProgressBar::setValue(int i) {
+	_pb.setValue(i);
+	QApplication::processEvents();
+}
+
+/**
+ * @brief Create KsMessageDialog.
+ *
+ * @param message: Text to be shown.
+ * @param parent: The parent of this widget.
+ */
+KsMessageDialog::KsMessageDialog(QString message, QWidget *parent)
+: QDialog(parent),
+  _text(message, this),
+  _closeButton("Close", this)
+{
+	resize(SCREEN_WIDTH / 10, FONT_HEIGHT * 8);
+
+	_layout.addWidget(&_text);
+	_layout.addWidget(&_closeButton);
+
+	connect(&_closeButton,	&QPushButton::pressed,
+		this,		&QWidget::close);
+
+	this->setLayout(&_layout);
+}
+
+/**
+ * @brief Create KsCheckBoxWidget.
+ *
+ * @param name: The name of this widget.
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxWidget::KsCheckBoxWidget(const QString &name, QWidget *parent)
+: QWidget(parent),
+  _allCb("all", this),
+  _cbWidget(this),
+  _cbLayout(&_cbWidget),
+  _topLayout(this),
+  _name(name),
+  _nameLabel(name + ":  ")
+{
+	setWindowTitle(_name);
+	setMinimumHeight(SCREEN_HEIGHT / 2);
+
+	connect(&_allCb,	&QCheckBox::clicked,
+		this,		&KsCheckBoxWidget::_checkAll);
+
+	_cbWidget.setLayout(&_cbLayout);
+
+	QToolBar *tb = new QToolBar(this);
+
+	tb->addWidget(&_nameLabel);
+	tb->addWidget(&_allCb);
+	_topLayout.addWidget(tb);
+
+	_topLayout.addWidget(&_cbWidget);
+	_topLayout.setContentsMargins(0, 0, 0, 0);
+
+	setLayout(&_topLayout);
+	_allCb.setCheckState(Qt::Checked);
+}
+
+/**
+ * Set the default state for all checkboxes (including the "all" checkbox).
+ */
+void KsCheckBoxWidget::setDefault(bool st)
+{
+	Qt::CheckState state = Qt::Unchecked;
+
+	if (st)
+		state = Qt::Checked;
+
+	_allCb.setCheckState(state);
+	_checkAll(state);
+}
+
+/** Get a vector containing the indexes of all checked boxes. */
+QVector<int> KsCheckBoxWidget::getCheckedIds()
+{
+	QVector<int> vec;
+	int n = _id.size();
+
+	for (int i = 0; i < n; ++i)
+		if (_checkState(i) == Qt::Checked)
+			vec.append(_id[i]);
+
+	return vec;
+}
+
+/**
+ * @brief Set the state of the checkboxes.
+ *
+ * @param v: Vector containing the bool values for all checkboxes.
+ */
+void KsCheckBoxWidget::set(QVector<bool> v)
+{
+	Qt::CheckState state;
+	int nChecks;
+
+	nChecks = (v.size() < _id.size()) ? v.size() : _id.size();
+
+	/* Start with the "all" checkbox being checked. */
+	_allCb.setCheckState(Qt::Checked);
+	for (int i = 0; i < nChecks; ++i) {
+		if (v[i]) {
+			state = Qt::Checked;
+		} else {
+			/*
+			 * At least one checkbox is unchecked. Uncheck
+			 * "all" as well.
+			 */
+			state = Qt::Unchecked;
+			_allCb.setCheckState(state);
+		}
+
+		_setCheckState(i, state);
+	}
+	_verify();
+}
+
+void KsCheckBoxWidget::_checkAll(bool st)
+{
+	Qt::CheckState state = Qt::Unchecked;
+	int n = _id.size();
+
+	if (st) state = Qt::Checked;
+
+	for (int i = 0; i < n; ++i) {
+		_setCheckState(i, state);
+	}
+
+	_verify();
+}
+
+/**
+ * @brief Create KsCheckBoxDialog.
+ *
+ * @param cbw: A KsCheckBoxWidget to be nested in this dialog.
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxDialog::KsCheckBoxDialog(KsCheckBoxWidget *cbw, QWidget *parent)
+: QDialog(parent), _checkBoxWidget(cbw),
+  _applyButton("Apply", this),
+  _cancelButton("Cancel", this)
+{
+	int buttonWidth;
+
+	setWindowTitle(cbw->name());
+	_topLayout.addWidget(_checkBoxWidget);
+
+	buttonWidth = STRING_WIDTH("--Cancel--");
+	_applyButton.setFixedWidth(buttonWidth);
+	_cancelButton.setFixedWidth(buttonWidth);
+
+	_buttonLayout.addWidget(&_applyButton);
+	_applyButton.setAutoDefault(false);
+
+	_buttonLayout.addWidget(&_cancelButton);
+	_cancelButton.setAutoDefault(false);
+
+	_buttonLayout.setAlignment(Qt::AlignLeft);
+	_topLayout.addLayout(&_buttonLayout);
+
+	_applyButtonConnection =
+		connect(&_applyButton,	&QPushButton::pressed,
+			this,		&KsCheckBoxDialog::_applyPress);
+
+	connect(&_applyButton,	&QPushButton::pressed,
+		this,		&QWidget::close);
+
+	connect(&_cancelButton,	&QPushButton::pressed,
+		this,		&QWidget::close);
+
+	this->setLayout(&_topLayout);
+}
+
+void KsCheckBoxDialog::_applyPress()
+{
+	QVector<int> vec = _checkBoxWidget->getCheckedIds();
+	emit apply(vec);
+
+	/*
+	 * Disconnect _applyButton. This is done in order to protect
+	 * against multiple clicks.
+	 */
+	disconnect(_applyButtonConnection);
+}
+
+
+/**
+ * @brief Create KsCheckBoxTable.
+ *
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxTable::KsCheckBoxTable(QWidget *parent)
+: QTableWidget(parent)
+{
+	setShowGrid(false);
+	horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
+	horizontalHeader()->setStretchLastSection(true);
+	setSelectionBehavior(QAbstractItemView::SelectRows);
+	setEditTriggers(QAbstractItemView::NoEditTriggers);
+	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+	verticalHeader()->setVisible(false);
+
+	connect(this, &QTableWidget::cellDoubleClicked,
+		this, &KsCheckBoxTable::_doubleClicked);
+}
+
+/**
+ * @brief Initialize the table.
+ *
+ * @param headers: The headers of the individual columns.
+ * @param size: The number of rows.
+ */
+void KsCheckBoxTable::init(QStringList headers, int size)
+{
+	QHBoxLayout *cbLayout;
+	QWidget *cbWidget;
+
+	setColumnCount(headers.count());
+	setRowCount(size);
+	setHorizontalHeaderLabels(headers);
+
+	_cb.resize(size);
+
+	for (int i = 0; i < size; ++i) {
+		cbWidget = new QWidget();
+		_cb[i] = new QCheckBox(cbWidget);
+		cbLayout = new QHBoxLayout(cbWidget);
+
+		cbLayout->addWidget(_cb[i]);
+		cbLayout->setAlignment(Qt::AlignCenter);
+		cbLayout->setContentsMargins(0, 0, 0, 0);
+
+		cbWidget->setLayout(cbLayout);
+		setCellWidget(i, 0, cbWidget);
+	}
+}
+
+/** Reimplemented event handler used to receive key press events. */
+void KsCheckBoxTable::keyPressEvent(QKeyEvent *event)
+{
+	if (event->key() == Qt::Key_Return) {
+		for (auto &s: selectedItems()) {
+			if (s->column() == 1)
+				emit changeState(s->row());
+		}
+	}
+
+	QApplication::processEvents();
+	QTableWidget::keyPressEvent(event);
+}
+
+/** Reimplemented event handler used to receive mouse press events. */
+void KsCheckBoxTable::mousePressEvent(QMouseEvent *event)
+{
+	if (event->button() == Qt::RightButton) {
+		for (auto &i: selectedItems())
+			i->setSelected(false);
+
+		return;
+	}
+
+	QApplication::processEvents();
+	QTableWidget::mousePressEvent(event);
+}
+
+void KsCheckBoxTable::_doubleClicked(int row, int col)
+{
+	emit changeState(row);
+	for (auto &i: selectedItems())
+		i->setSelected(false);
+}
+
+/**
+ * @brief Create KsCheckBoxTableWidget.
+ *
+ * @param name: The name of this widget.
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxTableWidget::KsCheckBoxTableWidget(const QString &name,
+					     QWidget *parent)
+: KsCheckBoxWidget(name, parent),
+  _table(this)
+{
+	connect(&_table,	&KsCheckBoxTable::changeState,
+		this,		&KsCheckBoxTableWidget::_changeState);
+}
+
+/** Initialize the KsCheckBoxTable and its layout. */
+void KsCheckBoxTableWidget::_initTable(QStringList headers, int size)
+{
+	_table.init(headers, size);
+
+	for (auto const & cb: _table._cb) {
+		connect(cb,	&QCheckBox::clicked,
+			this,	&KsCheckBoxTableWidget::_update);
+	}
+
+	_cbLayout.setContentsMargins(1, 1, 1, 1);
+	_cbLayout.addWidget(&_table);
+}
+
+/** Adjust the size of this widget according to its content. */
+void KsCheckBoxTableWidget::_adjustSize()
+{
+	int width;
+
+	_table.setVisible(false);
+	_table.resizeColumnsToContents();
+	_table.setVisible(true);
+
+	width = _table.horizontalHeader()->length() +
+		FONT_WIDTH * 3 +
+		style()->pixelMetric(QStyle::PM_ScrollBarExtent);
+
+	_cbWidget.resize(width, _cbWidget.height());
+
+	setMinimumWidth(_cbWidget.width() +
+			_cbLayout.contentsMargins().left() +
+			_cbLayout.contentsMargins().right() +
+			_topLayout.contentsMargins().left() +
+			_topLayout.contentsMargins().right());
+}
+
+void  KsCheckBoxTableWidget::_update(bool state)
+{
+	/* If a Checkbox is being unchecked. Unchecked "all" as well. */
+	if (!state)
+		_allCb.setCheckState(Qt::Unchecked);
+}
+
+void KsCheckBoxTableWidget::_changeState(int row)
+{
+	if (_table._cb[row]->checkState() == Qt::Checked)
+		_table._cb[row]->setCheckState(Qt::Unchecked);
+	else
+		_table._cb[row]->setCheckState(Qt::Checked);
+
+	_allCb.setCheckState(Qt::Checked);
+	for (auto &c: _table._cb) {
+		if (c->checkState() == Qt::Unchecked) {
+			_allCb.setCheckState(Qt::Unchecked);
+			break;
+		}
+	}
+}
+
+static void update_r(QTreeWidgetItem *item, Qt::CheckState state)
+{
+	int n;
+
+	item->setCheckState(0, state);
+
+	n = item->childCount();
+	for (int i = 0; i < n; ++i)
+		update_r(item->child(i), state);
+}
+
+/**
+ * @brief Create KsCheckBoxTree.
+ *
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxTree::KsCheckBoxTree(QWidget *parent)
+: QTreeWidget(parent)
+{
+	setColumnCount(2);
+	setHeaderHidden(true);
+	setSelectionBehavior(QAbstractItemView::SelectRows);
+	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+	connect(this, &KsCheckBoxTree::itemDoubleClicked,
+		this, &KsCheckBoxTree::_doubleClicked);
+}
+
+/** Reimplemented event handler used to receive key press events. */
+void KsCheckBoxTree::keyPressEvent(QKeyEvent *event)
+{
+	if (event->key() == Qt::Key_Return) {
+		/* Loop over all selected child items and change
+		* there states. */
+		for (auto &s: selectedItems()) {
+			if(s->childCount()) {
+				if (s->isExpanded())
+					continue;
+			}
+
+			if (s->checkState(0) == Qt::Unchecked)
+				s->setCheckState(0, Qt::Checked);
+			else
+				s->setCheckState(0, Qt::Unchecked);
+
+			if(s->childCount()) {
+				update_r(s, s->checkState(0));
+			}
+		}
+	}
+
+	emit verify();
+	QTreeWidget::keyPressEvent(event);
+}
+
+void KsCheckBoxTree::_doubleClicked(QTreeWidgetItem *item, int col)
+{
+	if (item->checkState(0) == Qt::Unchecked)
+		item->setCheckState(0, Qt::Checked);
+	else
+		item->setCheckState(0, Qt::Unchecked);
+
+	for (auto &i: selectedItems())
+		i->setSelected(false);
+
+	emit itemClicked(item, col);
+}
+
+/** Reimplemented event handler used to receive mouse press events. */
+void KsCheckBoxTree::mousePressEvent(QMouseEvent *event)
+{
+	if (event->button() == Qt::RightButton) {
+		for (auto &i: selectedItems())
+			i->setSelected(false);
+		return;
+	}
+
+	QApplication::processEvents();
+	QTreeWidget::mousePressEvent(event);
+}
+
+/**
+ * @brief Create KsCheckBoxTreeWidget.
+ *
+ * @param name: The name of this widget.
+ * @param parent: The parent of this widget.
+ */
+KsCheckBoxTreeWidget::KsCheckBoxTreeWidget(const QString &name,
+					   QWidget *parent)
+: KsCheckBoxWidget(name, parent),
+  _tree(this)
+{
+	connect(&_tree,	&KsCheckBoxTree::verify,
+		this,	&KsCheckBoxTreeWidget::_verify);
+}
+
+/** Initialize the KsCheckBoxTree and its layout. */
+void KsCheckBoxTreeWidget::_initTree()
+{
+	_tree.setSelectionMode(QAbstractItemView::MultiSelection);
+
+	connect(&_tree, &QTreeWidget::itemClicked,
+		this,	&KsCheckBoxTreeWidget::_update);
+
+	_cbLayout.setContentsMargins(1, 1, 1, 1);
+	_cbLayout.addWidget(&_tree);
+}
+
+/** Adjust the size of this widget according to its content. */
+void KsCheckBoxTreeWidget::_adjustSize()
+{
+	int width, n = _tree.topLevelItemCount();
+	if (n == 0)
+		return;
+
+	for (int i = 0; i < n; ++i)
+		_tree.topLevelItem(i)->setExpanded(true);
+
+	_tree.resizeColumnToContents(0);
+	if (_tree.topLevelItem(0)->child(0)) {
+		width = _tree.visualItemRect(_tree.topLevelItem(0)->child(0)).width();
+	} else {
+		width = _tree.visualItemRect(_tree.topLevelItem(0)).width();
+	}
+
+	width += FONT_WIDTH*3 + style()->pixelMetric(QStyle::PM_ScrollBarExtent);
+	_cbWidget.resize(width, _cbWidget.height());
+
+	for (int i = 0; i < n; ++i)
+		_tree.topLevelItem(i)->setExpanded(false);
+
+	setMinimumWidth(_cbWidget.width() +
+			_cbLayout.contentsMargins().left() +
+			_cbLayout.contentsMargins().right() +
+			_topLayout.contentsMargins().left() +
+			_topLayout.contentsMargins().right());
+}
+
+void KsCheckBoxTreeWidget::_update(QTreeWidgetItem *item, int column)
+{
+	/* Get the new state of the item. */
+	Qt::CheckState state = item->checkState(0);
+
+	/* Recursively update all items below this one. */
+	update_r(item, state);
+
+	/* Update all items above this one including the "all"
+	 * check box. */
+	_verify();
+}
+
+void KsCheckBoxTreeWidget::_verify()
+{
+	/* Set the state of the top level items according to the
+	* state of the childs. */
+	QTreeWidgetItem *topItem, *childItem;
+	for(int t = 0; t < _tree.topLevelItemCount(); ++t) {
+		topItem = _tree.topLevelItem(t);
+		if (topItem->childCount() == 0)
+			continue;
+
+		topItem->setCheckState(0, Qt::Checked);
+		for (int c = 0; c < topItem->childCount(); ++c) {
+			childItem = topItem->child(c);
+			if (childItem->checkState(0) == Qt::Unchecked)
+				topItem->setCheckState(0, Qt::Unchecked);
+		}
+	}
+
+	_allCb.setCheckState(Qt::Checked);
+	for (auto &c: _cb) {
+		if (c->checkState(0) == Qt::Unchecked) {
+			_allCb.setCheckState(Qt::Unchecked);
+			break;
+		}
+	}
+}
+
+/**
+ * @brief Create KsCPUCheckBoxWidget.
+ *
+ * @param pevent: Page event used to parse the page.
+ * @param parent: The parent of this widget.
+ */
+KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(struct tep_handle *pevent,
+					 QWidget *parent)
+: KsCheckBoxTreeWidget("CPUs", parent)
+{
+	int nCPUs(0), height(FONT_HEIGHT * 1.5);
+	KsPlot::Color cpuCol;
+	QString style;
+
+	style = QString("QTreeView::item { height: %1 ;}").arg(height);
+	_tree.setStyleSheet(style);
+
+	_initTree();
+
+	if (pevent)
+		nCPUs = pevent->cpus;
+
+	_id.resize(nCPUs);
+	_cb.resize(nCPUs);
+
+	for (int i = 0; i < nCPUs; ++i) {
+		cpuCol.setRainbowColor(i);
+		QTreeWidgetItem *cpuItem = new QTreeWidgetItem;
+		cpuItem->setText(0, "  ");
+		cpuItem->setText(1, QString("CPU %1").arg(i));
+		cpuItem->setCheckState(0, Qt::Checked);
+		cpuItem->setBackgroundColor(0, QColor(cpuCol.r(),
+						      cpuCol.g(),
+						      cpuCol.b()));
+		_tree.addTopLevelItem(cpuItem);
+		_id[i] = i;
+		_cb[i] = cpuItem;
+	}
+
+	_adjustSize();
+}
+
+/**
+ * @brief Create KsEventsCheckBoxWidget.
+ *
+ * @param pevent: Page event used to parse the page.
+ * @param parent: The parent of this widget.
+ */
+KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(struct tep_handle *pevent,
+					       QWidget *parent)
+: KsCheckBoxTreeWidget("Events", parent)
+{
+	QTreeWidgetItem *sysItem, *evtItem;
+	QString sysName, evtName;
+	int nEvts(0), i(0);
+
+	if (pevent)
+		nEvts = pevent->nr_events;
+
+	_initTree();
+	_id.resize(nEvts);
+	_cb.resize(nEvts);
+
+	while (i < nEvts) {
+		sysName = pevent->events[i]->system;
+		sysItem = new QTreeWidgetItem;
+		sysItem->setText(0, sysName);
+		sysItem->setCheckState(0, Qt::Checked);
+		_tree.addTopLevelItem(sysItem);
+
+		while (sysName == pevent->events[i]->system) {
+			evtName = pevent->events[i]->name;
+			evtItem = new QTreeWidgetItem;
+			evtItem->setText(0, evtName);
+			evtItem->setCheckState(0, Qt::Checked);
+			evtItem->setFlags(evtItem->flags() |
+					  Qt::ItemIsUserCheckable);
+
+			sysItem->addChild(evtItem);
+
+			_id[i] = pevent->events[i]->id;
+			_cb[i] = evtItem;
+
+			if (++i == nEvts)
+				break;
+		}
+	}
+
+	_tree.sortItems(0, Qt::AscendingOrder);
+	_adjustSize();
+}
+
+/**
+ * @brief Create KsTasksCheckBoxWidget.
+ *
+ * @param pevent: Page event used to parse the page.
+ * @param cond: If True make a "Show Task" widget. Otherwise make "Hide Task".
+ * @param parent: The parent of this widget.
+ */
+KsTasksCheckBoxWidget::KsTasksCheckBoxWidget(struct tep_handle *pevent,
+					     bool cond, QWidget *parent)
+: KsCheckBoxTableWidget("Tasks", parent)
+{
+	kshark_context *kshark_ctx(nullptr);
+	QTableWidgetItem *pidItem, *comItem;
+	KsPlot::Color pidCol;
+	QStringList headers;
+	const char *comm;
+	int nTasks;
+
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	if (_cond)
+		headers << "Show" << "Pid" << "Task";
+	else
+		headers << "Hide" << "Pid" << "Task";
+
+	_id = KsUtils::getPidList();
+	nTasks = _id.count();
+	_initTable(headers, nTasks);
+
+	for (int i = 0; i < nTasks; ++i) {
+		pidItem	= new QTableWidgetItem(tr("%1").arg(_id[i]));
+		_table.setItem(i, 1, pidItem);
+
+		comm = tep_data_comm_from_pid(kshark_ctx->pevent, _id[i]);
+		comItem = new QTableWidgetItem(tr(comm));
+
+		pidItem->setBackgroundColor(QColor(pidCol.r(),
+						   pidCol.g(),
+						   pidCol.b()));
+
+		if (_id[i] == 0)
+			pidItem->setTextColor(Qt::white);
+
+		_table.setItem(i, 2, comItem);
+
+		pidCol.setRainbowColor(i);
+	}
+
+	_adjustSize();
+}
+
+/**
+ * @brief Create KsPluginCheckBoxWidget.
+ *
+ * @param pluginList: A list of plugin names.
+ * @param parent: The parent of this widget.
+ */
+KsPluginCheckBoxWidget::KsPluginCheckBoxWidget(QStringList pluginList,
+					       QWidget *parent)
+: KsCheckBoxTableWidget("Plugins", parent)
+{
+	QTableWidgetItem *nameItem, *infoItem;
+	QStringList headers;
+	int nPlgins;
+
+	headers << "Load" << "Name" << "Info";
+
+	nPlgins = pluginList.count();
+	_initTable(headers, nPlgins);
+	_id.resize(nPlgins);
+
+	for (int i = 0; i < nPlgins; ++i) {
+		nameItem = new QTableWidgetItem(pluginList[i]);
+		_table.setItem(i, 1, nameItem);
+		infoItem = new QTableWidgetItem(" -- ");
+		_table.setItem(i, 2, infoItem);
+		_id[i] = i;
+	}
+
+	_adjustSize();
+}
+
+/**
+ * @brief Create KsQuickEntryMenu.
+ *
+ * @param data: Input location for the KsDataStore object.
+ * @param row: The index of the entry used to initialize the menu.
+ * @param parent: The parent of this widget.
+ */
+KsQuickEntryMenu::KsQuickEntryMenu(KsDataStore *data, size_t row,
+				   QWidget *parent)
+: QMenu("Entry menu", parent),
+  _data(data),
+  _row(row),
+  _hideTaskAction(this),
+  _showTaskAction(this),
+  _hideEventAction(this),
+  _showEventAction(this),
+  _addTaskPlotAction(this)
+{
+	QString descr;
+
+	addSection("Quick Filter menu");
+
+	descr = "Hide task [";
+	descr += kshark_get_task_easy(_data->rows()[_row]);
+	descr += "-";
+	descr += QString("%1").arg(_data->rows()[_row]->pid);
+	descr += "]";
+
+	_hideTaskAction.setText(descr);
+
+	connect(&_hideTaskAction,	&QAction::triggered,
+		this,			&KsQuickEntryMenu::_hideTask);
+
+	addAction(&_hideTaskAction);
+
+	descr = "Show task [";
+	descr += kshark_get_task_easy(_data->rows()[_row]);
+	descr += "-";
+	descr += QString("%1").arg(_data->rows()[_row]->pid);
+	descr += "] only";
+
+	_showTaskAction.setText(descr);
+
+	connect(&_showTaskAction,	&QAction::triggered,
+		this,			&KsQuickEntryMenu::_showTask);
+
+	addAction(&_showTaskAction);
+
+	descr = "Hide event [";
+	descr += kshark_get_event_name_easy(_data->rows()[_row]);
+	descr += "]";
+
+	_hideEventAction.setText(descr);
+
+	connect(&_hideEventAction,	&QAction::triggered,
+		this,			&KsQuickEntryMenu::_hideEvent);
+
+	addAction(&_hideEventAction);
+
+	descr = "Show event [";
+	descr += kshark_get_event_name_easy(_data->rows()[_row]);
+	descr += "] only";
+
+	_showEventAction.setText(descr);
+
+	connect(&_showEventAction,	&QAction::triggered,
+		this,			&KsQuickEntryMenu::_showEvent);
+
+	addAction(&_showEventAction);
+
+	addSection("Quick Plot menu");
+	descr = "Add [";
+	descr += kshark_get_task_easy(_data->rows()[_row]);
+	descr += "-";
+	descr += QString("%1").arg(_data->rows()[_row]->pid);
+	descr += "] plot";
+
+	_addTaskPlotAction.setText(descr);
+
+	connect(&_addTaskPlotAction,	&QAction::triggered,
+		this,			&KsQuickEntryMenu::_addTaskPlot);
+
+	addAction(&_addTaskPlotAction);
+}
+
+void KsQuickEntryMenu::_hideTask()
+{
+	int pid = kshark_get_pid_easy(_data->rows()[_row]);
+
+	_data->applyNegTaskFilter(QVector<int>(1, pid));
+}
+
+void KsQuickEntryMenu::_showTask()
+{
+	int pid = kshark_get_pid_easy(_data->rows()[_row]);
+
+	_data->applyPosTaskFilter(QVector<int>(1, pid));
+}
+
+void KsQuickEntryMenu::_hideEvent()
+{
+	int eventId = kshark_get_event_id_easy(_data->rows()[_row]);
+
+	_data->applyNegEventFilter(QVector<int>(1, eventId));
+}
+
+void KsQuickEntryMenu::_showEvent()
+{
+	int eventId = kshark_get_event_id_easy(_data->rows()[_row]);
+
+	_data->applyPosEventFilter(QVector<int>(1, eventId));
+}
+
+void KsQuickEntryMenu::_addTaskPlot()
+{
+	int pid = kshark_get_pid_easy(_data->rows()[_row]);
+
+	emit plotTask(pid);
+}
diff --git a/kernel-shark-qt/src/KsWidgetsLib.hpp b/kernel-shark-qt/src/KsWidgetsLib.hpp
new file mode 100644
index 0000000..85e2675
--- /dev/null
+++ b/kernel-shark-qt/src/KsWidgetsLib.hpp
@@ -0,0 +1,370 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2016 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ */
+
+ /**
+  *  @file    KsWidgetsLib.hpp
+  *  @brief   Defines small widgets and dialogues used by the KernelShark GUI.
+  */
+
+#ifndef _KS_WIDGETS_LIB_H
+#define _KS_WIDGETS_LIB_H
+
+// Qt
+#include <QtWidgets>
+
+/**
+ * The KsProgressBar class provides a visualization of the progress of a
+ * running job.
+ */
+class KsProgressBar : public QWidget
+{
+	Q_OBJECT
+
+	QStatusBar	_sb;
+
+	QProgressBar	_pb;
+
+public:
+	KsProgressBar(QString message, QWidget *parent = nullptr);
+
+	void setValue(int i);
+};
+
+/** Defines the progress bar's maximum value. */
+#define KS_PROGRESS_BAR_MAX 200
+
+/**
+ * The KsMessageDialog class provides a widget showing a message and having
+ * a "Close" button.
+ */
+class KsMessageDialog : public QDialog
+{
+	QVBoxLayout	_layout;
+
+	QLabel		_text;
+
+	QPushButton	_closeButton;
+
+public:
+	explicit KsMessageDialog(QWidget *parent) = delete;
+
+	KsMessageDialog(QString message, QWidget *parent = nullptr);
+};
+
+/**
+ * The KsCheckBoxWidget class is the base class of all CheckBox widget used
+ * by KernelShark.
+ */
+class KsCheckBoxWidget : public QWidget
+{
+	Q_OBJECT
+public:
+	KsCheckBoxWidget(const QString &name = "",
+			 QWidget *parent = nullptr);
+
+	/** Get the name of the widget. */
+	QString name() const {return _name;}
+
+	/** Get the state of the "all" checkboxe. */
+	bool all() const
+	{
+		if(_allCb.checkState() == Qt::Checked)
+			return true;
+		return false;
+	}
+
+	void setDefault(bool);
+
+	void set(QVector<bool> v);
+
+	QVector<int> getCheckedIds();
+
+protected:
+	/** The "all" checkboxe. */
+	QCheckBox	_allCb;
+
+	/** A vector of Id numbers coupled to each checkboxe. */
+	QVector<int>	_id;
+
+	/** A nested widget used to position the checkboxes. */
+	QWidget		_cbWidget;
+
+	/** The layout of the nested widget. */
+	QVBoxLayout	_cbLayout;
+
+	/** The top level layout of this widget. */
+	QVBoxLayout	_topLayout;
+
+	/** The name of this widget. */
+	QString		_name;
+
+	/** A label to show the name of the widget. */
+	QLabel		_nameLabel;
+
+private:
+	virtual void _setCheckState(int i, Qt::CheckState st) = 0;
+
+	virtual Qt::CheckState _checkState(int i) const = 0;
+
+	virtual void _verify() {};
+
+	void _checkAll(bool);
+};
+
+/**
+ * The KsCheckBoxDialog class is the base class of all CheckBox dialogs
+ * used by KernelShark.
+ */
+class KsCheckBoxDialog : public QDialog
+{
+	Q_OBJECT
+public:
+	KsCheckBoxDialog() = delete;
+
+	KsCheckBoxDialog(KsCheckBoxWidget *cbw, QWidget *parent = nullptr);
+
+signals:
+	/** Signal emitted when the "Apply" button is pressed. */
+	void apply(QVector<int>);
+
+private:
+	void _applyPress();
+
+	QVBoxLayout		_topLayout;
+
+	QHBoxLayout		_buttonLayout;
+
+	KsCheckBoxWidget	*_checkBoxWidget;
+
+	QPushButton		_applyButton, _cancelButton;
+
+	QMetaObject::Connection		_applyButtonConnection;
+};
+
+/** The KsCheckBoxTable class provides a table of checkboxes. */
+class KsCheckBoxTable : public QTableWidget
+{
+	Q_OBJECT
+public:
+	explicit KsCheckBoxTable(QWidget *parent = nullptr);
+
+	void init(QStringList headers, int size);
+
+	/** A vector of checkboxes. */
+	QVector<QCheckBox*>	_cb;
+
+signals:
+	/** Signal emitted when a checkboxes changes state. */
+	void changeState(int row);
+
+protected:
+	void keyPressEvent(QKeyEvent *event) override;
+
+	void mousePressEvent(QMouseEvent *event) override;
+
+private:
+	void _doubleClicked(int row, int col);
+};
+
+/**
+ * The KsCheckBoxTableWidget class provides a widget to hold a table of
+ * checkboxes.
+ */
+class KsCheckBoxTableWidget : public KsCheckBoxWidget
+{
+	Q_OBJECT
+public:
+	KsCheckBoxTableWidget(const QString &name = "",
+			      QWidget *parent = nullptr);
+
+protected:
+	void _adjustSize();
+
+	void _initTable(QStringList headers, int size);
+
+	/** The KsCheckBoxTable, shown by this widget. */
+	KsCheckBoxTable		_table;
+
+private:
+	void _setCheckState(int i, Qt::CheckState st) override
+	{
+		_table._cb[i]->setCheckState(st);
+	}
+
+	Qt::CheckState _checkState(int i) const override
+	{
+		return _table._cb[i]->checkState();
+	}
+
+	void _update(bool);
+
+	void _changeState(int row);
+};
+
+/** The KsCheckBoxTree class provides a tree of checkboxes. */
+class KsCheckBoxTree : public QTreeWidget
+{
+	Q_OBJECT
+public:
+	explicit KsCheckBoxTree(QWidget *parent = nullptr);
+
+signals:
+	/**
+	 * Signal emitted when a checkboxes of the tree changes its state
+	 * and the state of all toplevel and child checkboxes has to be
+	 * reprocesed.
+	 */
+	void verify();
+
+protected:
+	void keyPressEvent(QKeyEvent *event) override;
+
+	void mousePressEvent(QMouseEvent *event) override;
+
+private:
+	void _doubleClicked(QTreeWidgetItem *item, int col);
+};
+
+/**
+ * The KsCheckBoxTreeWidget class provides a widget to hold a tree of
+ * checkboxes.
+ */
+class KsCheckBoxTreeWidget : public KsCheckBoxWidget
+{
+	Q_OBJECT
+public:
+	KsCheckBoxTreeWidget() = delete;
+
+	KsCheckBoxTreeWidget(const QString &name = "",
+			     QWidget *parent = nullptr);
+
+protected:
+	void _adjustSize();
+
+	void _initTree();
+
+	/** The KsCheckBoxTree, shown by this widget. */
+	KsCheckBoxTree			_tree;
+
+	/** A vector of Tree items (checkboxes). */
+	QVector<QTreeWidgetItem*>	_cb;
+
+private:
+	void _setCheckState(int i, Qt::CheckState st) override
+	{
+		_cb[i]->setCheckState(0, st);
+	}
+
+	Qt::CheckState _checkState(int i) const override
+	{
+		return _cb[i]->checkState(0);
+	}
+
+	void _update(QTreeWidgetItem *item, int column);
+
+	void _verify();
+};
+
+/**
+ * The KsCPUCheckBoxWidget class provides a widget for selecting CPU plots to
+ * show.
+ */
+struct KsCPUCheckBoxWidget : public KsCheckBoxTreeWidget
+{
+	KsCPUCheckBoxWidget() = delete;
+
+	KsCPUCheckBoxWidget(struct tep_handle *pe,
+			    QWidget *parent = nullptr);
+};
+
+/**
+ * The KsTasksCheckBoxWidget class provides a widget for selecting Tasks
+ * to show or hide.
+ */
+struct KsTasksCheckBoxWidget : public KsCheckBoxTableWidget
+{
+	KsTasksCheckBoxWidget() = delete;
+
+	KsTasksCheckBoxWidget(struct tep_handle *pe,
+			      bool cond = true,
+			      QWidget *parent = nullptr);
+
+private:
+	/**
+	 * A positive condition means that you want to show Tasks and
+	 * a negative condition means that you want to hide Tasks.
+	 */
+	bool		_cond;
+};
+
+/**
+ * The KsEventsCheckBoxWidget class provides a widget for selecting Trace
+ * events to show or hide.
+ */
+struct KsEventsCheckBoxWidget : public KsCheckBoxTreeWidget
+{
+	KsEventsCheckBoxWidget() = delete;
+
+	KsEventsCheckBoxWidget(struct tep_handle *pe,
+			       QWidget *parent = nullptr);
+};
+
+/**
+ * The KsPluginCheckBoxWidget class provides a widget for selecting plugins.
+ */
+struct KsPluginCheckBoxWidget : public KsCheckBoxTableWidget
+{
+	KsPluginCheckBoxWidget() = delete;
+
+	KsPluginCheckBoxWidget(QStringList pluginList,
+			       QWidget *parent = nullptr);
+};
+
+class KsDataStore;
+class KsGLWidget;
+
+/**
+ * The KsQuickFilterMenu class provides a menu for easy filtering and plotting.
+ * The menu is initialized from a single kshark_entry and uses the content of
+ * this entry to provides quick actions for filtering and plottin.
+ */
+class KsQuickEntryMenu : public QMenu
+{
+	Q_OBJECT
+public:
+	KsQuickEntryMenu() = delete;
+
+	explicit KsQuickEntryMenu(KsDataStore *data,
+				  size_t row,
+				  QWidget *parent = nullptr);
+
+signals:
+	/** Signal to add a task plot. */
+	void plotTask(int);
+
+private:
+	void _hideTask();
+
+	void _showTask();
+
+	void _hideEvent();
+
+	void _showEvent();
+
+	void _addTaskPlot();
+
+	KsDataStore	*_data;
+
+	size_t		 _row;
+
+	QAction _hideTaskAction, _showTaskAction;
+
+	QAction _hideEventAction, _showEventAction;
+
+	QAction _addTaskPlotAction;
+};
+
+#endif
-- 
2.17.1

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

* [PATCH 4/4] kernel-shark-qt: Add widget demo example.
  2018-10-08 15:16 [PATCH 0/4] Add basic components to be used by the Qt GUI Yordan Karadzhov
                   ` (2 preceding siblings ...)
  2018-10-08 15:16 ` [PATCH 3/4] kernel-shark-qt: Add Widgets Lib Yordan Karadzhov
@ 2018-10-08 15:16 ` Yordan Karadzhov
  2018-10-09 16:45   ` Steven Rostedt
  3 siblings, 1 reply; 15+ messages in thread
From: Yordan Karadzhov @ 2018-10-08 15:16 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel, Yordan Karadzhov, Yordan Karadzhov

From: Yordan Karadzhov <ykaradzhov@vmware.com>

This patch introduces a basic example, showing how to use KsUtils and
KsWidgetsLib.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark-qt/examples/CMakeLists.txt |   4 +
 kernel-shark-qt/examples/widgetdemo.cpp | 159 ++++++++++++++++++++++++
 2 files changed, 163 insertions(+)
 create mode 100644 kernel-shark-qt/examples/widgetdemo.cpp

diff --git a/kernel-shark-qt/examples/CMakeLists.txt b/kernel-shark-qt/examples/CMakeLists.txt
index 0c83293..e16216e 100644
--- a/kernel-shark-qt/examples/CMakeLists.txt
+++ b/kernel-shark-qt/examples/CMakeLists.txt
@@ -19,3 +19,7 @@ target_link_libraries(confio   kshark)
 message(STATUS "dataplot")
 add_executable(dplot          dataplot.cpp)
 target_link_libraries(dplot   kshark-plot)
+
+message(STATUS "widgetdemo")
+add_executable(widgetdemo          widgetdemo.cpp)
+target_link_libraries(widgetdemo   kshark-gui)
diff --git a/kernel-shark-qt/examples/widgetdemo.cpp b/kernel-shark-qt/examples/widgetdemo.cpp
new file mode 100644
index 0000000..c9ce86b
--- /dev/null
+++ b/kernel-shark-qt/examples/widgetdemo.cpp
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+// C
+#include <sys/stat.h>
+#include <getopt.h>
+#include <unistd.h>
+
+// C++
+#include <iostream>
+
+// Qt
+#include <QtWidgets>
+
+// KernelShark
+#include "KsUtils.hpp"
+#include "KsWidgetsLib.hpp"
+
+#define default_input_file (char*)"trace.dat"
+
+static char *input_file = nullptr;
+
+using namespace std;
+
+void usage(const char *prog)
+{
+	cout << "Usage: " << prog << endl
+	     << "  -h	Display this help message\n"
+	     << "  -v	Display version and exit\n"
+	     << "  -i	input_file, default is " << default_input_file << endl
+	     << "  -p	register plugin, use plugin name, absolute or relative path\n"
+	     << "  -u	unregister plugin, use plugin name or absolute path\n";
+}
+
+struct TaskPrint : public QObject
+{
+	tep_handle	*_pevent;
+
+	void print(QVector<int> pids)
+	{
+		for (auto const &pid: pids)
+			cout << "task: "
+			     << tep_data_comm_from_pid(_pevent, pid)
+			     << "  pid: " << pid << endl;
+	}
+};
+
+int main(int argc, char **argv)
+{
+	kshark_context *kshark_ctx(nullptr);
+	QApplication a(argc, argv);
+	KsPluginManager plugins;
+	KsDataStore data;
+	size_t nRows(0);
+	int c;
+
+	if (!kshark_instance(&kshark_ctx))
+		return 1;
+
+	while ((c = getopt(argc, argv, "hvi:p:u:")) != -1) {
+		switch(c) {
+		case 'v':
+			printf("kshark-gui %s\n", KS_VERSION_STRING);
+			return 0;
+
+		case 'i':
+			input_file = optarg;
+			break;
+
+		case 'p':
+			plugins.registerPlugin(QString(optarg));
+			break;
+
+		case 'u':
+			plugins.unregisterPlugin(QString(optarg));
+			break;
+
+		case 'h':
+		default:
+			usage(argv[0]);
+			break;
+		}
+	}
+
+	if (!input_file) {
+			struct stat st;
+			if (stat(default_input_file, &st) == 0)
+				input_file = default_input_file;
+	}
+
+	if (input_file) {
+		data.loadDataFile(input_file);
+		nRows = data.size();
+	} else {
+		cerr << "No input file is provided.\n";
+	}
+
+	cout << nRows << " entries loaded\n";
+
+	auto lamPrintPl = [&] ()
+	{
+		kshark_plugin_list *pl;
+		for (pl = kshark_ctx->plugins; pl; pl = pl->next)
+			cout << pl->file << endl;
+	};
+
+	cout << "\n\n";
+	lamPrintPl();
+	sleep(1);
+
+	QVector<bool> registeredPlugins;
+	QStringList pluginsList;
+
+	pluginsList << plugins._ksPluginList
+		    << plugins._userPluginList;
+
+	registeredPlugins << plugins._registeredKsPlugins
+			  << plugins._registeredUserPlugins;
+
+	KsCheckBoxWidget *pluginCBD
+		= new KsPluginCheckBoxWidget(pluginsList);
+
+	pluginCBD->set(registeredPlugins);
+
+	KsCheckBoxDialog *dialog1 = new KsCheckBoxDialog(pluginCBD);
+	QObject::connect(dialog1,	&KsCheckBoxDialog::apply,
+			&plugins,	&KsPluginManager::updatePlugins);
+
+	dialog1->show();
+	a.exec();
+
+	cout << "\n\nYou selected\n";
+	lamPrintPl();
+	sleep(1);
+
+	if (!nRows)
+		return 1;
+
+	KsCheckBoxWidget *tasks_cbd =
+		new KsTasksCheckBoxWidget(data.pevent(), true);
+
+	tasks_cbd->setDefault(false);
+
+	TaskPrint p;
+	p._pevent = data.pevent();
+
+	KsCheckBoxDialog *dialog2 = new KsCheckBoxDialog(tasks_cbd);
+	QObject::connect(dialog2,	&KsCheckBoxDialog::apply,
+			 &p,		&TaskPrint::print);
+
+	cout << "\n\nYou selected\n";
+	dialog2->show();
+	a.exec();
+
+	return 0;
+}
-- 
2.17.1

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

* Re: [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils
  2018-10-08 15:16 ` [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils Yordan Karadzhov
@ 2018-10-09 16:34   ` Steven Rostedt
  2018-10-10 14:12     ` Yordan Karadzhov
                       ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Steven Rostedt @ 2018-10-09 16:34 UTC (permalink / raw)
  To: Yordan Karadzhov; +Cc: linux-trace-devel, Yordan Karadzhov

On Mon,  8 Oct 2018 18:16:27 +0300
Yordan Karadzhov <y.karadz@gmail.com> wrote:


> index 0000000..2c4cecc
> --- /dev/null
> +++ b/kernel-shark-qt/src/KsUtils.cpp
> @@ -0,0 +1,584 @@
> +// SPDX-License-Identifier: LGPL-2.1
> +
> +/*
> + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
> + */
> +
> +/**
> + *  @file    KsUtils.cpp
> + *  @brief   KernelShark Utils.
> + */
> +
> +// KernelShark
> +#include "KsUtils.hpp"
> +
> +namespace KsUtils {
> +
> +/** @brief Geat a sorteg vector of Task's Pids.  */

 "sorteg"?

> +QVector<int> getPidList()
> +{
> +	kshark_context *kshark_ctx(nullptr);
> +	int nTasks, *tempPids;
> +	QVector<int> pids;
> +
> +	if (!kshark_instance(&kshark_ctx))
> +		return pids;
> +
> +	nTasks = kshark_get_task_pids(kshark_ctx, &tempPids);
> +	for (int r = 0; r < nTasks; ++r) {
> +		pids.append(tempPids[r]);
> +	}
> +
> +	free(tempPids);
> +
> +	qSort(pids);
> +
> +	return pids;
> +}
> +
> +/**
> + * Set the bit of the filter mask of the kshark session context responsible
> + * for the visibility of the events in the Table View.
> + */
> +void listFilterSync(bool state)
> +{
> +	kshark_context *kshark_ctx(nullptr);

Add space here.

> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	if (state) {
> +		kshark_ctx->filter_mask |= KS_TEXT_VIEW_FILTER_MASK;
> +	} else {
> +		kshark_ctx->filter_mask &= ~KS_TEXT_VIEW_FILTER_MASK;
> +	}
> +}
> +
> +/**
> + * Set the bit of the filter mask of the kshark session context responsible
> + * for the visibility of the events in the Graph View.
> + */
> +void graphFilterSync(bool state)
> +{
> +	kshark_context *kshark_ctx(nullptr);

Add space here.

> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	if (state) {
> +		kshark_ctx->filter_mask |= KS_GRAPH_VIEW_FILTER_MASK;
> +	} else {
> +		kshark_ctx->filter_mask &= ~KS_GRAPH_VIEW_FILTER_MASK;
> +	}
> +}
> +
> +/**
> + * @brief Simple CPU matching function to be user for data collections.
> + *
> + * @param kshark_ctx: Input location for the session context pointer.
> + * @param e: kshark_entry to be checked.
> + * @param cpu: Matching condition value.
> + *
> + * @returns True if the CPU of the entry matches the value of "cpu" and
> + * 	    the entry is visibility in Graph. Otherwise false.
> + */
> +bool matchCPUVisible(struct kshark_context *kshark_ctx,
> +		     struct kshark_entry *e, int cpu)
> +{
> +	if (e->cpu == cpu && (e->visible & KS_GRAPH_VIEW_FILTER_MASK))
> +		return true;
> +
> +	return false;

BTW, you can make the above:

	return (e->cpu == cpu) &&
		(e->visible & KS_GRAPH_VIEW_FILTER_MASK);

> +}
> +
> +}; // KsUtils
> +
> +/** A stream operator for converting QColor into KsPlot::Color. */
> +KsPlot::Color& operator <<(KsPlot::Color &thisColor, const QColor &c)
> +{
> +	thisColor.set(c.red(), c.green(), c.blue());
> +
> +	return thisColor;
> +}
> +
> +/** Create a default (empty) KsDataStore. */
> +KsDataStore::KsDataStore(QWidget *parent)
> +: QObject(parent),
> +  _pevent(nullptr),
> +  _rows(nullptr),
> +  _dataSize(0)
> +{}
> +
> +/** Destroy the KsDataStore object. */
> +KsDataStore::~KsDataStore()
> +{}
> +
> +/** Load trace data for file. */
> +void KsDataStore::loadDataFile(const QString &file)
> +{
> +	kshark_context *kshark_ctx(nullptr);

Add space here.

> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	clear();
> +
> +	if (!kshark_open(kshark_ctx, file.toStdString().c_str()) ||
> +	    !kshark_ctx->handle ||
> +	    !kshark_ctx->pevent) {

Hmm, if the kshark_open() succeeds but for some reason there's not a
pevent (can that happen?) should we do a kshark_close?

> +		qCritical() << "ERROR Loading file " << file;
> +		return;
> +	}
> +
> +	_pevent = kshark_ctx->pevent;

BTW, we need to rename "pevent" to "tep", as that name is now obsolete.

> +
> +	if (kshark_ctx->event_handlers == nullptr)
> +		kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT);
> +	else
> +		kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_UPDATE);
> +
> +	_dataSize = kshark_load_data_entries(kshark_ctx, &_rows);
> +}
> +
> +void KsDataStore::_freeData()
> +{
> +	if (_dataSize) {
> +		for (size_t r = 0; r < _dataSize; ++r)
> +			free(_rows[r]);
> +
> +		free(_rows);
> +		_rows = nullptr;
> +	}
> +}
> +
> +/** Reload the trace data. */
> +void KsDataStore::reload()
> +{
> +	kshark_context *kshark_ctx(nullptr);

Add space here.

> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	_freeData();
> +
> +	_dataSize = kshark_load_data_entries(kshark_ctx, &_rows);
> +	_pevent = kshark_ctx->pevent;
> +
> +	emit updateWidgets(this);
> +}
> +
> +/** Free the loaded trace data and close the file. */
> +void KsDataStore::clear()
> +{
> +	kshark_context *kshark_ctx(nullptr);
> +
> +	_freeData();
> +
> +	_pevent = nullptr;
> +
> +	if (kshark_instance(&kshark_ctx) &&
> +	    kshark_ctx->handle)

You can keep the two on the same line, even if it breaks the 80
character limit.

> +		kshark_close(kshark_ctx);
> +}
> +
> +/** Update the visibility of the entries (filter). */
> +void KsDataStore::update()
> +{
> +	kshark_context *kshark_ctx(nullptr);

Add space here.

> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	if (kshark_filter_is_set(kshark_ctx)) {
> +		kshark_filter_entries(kshark_ctx, _rows, _dataSize);
> +		emit updateWidgets(this);
> +	}
> +}
> +
> +/** Register a collection of visible entries for each CPU. */
> +void KsDataStore::registerCPUCollections()
> +{
> +	kshark_context *kshark_ctx(nullptr);

Add space here.

> +	if (!kshark_instance(&kshark_ctx) ||
> +	    !kshark_filter_is_set(kshark_ctx))
> +		return;
> +
> +	int nCPUs = _pevent->cpus;
> +	for (int cpu = 0; cpu < nCPUs; ++cpu) {
> +		kshark_register_data_collection(kshark_ctx,
> +						_rows, _dataSize,
> +						KsUtils::matchCPUVisible,
> +						cpu,
> +						0);
> +	}
> +}
> +
> +void KsDataStore::_unregisterCPUCollections()
> +{
> +	kshark_context *kshark_ctx(nullptr);

Add space here.

> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	int nCPUs = _pevent->cpus;
> +	for (int cpu = 0; cpu < nCPUs; ++cpu) {
> +		kshark_unregister_data_collection(&kshark_ctx->collections,
> +						  KsUtils::matchCPUVisible,
> +						  cpu);
> +	}
> +}
> +
> +void KsDataStore::_applyIdFilter(int filterId, QVector<int> vec)
> +{
> +	kshark_context *kshark_ctx(nullptr);

Add space here.

> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	switch (filterId) {
> +		case KS_SHOW_EVENT_FILTER:
> +		case KS_HIDE_EVENT_FILTER:
> +			kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER);
> +			kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER);

Hmm, I'm curious to why you clear both SHOW/HIDE filters if the
filterId is one of SHOW or HIDE?

Perhaps a comment should be here explaining it too.


> +			break;
> +		case KS_SHOW_TASK_FILTER:
> +		case KS_HIDE_TASK_FILTER:
> +			kshark_filter_clear(kshark_ctx, KS_SHOW_TASK_FILTER);
> +			kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER);
> +			break;
> +		default:
> +			return;
> +	}
> +
> +	for (auto &&pid: vec)
> +		kshark_filter_add_id(kshark_ctx, filterId, pid);
> +
> +	if (!_pevent)
> +		return;
> +
> +	_unregisterCPUCollections();
> +
> +	/*
> +	 * If the advanced event filter is set the data has to be reloaded,

I think you need a comma between "set" and "the".

> +	 * because the advanced filter uses tep_records.
> +	 */
> +	if (kshark_ctx->advanced_event_filter->filters)
> +		reload();
> +	else
> +		kshark_filter_entries(kshark_ctx, _rows, _dataSize);
> +
> +	registerCPUCollections();
> +
> +	emit updateWidgets(this);
> +}
> +
> +/** Apply Show Task filter. */
> +void KsDataStore::applyPosTaskFilter(QVector<int> vec)
> +{
> +	_applyIdFilter(KS_SHOW_TASK_FILTER, vec);
> +}
> +
> +/** Apply Hide Task filter. */
> +void KsDataStore::applyNegTaskFilter(QVector<int> vec)
> +{
> +	_applyIdFilter(KS_HIDE_TASK_FILTER, vec);
> +}
> +
> +/** Apply Show Event filter. */
> +void KsDataStore::applyPosEventFilter(QVector<int> vec)
> +{
> +	_applyIdFilter(KS_SHOW_EVENT_FILTER, vec);
> +}
> +
> +/** Apply Hide Event filter. */
> +void KsDataStore::applyNegEventFilter(QVector<int> vec)
> +{
> +	_applyIdFilter(KS_HIDE_EVENT_FILTER, vec);
> +}
> +
> +/** Disable all filters. */
> +void KsDataStore::clearAllFilters()
> +{
> +	kshark_context *kshark_ctx(nullptr);
> +	kshark_instance(&kshark_ctx);
> +
> +	if (!_pevent)
> +		return;
> +
> +	_unregisterCPUCollections();
> +
> +	kshark_filter_clear(kshark_ctx, KS_SHOW_TASK_FILTER);
> +	kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER);
> +	kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER);
> +	kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER);
> +
> +	tep_filter_reset(kshark_ctx->advanced_event_filter);
> +	kshark_clear_all_filters(kshark_ctx, _rows, _dataSize);
> +
> +	emit updateWidgets(this);
> +}
> +
> +/**
> + * @brief Create Plugin Manager. Use list of plugins declared in the
> + *	  CMake-generated header file.
> + */
> +KsPluginManager::KsPluginManager(QWidget *parent)
> +: QObject(parent)
> +{
> +	kshark_context *kshark_ctx(nullptr);
> +	_parsePluginList();
> +
> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	registerFromList(kshark_ctx);
> +}
> +
> +/** Parse the plugin list declared in the CMake-generated header file. */
> +void KsPluginManager::_parsePluginList()
> +{
> +	_ksPluginList = KsUtils::getPluginList();
> +	int nPlugins = _ksPluginList.count();
> +
> +	_registeredKsPlugins.resize(nPlugins);
> +	for (int i = 0; i < nPlugins; ++i) {
> +		if (_ksPluginList[i].contains(" default", Qt::CaseInsensitive)) {
> +			_ksPluginList[i].remove(" default", Qt::CaseInsensitive);
> +			_registeredKsPlugins[i] = true;
> +		} else {
> +			_registeredKsPlugins[i] = false;
> +		}
> +	}
> +}
> +
> +/**
> + * Register the plugins by using the information in "_ksPluginList" and
> + * "_registeredKsPlugins".
> + */
> +void KsPluginManager::registerFromList(kshark_context *kshark_ctx)
> +{
> +	auto lamRegBuiltIn = [&kshark_ctx](const QString &plugin)
> +	{
> +		char *lib;
> +		int n;
> +		n = asprintf(&lib, "%s/lib/plugin-%s.so",
> +			     KS_DIR, plugin.toStdString().c_str());
> +		if (n > 0) {

Usually the if statement after a call should be the error path, unless
we need to ignore the error. That is:

		if (n <= 0)
			return;

Then the below is not indented.

> +			kshark_register_plugin(kshark_ctx, lib);
> +			free(lib);
> +		}
> +	};
> +
> +	auto lamRegUser = [&kshark_ctx](const QString &plugin)
> +	{
> +		const char *lib = plugin.toStdString().c_str();
> +		kshark_register_plugin(kshark_ctx, lib);
> +	};
> +
> +	_forEachInList(_ksPluginList,
> +		       _registeredKsPlugins,
> +		       lamRegBuiltIn);
> +
> +	_forEachInList(_userPluginList,
> +		       _registeredUserPlugins,
> +		       lamRegUser);
> +}
> +
> +/**
> + * Unegister the plugins by using the information in "_ksPluginList" and
> + * "_registeredKsPlugins".
> + */
> +void KsPluginManager::unregisterFromList(kshark_context *kshark_ctx)
> +{
> +	auto lamUregBuiltIn = [&kshark_ctx] (const QString &plugin)
> +	{
> +		char *lib;
> +		int n;
> +		n = asprintf(&lib, "%s/lib/plugin-%s.so",
> +			     KS_DIR, plugin.toStdString().c_str());
> +		if (n > 0) {

same here.

> +			kshark_unregister_plugin(kshark_ctx, lib);
> +			free(lib);
> +		}
> +	};
> +
> +	auto lamUregUser = [&kshark_ctx] (const QString &plugin)
> +	{
> +		const char *lib = plugin.toStdString().c_str();
> +		kshark_unregister_plugin(kshark_ctx, lib);
> +	};
> +
> +	_forEachInList(_ksPluginList,
> +		       _registeredKsPlugins,
> +			lamUregBuiltIn);
> +
> +	_forEachInList(_userPluginList,
> +		       _registeredUserPlugins,
> +			lamUregUser);
> +}
> +
> +/**
> + * @brief Register a Plugin.
> + *
> + * @param plugin: provide here the name of the plugin (as in the CMake-generated
> + *		  header file) of a name of the plugin's library file (.so).
> + */
> +void KsPluginManager::registerPlugin(const QString &plugin)
> +{
> +	kshark_context *kshark_ctx(nullptr);
> +	char *lib;
> +	int n;
> +
> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	for (int i = 0; i < _ksPluginList.count(); ++i) {
> +		if (_ksPluginList[i] == plugin) {
> +			/*
> +			 * The argument is the name of the plugin. From the
> +			 * name get the library .so file.
> +			 */
> +			n = asprintf(&lib, "%s/lib/plugin-%s.so",
> +					KS_DIR, plugin.toStdString().c_str());
> +			if (n > 0) {

This is fine to keep it this way, as we return either way.

> +				kshark_register_plugin(kshark_ctx, lib);
> +				_registeredKsPlugins[i] = true;
> +				free(lib);
> +			}
> +
> +			return;

Add space here.

> +		} else if (plugin.contains("/lib/plugin-" + _ksPluginList[i],
> +					   Qt::CaseInsensitive)) {
> +			/*
> +			 * The argument is the name of the library .so file.
> +			 */
> +			n = asprintf(&lib, "%s", plugin.toStdString().c_str());
> +			if (n > 0) {
> +				kshark_register_plugin(kshark_ctx, lib);
> +				_registeredKsPlugins[i] = true;
> +				free(lib);
> +			}
> +
> +			return;
> +		}
> +	}
> +
> +	/* No plugin with this name in the list. Try to add it anyway. */
> +	if (plugin.endsWith(".so") && QFileInfo::exists(plugin)) {
> +		kshark_register_plugin(kshark_ctx,
> +				       plugin.toStdString().c_str());
> +
> +		_userPluginList.append(plugin);
> +		_registeredUserPlugins.append(true);
> +	} else {
> +		qCritical() << "ERROR: " << plugin << "cannot be registered!";
> +	}
> +}
> +
> +/** @brief Unregister a Plugin.
> + *<br> WARNING: Do not use this function to unregister User plugins.

Hmm, do we need the <br> above? (if this is required by DocGen I find
it rather ugly :-( )

Also, if this is not to be used to unregister User Plugins, can you add
what should be used to unregister them?


> + * @param plugin: provide here the name of the plugin (as in the CMake-generated
> + *		  header file) of a name of the plugin's library file (.so).
> + *
> + */
> +void KsPluginManager::unregisterPlugin(const QString &plugin)
> +{
> +	kshark_context *kshark_ctx(nullptr);
> +	char *lib;
> +	int n;
> +
> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	for (int i = 0; i < _ksPluginList.count(); ++i) {
> +		if (_ksPluginList[i] == plugin) {
> +			/*
> +			 * The argument is the name of the plugin. From the
> +			 * name get the library .so file.
> +			 */
> +			n = asprintf(&lib, "%s/lib/plugin-%s.so", KS_DIR,
> +				     plugin.toStdString().c_str());
> +			if (n > 0) {
> +				kshark_unregister_plugin(kshark_ctx, lib);
> +				_registeredKsPlugins[i] = false;
> +				free(lib);
> +			}
> +
> +			return;
> +		} else if  (plugin.contains("/lib/plugin-" +
> +			                   _ksPluginList[i], Qt::CaseInsensitive)) {
> +			/*
> +			 * The argument is the name of the library .so file.
> +			 */
> +			n = asprintf(&lib, "%s", plugin.toStdString().c_str());
> +			if (n > 0) {
> +				kshark_unregister_plugin(kshark_ctx, lib);
> +				_registeredKsPlugins[i] = false;
> +				free(lib);
> +			}
> +
> +			return;
> +		}
> +	}
> +}
> +
> +/** Unload all plugins. */
> +void KsPluginManager::unloadAll()
> +{
> +	kshark_context *kshark_ctx(nullptr);
> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_CLOSE);
> +	kshark_free_plugin_list(kshark_ctx->plugins);
> +	kshark_ctx->plugins = nullptr;
> +	kshark_free_event_handler_list(kshark_ctx->event_handlers);
> +
> +	unregisterFromList(kshark_ctx);
> +}
> +
> +/** @brief Update (change) the Plugins.
> + *
> + * @param pluginIds: The indexes of the plugins to be loaded.
> + */
> +void KsPluginManager::updatePlugins(QVector<int> pluginIds)
> +{
> +	kshark_context *kshark_ctx(nullptr);

Add space here.

> +	if (!kshark_instance(&kshark_ctx))
> +		return;
> +
> +	auto register_plugins = [&] (QVector<int> ids)
> +	{
> +		int nKsPlugins = _registeredKsPlugins.count();
> +
> +		/* First clear all registered plugins. */
> +		for (auto &p: _registeredKsPlugins)
> +			p = false;
> +		for (auto &p: _registeredUserPlugins)
> +			p = false;
> +
> +		/* The vector contains the indexes of those to register. */
> +		for (auto const &p: ids) {
> +			if (p < nKsPlugins)
> +				_registeredKsPlugins[p] = true;
> +			else
> +				_registeredUserPlugins[p - nKsPlugins] = true;
> +		}
> +		registerFromList(kshark_ctx);
> +	};
> +
> +	if (!kshark_ctx->pevent) {
> +		kshark_free_plugin_list(kshark_ctx->plugins);
> +		kshark_ctx->plugins = nullptr;
> +
> +		/*
> +		 * No data is loaded. For the moment, just register the
> +		 * plugins. Handling of the plugins will be done after
> +		 * we load a data file.
> +		 */
> +		register_plugins(pluginIds);
> +		return;
> +	}
> +
> +	/* Clean up all old plugins first. */
> +	unloadAll();
> +
> +	/* Now load. */
> +	register_plugins(pluginIds);
> +	kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT);
> +
> +	emit dataReload();
> +}
> diff --git a/kernel-shark-qt/src/KsUtils.hpp b/kernel-shark-qt/src/KsUtils.hpp
> new file mode 100644
> index 0000000..40142ca
> --- /dev/null
> +++ b/kernel-shark-qt/src/KsUtils.hpp

Is this private to libkshark and not going to be exported?

In other words, do we need to worry about namespace?

-- Steve

> @@ -0,0 +1,231 @@
> +/* SPDX-License-Identifier: LGPL-2.1 */
> +
> +/*
> + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
> + */
> +
> +/**
> + *  @file    KsUtils.hpp
> + *  @brief   KernelShark Utils.
> + */
> +
> +#ifndef _KS_UTILS_H
> +#define _KS_UTILS_H
> +
> +// C++ 11
> +#include <chrono>
> +
> +// Qt
> +#include <QtWidgets>
> +
> +// KernelShark
> +#include "libkshark.h"
> +#include "libkshark-model.h"
> +#include "KsCmakeDef.hpp"
> +#include "KsPlotTools.hpp"
> +
> +/** Macro providing the height of the screen in pixels. */
> +#define SCREEN_HEIGHT  QApplication::desktop()->screenGeometry().height()
> +
> +/** Macro providing the width of the screen in pixels. */
> +#define SCREEN_WIDTH   QApplication::desktop()->screenGeometry().width()
> +
> +//! @cond Doxygen_Suppress
> +
> +auto fontHeight = [] ()
> +{
> +	QFont font;
> +	QFontMetrics fm(font);
> +	return fm.height();
> +};
> +
> +auto stringWidth = [](QString s)
> +{
> +	QFont font;
> +	QFontMetrics fm(font);
> +	return fm.width(s);
> +};
> +
> +//! @endcond
> +
> +/** Macro providing the height of the font in pixels. */
> +#define FONT_HEIGHT		fontHeight()
> +
> +/** Macro providing the width of the font in pixels. */
> +#define FONT_WIDTH 		stringWidth("4")
> +
> +/** Macro providing the width of a string in pixels. */
> +#define STRING_WIDTH(s)		stringWidth(s)
> +
> +/** Macro providing the height of the KernelShark graphs in pixels. */
> +#define KS_GRAPH_HEIGHT	(FONT_HEIGHT*2)
> +
> +//! @cond Doxygen_Suppress
> +
> +#define KS_JSON_CAST(doc) \
> +reinterpret_cast<json_object *>(doc)
> +
> +#define KS_C_STR_CAST(doc) \
> +reinterpret_cast<const char *>(doc)
> +
> +typedef std::chrono::high_resolution_clock::time_point  hd_time;
> +
> +#define GET_TIME std::chrono::high_resolution_clock::now()
> +
> +#define GET_DURATION(t0) \
> +std::chrono::duration_cast<std::chrono::duration<double>>( \
> +std::chrono::high_resolution_clock::now() - t0).count()
> +
> +//! @endcond
> +
> +namespace KsUtils {
> +
> +QVector<int> getPidList();
> +
> +/** @brief Geat the list of plugins. */
> +inline QStringList getPluginList() {return plugins.split(";");}
> +
> +void listFilterSync(bool state);
> +
> +void graphFilterSync(bool state);
> +
> +/** @brief Convert the timestamp of the trace record into a string showing
> + *	   the time in seconds.
> + *
> + * @param ts: Input location for the timestamp.
> + * @param prec: the number of digits after the decimal point in the return
> + *		string.
> + *
> + * @returns String showing the time in seconds.
> + */
> +inline QString Ts2String(int64_t ts, int prec)
> +{
> +	return QString::number(ts * 1e-9, 'f', prec);
> +}
> +
> +bool matchCPUVisible(struct kshark_context *kshark_ctx,
> +			      struct kshark_entry *e, int cpu);
> +}; // KsUtils
> +
> +/** Identifier of the Dual Marker active state. */
> +enum class DualMarkerState {
> +	A,
> +	B
> +};
> +
> +/**
> + * The KsDataStore class provides the access to trace data for all KernelShark
> + * widgets.
> + */
> +class KsDataStore : public QObject
> +{
> +	Q_OBJECT
> +public:
> +	explicit KsDataStore(QWidget *parent = nullptr);
> +
> +	~KsDataStore();
> +
> +	void loadDataFile(const QString &file);
> +
> +	void clear();
> +
> +	/** Get the page event used to parse the page.. */
> +	tep_handle *pevent() const {return _pevent;}
> +
> +	/** Get the trace data array.. */
> +	struct kshark_entry **rows() const {return _rows;}
> +
> +	/** Get the size of the data array. */
> +	size_t size() const {return _dataSize;}
> +
> +	void reload();
> +
> +	void update();
> +
> +	void registerCPUCollections();
> +
> +	void applyPosTaskFilter(QVector<int>);
> +
> +	void applyNegTaskFilter(QVector<int>);
> +
> +	void applyPosEventFilter(QVector<int>);
> +
> +	void applyNegEventFilter(QVector<int>);
> +
> +	void clearAllFilters();
> +
> +signals:
> +	/**
> +	 * This signal is emitted when the data has changed and the View
> +	 * widgets have to update.
> +	 */
> +	void updateWidgets(KsDataStore *);
> +
> +private:
> +	/** Page event used to parse the page. */
> +	tep_handle		*_pevent;
> +
> +	/** Trace data array. */
> +	struct kshark_entry	**_rows;
> +
> +	/** The size of the data array. */
> +	size_t			_dataSize;
> +
> +	void _freeData();
> +	void _unregisterCPUCollections();
> +	void _applyIdFilter(int filterId, QVector<int> vec);
> +};
> +
> +/** A Plugin Manage class. */
> +class KsPluginManager : public QObject
> +{
> +	Q_OBJECT
> +public:
> +	explicit KsPluginManager(QWidget *parent = nullptr);
> +
> +	/** A list of available built-in plugins. */
> +	QStringList	_ksPluginList;
> +
> +	/** A list of registered built-in plugins. */
> +	QVector<bool>	_registeredKsPlugins;
> +
> +	/** A list of available user plugins. */
> +	QStringList	_userPluginList;
> +
> +	/** A list of registered user plugins. */
> +	QVector<bool>	_registeredUserPlugins;
> +
> +	void registerFromList(kshark_context *kshark_ctx);
> +	void unregisterFromList(kshark_context *kshark_ctx);
> +
> +	void registerPlugin(const QString &plugin);
> +	void unregisterPlugin(const QString &plugin);
> +	void unloadAll();
> +
> +	void updatePlugins(QVector<int> pluginId);
> +
> +signals:
> +	/** This signal is emitted when a plugin is loaded or unloaded. */
> +	void dataReload();
> +
> +private:
> +	void _parsePluginList();
> +
> +	template <class T>
> +	void _forEachInList(const QStringList &pl,
> +			    const QVector<bool> &reg,
> +			    T action)
> +	{
> +		int nPlugins;
> +		nPlugins = pl.count();
> +		for (int i = 0; i < nPlugins; ++i) {
> +			if (reg[i]) {
> +				action(pl[i]);
> +			}
> +		}
> +	}
> +};
> +
> +KsPlot::Color& operator <<(KsPlot::Color &thisColor, const QColor &c);
> +
> +#endif

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

* Re: [PATCH 3/4] kernel-shark-qt: Add Widgets Lib
  2018-10-08 15:16 ` [PATCH 3/4] kernel-shark-qt: Add Widgets Lib Yordan Karadzhov
@ 2018-10-09 16:42   ` Steven Rostedt
  0 siblings, 0 replies; 15+ messages in thread
From: Steven Rostedt @ 2018-10-09 16:42 UTC (permalink / raw)
  To: Yordan Karadzhov; +Cc: linux-trace-devel, Yordan Karadzhov

On Mon,  8 Oct 2018 18:16:28 +0300
Yordan Karadzhov <y.karadz@gmail.com> wrote:

> From: Yordan Karadzhov <ykaradzhov@vmware.com>
> 
> This patch defines various small widgets and dialogues to be used by
> the KernelShark GUI.
> 
> Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
> ---
>  kernel-shark-qt/src/CMakeLists.txt   |   6 +-
>  kernel-shark-qt/src/KsWidgetsLib.cpp | 873 +++++++++++++++++++++++++++
>  kernel-shark-qt/src/KsWidgetsLib.hpp | 370 ++++++++++++
>  3 files changed, 1247 insertions(+), 2 deletions(-)
>  create mode 100644 kernel-shark-qt/src/KsWidgetsLib.cpp
>  create mode 100644 kernel-shark-qt/src/KsWidgetsLib.hpp
> 
> diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt
> index e897e9a..2ac79ca 100644
> --- a/kernel-shark-qt/src/CMakeLists.txt
> +++ b/kernel-shark-qt/src/CMakeLists.txt
> @@ -31,11 +31,13 @@ endif (OPENGL_FOUND AND GLUT_FOUND)
>  if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
>  
>      message(STATUS "libkshark-gui")
> -    set (ks-guiLib_hdr  KsUtils.hpp)
> +    set (ks-guiLib_hdr  KsUtils.hpp
> +                        KsWidgetsLib.hpp)
>  
>      QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr})
>  
> -    add_library(kshark-gui  SHARED  ${ks-guiLib_hdr_moc}    KsUtils.cpp)
> +    add_library(kshark-gui  SHARED  ${ks-guiLib_hdr_moc}    KsUtils.cpp
> +                                                            KsWidgetsLib.cpp)
>  
>      target_link_libraries(kshark-gui kshark-plot
>                                       ${CMAKE_DL_LIBS}
> diff --git a/kernel-shark-qt/src/KsWidgetsLib.cpp b/kernel-shark-qt/src/KsWidgetsLib.cpp
> new file mode 100644
> index 0000000..c6ae266
> --- /dev/null
> +++ b/kernel-shark-qt/src/KsWidgetsLib.cpp
> @@ -0,0 +1,873 @@
> +// SPDX-License-Identifier: LGPL-2.1
> +
> +/*
> + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
> + */
> +
> +/**
> + *  @file    KsWidgetsLib.cpp
> + *  @brief   Defines small widgets and dialogues used by the KernelShark GUI.
> + */
> +
> +// KernelShark
> +#include "libkshark.h"
> +#include "KsUtils.hpp"
> +#include "KsCmakeDef.hpp"
> +#include "KsPlotTools.hpp"
> +#include "KsWidgetsLib.hpp"
> +
> +/**
> + * @brief Create KsProgressBar.
> + *
> + * @param message: Text to be shown.
> + * @param parent: The parent of this widget.
> + */
> +KsProgressBar::KsProgressBar(QString message, QWidget *parent)
> +: QWidget(parent),
> +  _sb(this),
> +  _pb(&_sb) {
> +	resize(FONT_WIDTH * 50, FONT_HEIGHT * 5);

Where did the magic numbers 50 and 5 come from?

Can we make them into macros that define what they are.

> +	setWindowTitle("KernelShark");
> +	setLayout(new QVBoxLayout);
> +
> +	_pb.setOrientation(Qt::Horizontal);
> +	_pb.setTextVisible(false);
> +	_pb.setRange(0, KS_PROGRESS_BAR_MAX);
> +	_pb.setValue(1);
> +
> +	_sb.addPermanentWidget(&_pb, 1);
> +
> +	layout()->addWidget(new QLabel(message));
> +	layout()->addWidget(&_sb);
> +
> +	setWindowFlags(Qt::WindowStaysOnTopHint);
> +
> +	show();
> +}
> +
> +/** @brief Set the state of the progressbar.
> + *
> + * @param i: A value ranging from 0 to KS_PROGRESS_BAR_MAX.
> + */
> +void KsProgressBar::setValue(int i) {
> +	_pb.setValue(i);
> +	QApplication::processEvents();
> +}
> +
> +/**
> + * @brief Create KsMessageDialog.
> + *
> + * @param message: Text to be shown.
> + * @param parent: The parent of this widget.
> + */
> +KsMessageDialog::KsMessageDialog(QString message, QWidget *parent)
> +: QDialog(parent),
> +  _text(message, this),
> +  _closeButton("Close", this)
> +{
> +	resize(SCREEN_WIDTH / 10, FONT_HEIGHT * 8);

Same here with 10 and 8.

> +
> +	_layout.addWidget(&_text);
> +	_layout.addWidget(&_closeButton);
> +
> +	connect(&_closeButton,	&QPushButton::pressed,
> +		this,		&QWidget::close);
> +
> +	this->setLayout(&_layout);
> +}
> +
> +/**
> + * @brief Create KsCheckBoxWidget.
> + *
> + * @param name: The name of this widget.
> + * @param parent: The parent of this widget.
> + */
> +KsCheckBoxWidget::KsCheckBoxWidget(const QString &name, QWidget *parent)
> +: QWidget(parent),
> +  _allCb("all", this),
> +  _cbWidget(this),
> +  _cbLayout(&_cbWidget),
> +  _topLayout(this),
> +  _name(name),
> +  _nameLabel(name + ":  ")
> +{
> +	setWindowTitle(_name);
> +	setMinimumHeight(SCREEN_HEIGHT / 2);
> +
> +	connect(&_allCb,	&QCheckBox::clicked,
> +		this,		&KsCheckBoxWidget::_checkAll);
> +
> +	_cbWidget.setLayout(&_cbLayout);
> +
> +	QToolBar *tb = new QToolBar(this);
> +
> +	tb->addWidget(&_nameLabel);
> +	tb->addWidget(&_allCb);
> +	_topLayout.addWidget(tb);
> +
> +	_topLayout.addWidget(&_cbWidget);
> +	_topLayout.setContentsMargins(0, 0, 0, 0);
> +
> +	setLayout(&_topLayout);
> +	_allCb.setCheckState(Qt::Checked);
> +}
> +
> +/**
> + * Set the default state for all checkboxes (including the "all" checkbox).
> + */
> +void KsCheckBoxWidget::setDefault(bool st)
> +{
> +	Qt::CheckState state = Qt::Unchecked;
> +
> +	if (st)
> +		state = Qt::Checked;
> +
> +	_allCb.setCheckState(state);
> +	_checkAll(state);
> +}
> +
> +/** Get a vector containing the indexes of all checked boxes. */
> +QVector<int> KsCheckBoxWidget::getCheckedIds()
> +{
> +	QVector<int> vec;
> +	int n = _id.size();
> +
> +	for (int i = 0; i < n; ++i)
> +		if (_checkState(i) == Qt::Checked)
> +			vec.append(_id[i]);
> +
> +	return vec;
> +}
> +
> +/**
> + * @brief Set the state of the checkboxes.
> + *
> + * @param v: Vector containing the bool values for all checkboxes.
> + */
> +void KsCheckBoxWidget::set(QVector<bool> v)
> +{
> +	Qt::CheckState state;
> +	int nChecks;
> +
> +	nChecks = (v.size() < _id.size()) ? v.size() : _id.size();
> +
> +	/* Start with the "all" checkbox being checked. */
> +	_allCb.setCheckState(Qt::Checked);
> +	for (int i = 0; i < nChecks; ++i) {
> +		if (v[i]) {
> +			state = Qt::Checked;
> +		} else {
> +			/*
> +			 * At least one checkbox is unchecked. Uncheck
> +			 * "all" as well.
> +			 */
> +			state = Qt::Unchecked;
> +			_allCb.setCheckState(state);
> +		}
> +
> +		_setCheckState(i, state);
> +	}
> +	_verify();
> +}
> +
> +void KsCheckBoxWidget::_checkAll(bool st)
> +{
> +	Qt::CheckState state = Qt::Unchecked;
> +	int n = _id.size();
> +
> +	if (st) state = Qt::Checked;
> +
> +	for (int i = 0; i < n; ++i) {
> +		_setCheckState(i, state);
> +	}
> +
> +	_verify();
> +}
> +
> +/**
> + * @brief Create KsCheckBoxDialog.
> + *
> + * @param cbw: A KsCheckBoxWidget to be nested in this dialog.
> + * @param parent: The parent of this widget.
> + */
> +KsCheckBoxDialog::KsCheckBoxDialog(KsCheckBoxWidget *cbw, QWidget *parent)
> +: QDialog(parent), _checkBoxWidget(cbw),
> +  _applyButton("Apply", this),
> +  _cancelButton("Cancel", this)
> +{
> +	int buttonWidth;
> +
> +	setWindowTitle(cbw->name());
> +	_topLayout.addWidget(_checkBoxWidget);
> +
> +	buttonWidth = STRING_WIDTH("--Cancel--");
> +	_applyButton.setFixedWidth(buttonWidth);
> +	_cancelButton.setFixedWidth(buttonWidth);
> +
> +	_buttonLayout.addWidget(&_applyButton);
> +	_applyButton.setAutoDefault(false);
> +
> +	_buttonLayout.addWidget(&_cancelButton);
> +	_cancelButton.setAutoDefault(false);
> +
> +	_buttonLayout.setAlignment(Qt::AlignLeft);
> +	_topLayout.addLayout(&_buttonLayout);
> +
> +	_applyButtonConnection =
> +		connect(&_applyButton,	&QPushButton::pressed,
> +			this,		&KsCheckBoxDialog::_applyPress);
> +
> +	connect(&_applyButton,	&QPushButton::pressed,
> +		this,		&QWidget::close);
> +
> +	connect(&_cancelButton,	&QPushButton::pressed,
> +		this,		&QWidget::close);
> +
> +	this->setLayout(&_topLayout);
> +}
> +
> +void KsCheckBoxDialog::_applyPress()
> +{
> +	QVector<int> vec = _checkBoxWidget->getCheckedIds();
> +	emit apply(vec);
> +
> +	/*
> +	 * Disconnect _applyButton. This is done in order to protect
> +	 * against multiple clicks.
> +	 */
> +	disconnect(_applyButtonConnection);
> +}
> +
> +
> +/**
> + * @brief Create KsCheckBoxTable.
> + *
> + * @param parent: The parent of this widget.
> + */
> +KsCheckBoxTable::KsCheckBoxTable(QWidget *parent)
> +: QTableWidget(parent)
> +{
> +	setShowGrid(false);
> +	horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
> +	horizontalHeader()->setStretchLastSection(true);
> +	setSelectionBehavior(QAbstractItemView::SelectRows);
> +	setEditTriggers(QAbstractItemView::NoEditTriggers);
> +	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
> +	verticalHeader()->setVisible(false);
> +
> +	connect(this, &QTableWidget::cellDoubleClicked,
> +		this, &KsCheckBoxTable::_doubleClicked);
> +}
> +
> +/**
> + * @brief Initialize the table.
> + *
> + * @param headers: The headers of the individual columns.
> + * @param size: The number of rows.
> + */
> +void KsCheckBoxTable::init(QStringList headers, int size)
> +{
> +	QHBoxLayout *cbLayout;
> +	QWidget *cbWidget;
> +
> +	setColumnCount(headers.count());
> +	setRowCount(size);
> +	setHorizontalHeaderLabels(headers);
> +
> +	_cb.resize(size);
> +
> +	for (int i = 0; i < size; ++i) {
> +		cbWidget = new QWidget();
> +		_cb[i] = new QCheckBox(cbWidget);
> +		cbLayout = new QHBoxLayout(cbWidget);
> +
> +		cbLayout->addWidget(_cb[i]);
> +		cbLayout->setAlignment(Qt::AlignCenter);
> +		cbLayout->setContentsMargins(0, 0, 0, 0);
> +
> +		cbWidget->setLayout(cbLayout);
> +		setCellWidget(i, 0, cbWidget);
> +	}
> +}
> +
> +/** Reimplemented event handler used to receive key press events. */
> +void KsCheckBoxTable::keyPressEvent(QKeyEvent *event)
> +{
> +	if (event->key() == Qt::Key_Return) {
> +		for (auto &s: selectedItems()) {
> +			if (s->column() == 1)
> +				emit changeState(s->row());
> +		}
> +	}
> +
> +	QApplication::processEvents();
> +	QTableWidget::keyPressEvent(event);
> +}
> +
> +/** Reimplemented event handler used to receive mouse press events. */
> +void KsCheckBoxTable::mousePressEvent(QMouseEvent *event)
> +{
> +	if (event->button() == Qt::RightButton) {
> +		for (auto &i: selectedItems())
> +			i->setSelected(false);
> +
> +		return;
> +	}
> +
> +	QApplication::processEvents();
> +	QTableWidget::mousePressEvent(event);
> +}
> +
> +void KsCheckBoxTable::_doubleClicked(int row, int col)
> +{
> +	emit changeState(row);
> +	for (auto &i: selectedItems())
> +		i->setSelected(false);
> +}
> +
> +/**
> + * @brief Create KsCheckBoxTableWidget.
> + *
> + * @param name: The name of this widget.
> + * @param parent: The parent of this widget.
> + */
> +KsCheckBoxTableWidget::KsCheckBoxTableWidget(const QString &name,
> +					     QWidget *parent)
> +: KsCheckBoxWidget(name, parent),
> +  _table(this)
> +{
> +	connect(&_table,	&KsCheckBoxTable::changeState,
> +		this,		&KsCheckBoxTableWidget::_changeState);
> +}
> +
> +/** Initialize the KsCheckBoxTable and its layout. */
> +void KsCheckBoxTableWidget::_initTable(QStringList headers, int size)
> +{
> +	_table.init(headers, size);
> +
> +	for (auto const & cb: _table._cb) {
> +		connect(cb,	&QCheckBox::clicked,
> +			this,	&KsCheckBoxTableWidget::_update);
> +	}
> +
> +	_cbLayout.setContentsMargins(1, 1, 1, 1);
> +	_cbLayout.addWidget(&_table);
> +}
> +
> +/** Adjust the size of this widget according to its content. */
> +void KsCheckBoxTableWidget::_adjustSize()
> +{
> +	int width;
> +
> +	_table.setVisible(false);
> +	_table.resizeColumnsToContents();
> +	_table.setVisible(true);
> +
> +	width = _table.horizontalHeader()->length() +
> +		FONT_WIDTH * 3 +
> +		style()->pixelMetric(QStyle::PM_ScrollBarExtent);
> +
> +	_cbWidget.resize(width, _cbWidget.height());
> +
> +	setMinimumWidth(_cbWidget.width() +
> +			_cbLayout.contentsMargins().left() +
> +			_cbLayout.contentsMargins().right() +
> +			_topLayout.contentsMargins().left() +
> +			_topLayout.contentsMargins().right());
> +}
> +
> +void  KsCheckBoxTableWidget::_update(bool state)
> +{
> +	/* If a Checkbox is being unchecked. Unchecked "all" as well. */
> +	if (!state)
> +		_allCb.setCheckState(Qt::Unchecked);
> +}
> +
> +void KsCheckBoxTableWidget::_changeState(int row)
> +{
> +	if (_table._cb[row]->checkState() == Qt::Checked)
> +		_table._cb[row]->setCheckState(Qt::Unchecked);
> +	else
> +		_table._cb[row]->setCheckState(Qt::Checked);
> +
> +	_allCb.setCheckState(Qt::Checked);
> +	for (auto &c: _table._cb) {
> +		if (c->checkState() == Qt::Unchecked) {
> +			_allCb.setCheckState(Qt::Unchecked);
> +			break;
> +		}
> +	}
> +}
> +
> +static void update_r(QTreeWidgetItem *item, Qt::CheckState state)
> +{
> +	int n;
> +
> +	item->setCheckState(0, state);
> +
> +	n = item->childCount();
> +	for (int i = 0; i < n; ++i)
> +		update_r(item->child(i), state);
> +}
> +
> +/**
> + * @brief Create KsCheckBoxTree.
> + *
> + * @param parent: The parent of this widget.
> + */
> +KsCheckBoxTree::KsCheckBoxTree(QWidget *parent)
> +: QTreeWidget(parent)
> +{
> +	setColumnCount(2);
> +	setHeaderHidden(true);
> +	setSelectionBehavior(QAbstractItemView::SelectRows);
> +	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
> +
> +	connect(this, &KsCheckBoxTree::itemDoubleClicked,
> +		this, &KsCheckBoxTree::_doubleClicked);
> +}
> +
> +/** Reimplemented event handler used to receive key press events. */
> +void KsCheckBoxTree::keyPressEvent(QKeyEvent *event)
> +{
> +	if (event->key() == Qt::Key_Return) {
> +		/* Loop over all selected child items and change
> +		* there states. */
> +		for (auto &s: selectedItems()) {
> +			if(s->childCount()) {
> +				if (s->isExpanded())
> +					continue;
> +			}
> +
> +			if (s->checkState(0) == Qt::Unchecked)
> +				s->setCheckState(0, Qt::Checked);
> +			else
> +				s->setCheckState(0, Qt::Unchecked);
> +
> +			if(s->childCount()) {
> +				update_r(s, s->checkState(0));
> +			}
> +		}
> +	}
> +
> +	emit verify();
> +	QTreeWidget::keyPressEvent(event);
> +}
> +
> +void KsCheckBoxTree::_doubleClicked(QTreeWidgetItem *item, int col)
> +{
> +	if (item->checkState(0) == Qt::Unchecked)
> +		item->setCheckState(0, Qt::Checked);
> +	else
> +		item->setCheckState(0, Qt::Unchecked);
> +
> +	for (auto &i: selectedItems())
> +		i->setSelected(false);
> +
> +	emit itemClicked(item, col);
> +}
> +
> +/** Reimplemented event handler used to receive mouse press events. */
> +void KsCheckBoxTree::mousePressEvent(QMouseEvent *event)
> +{
> +	if (event->button() == Qt::RightButton) {
> +		for (auto &i: selectedItems())
> +			i->setSelected(false);
> +		return;
> +	}
> +
> +	QApplication::processEvents();
> +	QTreeWidget::mousePressEvent(event);
> +}
> +
> +/**
> + * @brief Create KsCheckBoxTreeWidget.
> + *
> + * @param name: The name of this widget.
> + * @param parent: The parent of this widget.
> + */
> +KsCheckBoxTreeWidget::KsCheckBoxTreeWidget(const QString &name,
> +					   QWidget *parent)
> +: KsCheckBoxWidget(name, parent),
> +  _tree(this)
> +{
> +	connect(&_tree,	&KsCheckBoxTree::verify,
> +		this,	&KsCheckBoxTreeWidget::_verify);
> +}
> +
> +/** Initialize the KsCheckBoxTree and its layout. */
> +void KsCheckBoxTreeWidget::_initTree()
> +{
> +	_tree.setSelectionMode(QAbstractItemView::MultiSelection);
> +
> +	connect(&_tree, &QTreeWidget::itemClicked,
> +		this,	&KsCheckBoxTreeWidget::_update);
> +
> +	_cbLayout.setContentsMargins(1, 1, 1, 1);
> +	_cbLayout.addWidget(&_tree);
> +}
> +
> +/** Adjust the size of this widget according to its content. */
> +void KsCheckBoxTreeWidget::_adjustSize()
> +{
> +	int width, n = _tree.topLevelItemCount();
> +	if (n == 0)
> +		return;
> +
> +	for (int i = 0; i < n; ++i)
> +		_tree.topLevelItem(i)->setExpanded(true);
> +
> +	_tree.resizeColumnToContents(0);
> +	if (_tree.topLevelItem(0)->child(0)) {
> +		width = _tree.visualItemRect(_tree.topLevelItem(0)->child(0)).width();
> +	} else {
> +		width = _tree.visualItemRect(_tree.topLevelItem(0)).width();
> +	}
> +
> +	width += FONT_WIDTH*3 + style()->pixelMetric(QStyle::PM_ScrollBarExtent);
> +	_cbWidget.resize(width, _cbWidget.height());
> +
> +	for (int i = 0; i < n; ++i)
> +		_tree.topLevelItem(i)->setExpanded(false);
> +
> +	setMinimumWidth(_cbWidget.width() +
> +			_cbLayout.contentsMargins().left() +
> +			_cbLayout.contentsMargins().right() +
> +			_topLayout.contentsMargins().left() +
> +			_topLayout.contentsMargins().right());
> +}
> +
> +void KsCheckBoxTreeWidget::_update(QTreeWidgetItem *item, int column)
> +{
> +	/* Get the new state of the item. */
> +	Qt::CheckState state = item->checkState(0);
> +
> +	/* Recursively update all items below this one. */
> +	update_r(item, state);
> +
> +	/* Update all items above this one including the "all"
> +	 * check box. */

The above comment format needs to be fixed.

> +	_verify();
> +}
> +
> +void KsCheckBoxTreeWidget::_verify()
> +{
> +	/* Set the state of the top level items according to the
> +	* state of the childs. */

The above one too.

-- Steve

> +	QTreeWidgetItem *topItem, *childItem;
> +	for(int t = 0; t < _tree.topLevelItemCount(); ++t) {
> +		topItem = _tree.topLevelItem(t);
> +		if (topItem->childCount() == 0)
> +			continue;
> +
> +		topItem->setCheckState(0, Qt::Checked);
> +		for (int c = 0; c < topItem->childCount(); ++c) {
> +			childItem = topItem->child(c);
> +			if (childItem->checkState(0) == Qt::Unchecked)
> +				topItem->setCheckState(0, Qt::Unchecked);
> +		}
> +	}
> +
> +	_allCb.setCheckState(Qt::Checked);
> +	for (auto &c: _cb) {
> +		if (c->checkState(0) == Qt::Unchecked) {
> +			_allCb.setCheckState(Qt::Unchecked);
> +			break;
> +		}
> +	}
> +}
> +

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

* Re: [PATCH 4/4] kernel-shark-qt: Add widget demo example.
  2018-10-08 15:16 ` [PATCH 4/4] kernel-shark-qt: Add widget demo example Yordan Karadzhov
@ 2018-10-09 16:45   ` Steven Rostedt
  0 siblings, 0 replies; 15+ messages in thread
From: Steven Rostedt @ 2018-10-09 16:45 UTC (permalink / raw)
  To: Yordan Karadzhov; +Cc: linux-trace-devel, Yordan Karadzhov

On Mon,  8 Oct 2018 18:16:29 +0300
Yordan Karadzhov <y.karadz@gmail.com> wrote:

> From: Yordan Karadzhov <ykaradzhov@vmware.com>
> 
> This patch introduces a basic example, showing how to use KsUtils and
> KsWidgetsLib.
> 
> Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
> ---
>  kernel-shark-qt/examples/CMakeLists.txt |   4 +
>  kernel-shark-qt/examples/widgetdemo.cpp | 159 ++++++++++++++++++++++++
>  2 files changed, 163 insertions(+)
>  create mode 100644 kernel-shark-qt/examples/widgetdemo.cpp
> 
> diff --git a/kernel-shark-qt/examples/CMakeLists.txt b/kernel-shark-qt/examples/CMakeLists.txt
> index 0c83293..e16216e 100644
> --- a/kernel-shark-qt/examples/CMakeLists.txt
> +++ b/kernel-shark-qt/examples/CMakeLists.txt
> @@ -19,3 +19,7 @@ target_link_libraries(confio   kshark)
>  message(STATUS "dataplot")
>  add_executable(dplot          dataplot.cpp)
>  target_link_libraries(dplot   kshark-plot)
> +
> +message(STATUS "widgetdemo")
> +add_executable(widgetdemo          widgetdemo.cpp)
> +target_link_libraries(widgetdemo   kshark-gui)
> diff --git a/kernel-shark-qt/examples/widgetdemo.cpp b/kernel-shark-qt/examples/widgetdemo.cpp
> new file mode 100644
> index 0000000..c9ce86b
> --- /dev/null
> +++ b/kernel-shark-qt/examples/widgetdemo.cpp
> @@ -0,0 +1,159 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
> + */
> +
> +// C
> +#include <sys/stat.h>
> +#include <getopt.h>
> +#include <unistd.h>
> +
> +// C++
> +#include <iostream>
> +
> +// Qt
> +#include <QtWidgets>
> +
> +// KernelShark
> +#include "KsUtils.hpp"
> +#include "KsWidgetsLib.hpp"
> +
> +#define default_input_file (char*)"trace.dat"
> +
> +static char *input_file = nullptr;
> +
> +using namespace std;
> +
> +void usage(const char *prog)
> +{
> +	cout << "Usage: " << prog << endl
> +	     << "  -h	Display this help message\n"
> +	     << "  -v	Display version and exit\n"
> +	     << "  -i	input_file, default is " << default_input_file << endl
> +	     << "  -p	register plugin, use plugin name, absolute or relative path\n"
> +	     << "  -u	unregister plugin, use plugin name or absolute path\n";

Add a exit here, because when I ran this with -h, it still runs the
code.

-- Steve

> +}
> +
> +struct TaskPrint : public QObject
> +{
> +	tep_handle	*_pevent;
> +
> +	void print(QVector<int> pids)
> +	{
> +		for (auto const &pid: pids)
> +			cout << "task: "
> +			     << tep_data_comm_from_pid(_pevent, pid)
> +			     << "  pid: " << pid << endl;
> +	}
> +};
> +
> +int main(int argc, char **argv)
> +{
> +	kshark_context *kshark_ctx(nullptr);
> +	QApplication a(argc, argv);
> +	KsPluginManager plugins;
> +	KsDataStore data;
> +	size_t nRows(0);
> +	int c;
> +
> +	if (!kshark_instance(&kshark_ctx))
> +		return 1;
> +
> +	while ((c = getopt(argc, argv, "hvi:p:u:")) != -1) {
> +		switch(c) {
> +		case 'v':
> +			printf("kshark-gui %s\n", KS_VERSION_STRING);
> +			return 0;
> +
> +		case 'i':
> +			input_file = optarg;
> +			break;
> +
> +		case 'p':
> +			plugins.registerPlugin(QString(optarg));
> +			break;
> +
> +		case 'u':
> +			plugins.unregisterPlugin(QString(optarg));
> +			break;
> +
> +		case 'h':
> +		default:
> +			usage(argv[0]);
> +			break;
> +		}
> +	}
> +
> +	if (!input_file) {
> +			struct stat st;
> +			if (stat(default_input_file, &st) == 0)
> +				input_file = default_input_file;
> +	}
> +
> +	if (input_file) {
> +		data.loadDataFile(input_file);
> +		nRows = data.size();
> +	} else {
> +		cerr << "No input file is provided.\n";
> +	}
> +
> +	cout << nRows << " entries loaded\n";
> +
> +	auto lamPrintPl = [&] ()
> +	{
> +		kshark_plugin_list *pl;
> +		for (pl = kshark_ctx->plugins; pl; pl = pl->next)
> +			cout << pl->file << endl;
> +	};
> +
> +	cout << "\n\n";
> +	lamPrintPl();
> +	sleep(1);
> +
> +	QVector<bool> registeredPlugins;
> +	QStringList pluginsList;
> +
> +	pluginsList << plugins._ksPluginList
> +		    << plugins._userPluginList;
> +
> +	registeredPlugins << plugins._registeredKsPlugins
> +			  << plugins._registeredUserPlugins;
> +
> +	KsCheckBoxWidget *pluginCBD
> +		= new KsPluginCheckBoxWidget(pluginsList);
> +
> +	pluginCBD->set(registeredPlugins);
> +
> +	KsCheckBoxDialog *dialog1 = new KsCheckBoxDialog(pluginCBD);
> +	QObject::connect(dialog1,	&KsCheckBoxDialog::apply,
> +			&plugins,	&KsPluginManager::updatePlugins);
> +
> +	dialog1->show();
> +	a.exec();
> +
> +	cout << "\n\nYou selected\n";
> +	lamPrintPl();
> +	sleep(1);
> +
> +	if (!nRows)
> +		return 1;
> +
> +	KsCheckBoxWidget *tasks_cbd =
> +		new KsTasksCheckBoxWidget(data.pevent(), true);
> +
> +	tasks_cbd->setDefault(false);
> +
> +	TaskPrint p;
> +	p._pevent = data.pevent();
> +
> +	KsCheckBoxDialog *dialog2 = new KsCheckBoxDialog(tasks_cbd);
> +	QObject::connect(dialog2,	&KsCheckBoxDialog::apply,
> +			 &p,		&TaskPrint::print);
> +
> +	cout << "\n\nYou selected\n";
> +	dialog2->show();
> +	a.exec();
> +
> +	return 0;
> +}

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

* Re: [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils
  2018-10-09 16:34   ` Steven Rostedt
@ 2018-10-10 14:12     ` Yordan Karadzhov
  2018-10-10 15:22       ` Steven Rostedt
  2018-10-10 15:27     ` Yordan Karadzhov
  2018-10-10 15:27     ` Yordan Karadzhov
  2 siblings, 1 reply; 15+ messages in thread
From: Yordan Karadzhov @ 2018-10-10 14:12 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: linux-trace-devel, Yordan Karadzhov



On  9.10.2018 19:34, Steven Rostedt wrote:
>> +	if (!kshark_instance(&kshark_ctx))
>> +		return;
>> +
>> +	switch (filterId) {
>> +		case KS_SHOW_EVENT_FILTER:
>> +		case KS_HIDE_EVENT_FILTER:
>> +			kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER);
>> +			kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER);
> Hmm, I'm curious to why you clear both SHOW/HIDE filters if the
> filterId is one of SHOW or HIDE?
> 
> Perhaps a comment should be here explaining it too.
> 
> 

This enforces that we cannot have both SHOW and HIDE filters being set.
I think that, having SHOW and HIDE filters set in the same time can be 
useful in very limited number of cases. On the other hand this is an 
easy way to confuse yourself.

Note that this restriction is at the level of the GUI code. The C API 
allows for having both SHOW and HIDE filters in the same time.

Thanks!
Yordan

>> +			break;
>> +		case KS_SHOW_TASK_FILTER:
>> +		case KS_HIDE_TASK_FILTER:
>> +			kshark_filter_clear(kshark_ctx, KS_SHOW_TASK_FILTER);
>> +			kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER);
>> +			break;
>> +		default:
>> +			return;
>> +	}
>> +
>> +	for (auto &&pid: vec)
>> +		kshark_filter_add_id(kshark_ctx, filterId, pid);
>> +

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

* Re: [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils
  2018-10-10 14:12     ` Yordan Karadzhov
@ 2018-10-10 15:22       ` Steven Rostedt
  2018-10-10 15:25         ` Yordan Karadzhov
  0 siblings, 1 reply; 15+ messages in thread
From: Steven Rostedt @ 2018-10-10 15:22 UTC (permalink / raw)
  To: Yordan Karadzhov; +Cc: linux-trace-devel

On Wed, 10 Oct 2018 17:12:40 +0300
Yordan Karadzhov <ykaradzhov@vmware.com> wrote:

> On  9.10.2018 19:34, Steven Rostedt wrote:
> >> +	if (!kshark_instance(&kshark_ctx))
> >> +		return;
> >> +
> >> +	switch (filterId) {
> >> +		case KS_SHOW_EVENT_FILTER:
> >> +		case KS_HIDE_EVENT_FILTER:
> >> +			kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER);
> >> +			kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER);  
> > Hmm, I'm curious to why you clear both SHOW/HIDE filters if the
> > filterId is one of SHOW or HIDE?
> > 
> > Perhaps a comment should be here explaining it too.
> > 
> >   
> 
> This enforces that we cannot have both SHOW and HIDE filters being set.
> I think that, having SHOW and HIDE filters set in the same time can be 
> useful in very limited number of cases. On the other hand this is an 
> easy way to confuse yourself.
> 
> Note that this restriction is at the level of the GUI code. The C API 
> allows for having both SHOW and HIDE filters in the same time.
>

Actually, there are real uses to do both. You may want to show a
specific kind of event, and then you may want to filter a subset of
that event.

-- Steve

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

* Re: [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils
  2018-10-10 15:22       ` Steven Rostedt
@ 2018-10-10 15:25         ` Yordan Karadzhov
  2018-10-10 19:02           ` Steven Rostedt
  0 siblings, 1 reply; 15+ messages in thread
From: Yordan Karadzhov @ 2018-10-10 15:25 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: linux-trace-devel



On 10.10.2018 18:22, Steven Rostedt wrote:
> On Wed, 10 Oct 2018 17:12:40 +0300
> Yordan Karadzhov <ykaradzhov@vmware.com> wrote:
> 
>> On  9.10.2018 19:34, Steven Rostedt wrote:
>>>> +	if (!kshark_instance(&kshark_ctx))
>>>> +		return;
>>>> +
>>>> +	switch (filterId) {
>>>> +		case KS_SHOW_EVENT_FILTER:
>>>> +		case KS_HIDE_EVENT_FILTER:
>>>> +			kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER);
>>>> +			kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER);
>>> Hmm, I'm curious to why you clear both SHOW/HIDE filters if the
>>> filterId is one of SHOW or HIDE?
>>>
>>> Perhaps a comment should be here explaining it too.
>>>
>>>    
>>
>> This enforces that we cannot have both SHOW and HIDE filters being set.
>> I think that, having SHOW and HIDE filters set in the same time can be
>> useful in very limited number of cases. On the other hand this is an
>> easy way to confuse yourself.
>>
>> Note that this restriction is at the level of the GUI code. The C API
>> allows for having both SHOW and HIDE filters in the same time.
>>
> 
> Actually, there are real uses to do both. You may want to show a
> specific kind of event, and then you may want to filter a subset of
> that event.
> 

But if you want to filter a subset of one event you have to use the 
advanced filtering, while the logic in the "switch" is only for the "Id 
filters".

Thanks!
Yordan


> -- Steve
> 

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

* Re: [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils
  2018-10-09 16:34   ` Steven Rostedt
  2018-10-10 14:12     ` Yordan Karadzhov
@ 2018-10-10 15:27     ` Yordan Karadzhov
  2018-10-10 15:27     ` Yordan Karadzhov
  2 siblings, 0 replies; 15+ messages in thread
From: Yordan Karadzhov @ 2018-10-10 15:27 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: linux-trace-devel, Yordan Karadzhov



On  9.10.2018 19:34, Steven Rostedt wrote:
>> +
>> +/** @brief Unregister a Plugin.
>> + *<br> WARNING: Do not use this function to unregister User plugins.
> Hmm, do we need the <br> above? (if this is required by DocGen I find
> it rather ugly:-(  )

<br> means "break the line". Perhaps I can make it like this:


/** @brief Unregister a Plugin.
  *<br>
  * WARNING: Do not use this function to unregister User plugins.
  *
  * @param plugin: provide here the name of the plugin [...]
  *
  */

Thanks!
Yordan

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

* Re: [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils
  2018-10-09 16:34   ` Steven Rostedt
  2018-10-10 14:12     ` Yordan Karadzhov
  2018-10-10 15:27     ` Yordan Karadzhov
@ 2018-10-10 15:27     ` Yordan Karadzhov
  2018-10-10 19:04       ` Steven Rostedt
  2 siblings, 1 reply; 15+ messages in thread
From: Yordan Karadzhov @ 2018-10-10 15:27 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: linux-trace-devel, Yordan Karadzhov


On  9.10.2018 19:34, Steven Rostedt wrote:
> Is this private to libkshark and not going to be exported?
> 
> In other words, do we need to worry about namespace?

The namespace here is used mostly for making the code easy to read.
C++ people do this because it makes the code look more OO-ish.

Note that

namespace Foo
{
	bool bar1(int x);

	void bar2();
};

is equivalent to

class Foo {
	static bool bar1(int x);

	static void bar2();
};

Thanks!
Yordan

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

* Re: [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils
  2018-10-10 15:25         ` Yordan Karadzhov
@ 2018-10-10 19:02           ` Steven Rostedt
  0 siblings, 0 replies; 15+ messages in thread
From: Steven Rostedt @ 2018-10-10 19:02 UTC (permalink / raw)
  To: Yordan Karadzhov; +Cc: linux-trace-devel

On Wed, 10 Oct 2018 18:25:52 +0300
Yordan Karadzhov <ykaradzhov@vmware.com> wrote:

> > Actually, there are real uses to do both. You may want to show a
> > specific kind of event, and then you may want to filter a subset of
> > that event.
> >   
> 
> But if you want to filter a subset of one event you have to use the 
> advanced filtering, while the logic in the "switch" is only for the "Id 
> filters".

I guess I was thinking about filtering to show all events under a
specific system, and then hiding events from within that system, but it
probably is just easier to pick those events not to show in the gui (I
was playing with the old KS to see how it did things).

-- Steve

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

* Re: [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils
  2018-10-10 15:27     ` Yordan Karadzhov
@ 2018-10-10 19:04       ` Steven Rostedt
  0 siblings, 0 replies; 15+ messages in thread
From: Steven Rostedt @ 2018-10-10 19:04 UTC (permalink / raw)
  To: Yordan Karadzhov; +Cc: linux-trace-devel

On Wed, 10 Oct 2018 18:27:53 +0300
Yordan Karadzhov <ykaradzhov@vmware.com> wrote:

> On  9.10.2018 19:34, Steven Rostedt wrote:
> > Is this private to libkshark and not going to be exported?
> > 
> > In other words, do we need to worry about namespace?  
> 
> The namespace here is used mostly for making the code easy to read.
> C++ people do this because it makes the code look more OO-ish.
> 
> Note that

Never mind. My question was because I *missed* seeing:

 +namespace KsUtils {

And was asking if we want to have a namespace.

-- Steve

> 
> namespace Foo
> {
> 	bool bar1(int x);
> 
> 	void bar2();
> };
> 
> is equivalent to
> 
> class Foo {
> 	static bool bar1(int x);
> 
> 	static void bar2();
> };
> 
> Thanks!
> Yordan

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

end of thread, other threads:[~2018-10-11  2:28 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-08 15:16 [PATCH 0/4] Add basic components to be used by the Qt GUI Yordan Karadzhov
2018-10-08 15:16 ` [PATCH 1/4] kernel-shark-qt: Add Qt as a third party dependency Yordan Karadzhov
2018-10-08 15:16 ` [PATCH 2/4] kernel-shark-qt: Add KernalShark Utils Yordan Karadzhov
2018-10-09 16:34   ` Steven Rostedt
2018-10-10 14:12     ` Yordan Karadzhov
2018-10-10 15:22       ` Steven Rostedt
2018-10-10 15:25         ` Yordan Karadzhov
2018-10-10 19:02           ` Steven Rostedt
2018-10-10 15:27     ` Yordan Karadzhov
2018-10-10 15:27     ` Yordan Karadzhov
2018-10-10 19:04       ` Steven Rostedt
2018-10-08 15:16 ` [PATCH 3/4] kernel-shark-qt: Add Widgets Lib Yordan Karadzhov
2018-10-09 16:42   ` Steven Rostedt
2018-10-08 15:16 ` [PATCH 4/4] kernel-shark-qt: Add widget demo example Yordan Karadzhov
2018-10-09 16:45   ` Steven Rostedt

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