@@ -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
@@ -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
new file mode 100644
@@ -0,0 +1,594 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+/**
+ * @file KsUtils.cpp
+ * @brief KernelShark Utils.
+ */
+
+// KernelShark
+#include "KsUtils.hpp"
+
+namespace KsUtils {
+
+/** @brief Get a sorted 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)
+{
+ 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),
+ _tep(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())) {
+ qCritical() << "ERROR Loading file " << file;
+ return;
+ }
+
+ _tep = 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);
+ _tep = kshark_ctx->pevent;
+
+ emit updateWidgets(this);
+}
+
+/** Free the loaded trace data and close the file. */
+void KsDataStore::clear()
+{
+ kshark_context *kshark_ctx(nullptr);
+
+ _freeData();
+ _tep = 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 = _tep->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 = _tep->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 (!_tep)
+ 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);
+
+ if (!kshark_instance(&kshark_ctx) || !_tep)
+ 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)
+ return;
+
+ 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)
+ return;
+
+ 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 Built in KernelShark plugin.
+ *<br>
+ * WARNING: Do not use this function to unregister User plugins.
+ * Instead use directly kshark_unregister_plugin().
+ *
+ * @param plugin: provide here the name of the plugin (as in the CMake-generated
+ * header file) or 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();
+}
new file mode 100644
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.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 trace event parser. */
+ tep_handle *tep() const {return _tep;}
+
+ /** 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 *_tep;
+
+ /** 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> ®,
+ 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