| // 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" |
| #include "KsMainWindow.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. */ |
| bool KsSession::importFromFile(QString jfileName) |
| { |
| kshark_config_doc *configTmp = |
| kshark_open_config_file(jfileName.toStdString().c_str(), |
| "kshark.config.session"); |
| |
| if (configTmp) { |
| kshark_free_config_doc(_config); |
| _config = configTmp; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** 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; |
| |
| if (window.isFullScreen()) { |
| jwindow = json_object_new_string("FullScreen"); |
| } else { |
| 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(KsMainWindow *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); |
| if (json_object_get_type(jwindow) == json_type_string && |
| QString(json_object_get_string(jwindow)) == "FullScreen") { |
| window->setFullScreenMode(true); |
| return; |
| } |
| |
| 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->setFullScreenMode(false); |
| 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(1), viewSize(1); |
| 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); |
| if (graphSize == 0 && viewSize == 0) { |
| /* 0/0 spliter ratio is undefined. Make it 1/1. */ |
| viewSize = graphSize = 1; |
| } |
| } |
| |
| 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()); |
| if (dm->activeMarker()._isSet) { |
| 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; |
| const char *pluginName; |
| QVector<int> pluginIds; |
| int length, index; |
| bool loaded; |
| |
| 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); |
| pluginName = json_object_get_string(json_object_array_get_idx(jpl, 0)); |
| index = pm->_ksPluginList.indexOf(pluginName); |
| loaded = json_object_get_boolean(json_object_array_get_idx(jpl, 1)); |
| if (index >= 0 && loaded) |
| pluginIds.append(index); |
| } |
| } |
| |
| pm->updatePlugins(pluginIds); |
| } |