@@ -44,6 +44,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp
KsModels.cpp
+ KsSession.cpp
KsGLWidget.cpp
KsDualMarker.cpp
KsWidgetsLib.cpp
new file mode 100644
@@ -0,0 +1,574 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+/**
+ * @file KsSession.cpp
+ * @brief KernelShark Session.
+ */
+
+// KernelShark
+#include "libkshark.h"
+#include "KsSession.hpp"
+
+/** Create a KsSession object. */
+KsSession::KsSession()
+{
+ _config = kshark_config_new("kshark.config.session",
+ KS_CONFIG_JSON);
+}
+
+/** Destroy a KsSession object. */
+KsSession::~KsSession()
+{
+ kshark_free_config_doc(_config);
+}
+
+/** Import a user session from a Json file. */
+void KsSession::importFromFile(QString jfileName)
+{
+ if (_config)
+ kshark_free_config_doc(_config);
+
+ _config = kshark_open_config_file(jfileName.toStdString().c_str(),
+ "kshark.config.session");
+}
+
+/** Export the current user session from a Json file. */
+void KsSession::exportToFile(QString jfileName)
+{
+ kshark_save_config_file(jfileName.toStdString().c_str(), _config);
+}
+
+/**
+ * @brief Save the state of the visualization model.
+ *
+ * @param histo: Input location for the model descriptor.
+ */
+void KsSession::saveVisModel(kshark_trace_histo *histo)
+{
+ kshark_config_doc *model =
+ kshark_export_model(histo, KS_CONFIG_JSON);
+
+ kshark_config_doc_add(_config, "Model", model);
+}
+
+/**
+ * @brief Load the state of the visualization model.
+ *
+ * @param model: Input location for the KsGraphModel object.
+ */
+void KsSession::loadVisModel(KsGraphModel *model)
+{
+ kshark_config_doc *modelConf = kshark_config_alloc(KS_CONFIG_JSON);
+
+ if (!kshark_config_doc_get(_config, "Model", modelConf))
+ return;
+
+ kshark_import_model(model->histo(), modelConf);
+ model->update();
+}
+
+/** Save the trace data file. */
+void KsSession::saveDataFile(QString fileName)
+{
+ kshark_config_doc *file =
+ kshark_export_trace_file(fileName.toStdString().c_str(),
+ KS_CONFIG_JSON);
+
+ kshark_config_doc_add(_config, "Data", file);
+}
+
+/** Get the trace data file. */
+QString KsSession::getDataFile(kshark_context *kshark_ctx)
+{
+ kshark_config_doc *file = kshark_config_alloc(KS_CONFIG_JSON);
+ const char *file_str;
+
+ if (!kshark_config_doc_get(_config, "Data", file))
+ return QString();
+
+ file_str = kshark_import_trace_file(kshark_ctx, file);
+ if (file_str)
+ return QString(file_str);
+
+ return QString();
+}
+
+/**
+ * @brief Save the configuration of the filters.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ */
+void KsSession::saveFilters(kshark_context *kshark_ctx)
+{
+ kshark_config_doc *filters =
+ kshark_export_all_filters(kshark_ctx, KS_CONFIG_JSON);
+
+ kshark_config_doc_add(_config, "Filters", filters);
+}
+
+/**
+ * @brief Load the configuration of the filters and filter the data.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ * @param data: Input location for KsDataStore object;
+ */
+void KsSession::loadFilters(kshark_context *kshark_ctx, KsDataStore *data)
+{
+ kshark_config_doc *filters = kshark_config_alloc(KS_CONFIG_JSON);
+
+ if (!kshark_config_doc_get(_config, "Filters", filters))
+ return;
+
+ kshark_import_all_filters(kshark_ctx, filters);
+
+ if (kshark_ctx->advanced_event_filter->filters)
+ data->reload();
+ else
+ kshark_filter_entries(kshark_ctx, data->rows(), data->size());
+
+ data->registerCPUCollections();
+
+ emit data->updateWidgets(data);
+}
+
+/**
+ * @brief Save the state of the table.
+ *
+ * @param view: Input location for the KsTraceViewer widget.
+ */
+void KsSession::saveTable(const KsTraceViewer &view) {
+ kshark_config_doc *topRow = kshark_config_alloc(KS_CONFIG_JSON);
+ int64_t r = view.getTopRow();
+
+ topRow->conf_doc = json_object_new_int64(r);
+ kshark_config_doc_add(_config, "ViewTop",topRow);
+}
+
+/**
+ * @brief Load the state of the table.
+ *
+ * @param view: Input location for the KsTraceViewer widget.
+ */
+void KsSession::loadTable(KsTraceViewer *view) {
+ kshark_config_doc *topRow = kshark_config_alloc(KS_CONFIG_JSON);
+ size_t r = 0;
+
+ if (!kshark_config_doc_get(_config, "ViewTop", topRow))
+ return;
+
+ if (_config->format == KS_CONFIG_JSON)
+ r = json_object_get_int64(KS_JSON_CAST(topRow->conf_doc));
+
+ view->setTopRow(r);
+}
+
+/**
+ * @brief Save the KernelShark Main window size.
+ *
+ * @param window: Input location for the KsMainWindow widget.
+ */
+void KsSession::saveMainWindowSize(const QMainWindow &window)
+{
+ kshark_config_doc *windowConf = kshark_config_alloc(KS_CONFIG_JSON);
+ int width = window.width(), height = window.height();
+ json_object *jwindow = json_object_new_array();
+
+ json_object_array_put_idx(jwindow, 0, json_object_new_int(width));
+ json_object_array_put_idx(jwindow, 1, json_object_new_int(height));
+
+ windowConf->conf_doc = jwindow;
+ kshark_config_doc_add(_config, "MainWindow", windowConf);
+}
+
+/**
+ * @brief Load the KernelShark Main window size.
+ *
+ * @param window: Input location for the KsMainWindow widget.
+ */
+void KsSession::loadMainWindowSize(QMainWindow *window)
+{
+ kshark_config_doc *windowConf = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jwindow, *jwidth, *jheight;
+ int width, height;
+
+ if (!kshark_config_doc_get(_config, "MainWindow", windowConf))
+ return;
+
+ if (_config->format == KS_CONFIG_JSON) {
+ jwindow = KS_JSON_CAST(windowConf->conf_doc);
+ jwidth = json_object_array_get_idx(jwindow, 0);
+ jheight = json_object_array_get_idx(jwindow, 1);
+
+ width = json_object_get_int(jwidth);
+ height = json_object_get_int(jheight);
+
+ window->resize(width, height);
+ }
+}
+
+/**
+ * @brief Save the state of the Main window spliter.
+ *
+ * @param splitter: Input location for the splitter widget.
+ */
+void KsSession::saveSplitterSize(const QSplitter &splitter)
+{
+ kshark_config_doc *spl = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jspl = json_object_new_array();
+ QList<int> sizes = splitter.sizes();
+
+ json_object_array_put_idx(jspl, 0, json_object_new_int(sizes[0]));
+ json_object_array_put_idx(jspl, 1, json_object_new_int(sizes[1]));
+
+ spl->conf_doc = jspl;
+ kshark_config_doc_add(_config, "Splitter", spl);
+}
+
+/**
+ * @brief Load the state of the Main window spliter.
+ *
+ * @param splitter: Input location for the splitter widget.
+ */
+void KsSession::loadSplitterSize(QSplitter *splitter)
+{
+ kshark_config_doc *spl = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jspl, *jgraphsize, *jviewsize;
+ int graphSize, viewSize;
+ QList<int> sizes;
+
+ if (!kshark_config_doc_get(_config, "Splitter", spl))
+ return;
+
+ if (_config->format == KS_CONFIG_JSON) {
+ jspl = KS_JSON_CAST(spl->conf_doc);
+ jgraphsize = json_object_array_get_idx(jspl, 0);
+ jviewsize = json_object_array_get_idx(jspl, 1);
+
+ graphSize = json_object_get_int(jgraphsize);
+ viewSize = json_object_get_int(jviewsize);
+ }
+
+ sizes << graphSize << viewSize;
+ splitter->setSizes(sizes);
+}
+
+/** @brief Save the Color scheme used. */
+void KsSession::saveColorScheme() {
+ kshark_config_doc *colSch = kshark_config_alloc(KS_CONFIG_JSON);
+ double s = KsPlot::Color::getRainbowFrequency();
+
+ colSch->conf_doc = json_object_new_double(s);
+ kshark_config_doc_add(_config, "ColorScheme", colSch);
+}
+
+/** @brief Get the Color scheme used. */
+float KsSession::getColorScheme() {
+ kshark_config_doc *colSch = kshark_config_alloc(KS_CONFIG_JSON);
+
+ /* Default color scheme. */
+ float s = 0.75;
+
+ if (!kshark_config_doc_get(_config, "ColorScheme", colSch))
+ return s;
+
+ if (_config->format == KS_CONFIG_JSON)
+ s = json_object_get_double(KS_JSON_CAST(colSch->conf_doc));
+
+ return s;
+}
+
+/**
+ * @brief Save the list of the graphs plotted.
+ *
+ * @param glw: Input location for the KsGLWidget widget.
+ */
+void KsSession::saveGraphs(const KsGLWidget &glw)
+{
+ _saveCPUPlots(glw._cpuList);
+ _saveTaskPlots(glw._taskList);
+}
+
+/**
+ * @brief Load the list of the graphs and plot.
+ *
+ * @param graphs: Input location for the KsTraceGraph widget.
+ */
+void KsSession::loadGraphs(KsTraceGraph *graphs)
+{
+ graphs->cpuReDraw(_getCPUPlots());
+ graphs->taskReDraw(_getTaskPlots());
+}
+
+void KsSession::_saveCPUPlots(const QVector<int> &cpus)
+{
+ kshark_config_doc *cpuPlts = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jcpus = json_object_new_array();
+
+ for (int i = 0; i < cpus.count(); ++i) {
+ json_object *jcpu = json_object_new_int(cpus[i]);
+ json_object_array_put_idx(jcpus, i, jcpu);
+ }
+
+ cpuPlts->conf_doc = jcpus;
+ kshark_config_doc_add(_config, "CPUPlots", cpuPlts);
+}
+
+QVector<int> KsSession::_getCPUPlots()
+{
+ kshark_config_doc *cpuPlts = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jcpus;
+ QVector<int> cpus;
+ size_t length;
+
+ if (!kshark_config_doc_get(_config, "CPUPlots", cpuPlts))
+ return cpus;
+
+ if (_config->format == KS_CONFIG_JSON) {
+ jcpus = KS_JSON_CAST(cpuPlts->conf_doc);
+ length = json_object_array_length(jcpus);
+ for (size_t i = 0; i < length; ++i) {
+ int cpu = json_object_get_int(json_object_array_get_idx(jcpus,
+ i));
+ cpus.append(cpu);
+ }
+ }
+
+ return cpus;
+}
+
+void KsSession::_saveTaskPlots(const QVector<int> &tasks)
+{
+ kshark_config_doc *taskPlts = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jtasks = json_object_new_array();
+
+ for (int i = 0; i < tasks.count(); ++i) {
+ json_object *jtask = json_object_new_int(tasks[i]);
+ json_object_array_put_idx(jtasks, i, jtask);
+ }
+
+ taskPlts->conf_doc = jtasks;
+ kshark_config_doc_add(_config, "TaskPlots", taskPlts);
+}
+
+QVector<int> KsSession::_getTaskPlots()
+{
+ kshark_config_doc *taskPlts = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jtasks;
+ QVector<int> tasks;
+ size_t length;
+
+ if (!kshark_config_doc_get(_config, "TaskPlots", taskPlts))
+ return tasks;
+
+ if (_config->format == KS_CONFIG_JSON) {
+ jtasks = KS_JSON_CAST(taskPlts->conf_doc);
+ length = json_object_array_length(jtasks);
+ for (size_t i = 0; i < length; ++i) {
+ int pid = json_object_get_int(json_object_array_get_idx(jtasks,
+ i));
+ tasks.append(pid);
+ }
+ }
+
+ return tasks;
+}
+
+/**
+ * @brief Save the state of the Dual marker.
+ *
+ * @param dm: Input location for the KsDualMarkerSM object.
+ */
+void KsSession::saveDualMarker(KsDualMarkerSM *dm)
+{
+ struct kshark_config_doc *markers =
+ kshark_config_new("kshark.config.markers", KS_CONFIG_JSON);
+ json_object *jd_mark = KS_JSON_CAST(markers->conf_doc);
+
+ auto save_mark = [&jd_mark] (KsGraphMark *m, const char *name)
+ {
+ json_object *jmark = json_object_new_object();
+
+ if (m->_isSet) {
+ json_object_object_add(jmark, "isSet",
+ json_object_new_boolean(true));
+
+ json_object_object_add(jmark, "row",
+ json_object_new_int(m->_pos));
+ } else {
+ json_object_object_add(jmark, "isSet",
+ json_object_new_boolean(false));
+ }
+
+ json_object_object_add(jd_mark, name, jmark);
+ };
+
+ save_mark(&dm->markerA(), "markA");
+ save_mark(&dm->markerB(), "markB");
+
+ if (dm->getState() == DualMarkerState::A)
+ json_object_object_add(jd_mark, "Active",
+ json_object_new_string("A"));
+ else
+ json_object_object_add(jd_mark, "Active",
+ json_object_new_string("B"));
+
+ kshark_config_doc_add(_config, "Markers", markers);
+}
+
+/**
+ * @brief Load the state of the Dual marker.
+ *
+ * @param dm: Input location for the KsDualMarkerSM object.
+ * @param graphs: Input location for the KsTraceGraph widget.
+ */
+void KsSession::loadDualMarker(KsDualMarkerSM *dm, KsTraceGraph *graphs)
+{
+ uint64_t pos;
+
+ dm->reset();
+ dm->setState(DualMarkerState::A);
+
+ if (_getMarker("markA", &pos)) {
+ graphs->markEntry(pos);
+ } else {
+ dm->markerA().remove();
+ }
+
+ dm->setState(DualMarkerState::B);
+ if (_getMarker("markB", &pos)) {
+ graphs->markEntry(pos);
+ } else {
+ dm->markerB().remove();
+ }
+
+ dm->setState(_getMarkerState());
+ pos = dm->activeMarker()._pos;
+
+ emit graphs->glPtr()->updateView(pos, true);
+}
+
+json_object *KsSession::_getMarkerJson()
+{
+ struct kshark_config_doc *markers =
+ kshark_config_alloc(KS_CONFIG_JSON);
+
+ if (!kshark_config_doc_get(_config, "Markers", markers) ||
+ !kshark_type_check(markers, "kshark.config.markers"))
+ return nullptr;
+
+ return KS_JSON_CAST(markers->conf_doc);
+}
+
+bool KsSession::_getMarker(const char* name, size_t *pos)
+{
+ json_object *jd_mark, *jmark;
+
+ *pos = 0;
+ jd_mark = _getMarkerJson();
+ if (!jd_mark)
+ return false;
+
+ if (json_object_object_get_ex(jd_mark, name, &jmark)) {
+ json_object *jis_set;
+ json_object_object_get_ex(jmark, "isSet", &jis_set);
+ if (!json_object_get_boolean(jis_set))
+ return false;
+
+ json_object *jpos;
+ json_object_object_get_ex(jmark, "row", &jpos);
+ *pos = json_object_get_int64(jpos);
+ }
+
+ return true;
+}
+
+DualMarkerState KsSession::_getMarkerState()
+{
+ json_object *jd_mark, *jstate;
+ const char* state;
+
+ jd_mark = _getMarkerJson();
+ json_object_object_get_ex(jd_mark, "Active", &jstate);
+ state = json_object_get_string(jstate);
+
+ if (strcmp(state, "A") == 0)
+ return DualMarkerState::A;
+
+ return DualMarkerState::B;
+}
+
+/**
+ * @brief Save the configuration of the plugins.
+ *
+ * @param pm: Input location for the KsPluginManager object.
+ */
+void KsSession::savePlugins(const KsPluginManager &pm)
+{
+ struct kshark_config_doc *plugins =
+ kshark_config_new("kshark.config.plugins", KS_CONFIG_JSON);
+ json_object *jplugins = KS_JSON_CAST(plugins->conf_doc);
+ const QVector<bool> ®isteredPlugins = pm._registeredKsPlugins;
+ const QStringList &pluginList = pm._ksPluginList;
+ int nPlugins = pluginList.length();
+ json_object *jlist, *jpl;
+ QByteArray array;
+ char* buffer;
+ bool active;
+
+ jlist = json_object_new_array();
+ for (int i = 0; i < nPlugins; ++i) {
+ array = pluginList[i].toLocal8Bit();
+ buffer = array.data();
+ jpl = json_object_new_array();
+ json_object_array_put_idx(jpl, 0, json_object_new_string(buffer));
+
+ active = registeredPlugins[i];
+ json_object_array_put_idx(jpl, 1, json_object_new_boolean(active));
+ json_object_array_put_idx(jlist, i, jpl);
+ }
+
+ json_object_object_add(jplugins, "Plugin List", jlist);
+ kshark_config_doc_add(_config, "Plugins", plugins);
+}
+
+/**
+ * @brief Load the configuration of the plugins.
+ *
+ * @param kshark_ctx: Input location for context pointer.
+ * @param pm: Input location for the KsPluginManager object.
+ */
+void KsSession::loadPlugins(kshark_context *kshark_ctx, KsPluginManager *pm)
+{
+ kshark_config_doc *plugins = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jplugins, *jlist, *jpl;
+ int length;
+
+ if (!kshark_config_doc_get(_config, "Plugins", plugins) ||
+ !kshark_type_check(plugins, "kshark.config.plugins"))
+ return;
+
+ if (plugins->format == KS_CONFIG_JSON) {
+ jplugins = KS_JSON_CAST(plugins->conf_doc);
+ json_object_object_get_ex(jplugins, "Plugin List", &jlist);
+ if (!jlist ||
+ json_object_get_type(jlist) != json_type_array ||
+ !json_object_array_length(jlist))
+ return;
+
+ length = json_object_array_length(jlist);
+ for (int i = 0; i < length; ++i) {
+ jpl = json_object_array_get_idx(jlist, i);
+ pm->_ksPluginList[i] =
+ json_object_get_string(json_object_array_get_idx(jpl, 0));
+
+ pm->_registeredKsPlugins[i] =
+ json_object_get_boolean(json_object_array_get_idx(jpl, 1));
+ }
+ }
+
+ pm->registerFromList(kshark_ctx);
+}
new file mode 100644
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+/**
+ * @file KsSession.hpp
+ * @brief KernelShark Session.
+ */
+
+#ifndef _KS_SESSION_H
+#define _KS_SESSION_H
+
+// Qt
+#include <QtWidgets>
+
+// KernelShark
+#include "KsDualMarker.hpp"
+#include "KsTraceGraph.hpp"
+#include "KsTraceViewer.hpp"
+
+/**
+ * The KsSession class provides instruments for importing/exporting the state
+ * of the different components of the GUI from/to Json documents. These
+ * instruments are used to save/load user session in the GUI.
+ */
+class KsSession
+{
+public:
+ KsSession();
+
+ virtual ~KsSession();
+
+ /** Get the configuration document object. */
+ kshark_config_doc *getConfDocPtr() const {return _config;}
+
+ void importFromFile(QString jfileName);
+
+ void exportToFile(QString jfileName);
+
+ void saveDataFile(QString fileName);
+
+ QString getDataFile(kshark_context *kshark_ctx);
+
+ void saveVisModel(kshark_trace_histo *histo);
+
+ void loadVisModel(KsGraphModel *model);
+
+ void saveGraphs(const KsGLWidget &glw);
+
+ void loadGraphs(KsTraceGraph *graphs);
+
+ void saveFilters(kshark_context *kshark_ctx);
+
+ void loadFilters(kshark_context *kshark_ctx, KsDataStore *data);
+
+ void saveMainWindowSize(const QMainWindow &window);
+
+ void loadMainWindowSize(QMainWindow *window);
+
+ void saveSplitterSize(const QSplitter &splitter);
+
+ void loadSplitterSize(QSplitter *splitter);
+
+ void saveDualMarker(KsDualMarkerSM *dm);
+
+ void loadDualMarker(KsDualMarkerSM *dmm, KsTraceGraph *graphs);
+
+ void savePlugins(const KsPluginManager &pm);
+
+ void loadPlugins(kshark_context *kshark_ctx, KsPluginManager *pm);
+
+ void saveTable(const KsTraceViewer &view);
+
+ void loadTable(KsTraceViewer *view);
+
+ void saveColorScheme();
+
+ float getColorScheme();
+
+private:
+ kshark_config_doc *_config;
+
+ json_object *_getMarkerJson();
+
+ void _saveCPUPlots(const QVector<int> &cpus);
+
+ QVector<int> _getCPUPlots();
+
+ void _saveTaskPlots(const QVector<int> &tasks);
+
+ QVector<int> _getTaskPlots();
+
+ bool _getMarker(const char* name, size_t *pos);
+
+ DualMarkerState _getMarkerState();
+};
+
+#endif