kernel-sharkqt: Add streams to GUI
This patch modifies the GUI code in order to make it compatible
with the new version of the C API.
Signed-off-by: Yordan Karadzhov <ykaradzhov@vmware.com>
diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt
index fc3d371..5b7f998 100644
--- a/kernel-shark-qt/src/CMakeLists.txt
+++ b/kernel-shark-qt/src/CMakeLists.txt
@@ -28,69 +28,69 @@
endif (OPENGL_FOUND AND GLUT_FOUND)
-# if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
+if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
+
+ message(STATUS "libkshark-gui")
+ set (ks-guiLib_hdr KsUtils.hpp
+ KsModels.hpp
+ KsGLWidget.hpp
+ KsDualMarker.hpp
+ KsWidgetsLib.hpp
+ KsTraceGraph.hpp
+ KsTraceViewer.hpp
+ KsMainWindow.hpp
+ KsCaptureDialog.hpp
+ KsQuickContextMenu.hpp
+ KsAdvFilteringDialog.hpp)
#
-# message(STATUS "libkshark-gui")
-# set (ks-guiLib_hdr KsUtils.hpp
-# KsModels.hpp
-# KsGLWidget.hpp
-# KsDualMarker.hpp
-# KsWidgetsLib.hpp
-# KsTraceGraph.hpp
-# KsTraceViewer.hpp
-# KsMainWindow.hpp
-# KsCaptureDialog.hpp
-# KsQuickContextMenu.hpp
-# KsAdvFilteringDialog.hpp)
+ QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr})
+
+ add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp
+ KsModels.cpp
+ KsSession.cpp
+ KsGLWidget.cpp
+ KsDualMarker.cpp
+ KsWidgetsLib.cpp
+ KsTraceGraph.cpp
+ KsTraceViewer.cpp
+ KsMainWindow.cpp
+ KsCaptureDialog.cpp
+ KsQuickContextMenu.cpp
+ KsAdvFilteringDialog.cpp)
#
-# QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr})
-#
-# add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp
-# KsModels.cpp
-# KsSession.cpp
-# KsGLWidget.cpp
-# KsDualMarker.cpp
-# KsWidgetsLib.cpp
-# KsTraceGraph.cpp
-# KsTraceViewer.cpp
-# KsMainWindow.cpp
-# KsCaptureDialog.cpp
-# KsQuickContextMenu.cpp
-# KsAdvFilteringDialog.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}")
-#
-# message(STATUS "kernelshark")
-# add_executable(kernelshark kernelshark.cpp)
-# target_link_libraries(kernelshark kshark-gui)
-#
-# message(STATUS "kshark-record")
-# add_executable(kshark-record kshark-record.cpp)
-# target_link_libraries(kshark-record kshark-gui)
-#
-# install(TARGETS kernelshark kshark-record kshark kshark-plot kshark-gui
-# RUNTIME DESTINATION /usr/local/bin/
-# LIBRARY DESTINATION /usr/local/lib/kshark/)
-#
-# install(FILES "${KS_DIR}/kernelshark.desktop"
-# DESTINATION /usr/share/applications/)
-#
-# install(FILES "${KS_DIR}/org.freedesktop.kshark-record.policy"
-# DESTINATION /usr/share/polkit-1/actions/)
-#
-# install(PROGRAMS "${KS_DIR}/bin/kshark-su-record"
-# DESTINATION /usr/local/bin/)
-#
-# endif (Qt5Widgets_FOUND AND Qt5Network_FOUND)
-#
-# add_subdirectory(plugins)
+ 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}")
+
+ message(STATUS "kernelshark")
+ add_executable(kernelshark kernelshark.cpp)
+ target_link_libraries(kernelshark kshark-gui)
+
+ message(STATUS "kshark-record")
+ add_executable(kshark-record kshark-record.cpp)
+ target_link_libraries(kshark-record kshark-gui)
+
+ install(TARGETS kernelshark kshark-record kshark kshark-plot kshark-gui
+ RUNTIME DESTINATION /usr/local/bin/
+ LIBRARY DESTINATION /usr/local/lib/kshark/)
+
+ install(FILES "${KS_DIR}/kernelshark.desktop"
+ DESTINATION /usr/share/applications/)
+
+ install(FILES "${KS_DIR}/org.freedesktop.kshark-record.policy"
+ DESTINATION /usr/share/polkit-1/actions/)
+
+ install(PROGRAMS "${KS_DIR}/bin/kshark-su-record"
+ DESTINATION /usr/local/bin/)
+
+endif (Qt5Widgets_FOUND AND Qt5Network_FOUND)
+
+add_subdirectory(plugins)
find_program(DO_AS_ROOT pkexec)
diff --git a/kernel-shark-qt/src/plugins/kvm_events.c b/kernel-shark-qt/src/plugins/kvm_events.c
new file mode 100644
index 0000000..9382b53
--- /dev/null
+++ b/kernel-shark-qt/src/plugins/kvm_events.c
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+/**
+ * @file rename_sched_events.c
+ * @brief A plugin to deal with renamed threads.
+ */
+
+#ifndef _KS_PLUGIN_SHED_RENAME_H
+#define _KS_PLUGIN_SHED_RENAME_H
+
+// KernelShark
+#include "libkshark.h"
+#include "libkshark-model.h"
+
+/** Structure representing a plugin-specific context. */
+struct plugin_rename_context {
+ /** Stream identifier of the Monitor data. */
+ uint8_t monitor_stream_id;
+
+ /** Pointer to the kvm_entry_event object. */
+ struct tep_event_format *kvm_entry_event;
+
+ /** Pointer to the sched_switch_next_field format descriptor. */
+ struct tep_format_field *kvm_vcpu_id_field;
+
+
+};
+
+/** Plugin context instances. */
+static struct plugin_rename_context *
+plugin_context_handler[KS_MAX_NUM_STREAMS] = {NULL};
+
+static void plugin_close(int sd)
+{
+ free(plugin_context_handler[sd]);
+ plugin_context_handler[sd] = NULL;
+}
+
+// static void free_plugin_context()
+// {
+// int i;
+//
+// for (i = 0; i < KS_MAX_NUM_STREAMS; ++i)
+// plugin_close(i);
+// }
+
+static bool
+plugin_update_stream_context(struct kshark_context *kshark_ctx, int sd)
+{
+ struct plugin_rename_context *plugin_ctx;
+ struct tep_event_format *event;
+ struct kshark_data_stream *stream;
+
+// printf("#### plugin_update_stream_context %i %p: %p %p\n", sd, plugin_context_handler, plugin_context_handler[0], plugin_context_handler[1]);
+
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return false;
+
+ plugin_ctx = malloc(sizeof(*plugin_ctx));
+ printf("plugin_update_stream_context %i %p\n", sd, plugin_ctx);
+ plugin_ctx->handle = stream->handle;
+ plugin_ctx->pevent = stream->pevent;
+
+ event = tep_find_event_by_name(plugin_ctx->pevent,
+ "sched", "sched_switch");
+ if (!event)
+ return false;
+
+ plugin_ctx->sched_switch_event = event;
+ plugin_ctx->sched_switch_next_field =
+ tep_find_any_field(event, "next_pid");
+
+ plugin_ctx->sched_switch_comm_field =
+ tep_find_field(event, "next_comm");
+
+ plugin_ctx->done = false;
+ plugin_context_handler[sd] = plugin_ctx;
+ printf("plugin_update_stream_context %i done %p: %p %p\n", sd, plugin_context_handler, plugin_context_handler[0], plugin_context_handler[1]);
+ return true;
+}
+
+static bool plugin_update_context(struct kshark_context *kshark_ctx)
+{
+ int *stream_ids, i;
+
+ stream_ids = kshark_all_streams(kshark_ctx);
+ for (i = 0; i < kshark_ctx->n_streams; ++i) {
+ if (!plugin_update_stream_context(kshark_ctx, stream_ids[i]))
+ goto fail;
+ }
+
+ return true;
+
+ fail:
+ free_plugin_context();
+
+ return false;
+}
+
+static void plugin_kvm_action(struct kshark_context *kshark_ctx,
+ struct tep_record *rec,
+ struct kshark_entry *entry)
+{}
+
+static int plugin_get_next_pid(struct tep_record *record, int sd)
+{
+ unsigned long long val;
+ struct plugin_rename_context *plugin_ctx =
+ plugin_context_handler[sd];
+
+ tep_read_number_field(plugin_ctx->sched_switch_next_field,
+ record->data, &val);
+ return val;
+}
+
+static bool plugin_sched_switch_match_pid(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e,
+ int sd, int pid)
+{
+ struct plugin_rename_context *plugin_ctx =
+ plugin_context_handler[e->stream_id];
+ struct tep_record *record = NULL;
+ int switch_pid;
+
+ if (plugin_ctx->sched_switch_event &&
+ e->stream_id == sd &&
+ e->event_id == plugin_ctx->sched_switch_event->id) {
+ if (e->event_id == KS_EVENT_OVERFLOW)
+ return false;
+
+ record = kshark_read_at(kshark_ctx, sd, e->offset);
+ if (!record) {
+ printf("%i %i %lu\n", sd, e->event_id, e->offset);
+ return false;
+ }
+
+ switch_pid = plugin_get_next_pid(record, sd);
+ free(record);
+
+ if (switch_pid == pid)
+ return true;
+ }
+
+ return false;
+}
+
+static void kvm_draw_nop(struct kshark_cpp_argv *argv,
+ int sd, int pid, int draw_action)
+{}
+
+static int plugin_rename_sched_init(struct kshark_context *kshark_ctx, int sd)
+{
+ struct plugin_rename_context *plugin_ctx;
+
+ if (!plugin_update_stream_context(kshark_ctx, sd))
+ return 0;
+
+ plugin_ctx = plugin_context_handler[sd];
+ kshark_register_event_handler(&kshark_ctx->event_handlers,
+ plugin_ctx->sched_switch_event->id,
+ sd,
+ plugin_nop,
+ plugin_rename);
+
+ return kshark_ctx->n_streams;
+}
+
+static int plugin_rename_sched_close(struct kshark_context *kshark_ctx, int sd)
+{
+ struct plugin_rename_context *plugin_ctx;
+ plugin_ctx = plugin_context_handler[sd];
+ if (!plugin_ctx)
+ return 0;
+
+ kshark_unregister_event_handler(&kshark_ctx->event_handlers,
+ plugin_ctx->sched_switch_event->id,
+ sd,
+ plugin_nop,
+ plugin_rename);
+
+ plugin_close(sd);
+
+ return kshark_ctx->n_streams;
+}
+
+/** Load this plugin. */
+int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx, int sd)
+{
+ printf("--> rename init %i\n", sd);
+ return plugin_rename_sched_init(kshark_ctx, sd);
+}
+
+/** Unload this plugin. */
+int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx, int sd)
+{
+ printf("<-- rename close %i\n", sd);
+ return plugin_rename_sched_close(kshark_ctx, sd);
+}
+
+#endif
diff --git a/kernel-shark-qt/src/plugins/rename_sched_events.c b/kernel-shark-qt/src/plugins/rename_sched_events.c
index e8a2825..6e15dbb 100644
--- a/kernel-shark-qt/src/plugins/rename_sched_events.c
+++ b/kernel-shark-qt/src/plugins/rename_sched_events.c
@@ -17,7 +17,7 @@
#include "libkshark-model.h"
/** Structure representing a plugin-specific context. */
-struct plugin_sched_context {
+struct plugin_rename_context {
/** Input handle for the trace data file. */
struct tracecmd_input *handle;
@@ -37,24 +37,43 @@
bool done;
};
-/** Plugin context instance. */
-static struct plugin_sched_context *plugin_sched_context_handler = NULL;
+/** Plugin context instances. */
+static struct plugin_rename_context *
+plugin_context_handler[KS_MAX_NUM_STREAMS] = {NULL};
-static bool plugin_sched_update_context(struct kshark_context *kshark_ctx)
+static void plugin_close(int sd)
{
- struct plugin_sched_context *plugin_ctx;
+ free(plugin_context_handler[sd]);
+ plugin_context_handler[sd] = NULL;
+}
+
+// static void free_plugin_context()
+// {
+// int i;
+//
+// for (i = 0; i < KS_MAX_NUM_STREAMS; ++i)
+// plugin_close(i);
+// }
+
+static bool
+plugin_update_stream_context(struct kshark_context *kshark_ctx, int sd)
+{
+ struct plugin_rename_context *plugin_ctx;
struct tep_event_format *event;
+ struct kshark_data_stream *stream;
- if (!plugin_sched_context_handler) {
- plugin_sched_context_handler =
- malloc(sizeof(*plugin_sched_context_handler));
- }
+// printf("#### plugin_update_stream_context %i %p: %p %p\n", sd, plugin_context_handler, plugin_context_handler[0], plugin_context_handler[1]);
- plugin_ctx = plugin_sched_context_handler;
- plugin_ctx->handle = kshark_ctx->handle;
- plugin_ctx->pevent = kshark_ctx->pevent;
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return false;
- event = tep_find_event_by_name(plugin_ctx->pevent,
+ plugin_ctx = malloc(sizeof(*plugin_ctx));
+ printf("plugin_update_stream_context %i %p\n", sd, plugin_ctx);
+ plugin_ctx->handle = stream->handle;
+ plugin_ctx->pevent = stream->pevent;
+
+ event = tep_find_event_by_name(plugin_ctx->pevent,
"sched", "sched_switch");
if (!event)
return false;
@@ -67,20 +86,39 @@
tep_find_field(event, "next_comm");
plugin_ctx->done = false;
-
+ plugin_context_handler[sd] = plugin_ctx;
+ printf("plugin_update_stream_context %i done %p: %p %p\n", sd, plugin_context_handler, plugin_context_handler[0], plugin_context_handler[1]);
return true;
}
+// static bool plugin_update_context(struct kshark_context *kshark_ctx)
+// {
+// int *stream_ids, i;
+//
+// stream_ids = kshark_all_streams(kshark_ctx);
+// for (i = 0; i < kshark_ctx->n_streams; ++i) {
+// if (!plugin_update_stream_context(kshark_ctx, stream_ids[i]))
+// goto fail;
+// }
+//
+// return true;
+//
+// fail:
+// free_plugin_context();
+//
+// return false;
+// }
+
static void plugin_nop(struct kshark_context *kshark_ctx,
struct tep_record *rec,
struct kshark_entry *entry)
{}
-static int plugin_get_next_pid(struct tep_record *record)
+static int plugin_get_next_pid(struct tep_record *record, int sd)
{
unsigned long long val;
- struct plugin_sched_context *plugin_ctx =
- plugin_sched_context_handler;
+ struct plugin_rename_context *plugin_ctx =
+ plugin_context_handler[sd];
tep_read_number_field(plugin_ctx->sched_switch_next_field,
record->data, &val);
@@ -89,18 +127,26 @@
static bool plugin_sched_switch_match_pid(struct kshark_context *kshark_ctx,
struct kshark_entry *e,
- int pid)
+ int sd, int pid)
{
- struct plugin_sched_context *plugin_ctx =
- plugin_sched_context_handler;
+ struct plugin_rename_context *plugin_ctx =
+ plugin_context_handler[e->stream_id];
struct tep_record *record = NULL;
int switch_pid;
if (plugin_ctx->sched_switch_event &&
+ e->stream_id == sd &&
e->event_id == plugin_ctx->sched_switch_event->id) {
- record = kshark_read_at(kshark_ctx, e->offset);
+ if (e->event_id == KS_EVENT_OVERFLOW)
+ return false;
- switch_pid = plugin_get_next_pid(record);
+ record = kshark_read_at(kshark_ctx, sd, e->offset);
+ if (!record) {
+ printf("%i %i %lu\n", sd, e->event_id, e->offset);
+ return false;
+ }
+
+ switch_pid = plugin_get_next_pid(record, sd);
free(record);
if (switch_pid == pid)
@@ -111,97 +157,104 @@
}
static void plugin_rename(struct kshark_cpp_argv *argv,
- int pid, int draw_action)
+ int sd, int pid, int draw_action)
{
- struct plugin_sched_context *plugin_ctx =
- plugin_sched_context_handler;
+ struct plugin_rename_context *plugin_ctx;
struct kshark_context *kshark_ctx;
const struct kshark_entry *entry;
struct kshark_entry_request req;
struct tep_record *record;
- int *pids, n_tasks, r;
+ int *stream_ids, *pids, n_tasks, i, r;
const char *comm;
ssize_t index;
- if (plugin_ctx->done)
- return;
-
req.first = argv->histo->data_size - 1;
req.n = argv->histo->data_size;
req.cond = plugin_sched_switch_match_pid;
req.vis_only = false;
+ printf("@@@ plugin_rename\n");
kshark_ctx = NULL;
- kshark_instance(&kshark_ctx);
- n_tasks = kshark_get_task_pids(kshark_ctx, &pids);
- for (r = 0; r < n_tasks; ++r) {
- req.val = pids[r];
- entry = kshark_get_entry_back(&req, argv->histo->data, &index);
- if (!entry)
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ stream_ids = kshark_all_streams(kshark_ctx);
+ for (i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = stream_ids[i];
+ plugin_ctx = plugin_context_handler[sd];
+ if (plugin_ctx->done)
continue;
- record = kshark_read_at(kshark_ctx, entry->offset);
- comm = record->data +
- plugin_ctx->sched_switch_comm_field->offset;
+ req.sd = sd;
+ n_tasks = kshark_get_task_pids(kshark_ctx, sd, &pids);
+ for (r = 0; r < n_tasks; ++r) {
+ req.val = pids[r];
+ entry = kshark_get_entry_back(&req, argv->histo->data, &index);
+ if (!entry)
+ continue;
- printf("%li task: %s pid: %i\n", index, comm, pids[r]);
+// record = kshark_read_at(kshark_ctx, sd, entry->offset);
+// comm = record->data +
+// plugin_ctx->sched_switch_comm_field->offset;
+
+ printf("%li task: %s pid: %i\n", index, comm, pids[r]);
+ }
+
+ plugin_ctx->done = true;
+ free(pids);
}
-
- plugin_ctx->done = true;
-
- free(pids);
}
-
-static int plugin_rename_sched_init(struct kshark_context *kshark_ctx)
+static int plugin_rename_sched_init(struct kshark_context *kshark_ctx, int sd)
{
- struct plugin_sched_context *plugin_ctx;
+ struct plugin_rename_context *plugin_ctx;
- if (!plugin_sched_update_context(kshark_ctx)) {
- free(plugin_sched_context_handler);
- plugin_sched_context_handler = NULL;
+ if (!plugin_update_stream_context(kshark_ctx, sd))
return 0;
- }
- plugin_ctx = plugin_sched_context_handler;
+ plugin_ctx = plugin_context_handler[sd];
kshark_register_event_handler(&kshark_ctx->event_handlers,
plugin_ctx->sched_switch_event->id,
+ sd,
plugin_nop,
plugin_rename);
- return 1;
+// printf("--> rename init %i %p %p\n", sd, plugin_context_handler[0], plugin_context_handler[1]);
+ return kshark_ctx->n_streams;
}
-static int plugin_rename_sched_close(struct kshark_context *kshark_ctx)
+static int plugin_rename_sched_close(struct kshark_context *kshark_ctx, int sd)
{
- struct plugin_sched_context *plugin_ctx;
-
- if (!plugin_sched_context_handler)
+ struct plugin_rename_context *plugin_ctx;
+// printf("--> rename close %i %p %p %p\n", sd, plugin_context_handler, plugin_context_handler[0], plugin_context_handler[1]);
+ plugin_ctx = plugin_context_handler[sd];
+ if (!plugin_ctx)
return 0;
- plugin_ctx = plugin_sched_context_handler;
-
kshark_unregister_event_handler(&kshark_ctx->event_handlers,
plugin_ctx->sched_switch_event->id,
+ sd,
plugin_nop,
plugin_rename);
- free(plugin_ctx);
- plugin_sched_context_handler = NULL;
+// printf("<-- rename close %i %p\n", sd, plugin_ctx);
+ plugin_close(sd);
- return 1;
+ return kshark_ctx->n_streams;
}
/** Load this plugin. */
-int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx)
+int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx, int sd)
{
- return plugin_rename_sched_init(kshark_ctx);
+ printf("--> rename init %i\n", sd);
+ return plugin_rename_sched_init(kshark_ctx, sd);
}
/** Unload this plugin. */
-int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx)
+int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx, int sd)
{
- return plugin_rename_sched_close(kshark_ctx);
+ printf("<-- rename close %i\n", sd);
+ return plugin_rename_sched_close(kshark_ctx, sd);
}
#endif
diff --git a/kernel-shark/examples/CMakeLists.txt b/kernel-shark/examples/CMakeLists.txt
index 1af98f6..88fe3a5 100644
--- a/kernel-shark/examples/CMakeLists.txt
+++ b/kernel-shark/examples/CMakeLists.txt
@@ -28,6 +28,6 @@
add_executable(mload multiload.c)
target_link_libraries(mload kshark)
-message(STATUS "multiplot")
-add_executable(mplot multiplot.cpp)
-target_link_libraries(mplot kshark-plot)
+# message(STATUS "multiplot")
+# add_executable(mplot multiplot.cpp)
+# target_link_libraries(mplot kshark-plot)
diff --git a/kernel-shark/examples/datafilter.c b/kernel-shark/examples/datafilter.c
index 2c81fd3..af6c301 100644
--- a/kernel-shark/examples/datafilter.c
+++ b/kernel-shark/examples/datafilter.c
@@ -64,7 +64,7 @@
* filterd entris in text format.
*/
kshark_ctx->filter_mask = KS_TEXT_VIEW_FILTER_MASK;
- kshark_filter_entries(kshark_ctx, sd, data, n_rows);
+ kshark_filter_stream_entries(kshark_ctx, sd, data, n_rows);
/* Print to the screen the first 10 visible entries. */
count = 0;
@@ -94,7 +94,7 @@
event->id);
}
- kshark_filter_entries(kshark_ctx, sd, data, n_rows);
+ kshark_filter_stream_entries(kshark_ctx, sd, data, n_rows);
/* Print to the screen the first 10 visible entries. */
count = 0;
diff --git a/kernel-shark/examples/datahisto.c b/kernel-shark/examples/datahisto.c
index c4b8bb5..ebafd4a 100644
--- a/kernel-shark/examples/datahisto.c
+++ b/kernel-shark/examples/datahisto.c
@@ -26,22 +26,22 @@
printf("bin %i {\n", bin);
if (strcmp(type, "cpu") == 0) {
e_front = ksmodel_get_entry_front(histo, bin, true,
- kshark_match_cpu, sd, val,
+ kshark_match_cpu, sd, &val,
NULL,
&i_front);
e_back = ksmodel_get_entry_back(histo, bin, true,
- kshark_match_cpu, sd, val,
+ kshark_match_cpu, sd, &val,
NULL,
&i_back);
} else if (strcmp(type, "task") == 0) {
e_front = ksmodel_get_entry_front(histo, bin, true,
- kshark_match_pid, sd, val,
+ kshark_match_pid, sd, &val,
NULL,
&i_front);
e_back = ksmodel_get_entry_back(histo, bin, true,
- kshark_match_pid, sd, val,
+ kshark_match_pid, sd, &val,
NULL,
&i_back);
} else {
diff --git a/kernel-shark/examples/multiplot.cpp b/kernel-shark/examples/multiplot.cpp
index f166aa5..c782f4a 100644
--- a/kernel-shark/examples/multiplot.cpp
+++ b/kernel-shark/examples/multiplot.cpp
@@ -51,7 +51,6 @@
stream = kshark_get_data_stream(kshark_ctx, sd);
nCPUs = tep_get_cpus(stream->pevent);
for (int cpu = 0; cpu < nCPUs; ++cpu) {
-// graph = new KsPlot::Graph(&histos[d], &colors);
graph = new KsPlot::Graph(&histo_m, &pidColors,
&pidColors);
diff --git a/kernel-shark/src/CMakeLists.txt b/kernel-shark/src/CMakeLists.txt
index faf323f..b7dbd7e 100644
--- a/kernel-shark/src/CMakeLists.txt
+++ b/kernel-shark/src/CMakeLists.txt
@@ -28,71 +28,71 @@
endif (OPENGL_FOUND AND GLUT_FOUND)
-#if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
-#
-# message(STATUS "libkshark-gui")
-# set (ks-guiLib_hdr KsUtils.hpp
-# KsModels.hpp
-# KsGLWidget.hpp
-# KsSearchFSM.hpp
-# KsDualMarker.hpp
-# KsWidgetsLib.hpp
-# KsTraceGraph.hpp
-# KsTraceViewer.hpp
-# KsMainWindow.hpp
-# KsCaptureDialog.hpp
-# KsQuickContextMenu.hpp
-# KsAdvFilteringDialog.hpp)
-#
-# QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr})
-#
-# add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp
-# KsModels.cpp
-# KsSession.cpp
-# KsGLWidget.cpp
-# KsSearchFSM.cpp
-# KsDualMarker.cpp
-# KsWidgetsLib.cpp
-# KsTraceGraph.cpp
-# KsTraceViewer.cpp
-# KsMainWindow.cpp
-# KsCaptureDialog.cpp
-# KsQuickContextMenu.cpp
-# KsAdvFilteringDialog.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}")
-#
-# message(STATUS "kernelshark")
-# add_executable(kernelshark kernelshark.cpp)
-# target_link_libraries(kernelshark kshark-gui)
-#
-# message(STATUS "kshark-record")
-# add_executable(kshark-record kshark-record.cpp)
-# target_link_libraries(kshark-record kshark-gui)
-#
-# install(TARGETS kernelshark kshark-record kshark kshark-plot kshark-gui
-# RUNTIME DESTINATION ${_INSTALL_PREFIX}/bin/
-# LIBRARY DESTINATION ${_INSTALL_PREFIX}/lib/kshark/)
-#
-# install(FILES "${KS_DIR}/kernelshark.desktop"
-# DESTINATION /usr/share/applications/)
-#
-# install(FILES "${KS_DIR}/org.freedesktop.kshark-record.policy"
-# DESTINATION /usr/share/polkit-1/actions/)
-#
-# install(PROGRAMS "${KS_DIR}/bin/kshark-su-record"
-# DESTINATION ${_INSTALL_PREFIX}/bin/)
-#
-#endif (Qt5Widgets_FOUND AND Qt5Network_FOUND)
-#
-#add_subdirectory(plugins)
+if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
+
+ message(STATUS "libkshark-gui")
+ set (ks-guiLib_hdr KsUtils.hpp
+ KsModels.hpp
+ KsGLWidget.hpp
+ KsSearchFSM.hpp
+ KsDualMarker.hpp
+ KsWidgetsLib.hpp
+ KsTraceGraph.hpp
+ KsTraceViewer.hpp
+ KsMainWindow.hpp
+ KsCaptureDialog.hpp
+ KsQuickContextMenu.hpp
+ KsAdvFilteringDialog.hpp)
+
+ QT5_WRAP_CPP(ks-guiLib_hdr_moc ${ks-guiLib_hdr})
+
+ add_library(kshark-gui SHARED ${ks-guiLib_hdr_moc} KsUtils.cpp
+ KsModels.cpp
+ KsSession.cpp
+ KsGLWidget.cpp
+ KsSearchFSM.cpp
+ KsDualMarker.cpp
+ KsWidgetsLib.cpp
+ KsTraceGraph.cpp
+ KsTraceViewer.cpp
+ KsMainWindow.cpp
+ KsCaptureDialog.cpp
+ KsQuickContextMenu.cpp
+ KsAdvFilteringDialog.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}")
+
+ message(STATUS "kernelshark")
+ add_executable(kernelshark kernelshark.cpp)
+ target_link_libraries(kernelshark kshark-gui)
+
+ message(STATUS "kshark-record")
+ add_executable(kshark-record kshark-record.cpp)
+ target_link_libraries(kshark-record kshark-gui)
+
+ install(TARGETS kernelshark kshark-record kshark kshark-plot kshark-gui
+ RUNTIME DESTINATION ${_INSTALL_PREFIX}/bin/
+ LIBRARY DESTINATION ${_INSTALL_PREFIX}/lib/kshark/)
+
+ install(FILES "${KS_DIR}/kernelshark.desktop"
+ DESTINATION /usr/share/applications/)
+
+ install(FILES "${KS_DIR}/org.freedesktop.kshark-record.policy"
+ DESTINATION /usr/share/polkit-1/actions/)
+
+ install(PROGRAMS "${KS_DIR}/bin/kshark-su-record"
+ DESTINATION ${_INSTALL_PREFIX}/bin/)
+
+endif (Qt5Widgets_FOUND AND Qt5Network_FOUND)
+
+add_subdirectory(plugins)
find_program(DO_AS_ROOT pkexec)
diff --git a/kernel-shark/src/KsAdvFilteringDialog.cpp b/kernel-shark/src/KsAdvFilteringDialog.cpp
index 1edf68b..f657efe 100644
--- a/kernel-shark/src/KsAdvFilteringDialog.cpp
+++ b/kernel-shark/src/KsAdvFilteringDialog.cpp
@@ -24,6 +24,7 @@
_sysEvLabel("System/Event: ", &_condToolBar1),
_opsLabel("Operator: ", this),
_fieldLabel("Field: ", this),
+ _streamComboBox(&_condToolBar1),
_systemComboBox(&_condToolBar1),
_eventComboBox(&_condToolBar1),
_opsComboBox(&_condToolBar2),
@@ -71,13 +72,14 @@
lamAddLine();
- _getFilters(kshark_ctx);
+ _getFilters();
if (_filters.count()) {
- _makeFilterTable(kshark_ctx);
+ _makeFilterTable();
lamAddLine();
}
+ _condToolBar1.addWidget(&_streamComboBox);
_condToolBar1.addWidget(&_sysEvLabel);
_condToolBar1.addWidget(&_systemComboBox);
_condToolBar1.addWidget(&_eventComboBox);
@@ -86,13 +88,16 @@
* Using the old Signal-Slot syntax because QComboBox::currentIndexChanged
* has overloads.
*/
+ connect(&_streamComboBox, SIGNAL(currentIndexChanged(const QString&)),
+ this, SLOT(_streamChanged(const QString&)));
+
connect(&_systemComboBox, SIGNAL(currentIndexChanged(const QString&)),
this, SLOT(_systemChanged(const QString&)));
connect(&_eventComboBox, SIGNAL(currentIndexChanged(const QString&)),
this, SLOT(_eventChanged(const QString&)));
- _setSystemCombo(kshark_ctx);
+ _setSystemCombo();
_condToolBar1.addSeparator();
_condToolBar1.addWidget(&_insertEvtButton);
@@ -149,15 +154,15 @@
this, &QWidget::close);
}
-void KsAdvFilteringDialog::_setSystemCombo(struct kshark_context *kshark_ctx)
+void KsAdvFilteringDialog::_setSystemCombo()
{
QStringList sysList;
tep_event **events;
int i(0), nEvts(0);
- if (kshark_ctx->pevent) {
- nEvts = tep_get_events_count(kshark_ctx->pevent);
- events = tep_list_events(kshark_ctx->pevent,
+ if (_stream->pevent) {
+ nEvts = tep_get_events_count(_stream->pevent);
+ events = tep_list_events(_stream->pevent,
TEP_EVENT_SORT_SYSTEM);
}
@@ -202,15 +207,15 @@
return OpsList;
}
-void KsAdvFilteringDialog::_getFilters(struct kshark_context *kshark_ctx)
+void KsAdvFilteringDialog::_getFilters()
{
tep_event **events;
char *str;
- events = tep_list_events(kshark_ctx->pevent, TEP_EVENT_SORT_SYSTEM);
+ events = tep_list_events(_stream->pevent, TEP_EVENT_SORT_SYSTEM);
for (int i = 0; events[i]; i++) {
- str = tep_filter_make_string(kshark_ctx->advanced_event_filter,
+ str = tep_filter_make_string(_stream->advanced_event_filter,
events[i]->id);
if (!str)
continue;
@@ -223,7 +228,7 @@
}
}
-void KsAdvFilteringDialog::_makeFilterTable(struct kshark_context *kshark_ctx)
+void KsAdvFilteringDialog::_makeFilterTable()
{
QMapIterator<int, QString> f(_filters);
QTableWidgetItem *i1, *i2, *i3;
@@ -272,19 +277,20 @@
}
}
+void KsAdvFilteringDialog::_streamChanged(const QString &sysName)
+{
+
+}
+
void KsAdvFilteringDialog::_systemChanged(const QString &sysName)
{
- kshark_context *kshark_ctx(NULL);
QStringList evtsList;
tep_event **events;
int i, nEvts;
_eventComboBox.clear();
- if (!kshark_instance(&kshark_ctx) || !kshark_ctx->pevent)
- return;
-
- nEvts = tep_get_events_count(kshark_ctx->pevent);
- events = tep_list_events(kshark_ctx->pevent, TEP_EVENT_SORT_SYSTEM);
+ nEvts = tep_get_events_count(_stream->pevent);
+ events = tep_list_events(_stream->pevent, TEP_EVENT_SORT_SYSTEM);
for (i = 0; i < nEvts; ++i) {
if (sysName == events[i]->system)
@@ -317,17 +323,13 @@
void KsAdvFilteringDialog::_eventChanged(const QString &evtName)
{
QString sysName = _systemComboBox.currentText();
- kshark_context *kshark_ctx(NULL);
QStringList fieldList;
tep_event **events;
int nEvts;
_fieldComboBox.clear();
- if (!kshark_instance(&kshark_ctx) || !kshark_ctx->pevent)
- return;
-
- nEvts = tep_get_events_count(kshark_ctx->pevent);
- events = tep_list_events(kshark_ctx->pevent, TEP_EVENT_SORT_SYSTEM);
+ nEvts = tep_get_events_count(_stream->pevent);
+ events = tep_list_events(_stream->pevent, TEP_EVENT_SORT_SYSTEM);
for (int i = 0; i < nEvts; ++i) {
if (evtName == events[i]->name &&
@@ -383,19 +385,15 @@
void KsAdvFilteringDialog::_applyPress()
{
QMapIterator<int, QString> f(_filters);
- kshark_context *kshark_ctx(NULL);
const char *text;
tep_errno ret;
char *filter;
int i(0);
- if (!kshark_instance(&kshark_ctx))
- return;
-
while (f.hasNext()) {
f.next();
if (_table->_cb[i]->checkState() == Qt::Checked) {
- tep_filter_remove_event(kshark_ctx->advanced_event_filter,
+ tep_filter_remove_event(_stream->advanced_event_filter,
f.key());
}
++i;
@@ -419,14 +417,14 @@
filter = (char*) malloc(strlen(text) + 1);
strcpy(filter, text);
- ret = tep_filter_add_filter_str(kshark_ctx->advanced_event_filter,
- filter);
+ ret = tep_filter_add_filter_str(_stream->advanced_event_filter,
+ filter);
if (ret < 0) {
char error_str[200];
- tep_strerror(kshark_ctx->pevent, ret, error_str,
- sizeof(error_str));
+ tep_strerror(_stream->pevent, ret, error_str,
+ sizeof(error_str));
fprintf(stderr, "filter failed due to: %s\n", error_str);
free(filter);
diff --git a/kernel-shark/src/KsAdvFilteringDialog.hpp b/kernel-shark/src/KsAdvFilteringDialog.hpp
index 2a534d0..647c0e9 100644
--- a/kernel-shark/src/KsAdvFilteringDialog.hpp
+++ b/kernel-shark/src/KsAdvFilteringDialog.hpp
@@ -32,6 +32,8 @@
void dataReload();
private:
+ kshark_data_stream *_stream;
+
int _noHelpHeight;
QMap<int, QString> _filters;
@@ -46,7 +48,7 @@
QLabel _descrLabel, _sysEvLabel, _opsLabel, _fieldLabel;
- QComboBox _systemComboBox, _eventComboBox;
+ QComboBox _streamComboBox, _systemComboBox, _eventComboBox;
QComboBox _opsComboBox, _fieldComboBox;
@@ -74,15 +76,17 @@
QStringList _operators();
- void _getFilters(struct kshark_context *kshark_ctx);
+ void _getFilters();
- void _makeFilterTable(struct kshark_context *kshark_ctx);
+ void _makeFilterTable();
QStringList _getEventFormatFields(struct tep_event *event);
- void _setSystemCombo(struct kshark_context *kshark_ctx);
+ void _setSystemCombo();
private slots:
+ void _streamChanged(const QString&);
+
void _systemChanged(const QString&);
void _eventChanged(const QString&);
diff --git a/kernel-shark/src/KsCaptureDialog.hpp b/kernel-shark/src/KsCaptureDialog.hpp
index d65f475..a0a0cb9 100644
--- a/kernel-shark/src/KsCaptureDialog.hpp
+++ b/kernel-shark/src/KsCaptureDialog.hpp
@@ -16,6 +16,7 @@
#include <QtWidgets>
// KernelShark
+#include "libkshark.h"
#include "KsWidgetsLib.hpp"
/**
diff --git a/kernel-shark/src/KsDualMarker.cpp b/kernel-shark/src/KsDualMarker.cpp
index 5dcbaae..8f5cc08 100644
--- a/kernel-shark/src/KsDualMarker.cpp
+++ b/kernel-shark/src/KsDualMarker.cpp
@@ -59,8 +59,8 @@
{
_isSet = false;
_bin = -1;
- _cpu = -1;
- _task = -1;
+// _cpu = -1;
+// _task = -1;
_pos = 0;
_mark._visible = false;
@@ -77,13 +77,15 @@
*/
bool KsGraphMark::set(const KsDataStore &data,
kshark_trace_histo *histo,
- size_t pos, int cpuGraph, int taskGraph)
+ size_t pos, int sd/*,
+ int cpuGraph, int taskGraph*/)
{
_isSet = true;
_pos = pos;
+ _sd = sd;
_ts = data.rows()[_pos]->ts;
- _cpu = cpuGraph;
- _task = taskGraph;
+// _cpu = cpuGraph;
+// _task = taskGraph;
if (_ts > histo->max || _ts < histo->min) {
_bin = -1;
@@ -109,7 +111,7 @@
if (!_isSet)
return false;
- return set(data, histo, this->_pos, this->_cpu, this->_task);
+ return set(data, histo, this->_pos, this->_sd/*, this->_cpu, this->_task*/);
}
/** Unset the Marker and make it invisible. */
@@ -315,10 +317,10 @@
KsGLWidget *glw)
{
if(_markA.update(data, glw->model()->histo()))
- glw->setMark(&_markA);
+ glw->setMarkPoints(data, &_markA);
if(_markB.update(data, glw->model()->histo()))
- glw->setMark(&_markB);
+ glw->setMarkPoints(data, &_markB);
updateLabels();
}
diff --git a/kernel-shark/src/KsDualMarker.hpp b/kernel-shark/src/KsDualMarker.hpp
index 597bddb..1040c8c 100644
--- a/kernel-shark/src/KsDualMarker.hpp
+++ b/kernel-shark/src/KsDualMarker.hpp
@@ -66,9 +66,8 @@
bool set(const KsDataStore &data,
kshark_trace_histo *histo,
- size_t pos,
- int cpuGraph,
- int taskGraph);
+ size_t pos, int sd/*,
+ int cpuGraph, int taskGraph*/);
bool update(const KsDataStore &data, kshark_trace_histo *histo);
@@ -83,18 +82,14 @@
void remove();
-public:
/** Is this marker set. */
bool _isSet;
/** The number of the bin this marker points to. */
int _bin;
- /** The index of the CPU Graph this marker points to. */
- int _cpu;
-
- /** The index of the Task Graph this marker points to. */
- int _task;
+ /** Data stream identifier of the Graph this marker points to. */
+ int _sd;
/** The index inside the data array this marker points to. */
size_t _pos;
diff --git a/kernel-shark/src/KsGLWidget.cpp b/kernel-shark/src/KsGLWidget.cpp
index 789514a..f0b1c8f 100644
--- a/kernel-shark/src/KsGLWidget.cpp
+++ b/kernel-shark/src/KsGLWidget.cpp
@@ -22,6 +22,7 @@
/** Create a default (empty) OpenGL widget. */
KsGLWidget::KsGLWidget(QWidget *parent)
: QOpenGLWidget(parent),
+// _sd(sd),
_hMargin(20),
_vMargin(30),
_vSpacing(20),
@@ -91,12 +92,17 @@
_drawAxisX();
/* Process and draw all graphs by using the built-in logic. */
- _makeGraphs(_cpuList, _taskList);
- for (auto const &g: _graphs)
+ _makeGraphs();
+
+ for (auto const &stream: _graphs)
+ for (auto const &g: stream)
+ g->draw(1.5 * _dpr);
+
+ for (auto const &g: _comboGraphs)
g->draw(1.5 * _dpr);
/* Process and draw all plugin-specific shapes. */
- _makePluginShapes(_cpuList, _taskList);
+ _makePluginShapes();
while (!_shapes.empty()) {
auto s = _shapes.front();
s->draw();
@@ -116,8 +122,8 @@
/** Reset (empty) the widget. */
void KsGLWidget::reset()
{
- _cpuList = {};
- _taskList = {};
+ _streamPlots.clear();
+ _streamPlots.clear();
_data = nullptr;
_model.reset();
}
@@ -132,7 +138,7 @@
}
int KsGLWidget::_getLastTask(struct kshark_trace_histo *histo,
- int bin, int cpu)
+ int bin, int sd, int cpu)
{
kshark_context *kshark_ctx(nullptr);
kshark_entry_collection *col;
@@ -143,15 +149,17 @@
col = kshark_find_data_collection(kshark_ctx->collections,
KsUtils::matchCPUVisible,
- cpu);
+ sd, &cpu, 1);
for (int b = bin; b >= 0; --b) {
- pid = ksmodel_get_pid_back(histo, b, cpu, false, col, nullptr);
+ pid = ksmodel_get_pid_back(histo, b, sd, cpu,
+ false, col, nullptr);
if (pid >= 0)
return pid;
}
return ksmodel_get_pid_back(histo, LOWER_OVERFLOW_BIN,
+ sd,
cpu,
false,
col,
@@ -159,7 +167,7 @@
}
int KsGLWidget::_getLastCPU(struct kshark_trace_histo *histo,
- int bin, int pid)
+ int bin, int sd, int pid)
{
kshark_context *kshark_ctx(nullptr);
kshark_entry_collection *col;
@@ -170,15 +178,17 @@
col = kshark_find_data_collection(kshark_ctx->collections,
kshark_match_pid,
- pid);
+ sd, &pid, 1);
for (int b = bin; b >= 0; --b) {
- cpu = ksmodel_get_cpu_back(histo, b, pid, false, col, nullptr);
+ cpu = ksmodel_get_cpu_back(histo, b, sd, pid,
+ false, col, nullptr);
if (cpu >= 0)
return cpu;
}
return ksmodel_get_cpu_back(histo, LOWER_OVERFLOW_BIN,
+ sd,
pid,
false,
col,
@@ -189,7 +199,7 @@
/** Reimplemented event handler used to receive mouse move events. */
void KsGLWidget::mouseMoveEvent(QMouseEvent *event)
{
- int bin, cpu, pid;
+ int bin, sd, cpu, pid;
size_t row;
bool ret;
@@ -197,22 +207,21 @@
_rangeBoundStretched(_posInRange(event->pos().x()));
bin = event->pos().x() - _hMargin;
- cpu = getPlotCPU(event->pos());
- pid = getPlotPid(event->pos());
+ getPlotInfo(event->pos(), &sd, &cpu, &pid);
- ret = _find(bin, cpu, pid, 5, false, &row);
+ ret = _find(bin, sd, cpu, pid, 5, false, &row);
if (ret) {
emit found(row);
} else {
if (cpu >= 0) {
- pid = _getLastTask(_model.histo(), bin, cpu);
+ pid = _getLastTask(_model.histo(), bin, sd, cpu);
}
if (pid > 0) {
- cpu = _getLastCPU(_model.histo(), bin, pid);
+ cpu = _getLastCPU(_model.histo(), bin, sd, pid);
}
- emit notFound(ksmodel_bin_ts(_model.histo(), bin), cpu, pid);
+ emit notFound(ksmodel_bin_ts(_model.histo(), bin), sd, cpu, pid);
}
}
@@ -325,9 +334,15 @@
*/
void KsGLWidget::loadData(KsDataStore *data)
{
+ kshark_context *kshark_ctx(nullptr);
+ QVector<int> plotVec;
uint64_t tMin, tMax;
+ int *streamIds, sd;
int nCPUs, nBins;
+ if (!kshark_instance(&kshark_ctx) || !kshark_ctx->n_streams)
+ return;
+
_data = data;
/*
@@ -335,26 +350,36 @@
* One bin will correspond to one pixel.
*/
nBins = width() - _hMargin * 2;
- nCPUs = tep_get_cpus(_data->tep());
-
_model.reset();
+ if (!_data->size())
+ return;
+
/* Now load the entire set of trace data. */
tMin = _data->rows()[0]->ts;
tMax = _data->rows()[_data->size() - 1]->ts;
ksmodel_set_bining(_model.histo(), nBins, tMin, tMax);
_model.fill(_data->rows(), _data->size());
- /* Make a default CPU list. All CPUs will be plotted. */
- _cpuList = {};
- for (int i = 0; i < nCPUs; ++i)
- _cpuList.append(i);
+ _streamPlots.clear();
+ /*
+ * Make a default CPU Taski lists. All CPUs from all Data streams will
+ * be plotted. No tasks will be plotted.
+ */
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ nCPUs = tep_get_cpus(_data->tep(sd));
+ plotVec.clear();
+ for (int i = 0; i < nCPUs; ++i)
+ plotVec.append(i);
- /* Make a default task list. No tasks will be plotted. */
- _taskList = {};
+ _streamPlots[sd]._cpuList = plotVec;
+ _streamPlots[sd]._taskList = {};
+ }
loadColors();
- _makeGraphs(_cpuList, _taskList);
+ _makeGraphs();
}
/**
@@ -373,85 +398,49 @@
* Position the graphical elements of the marker according to the current
* position of the graphs inside the GL widget.
*/
-void KsGLWidget::setMark(KsGraphMark *mark)
+void KsGLWidget::setMarkPoints(const KsDataStore &data, KsGraphMark *mark)
{
+ const kshark_entry *e = data.rows()[mark->_pos];
+ int sd = e->stream_id;
+
mark->_mark.setDPR(_dpr);
mark->_mark.setX(mark->_bin + _hMargin);
mark->_mark.setY(_vMargin / 2 + 2, height() - _vMargin);
- if (mark->_cpu >= 0) {
- mark->_mark.setCPUY(_graphs[mark->_cpu]->getBase());
- mark->_mark.setCPUVisible(true);
- } else {
- mark->_mark.setCPUVisible(false);
- }
+ mark->_mark.setCPUVisible(false);
+ mark->_mark.setTaskVisible(false);
+ mark->_mark.setComboVisible(false);
- if (mark->_task >= 0) {
- mark->_mark.setTaskY(_graphs[mark->_task]->getBase());
- mark->_mark.setTaskVisible(true);
- } else {
- mark->_mark.setTaskVisible(false);
- }
-}
-
-/**
- * @brief Check if a given KernelShark entry is ploted.
- *
- * @param e: Input location for the KernelShark entry.
- * @param graphCPU: Output location for index of the CPU graph to which this
- * entry belongs. If such a graph does not exist the outputted
- * value is "-1".
- * @param graphTask: Output location for index of the Task graph to which this
- * entry belongs. If such a graph does not exist the
- * outputted value is "-1".
- */
-void KsGLWidget::findGraphIds(const kshark_entry &e,
- int *graphCPU,
- int *graphTask)
-{
- int graph(0);
- bool cpuFound(false), taskFound(false);
-
- /*
- * Loop over all CPU graphs and try to find the one that
- * contains the entry.
- */
- for (auto const &c: _cpuList) {
- if (c == e.cpu) {
- cpuFound = true;
- break;
+ for (int i = 0; i < _streamPlots[sd]._cpuList.count(); ++i) {
+ if (_streamPlots[sd]._cpuList[i] == e->cpu) {
+ mark->_mark.setCPUY(_streamPlots[sd]._cpuPlotBase[i]);
+ mark->_mark.setCPUVisible(true);
}
- ++graph;
}
- if (cpuFound)
- *graphCPU = graph;
- else
- *graphCPU = -1;
-
- /*
- * Loop over all Task graphs and try to find the one that
- * contains the entry.
- */
- graph = _cpuList.count();
- for (auto const &p: _taskList) {
- if (p == e.pid) {
- taskFound = true;
- break;
+ for (int i = 0; i < _streamPlots[sd]._taskList.count(); ++i) {
+ if (_streamPlots[sd]._taskList[i] == e->pid) {
+ mark->_mark.setTaskY(_streamPlots[sd]._taskPlotBase[i]);
+ mark->_mark.setTaskVisible(true);
}
- ++graph;
}
- if (taskFound)
- *graphTask = graph;
- else
- *graphTask = -1;
+ for (auto const &c: _comboPlots) {
+ if (c._guestStreamId == e->stream_id && c._vcpu == e->cpu) {
+ mark->_mark.setComboY(c._vcpuBase);
+ mark->_mark.setComboVisible(true);
+ } else if (c._hostStreamId == e->stream_id &&
+ c._hostPid == e->pid) {
+ mark->_mark.setComboY(c._hostBase);
+ mark->_mark.setComboVisible(true);
+ }
+ }
}
void KsGLWidget::_drawAxisX()
{
KsPlot::Point a0(_hMargin, _vMargin / 4), a1(_hMargin, _vMargin / 2);
- KsPlot::Point b0(width()/2, _vMargin / 4), b1(width() / 2, _vMargin / 2);
+ KsPlot::Point b0(width() / 2, _vMargin / 4), b1(width() / 2, _vMargin / 2);
KsPlot::Point c0(width() - _hMargin, _vMargin / 4),
c1(width() - _hMargin, _vMargin / 2);
int lineSize = 2 * _dpr;
@@ -466,42 +455,68 @@
KsPlot::drawLine(a0, c0, {}, lineSize);
}
-void KsGLWidget::_makeGraphs(QVector<int> cpuList, QVector<int> taskList)
+void KsGLWidget::_makeGraphs()
{
+ int base(_vMargin + KS_GRAPH_HEIGHT);
+
/* The very first thing to do is to clean up. */
- for (auto &g: _graphs)
+ for (auto &stream: _graphs) {
+ for (auto &g: stream)
+ delete g;
+ stream.resize(0);
+ }
+
+ for (auto &g: _comboGraphs)
delete g;
- _graphs.resize(0);
+ _comboGraphs.resize(0);
if (!_data || !_data->size())
return;
- auto lamAddGraph = [&](KsPlot::Graph *graph) {
+ auto lamAddGraph = [&](int sd, KsPlot::Graph *graph) {
/*
- * Calculate the base level of the CPU graph inside the widget.
- * Remember that the "Y" coordinate is inverted.
- */
+ * Calculate the base level of the CPU graph inside the widget.
+ * Remember that the "Y" coordinate is inverted.
+ */
if (!graph)
return;
- int base = _vMargin +
- _vSpacing * _graphs.count() +
- KS_GRAPH_HEIGHT * (_graphs.count() + 1);
-
graph->setBase(base);
- _graphs.append(graph);
+
+ _graphs[sd].append(graph);
+ base += graph->height() + _vSpacing;
};
- /* Create CPU graphs according to the cpuList. */
- for (auto const &cpu: cpuList)
- lamAddGraph(_newCPUGraph(cpu));
+ for (auto it = _streamPlots.begin(); it != _streamPlots.end(); ++it) {
+ int sd = it.key();
+ /* Create CPU graphs according to the cpuList. */
+ it.value()._cpuPlotBase = {};
+ for (auto const &cpu: it.value()._cpuList) {
+ it.value()._cpuPlotBase.append(base);
+ lamAddGraph(sd, _newCPUGraph(sd, cpu));
+ }
+ /* Create Task graphs taskList to the taskList. */
+ it.value()._taskPlotBase = {};
+ for (auto const &pid: it.value()._taskList) {
+ it.value()._taskPlotBase.append(base);
+ lamAddGraph(sd, _newTaskGraph(sd, pid));
+ }
+ }
- /* Create Task graphs taskList to the taskList. */
- for (auto const &pid: taskList)
- lamAddGraph(_newTaskGraph(pid));
+ for (auto &cp: _comboPlots) {
+ KsPlot::ComboGraph *graph = _newComboGraph(cp._hostStreamId,
+ cp._hostPid,
+ cp._guestStreamId,
+ cp._vcpu);
+ graph->setBase(base);
+ _comboGraphs.append(graph);
+ cp._vcpuBase = base;
+ cp._hostBase = base + graph->height() / 2;
+ base += graph->height() + _vSpacing;
+ }
}
-void KsGLWidget::_makePluginShapes(QVector<int> cpuList, QVector<int> taskList)
+void KsGLWidget::_makePluginShapes()
{
kshark_context *kshark_ctx(nullptr);
kshark_event_handler *evt_handlers;
@@ -513,32 +528,37 @@
cppArgv._histo = _model.histo();
cppArgv._shapes = &_shapes;
- for (int g = 0; g < cpuList.count(); ++g) {
- cppArgv._graph = _graphs[g];
- evt_handlers = kshark_ctx->event_handlers;
- while (evt_handlers) {
- evt_handlers->draw_func(cppArgv.toC(),
- cpuList[g],
- KSHARK_PLUGIN_CPU_DRAW);
+ for (auto it = _streamPlots.constBegin(); it != _streamPlots.constEnd(); ++it) {
+ int sd = it.key();
+ for (int g = 0; g < it.value()._cpuList.count(); ++g) {
+ cppArgv._graph = _graphs[it.key()][g];
+ evt_handlers = kshark_ctx->event_handlers;
+ while (evt_handlers) {
+ evt_handlers->draw_func(cppArgv.toC(),
+ sd,
+ it.value()._cpuList[g],
+ KSHARK_PLUGIN_CPU_DRAW);
- evt_handlers = evt_handlers->next;
+ evt_handlers = evt_handlers->next;
+ }
}
- }
- for (int g = 0; g < taskList.count(); ++g) {
- cppArgv._graph = _graphs[cpuList.count() + g];
- evt_handlers = kshark_ctx->event_handlers;
- while (evt_handlers) {
- evt_handlers->draw_func(cppArgv.toC(),
- taskList[g],
- KSHARK_PLUGIN_TASK_DRAW);
+ for (int g = 0; g < it.value()._taskList.count(); ++g) {
+ cppArgv._graph = _graphs[it.key()][it.value()._cpuList.count() + g];
+ evt_handlers = kshark_ctx->event_handlers;
+ while (evt_handlers) {
+ evt_handlers->draw_func(cppArgv.toC(),
+ sd,
+ it.value()._taskList[g],
+ KSHARK_PLUGIN_TASK_DRAW);
- evt_handlers = evt_handlers->next;
+ evt_handlers = evt_handlers->next;
+ }
}
}
}
-KsPlot::Graph *KsGLWidget::_newCPUGraph(int cpu)
+KsPlot::Graph *KsGLWidget::_newCPUGraph(int sd, int cpu)
{
/* The CPU graph needs to know only the colors of the tasks. */
KsPlot::Graph *graph = new KsPlot::Graph(_model.histo(),
@@ -557,15 +577,15 @@
col = kshark_find_data_collection(kshark_ctx->collections,
KsUtils::matchCPUVisible,
- cpu);
+ sd, &cpu, 1);
graph->setDataCollectionPtr(col);
- graph->fillCPUGraph(cpu);
+ graph->fillCPUGraph(sd, cpu);
return graph;
}
-KsPlot::Graph *KsGLWidget::_newTaskGraph(int pid)
+KsPlot::Graph *KsGLWidget::_newTaskGraph(int sd, int pid)
{
/*
* The Task graph needs to know the colors of the tasks and the colors
@@ -584,7 +604,8 @@
graph->setHeight(KS_GRAPH_HEIGHT);
col = kshark_find_data_collection(kshark_ctx->collections,
- kshark_match_pid, pid);
+ kshark_match_pid, sd, &pid, 1);
+
if (!col) {
/*
* If a data collection for this task does not exist,
@@ -593,7 +614,8 @@
col = kshark_register_data_collection(kshark_ctx,
_data->rows(),
_data->size(),
- kshark_match_pid, pid,
+ kshark_match_pid,
+ sd, &pid, 1,
25);
}
@@ -616,7 +638,54 @@
}
graph->setDataCollectionPtr(col);
- graph->fillTaskGraph(pid);
+ graph->fillTaskGraph(sd, pid);
+
+ return graph;
+}
+
+KsPlot::ComboGraph *KsGLWidget::_newComboGraph(int sdHost, int pidHost, int sdGuest, int vcpu)
+{
+ /*
+ * The Combo graph needs to know the colors of the tasks and the colors
+ * of the CPUs.
+ */
+ KsPlot::ComboGraph *graph =
+ new KsPlot::ComboGraph(_model.histo(), &_pidColors,
+ &_cpuColors);
+ kshark_context *kshark_ctx(nullptr);
+ kshark_entry_collection *col;
+
+ if (!kshark_instance(&kshark_ctx))
+ return nullptr;
+
+ graph->setHMargin(_hMargin);
+
+ /* The Combo graph is two times taller than the normal graph. */
+ graph->setHeight(2 * KS_GRAPH_HEIGHT);
+
+ col = kshark_find_data_collection(kshark_ctx->collections,
+ KsUtils::matchCPUVisible,
+ sdGuest, &vcpu, 1);
+ graph->setGuestDataCollectionPtr(col);
+
+ col = kshark_find_data_collection(kshark_ctx->collections,
+ kshark_match_pid,
+ sdHost, &pidHost, 1);
+ if (!col) {
+ /*
+ * If a data collection for this task does not exist,
+ * register a new one.
+ */
+ col = kshark_register_data_collection(kshark_ctx,
+ _data->rows(),
+ _data->size(),
+ kshark_match_pid,
+ sdHost, &pidHost, 1,
+ 25);
+ }
+ graph->setHostDataCollectionPtr(col);
+
+ graph->fill(sdHost, pidHost, sdGuest, vcpu);
return graph;
}
@@ -636,18 +705,19 @@
bool KsGLWidget::find(const QPoint &point, int variance, bool joined,
size_t *index)
{
+ int bin, sd, cpu, pid;
+
/*
* Get the bin, pid and cpu numbers.
* Remember that one bin corresponds to one pixel.
*/
- int bin = point.x() - _hMargin;
- int cpu = getPlotCPU(point);
- int pid = getPlotPid(point);
+ bin = point.x() - _hMargin;
+ getPlotInfo(point, &sd, &cpu, &pid);
- return _find(bin, cpu, pid, variance, joined, index);
+ return _find(bin, sd, cpu, pid, variance, joined, index);
}
-int KsGLWidget::_getNextCPU(int pid, int bin)
+int KsGLWidget::_getNextCPU(int sd, int pid, int bin)
{
kshark_context *kshark_ctx(nullptr);
kshark_entry_collection *col;
@@ -658,12 +728,12 @@
col = kshark_find_data_collection(kshark_ctx->collections,
kshark_match_pid,
- pid);
+ sd, &pid, 1);
if (!col)
return KS_EMPTY_BIN;
for (int i = bin; i < _model.histo()->n_bins; ++i) {
- cpu = ksmodel_get_cpu_front(_model.histo(), i, pid,
+ cpu = ksmodel_get_cpu_front(_model.histo(), i, sd, pid,
false, col, nullptr);
if (cpu >= 0)
return cpu;
@@ -672,7 +742,7 @@
return KS_EMPTY_BIN;
}
-bool KsGLWidget::_find(int bin, int cpu, int pid,
+bool KsGLWidget::_find(int bin, int sd, int cpu, int pid,
int variance, bool joined, size_t *row)
{
int hSize = _model.histo()->n_bins;
@@ -690,7 +760,7 @@
auto lamGetEntryByCPU = [&](int b) {
/* Get the first data entry in this bin. */
found = ksmodel_first_index_at_cpu(_model.histo(),
- b, cpu);
+ b, sd, cpu);
if (found < 0) {
/*
* The bin is empty or the entire connect of the bin
@@ -706,7 +776,7 @@
auto lamGetEntryByPid = [&](int b) {
/* Get the first data entry in this bin. */
found = ksmodel_first_index_at_pid(_model.histo(),
- b, pid);
+ b, sd, pid);
if (found < 0) {
/*
* The bin is empty or the entire connect of the bin
@@ -772,7 +842,7 @@
* for an entry on the next CPU used by this task.
*/
if (!ret && joined) {
- cpu = _getNextCPU(pid, bin);
+ cpu = _getNextCPU(sd, pid, bin);
ret = lamFindEntryByCPU(bin);
}
@@ -857,7 +927,6 @@
* Calculate the new range of the histogram. The number of bins will
* stay the same.
*/
-
min = ksmodel_bin_ts(_model.histo(), binMin);
max = ksmodel_bin_ts(_model.histo(), binMax);
if (max - min < nBins) {
@@ -911,35 +980,55 @@
return posX;
}
-/** Get the CPU Id of the Graph plotted at given position. */
-int KsGLWidget::getPlotCPU(const QPoint &point)
+bool KsGLWidget::getPlotInfo(const QPoint &point, int *sd, int *cpu, int *pid)
{
- int cpuId, y = point.y();
+ int base, n;
- if (_cpuList.count() == 0)
- return -1;
+ *sd = *cpu = *pid = -1;
- cpuId = (y - _vMargin + _vSpacing / 2) / (_vSpacing + KS_GRAPH_HEIGHT);
- if (cpuId < 0 || cpuId >= _cpuList.count())
- return -1;
+ for (auto it = _streamPlots.constBegin(); it != _streamPlots.constEnd(); ++it) {
+ n = it.value()._cpuList.count();
+ for (int i = 0; i < n; ++i) {
+ base = it.value()._cpuPlotBase[i];
+ if (base - KS_GRAPH_HEIGHT < point.y() &&
+ point.y() < base) {
+ *sd = it.key();
+ *cpu = it.value()._cpuList[i];
- return _cpuList[cpuId];
-}
+ return true;
+ }
+ }
-/** Get the CPU Id of the Graph plotted at given position. */
-int KsGLWidget::getPlotPid(const QPoint &point)
-{
- int pidId, y = point.y();
+ n = it.value()._taskList.count();
+ for (int i = 0; i < n; ++i) {
+ base = it.value()._taskPlotBase[i];
+ if (base - KS_GRAPH_HEIGHT < point.y() &&
+ point.y() < base) {
+ *sd = it.key();
+ *pid = it.value()._taskList[i];
- if (_taskList.count() == 0)
- return -1;
+ return true;
+ }
+ }
+ }
- pidId = (y - _vMargin -
- _cpuList.count()*(KS_GRAPH_HEIGHT + _vSpacing) +
- _vSpacing / 2) / (_vSpacing + KS_GRAPH_HEIGHT);
+ for (auto const &cp: _comboPlots) {
+ base = cp._vcpuBase + _vSpacing / 4;
+ if (base - KS_GRAPH_HEIGHT < point.y() && point.y() < base) {
+ *sd = cp._guestStreamId;
+ *cpu = cp._vcpu;
- if (pidId < 0 || pidId >= _taskList.count())
- return -1;
+ return true;
+ }
- return _taskList[pidId];
+ base = cp._hostBase + _vSpacing / 4;
+ if (base - KS_GRAPH_HEIGHT < point.y() && point.y() < base) {
+ *sd = cp._hostStreamId;
+ *pid = cp._hostPid;
+
+ return true;
+ }
+ }
+
+ return false;
}
diff --git a/kernel-shark/src/KsGLWidget.hpp b/kernel-shark/src/KsGLWidget.hpp
index 3bcecf9..843aff2 100644
--- a/kernel-shark/src/KsGLWidget.hpp
+++ b/kernel-shark/src/KsGLWidget.hpp
@@ -21,6 +21,31 @@
#include "KsModels.hpp"
#include "KsDualMarker.hpp"
+struct KsPerStreamPlots {
+ /** CPUs to be plotted. */
+ QVector<int> _cpuList;
+ QVector<int> _cpuPlotBase;
+
+ /** Tasks to be plotted. */
+ QVector<int> _taskList;
+ QVector<int> _taskPlotBase;
+};
+
+struct KsVirtComboPlot {
+
+ int _hostStreamId;
+
+ int _hostPid;
+
+ int _guestStreamId;
+
+ int _vcpu;
+
+ int _hostBase;
+
+ int _vcpuBase;
+};
+
/**
* The KsGLWidget class provides a widget for rendering OpenGL graphics used
* to plot trace graphs.
@@ -69,23 +94,57 @@
KsGraphModel *model() {return &_model;}
/** Get the number of CPU graphs. */
- int cpuGraphCount() const {return _cpuList.count();}
+ int cpuGraphCount(int sd) const
+ {
+ auto it = _streamPlots.find(sd);
+ if (it != _streamPlots.end())
+ return it.value()._cpuList.count();
+ return 0;
+ }
/** Get the number of Task graphs. */
- int taskGraphCount() const {return _taskList.count();}
+ int taskGraphCount(int sd) const
+ {
+ auto it = _streamPlots.find(sd);
+ if (it != _streamPlots.end())
+ return it.value()._taskList.count();
+ return 0;
+ }
/** Get the total number of graphs. */
- int graphCount() const {return _cpuList.count() + _taskList.count();}
+ int graphCount(int sd) const
+ {
+ auto it = _streamPlots.find(sd);
+ if (it != _streamPlots.end())
+ return it.value()._taskList.count() +
+ it.value()._cpuList.count();
+
+ return 0;
+ }
+
+ int totGraphCount() const
+ {
+ int count(0);
+
+ for (auto const &s: _streamPlots)
+ count += s._taskList.count() +
+ s._cpuList.count();
+
+ return count;
+ }
+
+ int totComboGraphCount() const {return _comboPlots.count();}
/** Get the height of the widget. */
int height() const
{
- return graphCount() * (KS_GRAPH_HEIGHT + _vSpacing) +
+ return totGraphCount() * (KS_GRAPH_HEIGHT + _vSpacing) +
+ totComboGraphCount() * (KS_GRAPH_HEIGHT * 2 + _vSpacing) +
_vMargin * 2;
}
/** Get the device pixel ratio. */
- int dpr() const {return _dpr;}
+ int dpr() const {return _dpr;}
/** Get the size of the horizontal margin space. */
int hMargin() const {return _hMargin;}
@@ -96,24 +155,17 @@
/** Get the size of the vertical spaceing between the graphs. */
int vSpacing() const {return _vSpacing;}
- void setMark(KsGraphMark *mark);
-
- void findGraphIds(const kshark_entry &e,
- int *graphCPU,
- int *graphTask);
+ void setMarkPoints(const KsDataStore &data, KsGraphMark *mark);
bool find(const QPoint &point, int variance, bool joined,
size_t *index);
- int getPlotCPU(const QPoint &point);
+ bool getPlotInfo(const QPoint &point, int *sd, int *cpu, int *pid);
- int getPlotPid(const QPoint &point);
+ /** CPUs to Tasks (per data stream) be plotted. */
+ QMap<int, KsPerStreamPlots> _streamPlots;
- /** CPUs to be plotted. */
- QVector<int> _cpuList;
-
- /** Tasks to be plotted. */
- QVector<int> _taskList;
+ QVector<KsVirtComboPlot> _comboPlots;
signals:
/**
@@ -126,7 +178,7 @@
* This signal is emitted when the mouse moves but there is no visible
* KernelShark entry under the cursor.
*/
- void notFound(uint64_t ts, int cpu, int pid);
+ void notFound(uint64_t ts, int sd, int cpu, int pid);
/** This signal is emitted when the Plus key is pressed. */
void zoomIn();
@@ -159,7 +211,9 @@
void updateView(size_t pos, bool mark);
private:
- QVector<KsPlot::Graph*> _graphs;
+ QMap<int, QVector<KsPlot::Graph*>> _graphs;
+
+ QVector<KsPlot::ComboGraph*> _comboGraphs;
KsPlot::PlotObjList _shapes;
@@ -189,13 +243,16 @@
void _drawAxisX();
- void _makeGraphs(QVector<int> cpuMask, QVector<int> taskMask);
+ void _makeGraphs();
- KsPlot::Graph *_newCPUGraph(int cpu);
+ KsPlot::Graph *_newCPUGraph(int sd, int cpu);
- KsPlot::Graph *_newTaskGraph(int pid);
+ KsPlot::Graph *_newTaskGraph(int sd, int pid);
- void _makePluginShapes(QVector<int> cpuMask, QVector<int> taskMask);
+ KsPlot::ComboGraph *_newComboGraph(int sdHost, int pidHost,
+ int sdGuest, int vcpu);
+
+ void _makePluginShapes();
int _posInRange(int x);
@@ -207,14 +264,16 @@
bool _findAndSelect(QMouseEvent *event);
- bool _find(int bin, int cpu, int pid,
+ bool _find(int bin, int sd, int cpu, int pid,
int variance, bool joined, size_t *row);
- int _getNextCPU(int pid, int bin);
+ int _getNextCPU(int sd, int pid, int bin);
- int _getLastTask(struct kshark_trace_histo *histo, int bin, int cpu);
+ int _getLastTask(struct kshark_trace_histo *histo,
+ int bin, int sd, int cpu);
- int _getLastCPU(struct kshark_trace_histo *histo, int bin, int pid);
+ int _getLastCPU(struct kshark_trace_histo *histo,
+ int sd, int bin, int pid);
void _deselect();
};
diff --git a/kernel-shark/src/KsMainWindow.cpp b/kernel-shark/src/KsMainWindow.cpp
index 7afb721..222b8ad 100644
--- a/kernel-shark/src/KsMainWindow.cpp
+++ b/kernel-shark/src/KsMainWindow.cpp
@@ -42,7 +42,8 @@
_plugins(this),
_capture(this),
_captureLocalServer(this),
- _openAction("Open", this),
+ _openAction("Open Trace File", this),
+ _appendAction("Append Trace File", this),
_restoreSessionAction("Restore Last Session", this),
_importSessionAction("Import Session", this),
_exportSessionAction("Export Sassion", this),
@@ -59,6 +60,7 @@
_cpuSelectAction("CPUs", this),
_taskSelectAction("Tasks", this),
_managePluginsAction("Manage plugins", this),
+ _virtComboSelectAction("Virt. Combos", this),
_addPluginsAction("Add plugins", this),
_captureAction("Record", this),
_colorAction(this),
@@ -169,6 +171,13 @@
connect(&_openAction, &QAction::triggered,
this, &KsMainWindow::_open);
+ _appendAction.setIcon(QIcon::fromTheme("document-open"));
+ _appendAction.setShortcut(tr("Ctrl+A"));
+ _appendAction.setStatusTip("Append an existing data file");
+
+ connect(&_appendAction, &QAction::triggered,
+ this, &KsMainWindow::_append);
+
_restoreSessionAction.setIcon(QIcon::fromTheme("document-open-recent"));
connect(&_restoreSessionAction, &QAction::triggered,
this, &KsMainWindow::_restoreSession);
@@ -227,6 +236,9 @@
connect(&_taskSelectAction, &QAction::triggered,
this, &KsMainWindow::_taskSelect);
+ connect(&_virtComboSelectAction,&QAction::triggered,
+ this, &KsMainWindow::_virtComboSelect);
+
/* Tools menu */
_managePluginsAction.setShortcut(tr("Ctrl+P"));
_managePluginsAction.setIcon(QIcon::fromTheme("preferences-system"));
@@ -290,6 +302,7 @@
/* File menu */
file = menuBar()->addMenu("File");
file->addAction(&_openAction);
+ file->addAction(&_appendAction);
sessions = file->addMenu("Sessions");
sessions->setIcon(QIcon::fromTheme("document-properties"));
@@ -340,6 +353,7 @@
plots = menuBar()->addMenu("Plots");
plots->addAction(&_cpuSelectAction);
plots->addAction(&_taskSelectAction);
+ plots->addAction(&_virtComboSelectAction);
/* Tools menu */
tools = menuBar()->addMenu("Tools");
@@ -368,6 +382,18 @@
loadDataFile(fileName);
}
+void KsMainWindow::_append()
+{
+ QString fileName =
+ QFileDialog::getOpenFileName(this,
+ "Append File",
+ KS_DIR,
+ "trace-cmd files (*.dat);;All files (*)");
+
+ if (!fileName.isEmpty())
+ appendDataFile(fileName);
+}
+
void KsMainWindow::_restoreSession()
{
QString file = KS_CONF_DIR;
@@ -399,9 +425,9 @@
if (!kshark_instance(&kshark_ctx))
return;
- _session.saveGraphs(*_graph.glPtr());
_session.saveVisModel(_graph.glPtr()->model()->histo());
- _session.saveFilters(kshark_ctx);
+ _session.saveDataStreams(kshark_ctx);
+ _session.saveGraphs(kshark_ctx, _graph);
_session.saveDualMarker(&_mState);
_session.saveTable(_view);
_session.saveColorScheme();
@@ -456,7 +482,6 @@
void KsMainWindow::_importFilter()
{
kshark_context *kshark_ctx(nullptr);
- kshark_config_doc *conf;
QString fileName;
if (!kshark_instance(&kshark_ctx))
@@ -468,23 +493,12 @@
if (fileName.isEmpty())
return;
- conf = kshark_open_config_file(fileName.toStdString().c_str(),
- "kshark.config.filter");
- if (!conf)
- return;
-
- kshark_import_all_event_filters(kshark_ctx, conf);
- kshark_free_config_doc(conf);
-
- kshark_filter_entries(kshark_ctx, _data.rows(), _data.size());
- _filterSyncCBoxUpdate(kshark_ctx);
- emit _data.updateWidgets(&_data);
+ _session.loadFilters(kshark_ctx, fileName, &_data);
}
void KsMainWindow::_exportFilter()
{
kshark_context *kshark_ctx(nullptr);
- kshark_config_doc *conf(nullptr);
QString fileName;
if (!kshark_instance(&kshark_ctx))
@@ -504,9 +518,7 @@
}
}
- kshark_export_all_event_filters(kshark_ctx, &conf);
- kshark_save_config_file(fileName.toStdString().c_str(), conf);
- kshark_free_config_doc(conf);
+ _session.saveFilters(kshark_ctx, fileName);
}
void KsMainWindow::_listFilterSync(int state)
@@ -524,37 +536,72 @@
void KsMainWindow::_showEvents()
{
kshark_context *kshark_ctx(nullptr);
+ QVector<KsCheckBoxWidget *> cbds;
KsCheckBoxWidget *events_cb;
KsCheckBoxDialog *dialog;
+ kshark_data_stream *stream;
+ int *streamIds, sd;
if (!kshark_instance(&kshark_ctx))
return;
- events_cb = new KsEventsCheckBoxWidget(_data.tep(), this);
- dialog = new KsCheckBoxDialog(events_cb, this);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ stream = kshark_ctx->stream[sd];
+ events_cb = new KsEventsCheckBoxWidget(sd, this);
+ events_cb->setStream(QString(stream->file));
+ cbds.append(events_cb);
- if (!kshark_ctx->show_event_filter ||
- !kshark_ctx->show_event_filter->count) {
- events_cb->setDefault(true);
- } else {
- /*
- * The event filter contains IDs. Make this visible in the
- * CheckBox Widget.
- */
- tep_event **events =
- tep_list_events(_data.tep(), TEP_EVENT_SORT_SYSTEM);
- int nEvts = tep_get_events_count(_data.tep());
- QVector<bool> v(nEvts, false);
+ if (!stream->show_event_filter ||
+ !stream->show_event_filter->count) {
+ events_cb->setDefault(true);
+ } else {
+ /*
+ * The event filter contains IDs. Make this visible in
+ * the CheckBox Widget.
+ */
+ tep_event **events = tep_list_events(_data.tep(sd),
+ TEP_EVENT_SORT_SYSTEM);
+ int nEvts = tep_get_events_count(_data.tep(sd));
+ QVector<bool> v(nEvts, false);
+ for (int i = 0; i < nEvts; ++i) {
+ if (tracecmd_filter_id_find(stream->show_event_filter,
+ events[i]->id))
+ v[i] = true;
+ }
- for (int i = 0; i < nEvts; ++i) {
- if (tracecmd_filter_id_find(kshark_ctx->show_event_filter,
- events[i]->id))
- v[i] = true;
+ events_cb->set(v);
}
-
- events_cb->set(v);
}
+// events_cb = new KsEventsCheckBoxWidget(_data.tep(), this);
+// dialog = new KsCheckBoxDialog(events_cb, this);
+//
+// if (!kshark_ctx->show_event_filter ||
+// !kshark_ctx->show_event_filter->count) {
+// events_cb->setDefault(true);
+// } else {
+// /*
+// * The event filter contains IDs. Make this visible in the
+// * CheckBox Widget.
+// */
+// tep_event_format **events =
+// tep_list_events(_data.tep(), TEP_EVENT_SORT_SYSTEM);
+// int nEvts = tep_get_events_count(_data.tep());
+// QVector<bool> v(nEvts, false);
+//
+// for (int i = 0; i < nEvts; ++i) {
+// if (tracecmd_filter_id_find(kshark_ctx->show_event_filter,
+// events[i]->id))
+// v[i] = true;
+// }
+//
+// events_cb->set(v);
+// }
+
+ dialog = new KsCheckBoxDialog(cbds, this);
+
connect(dialog, &KsCheckBoxDialog::apply,
&_data, &KsDataStore::applyPosEventFilter);
@@ -564,32 +611,43 @@
void KsMainWindow::_showTasks()
{
kshark_context *kshark_ctx(nullptr);
+ QVector<KsCheckBoxWidget *> cbds;
+ kshark_data_stream *stream;
KsCheckBoxWidget *tasks_cbd;
KsCheckBoxDialog *dialog;
+ int *streamIds, sd;
if (!kshark_instance(&kshark_ctx))
return;
- tasks_cbd = new KsTasksCheckBoxWidget(_data.tep(), true, this);
- dialog = new KsCheckBoxDialog(tasks_cbd, this);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ stream = kshark_ctx->stream[sd];
+ tasks_cbd = new KsTasksCheckBoxWidget(sd, true, this);
+ tasks_cbd->setStream(QString(stream->file));
+ cbds.append(tasks_cbd);
- if (!kshark_ctx->show_task_filter ||
- !kshark_ctx->show_task_filter->count) {
- tasks_cbd->setDefault(true);
- } else {
- QVector<int> pids = KsUtils::getPidList();
- int nPids = pids.count();
- QVector<bool> v(nPids, false);
+ if (!stream->show_task_filter ||
+ !stream->show_task_filter->count) {
+ tasks_cbd->setDefault(true);
+ } else {
+ QVector<int> pids = KsUtils::getPidList(sd);
+ int nPids = pids.count();
+ QVector<bool> v(nPids, false);
- for (int i = 0; i < nPids; ++i) {
- if (tracecmd_filter_id_find(kshark_ctx->show_task_filter,
- pids[i]))
- v[i] = true;
+ for (int i = 0; i < nPids; ++i) {
+ if (tracecmd_filter_id_find(stream->show_task_filter,
+ pids[i]))
+ v[i] = true;
+ }
+
+ tasks_cbd->set(v);
}
-
- tasks_cbd->set(v);
}
+ dialog = new KsCheckBoxDialog(cbds, this);
+
connect(dialog, &KsCheckBoxDialog::apply,
&_data, &KsDataStore::applyPosTaskFilter);
@@ -599,32 +657,43 @@
void KsMainWindow::_hideTasks()
{
kshark_context *kshark_ctx(nullptr);
+ QVector<KsCheckBoxWidget *> cbds;
+ kshark_data_stream *stream;
KsCheckBoxWidget *tasks_cbd;
KsCheckBoxDialog *dialog;
+ int *streamIds, sd;
if (!kshark_instance(&kshark_ctx))
return;
- tasks_cbd = new KsTasksCheckBoxWidget(_data.tep(), false, this);
- dialog = new KsCheckBoxDialog(tasks_cbd, this);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ stream = kshark_ctx->stream[sd];
+ tasks_cbd = new KsTasksCheckBoxWidget(sd, false, this);
+ tasks_cbd->setStream(QString(stream->file));
+ cbds.append(tasks_cbd);
- if (!kshark_ctx->hide_task_filter ||
- !kshark_ctx->hide_task_filter->count) {
- tasks_cbd->setDefault(false);
- } else {
- QVector<int> pids = KsUtils::getPidList();
- int nPids = pids.count();
- QVector<bool> v(nPids, false);
+ if (!stream->hide_task_filter ||
+ !stream->hide_task_filter->count) {
+ tasks_cbd->setDefault(false);
+ } else {
+ QVector<int> pids = KsUtils::getPidList(sd);
+ int nPids = pids.count();
+ QVector<bool> v(nPids, false);
- for (int i = 0; i < nPids; ++i) {
- if (tracecmd_filter_id_find(kshark_ctx->hide_task_filter,
- pids[i]))
- v[i] = true;
+ for (int i = 0; i < nPids; ++i) {
+ if (tracecmd_filter_id_find(stream->hide_task_filter,
+ pids[i]))
+ v[i] = true;
+ }
+
+ tasks_cbd->set(v);
}
-
- tasks_cbd->set(v);
}
+ dialog = new KsCheckBoxDialog(cbds, this);
+
connect(dialog, &KsCheckBoxDialog::apply,
&_data, &KsDataStore::applyNegTaskFilter);
@@ -634,30 +703,40 @@
void KsMainWindow::_showCPUs()
{
kshark_context *kshark_ctx(nullptr);
- KsCheckBoxWidget *cpu_cbd;
+ QVector<KsCheckBoxWidget *> cbds;
+ kshark_data_stream *stream;
+ KsCheckBoxWidget *cpus_cbd;
KsCheckBoxDialog *dialog;
+ int *streamIds, sd, nCPUs;
if (!kshark_instance(&kshark_ctx))
return;
- cpu_cbd = new KsCPUCheckBoxWidget(_data.tep(), this);
- dialog = new KsCheckBoxDialog(cpu_cbd, this);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ stream = kshark_ctx->stream[sd];
+ cpus_cbd = new KsCPUCheckBoxWidget(sd, this);
+ cpus_cbd->setStream(QString(stream->file));
+ cbds.append(cpus_cbd);
- if (!kshark_ctx->show_cpu_filter ||
- !kshark_ctx->show_cpu_filter->count) {
- cpu_cbd->setDefault(true);
- } else {
- int nCPUs = tep_get_cpus(_data.tep());
- QVector<bool> v(nCPUs, false);
+ nCPUs = tep_get_cpus(_data.tep(sd));
+ if (!stream->show_cpu_filter ||
+ !stream->show_cpu_filter->count) {
+ cpus_cbd->setDefault(true);
+ } else {
+ QVector<bool> v(nCPUs, false);
+ for (int i = 0; i < nCPUs; ++i) {
+ if (tracecmd_filter_id_find(stream->show_cpu_filter, i))
+ v[i] = true;
+ }
- for (int i = 0; i < nCPUs; ++i) {
- if (tracecmd_filter_id_find(kshark_ctx->show_cpu_filter, i))
- v[i] = true;
+ cpus_cbd->set(v);
}
-
- cpu_cbd->set(v);
}
+ dialog = new KsCheckBoxDialog(cbds, this);
+
connect(dialog, &KsCheckBoxDialog::apply,
&_data, &KsDataStore::applyPosCPUFilter);
@@ -667,58 +746,67 @@
void KsMainWindow::_hideCPUs()
{
kshark_context *kshark_ctx(nullptr);
- KsCheckBoxWidget *cpu_cbd;
+ QVector<KsCheckBoxWidget *> cbds;
+ kshark_data_stream *stream;
+ KsCheckBoxWidget *cpus_cbd;
KsCheckBoxDialog *dialog;
+ int *streamIds, sd, nCPUs;
if (!kshark_instance(&kshark_ctx))
return;
- cpu_cbd = new KsCPUCheckBoxWidget(_data.tep(), this);
- dialog = new KsCheckBoxDialog(cpu_cbd, this);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ stream = kshark_ctx->stream[sd];
+ cpus_cbd = new KsCPUCheckBoxWidget(sd, this);
+ cpus_cbd->setStream(QString(stream->file));
+ cbds.append(cpus_cbd);
- if (!kshark_ctx->hide_cpu_filter ||
- !kshark_ctx->hide_cpu_filter->count) {
- cpu_cbd->setDefault(false);
- } else {
- int nCPUs = tep_get_cpus(_data.tep());
- QVector<bool> v(nCPUs, false);
+ nCPUs = tep_get_cpus(_data.tep(sd));
+ if (!stream->hide_cpu_filter ||
+ !stream->hide_cpu_filter->count) {
+ cpus_cbd->setDefault(false);
+ } else {
+ QVector<bool> v(nCPUs, false);
+ for (int i = 0; i < nCPUs; ++i) {
+ if (tracecmd_filter_id_find(stream->hide_cpu_filter, i))
+ v[i] = true;
+ }
- for (int i = 0; i < nCPUs; ++i) {
- if (tracecmd_filter_id_find(kshark_ctx->hide_cpu_filter,
- i))
- v[i] = true;
+ cpus_cbd->set(v);
}
-
- cpu_cbd->set(v);
}
+ dialog = new KsCheckBoxDialog(cbds, this);
+
connect(dialog, &KsCheckBoxDialog::apply,
- &_data, &KsDataStore::applyNegCPUFilter);
+ &_graph, &KsTraceGraph::cpuReDraw);
dialog->show();
}
void KsMainWindow::_advancedFiltering()
{
- KsAdvFilteringDialog *dialog;
-
- if (!_data.tep()) {
- QErrorMessage *em = new QErrorMessage(this);
- QString text("Unable to open Advanced filtering dialog.");
-
- text += " Tracing data has to be loaded first.";
-
- em->showMessage(text, "advancedFiltering");
- qCritical() << "ERROR: " << text;
-
- return;
- }
-
- dialog = new KsAdvFilteringDialog(this);
- connect(dialog, &KsAdvFilteringDialog::dataReload,
- &_data, &KsDataStore::reload);
-
- dialog->show();
+// KsAdvFilteringDialog *dialog;
+//
+// if (!_data.tep()) {
+// QErrorMessage *em = new QErrorMessage(this);
+// QString text("Unable to open Advanced filtering dialog.");
+//
+// text += " Tracing data has to be loaded first.";
+//
+// em->showMessage(text, "advancedFiltering");
+// qCritical() << "ERROR: " << text;
+//
+// return;
+// }
+//
+// dialog = new KsAdvFilteringDialog(this);
+// connect(dialog, &KsAdvFilteringDialog::dataReload,
+// &_data, &KsDataStore::reload);
+//
+// dialog->show();
}
void KsMainWindow::_clearFilters()
@@ -728,23 +816,36 @@
void KsMainWindow::_cpuSelect()
{
- KsCheckBoxWidget *cpus_cbd = new KsCPUCheckBoxWidget(_data.tep(), this);
- KsCheckBoxDialog *dialog = new KsCheckBoxDialog(cpus_cbd, this);
+ kshark_context *kshark_ctx(nullptr);
+ QVector<KsCheckBoxWidget *> cbds;
+ KsCheckBoxWidget *cpus_cbd;
+ KsCheckBoxDialog *dialog;
+ int *streamIds, sd, nCPUs;
- if(_data.tep()) {
- int nCPUs = tep_get_cpus(_data.tep());
- if (nCPUs == _graph.glPtr()->cpuGraphCount()) {
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ cpus_cbd = new KsCPUCheckBoxWidget(sd, this);
+ cpus_cbd->setStream(QString(kshark_ctx->stream[sd]->file));
+ cbds.append(cpus_cbd);
+
+ nCPUs = tep_get_cpus(_data.tep(sd));
+ if (nCPUs == _graph.glPtr()->cpuGraphCount(sd)) {
cpus_cbd->setDefault(true);
} else {
QVector<bool> v(nCPUs, false);
-
- for (auto const &cpu: _graph.glPtr()->_cpuList)
+ for (auto const &cpu: _graph.glPtr()->_streamPlots[sd]._cpuList)
v[cpu] = true;
cpus_cbd->set(v);
}
}
+ dialog = new KsCheckBoxDialog(cbds, this);
+
connect(dialog, &KsCheckBoxDialog::apply,
&_graph, &KsTraceGraph::cpuReDraw);
@@ -753,54 +854,99 @@
void KsMainWindow::_taskSelect()
{
- KsCheckBoxWidget *tasks_cbd = new KsTasksCheckBoxWidget(_data.tep(),
- true,
- this);
- KsCheckBoxDialog *dialog = new KsCheckBoxDialog(tasks_cbd, this);
- QVector<int> pids = KsUtils::getPidList();
- int nPids = pids.count();
+ kshark_context *kshark_ctx(nullptr);
+ QVector<KsCheckBoxWidget *> cbds;
+ KsCheckBoxWidget *tasks_cbd;
+ KsCheckBoxDialog *dialog;
+ int *streamIds, sd, nPids;
+ QVector<int> pids;
- if (nPids == _graph.glPtr()->taskGraphCount()) {
- tasks_cbd->setDefault(true);
- } else {
- QVector<bool> v(nPids, false);
- for (int i = 0; i < nPids; ++i) {
- for (auto const &pid: _graph.glPtr()->_taskList) {
- if (pids[i] == pid) {
- v[i] = true;
- break;
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ tasks_cbd = new KsTasksCheckBoxWidget(sd, true, this);
+ tasks_cbd->setStream(QString(kshark_ctx->stream[sd]->file));
+ cbds.append(tasks_cbd);
+
+ pids = KsUtils::getPidList(sd);
+ nPids = pids.count();
+ if (nPids == _graph.glPtr()->taskGraphCount(sd)) {
+ tasks_cbd->setDefault(true);
+ } else {
+ QVector<bool> v(nPids, false);
+ for (int i = 0; i < nPids; ++i) {
+ QVector<int> plots =
+ _graph.glPtr()->_streamPlots[sd]._taskList;
+ for (auto const &pid: plots) {
+ if (pids[i] == pid) {
+ v[i] = true;
+ break;
+ }
}
}
- }
- tasks_cbd->set(v);
+ tasks_cbd->set(v);
+ }
}
+ dialog = new KsCheckBoxDialog(cbds, this);
+
connect(dialog, &KsCheckBoxDialog::apply,
&_graph, &KsTraceGraph::taskReDraw);
dialog->show();
}
+void KsMainWindow::_virtComboSelect()
+{
+ kshark_context *kshark_ctx(nullptr);
+ KsComboPlotDialog *dialog;
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ dialog = new KsComboPlotDialog(this);
+
+ connect(dialog, &KsComboPlotDialog::apply,
+ &_graph, &KsTraceGraph::comboReDraw);
+
+ dialog->show();
+}
+
void KsMainWindow::_pluginSelect()
{
+ kshark_context *kshark_ctx(nullptr);
+ QVector<bool> registeredPlugins;
+ QVector<KsCheckBoxWidget *> cbds;
KsCheckBoxWidget *plugin_cbd;
KsCheckBoxDialog *dialog;
- QVector<bool> registeredPlugins;
+ int *streamIds, sd;
QStringList plugins;
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
plugins << _plugins._ksPluginList << _plugins._userPluginList;
registeredPlugins << _plugins._registeredKsPlugins
<< _plugins._registeredUserPlugins;
- plugin_cbd = new KsPluginCheckBoxWidget(plugins, this);
- plugin_cbd->set(registeredPlugins);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ plugin_cbd = new KsPluginCheckBoxWidget(sd, plugins, this);
+ plugin_cbd->setStream(QString(kshark_ctx->stream[sd]->file));
+ plugin_cbd->set(registeredPlugins);
+ cbds.append(plugin_cbd);
+ }
- dialog = new KsCheckBoxDialog(plugin_cbd, this);
+ dialog = new KsCheckBoxDialog(cbds, this);
connect(dialog, &KsCheckBoxDialog::apply,
- &_plugins, &KsPluginManager::updatePlugins);
+ &_plugins, &KsPluginManager::updatePlugins_hack);
dialog->show();
}
@@ -864,14 +1010,14 @@
void KsMainWindow::_aboutInfo()
{
- KsMessageDialog *message;
+ KsWidgetsLib::KsMessageDialog *message;
QString text;
text.append(" KernelShark\n\n version: ");
text.append(KS_VERSION_STRING);
text.append("\n");
- message = new KsMessageDialog(text);
+ message = new KsWidgetsLib::KsMessageDialog(text);
message->setWindowTitle("About");
message->show();
}
@@ -882,13 +1028,12 @@
QUrl::TolerantMode));
}
-/** Load trace data for file. */
-void KsMainWindow::loadDataFile(const QString& fileName)
+void KsMainWindow::_load(const QString& fileName, bool append)
{
- char buff[FILENAME_MAX];
QString pbLabel("Loading ");
bool loadDone = false;
struct stat st;
+ double shift;
int ret;
ret = stat(fileName.toStdString().c_str(), &st);
@@ -904,9 +1049,16 @@
qInfo() << "Loading " << fileName;
- _mState.reset();
- _view.reset();
- _graph.reset();
+ if (append) {
+ bool ok;
+ shift = QInputDialog::getDouble(this, tr("Append Trace file"),
+ tr("Offset [usec]:"), 0,
+ INT_MIN, INT_MAX, 1, &ok);
+ if (ok)
+ shift *= 1000.;
+ else
+ shift = 0.;
+ }
if (fileName.size() < 40) {
pbLabel += fileName;
@@ -916,14 +1068,29 @@
}
setWindowTitle("Kernel Shark");
- KsProgressBar pb(pbLabel);
+ KsWidgetsLib::KsProgressBar pb(pbLabel);
QApplication::processEvents();
- auto lamLoadJob = [&](KsDataStore *d) {
+ _view.reset();
+ _graph.reset();
+
+ auto lamLoadJob = [&] (KsDataStore *d) {
d->loadDataFile(fileName);
loadDone = true;
};
- std::thread tload(lamLoadJob, &_data);
+
+ auto lamAppendJob = [&] (KsDataStore *d) {
+ d->appendDataFile(fileName, shift);
+ loadDone = true;
+ };
+
+ std::thread job;
+ if (append) {
+ job = std::thread(lamAppendJob, &_data);
+ } else {
+ job = std::thread(lamLoadJob, &_data);
+ }
+// std::thread job(lamLoadJob, &_data);
for (int i = 0; i < 160; ++i) {
/*
@@ -937,7 +1104,7 @@
usleep(150000);
}
- tload.join();
+ job.join();
if (!_data.size()) {
QString text("File ");
@@ -950,17 +1117,26 @@
}
pb.setValue(165);
- _view.loadData(&_data);
+ _view.loadData(&_data);
pb.setValue(180);
+
_graph.loadData(&_data);
pb.setValue(195);
- setWindowTitle("Kernel Shark (" + fileName + ")");
+}
- if (realpath(fileName.toStdString().c_str(), buff)) {
- QString path(buff);
- _session.saveDataFile(path);
- }
+/** Load trace data for file. */
+void KsMainWindow::loadDataFile(const QString& fileName)
+{
+ _mState.reset();
+ _load(fileName, false);
+ setWindowTitle("Kernel Shark (" + fileName + ")");
+}
+
+/** Append trace data for file. */
+void KsMainWindow::appendDataFile(const QString& fileName)
+{
+ _load(fileName, true);
}
void KsMainWindow::_error(const QString &text, const QString &errCode,
@@ -1004,6 +1180,9 @@
return;
}
+ KsWidgetsLib::KsProgressBar pb("Loading session settings ...");
+ pb.setValue(10);
+
if (!_session.importFromFile(fileName)) {
QString text("Unable to open session description file ");
@@ -1015,42 +1194,29 @@
}
_session.loadPlugins(kshark_ctx, &_plugins);
+ pb.setValue(20);
- QString dataFile(_session.getDataFile(kshark_ctx));
- if (dataFile.isEmpty()) {
- QString text("Unable to open trace data file for session ");
-
- text.append(fileName);
- text.append("\n");
- _error(text, "loadSessErr1", true, true);
-
- return;
- }
-
- loadDataFile(dataFile);
- if (!_data.tep()) {
+ _session.loadDataStreams(kshark_ctx, &_data);
+ if (!kshark_ctx->n_streams) {
_plugins.unloadAll();
return;
}
- KsProgressBar pb("Loading session settings ...");
- pb.setValue(10);
+ _view.loadData(&_data);
+ _graph.loadData(&_data);
- _session.loadGraphs(&_graph);
- pb.setValue(20);
-
- _session.loadFilters(kshark_ctx, &_data);
_filterSyncCBoxUpdate(kshark_ctx);
- pb.setValue(130);
+ pb.setValue(110);
_session.loadSplitterSize(&_splitter);
_session.loadMainWindowSize(this);
this->show();
- pb.setValue(140);
+ pb.setValue(120);
_session.loadDualMarker(&_mState, &_graph);
_session.loadVisModel(_graph.glPtr()->model());
_mState.updateMarkers(_data, _graph.glPtr());
+ _session.loadGraphs(kshark_ctx, _graph);
pb.setValue(170);
_session.loadTable(&_view);
diff --git a/kernel-shark/src/KsMainWindow.hpp b/kernel-shark/src/KsMainWindow.hpp
index 78cd442..37192df 100644
--- a/kernel-shark/src/KsMainWindow.hpp
+++ b/kernel-shark/src/KsMainWindow.hpp
@@ -35,6 +35,8 @@
void loadDataFile(const QString &fileName);
+ void appendDataFile(const QString &fileName);
+
void loadSession(const QString &fileName);
/**
@@ -97,6 +99,8 @@
// File menu.
QAction _openAction;
+ QAction _appendAction;
+
QAction _restoreSessionAction;
QAction _importSessionAction;
@@ -129,6 +133,8 @@
QAction _taskSelectAction;
+ QAction _virtComboSelectAction;
+
// Tools menu.
QAction _managePluginsAction;
@@ -151,8 +157,12 @@
QShortcut _deselectShortcut;
+ void _load(const QString& fileName, bool append);
+
void _open();
+ void _append();
+
void _restoreSession();
void _importSession();
@@ -185,6 +195,8 @@
void _taskSelect();
+ void _virtComboSelect();
+
void _pluginSelect();
void _pluginAdd();
diff --git a/kernel-shark/src/KsModels.cpp b/kernel-shark/src/KsModels.cpp
index b89fee8..8c6994a 100644
--- a/kernel-shark/src/KsModels.cpp
+++ b/kernel-shark/src/KsModels.cpp
@@ -197,7 +197,7 @@
: QAbstractTableModel(parent),
_data(nullptr),
_nRows(0),
- _header({"#", "CPU", "Time Stamp", "Task", "PID",
+ _header({" >> ", "#", "CPU", "Time Stamp", "Task", "PID",
"Latency", "Event", "Info"}),
_markA(KS_NO_ROW_SELECTED),
_markB(KS_NO_ROW_SELECTED)
@@ -211,14 +211,21 @@
QVariant KsViewModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::ForegroundRole) {
- if (index.row() == _markA)
+ if (index.row() == _markA && index.column() != 0)
return QVariant::fromValue(QColor(Qt::white));
- if (index.row() == _markB)
+ if (index.row() == _markB && index.column() != 0)
return QVariant::fromValue(QColor(Qt::white));
}
if (role == Qt::BackgroundRole) {
+ if (index.column() == TRACE_VIEW_STREAM_ID) {
+ int sd = _data[index.row()]->stream_id;
+ QColor col = KsUtils::getStreamColor(sd);
+
+ return QVariant::fromValue(col);
+ }
+
if (index.row() == _markA)
return QVariant::fromValue(QColor(_colorMarkA));
@@ -238,6 +245,8 @@
int pid;
switch (column) {
+ case TRACE_VIEW_STREAM_ID :
+ return QString("%1").arg(_data[row]->stream_id);
case TRACE_VIEW_COL_INDEX :
return QString("%1").arg(row);
diff --git a/kernel-shark/src/KsModels.hpp b/kernel-shark/src/KsModels.hpp
index 3faaf4a..8e4df35 100644
--- a/kernel-shark/src/KsModels.hpp
+++ b/kernel-shark/src/KsModels.hpp
@@ -93,6 +93,9 @@
/** Table columns Identifiers. */
enum {
+ /** Identifier of the Data stream. */
+ TRACE_VIEW_STREAM_ID,
+
/** Identifier of the Index column. */
TRACE_VIEW_COL_INDEX,
@@ -192,8 +195,12 @@
*/
int mapRowFromSource(int r) const
{
- /*This works because the row number is shown in column "0". */
- return this->data(this->index(r, 0)).toInt();
+ /*
+ * This works because the row number is shown in column
+ * TRACE_VIEW_COL_INDEX.
+ */
+ int col = KsViewModel::TRACE_VIEW_COL_INDEX;
+ return this->data(this->index(r, col)).toInt();
}
/** Get the source model. */
diff --git a/kernel-shark/src/KsPlotTools.cpp b/kernel-shark/src/KsPlotTools.cpp
index 4447bea..910979e 100644
--- a/kernel-shark/src/KsPlotTools.cpp
+++ b/kernel-shark/src/KsPlotTools.cpp
@@ -457,6 +457,8 @@
_cpu._size = 5.5f;
_task._color = Color(0, 255, 0);
_task._size = 5.5f;
+ _combo._color = Color(225, 100, 255);
+ _combo._size = 5.5f;
}
void Mark::_draw(const Color &col, float size) const
@@ -464,6 +466,7 @@
drawLine(_a, _b, col, size);
_cpu.draw();
_task.draw();
+ _combo.draw();
}
/**
@@ -474,7 +477,7 @@
void Mark::setDPR(int dpr)
{
_size = 1.5 * dpr;
- _task._size = _cpu._size = 1.5 + 4.0 * dpr;
+ _task._size = _cpu._size = _combo._size = 1.5 + 4.0 * dpr;
}
/**
@@ -488,6 +491,7 @@
_b.setX(x);
_cpu.setX(x);
_task.setX(x);
+ _combo.setX(x);
}
/**
@@ -533,6 +537,26 @@
}
/**
+ * @brief Set the visiblity of the Mark's Combo point.
+ *
+ * @param v: If True, the Task point will be visible.
+ */
+void Mark::setComboVisible(bool v)
+{
+ _combo._visible = v;
+}
+
+/**
+ * @brief Set the Y coordinates (vertical) of the Mark's Combo points.
+ *
+ * @param yCombo: Y coordinate of the Mark's Task point.
+ */
+void Mark::setComboY(int yCombo)
+{
+ _combo.setY(yCombo);
+}
+
+/**
* @brief Set the visiblity of the Mark's Task points.
*
* @param v: If True, the Task point will be visible.
@@ -577,7 +601,8 @@
_collectionPtr(nullptr),
_binColors(nullptr),
_ensembleColors(nullptr),
- _zeroSuppress(false)
+ _zeroSuppress(false),
+ _drawBase(true)
{}
/**
@@ -592,10 +617,12 @@
_bins(new(std::nothrow) Bin[histo->n_bins]),
_size(histo->n_bins),
_hMargin(30),
+ _height(50),
_collectionPtr(nullptr),
_binColors(bct),
_ensembleColors(ect),
- _zeroSuppress(false)
+ _zeroSuppress(false),
+ _drawBase(true)
{
if (!_bins) {
_size = 0;
@@ -1082,7 +1109,6 @@
_collectionPtr,
nullptr);
if (pidCpu0 < 0 && pidCpuLOB == pid) {
-
/*
* The Task is the last one running on this
* CPU. Set the Pid of the bin. In this case
@@ -1119,11 +1145,13 @@
int lastPid(-1), b(0), boxH(_height * .3);
Rectangle taskBox;
- /*
- * Start by drawing a line between the base points of the first and
- * the last bin.
- */
- drawLine(_bins[0]._base, _bins[_size - 1]._base, {}, size);
+ if (_drawBase) {
+ /*
+ * Start by drawing a line between the base points of the first and
+ * the last bin.
+ */
+ drawLine(_bins[0]._base, _bins[_size - 1]._base, {}, size);
+ }
/* Draw as vartical lines all bins containing data. */
for (int i = 0; i < _size; ++i)
@@ -1213,4 +1241,241 @@
}
}
+ComboGraph::ComboGraph()
+: _histoPtr(nullptr),
+ _host(),
+ _guest()
+{
+ _init();
+}
+
+ComboGraph::ComboGraph(kshark_trace_histo *histo,
+ KsPlot::ColorTable *bct,
+ KsPlot::ColorTable *ect)
+: _histoPtr(histo),
+ _host(histo, bct, ect),
+ _guest(histo, bct, bct)
+{
+ _init();
+}
+
+void ComboGraph::_init()
+{
+ _guest.drawBase(false);
+ _guest.setZeroSuppressed(true);
+}
+
+/**
+ * @brief This function will set the Y (vertical) coordinate of the
+ * ComboGraph's base. It is safe to use this function even if the Graph
+ * contains data.
+ *
+ * @param b: Y coordinate of the Graph's base in pixels.
+ */
+void ComboGraph::setBase(int b)
+{
+ _guest.setBase(b);
+ _host.setBase(b + _host.height());
+}
+
+/**
+ * @brief Set the vertical size (height) of the ComboGraph.
+ *
+ * @param h: the height of the Graph in pixels.
+ */
+void ComboGraph::setHeight(int h)
+{
+ _host.setHeight(h / 2);
+ _guest.setHeight(h / 2);
+}
+
+void ComboGraph::fill(int sdHost, int pidHost, int sdGuest, int vcpu)
+{
+ kshark_context *kshark_ctx(nullptr);
+ struct kshark_data_stream *stream;
+ tep_event *event;
+
+ _sdHost = sdHost;
+ _pidHost = pidHost;
+ _vcpuEntryId = _vcpuExitId = -1;
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ stream = kshark_get_data_stream(kshark_ctx, sdHost);
+ if (!stream)
+ return;
+
+ event = tep_find_event_by_name(stream->pevent,
+ "kvm", "kvm_entry");
+ if (event)
+ _vcpuEntryId = event->id;
+
+ event = tep_find_event_by_name(stream->pevent,
+ "kvm", "kvm_exit");
+ if (event)
+ _vcpuExitId = event->id;
+
+ _host.fillTaskGraph(sdHost, pidHost);
+ _guest.fillCPUGraph(sdGuest, vcpu);
+}
+
+bool kshark_match_event_id(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e, int sd, int *values)
+{
+ return e->stream_id == sd &&
+ e->pid == values[0] &&
+ e->event_id == values[1];
+}
+
+struct VirtBridge : public Shape {
+
+ Point _entryPointHost, _exitPointHost;
+
+ Point _entryPointGuest, _exitPointGuest;
+
+ void _draw(const Color &col, float size) const;
+};
+
+void VirtBridge::_draw(const Color &col, float size) const
+{
+ drawLine(_entryPointHost, _entryPointGuest, _color, _size);
+ drawLine(_entryPointGuest, _exitPointGuest, _color, _size + 1);
+ drawLine(_exitPointGuest, _exitPointHost, _color, _size);
+}
+
+struct VirtGap : public Shape {
+
+ Point _exitPoint, _entryPoint;
+
+ int _height;
+ void _draw(const Color &col, float size) const;
+};
+
+void VirtGap::_draw(const Color &col, float size) const
+{
+ if (_entryPoint.x() - _exitPoint.x() < 4)
+ return;
+
+ Point p0(_exitPoint.x() + _size, _exitPoint.y());
+ Point p1(_exitPoint.x() + _size, _exitPoint.y() - _height);
+ Point p2(_entryPoint.x() - _size , _entryPoint.y() );
+ Point p3(_entryPoint.x() -_size , _entryPoint.y() - _height);
+
+ Rectangle gap;
+
+ gap.setPoint(0, p0);
+ gap.setPoint(1, p1);
+ gap.setPoint(2, p2);
+ gap.setPoint(3, p3);
+
+ gap._color = {255, 255, 255};
+ gap.setFill(false);
+ gap.draw();
+}
+
+void ComboGraph::_drawBridge()
+{
+ const kshark_entry *entry, *exit;
+ ssize_t indexEntry, indexExit;
+ int values[2] = {_pidHost, -1};
+ VirtBridge bridge;
+ VirtGap gap;
+
+ bridge._entryPointHost = bridge._entryPointGuest
+ = _guest.getBin(0)._base;
+ bridge._size = 2;
+ bridge._visible = false;
+
+ gap._exitPoint = _guest.getBin(0)._base;
+ gap._size = 2;
+ gap._height = 10;
+ gap._visible = false;
+
+ auto lamStartBridg = [&] (int bin) {
+ bridge._entryPointHost = _host.getBin(bin)._base;
+ bridge._entryPointGuest = _guest.getBin(bin)._base;
+ bridge._color = _host.getBin(bin)._color;
+ bridge._visible = true;
+ };
+
+ auto lamCloseBridg = [&] (int bin) {
+ bridge._exitPointGuest = _guest.getBin(bin)._base;
+ bridge._exitPointHost = _host.getBin(bin)._base;
+ bridge._color = _host.getBin(bin)._color;
+ bridge._visible = true;
+ bridge.draw();
+ bridge._visible = false;
+ };
+
+ auto lamStartGap = [&] (int bin) {
+ gap._exitPoint = _guest.getBin(bin)._base;
+ gap._visible = true;
+ };
+
+ auto lamCloseGap = [&] (int bin) {
+ gap._entryPoint = _guest.getBin(bin)._base;
+ gap._visible = true;
+ gap.draw();
+ gap._visible = false;
+ };
+
+ for (int bin = 0; bin < _histoPtr->n_bins; ++bin) {
+ values[1] = _vcpuEntryId;
+ entry = ksmodel_get_entry_back(_histoPtr, bin, true,
+ kshark_match_event_id,
+ _sdHost, values,
+ nullptr, &indexEntry);
+
+ values[1] = _vcpuExitId;
+ exit = ksmodel_get_entry_back(_histoPtr, bin, true,
+ kshark_match_event_id,
+ _sdHost, values,
+ nullptr, &indexExit);
+
+ if (entry && !exit) {
+ lamStartBridg(bin);
+ lamCloseGap(bin);
+ }
+
+ if (exit && !entry) {
+ lamCloseBridg(bin);
+ lamStartGap(bin);
+ }
+
+ if (exit && entry) {
+ if (bridge._visible)
+ lamCloseBridg(bin);
+
+ if (gap._visible)
+ lamCloseGap(bin);
+
+ if (indexEntry > indexExit) {
+ lamStartBridg(bin);
+ } else {
+ lamStartBridg(bin);
+ lamCloseBridg(bin);
+ lamStartGap(bin);
+ }
+ }
+ }
+
+ bridge._exitPointGuest = bridge._exitPointHost =
+ _guest.getBin(_histoPtr->n_bins - 1)._base;
+ bridge.draw();
+}
+
+void ComboGraph::draw(float size)
+{
+ _host.draw();
+ _guest.draw();
+ _drawBridge();
+}
+
+void ComboGraph::setHMargin(int hMargin)
+{
+ _host.setHMargin(hMargin);
+ _guest.setHMargin(hMargin);
+}
+
}; // KsPlot
diff --git a/kernel-shark/src/KsPlotTools.hpp b/kernel-shark/src/KsPlotTools.hpp
index fe01d45..24b75e8 100644
--- a/kernel-shark/src/KsPlotTools.hpp
+++ b/kernel-shark/src/KsPlotTools.hpp
@@ -318,14 +318,30 @@
void setY(int yA, int yB);
+ int cpuY() const {return _cpu.y();}
+
void setCPUY(int yCPU);
+ bool cpuIsVisible() const {return _cpu._visible;}
+
void setCPUVisible(bool v);
+ int taskY() const {return _task.y();}
+
void setTaskY(int yTask);
+ bool taskIsVisible() const {return _task._visible;}
+
void setTaskVisible(bool v);
+ int comboY() const {return _combo.y();}
+
+ void setComboY(int yCombo);
+
+ bool comboIsVisible() const {return _combo._visible;}
+
+ void setComboVisible(bool v);
+
private:
void _draw(const Color &col, float size = 1.) const override;
@@ -340,6 +356,9 @@
/** A point indicating the position of the Mark in a Task graph. */
Point _task;
+
+ /** A point indicating the position of the Mark in a Combo graph. */
+ Point _combo;
};
/** This class represents a KernelShark graph's bin. */
@@ -396,7 +415,7 @@
*/
Graph(const Graph &) = delete;
- /* Disable moving. Same as copying.*/
+ /* Disable moving. Same as copying. */
Graph(Graph &&) = delete;
Graph(kshark_trace_histo *histo, KsPlot::ColorTable *bct,
@@ -437,7 +456,7 @@
void setHeight(int h);
/** @brief Get the vertical size (height) of the Graph. */
- int getHeight() const {return _height;}
+ int height() const {return _height;}
void setBinValue(int bin, int val);
@@ -468,7 +487,9 @@
*/
void setZeroSuppressed(bool zs) {_zeroSuppress = zs;}
-private:
+ void drawBase(bool b) {_drawBase = b;}
+
+protected:
/** Pointer to the model descriptor object. */
kshark_trace_histo *_histoPtr;
@@ -498,9 +519,82 @@
bool _zeroSuppress;
+ bool _drawBase;
+
void _initBins();
};
+class ComboGraph {
+public:
+ ComboGraph();
+
+ /*
+ * Disable copying. We can enable the Copy Constructor in the future,
+ * but only if we really need it for some reason.
+ */
+ ComboGraph(const Graph &) = delete;
+
+ /* Disable moving. Same as copying. */
+ ComboGraph(ComboGraph &&) = delete;
+
+ ComboGraph(kshark_trace_histo *histo, KsPlot::ColorTable *bct,
+ KsPlot::ColorTable *ect);
+
+ /* Keep this destructor virtual. */
+ virtual ~ComboGraph() {}
+
+ /**
+ * @brief Provide the Host graph with a Data Collection. This
+ * collection will be used to optimise the processing of the
+ * content of the bins.
+ *
+ * @param col: Input location for the data collection descriptor.
+ */
+ void setHostDataCollectionPtr(kshark_entry_collection *col) {
+ _host.setDataCollectionPtr(col);
+ }
+
+ /**
+ * @brief Provide the Guest graph with a Data Collection. This
+ * collection will be used to optimise the processing of the
+ * content of the bins.
+ *
+ * @param col: Input location for the data collection descriptor.
+ */
+ void setGuestDataCollectionPtr(kshark_entry_collection *col) {
+ _guest.setDataCollectionPtr(col);
+ }
+
+ void setBase(int b);
+
+ void setHeight(int h);
+
+ /** @brief Get the vertical size (height) of the Combo graph. */
+ int height() const {return _host.height() + _guest.height();}
+
+ void setHMargin(int hMargin);
+
+ void fill(int sdHost, int pidHost, int sdGuest, int vcpu);
+
+ void draw(float size = 1);
+
+private:
+ /** Pointer to the model descriptor object. */
+ kshark_trace_histo *_histoPtr;
+
+ Graph _host, _guest;
+
+ void _init();
+
+ void _drawBridge();
+
+ int _sdHost;
+
+ int _pidHost;
+
+ int _vcpuEntryId, _vcpuExitId;
+};
+
}; // KsPlot
#endif /* _KS_PLOT_TOOLS_H */
diff --git a/kernel-shark/src/KsQuickContextMenu.cpp b/kernel-shark/src/KsQuickContextMenu.cpp
index 6be818b..da20724 100644
--- a/kernel-shark/src/KsQuickContextMenu.cpp
+++ b/kernel-shark/src/KsQuickContextMenu.cpp
@@ -44,8 +44,8 @@
* @param dm: The State machine of the Dual marker.
* @param parent: The parent of this widget.
*/
-KsQuickContextMenu::KsQuickContextMenu(KsDataStore *data, size_t row,
- KsDualMarkerSM *dm,
+KsQuickContextMenu::KsQuickContextMenu(KsDualMarkerSM *dm,
+ KsDataStore *data, size_t row,
QWidget *parent)
: KsQuickMarkerMenu(dm, parent),
_data(data),
@@ -67,7 +67,7 @@
typedef void (KsQuickContextMenu::*mfp)();
QString taskName, parentName, descr;
KsTraceGraph *graphs;
- int pid, cpu;
+ int pid, cpu, sd;
if (!parent || !_data)
return;
@@ -75,6 +75,7 @@
taskName = kshark_get_task_easy(_data->rows()[_row]);
pid = kshark_get_pid_easy(_data->rows()[_row]);
cpu = _data->rows()[_row]->cpu;
+ sd = _data->rows()[_row]->stream_id;
auto lamAddAction = [this, &descr] (QAction *action, mfp mf) {
action->setText(descr);
@@ -127,9 +128,6 @@
addSection("Pointer plot menu");
if (parentName == "KsTraceViewer") {
- descr = QString("Show CPU [%1] only").arg(cpu);
- lamAddAction(&_showCPUAction, &KsQuickContextMenu::_showCPU);
-
descr = "Add [";
descr += taskName;
descr += "-";
@@ -141,7 +139,7 @@
if (parentName == "KsTraceGraph" &&
(graphs = dynamic_cast<KsTraceGraph *>(parent))) {
- if (graphs->glPtr()->_taskList.contains(pid)) {
+ if (graphs->glPtr()->_streamPlots[sd]._taskList.contains(pid)) {
descr = "Remove [";
descr += taskName;
descr += "-";
@@ -159,7 +157,7 @@
&KsQuickContextMenu::_addTaskPlot);
}
- if (graphs->glPtr()->_cpuList.contains(cpu)) {
+ if (graphs->glPtr()->_streamPlots[sd]._cpuList.contains(cpu)) {
descr = "Remove [CPU ";
descr += QString("%1").arg(cpu);
descr += "] plot";
@@ -178,62 +176,67 @@
void KsQuickContextMenu::_hideTask()
{
int pid = kshark_get_pid_easy(_data->rows()[_row]);
+ int sd = _data->rows()[_row]->stream_id;
kshark_context *kshark_ctx(nullptr);
QVector<int> vec;
if (!kshark_instance(&kshark_ctx))
return;
- vec =_getFilterVector(kshark_ctx->hide_task_filter, pid);
- _data->applyNegTaskFilter(vec);
+ vec =_getFilterVector(kshark_ctx->stream[sd]->hide_task_filter, pid);
+ _data->applyNegTaskFilter(sd, vec);
}
void KsQuickContextMenu::_showTask()
{
int pid = kshark_get_pid_easy(_data->rows()[_row]);
-
- _data->applyPosTaskFilter(QVector<int>(1, pid));
+ int sd = _data->rows()[_row]->stream_id;
+ _data->applyPosTaskFilter(sd, QVector<int>(1, pid));
}
void KsQuickContextMenu::_hideEvent()
{
int eventId = kshark_get_event_id_easy(_data->rows()[_row]);
+ int sd = _data->rows()[_row]->stream_id;
kshark_context *kshark_ctx(nullptr);
QVector<int> vec;
if (!kshark_instance(&kshark_ctx))
return;
- vec =_getFilterVector(kshark_ctx->hide_event_filter, eventId);
- _data->applyNegEventFilter(vec);
+ vec =_getFilterVector(kshark_ctx->stream[sd]->hide_event_filter, eventId);
+ _data->applyNegEventFilter(sd, vec);
}
void KsQuickContextMenu::_showEvent()
{
int eventId = kshark_get_event_id_easy(_data->rows()[_row]);
+ int sd = _data->rows()[_row]->stream_id;
- _data->applyPosEventFilter(QVector<int>(1, eventId));
+ _data->applyPosEventFilter(sd, QVector<int>(1, eventId));
}
void KsQuickContextMenu::_showCPU()
{
int cpu = _data->rows()[_row]->cpu;
+ int sd = _data->rows()[_row]->stream_id;
- _data->applyPosCPUFilter(QVector<int>(1, cpu));
+ _data->applyPosCPUFilter(sd, QVector<int>(1, cpu));
}
void KsQuickContextMenu::_hideCPU()
{
+ int sd = _data->rows()[_row]->stream_id;
kshark_context *kshark_ctx(nullptr);
QVector<int> vec;
if (!kshark_instance(&kshark_ctx))
return;
- vec =_getFilterVector(kshark_ctx->hide_cpu_filter,
+ vec =_getFilterVector(kshark_ctx->stream[sd]->hide_cpu_filter,
_data->rows()[_row]->cpu);
- _data->applyNegCPUFilter(vec);
+ _data->applyNegCPUFilter(sd, vec);
}
QVector<int> KsQuickContextMenu::_getFilterVector(tracecmd_filter_id *filter, int newId)
@@ -248,25 +251,27 @@
void KsQuickContextMenu::_addTaskPlot()
{
int pid = kshark_get_pid_easy(_data->rows()[_row]);
+ int sd = _data->rows()[_row]->stream_id;
- emit addTaskPlot(pid);
+ emit addTaskPlot(sd, pid);
}
void KsQuickContextMenu::_addCPUPlot()
{
- emit addCPUPlot(_data->rows()[_row]->cpu);
+ emit addCPUPlot(_data->rows()[_row]->stream_id, _data->rows()[_row]->cpu);
}
void KsQuickContextMenu::_removeTaskPlot()
{
int pid = kshark_get_pid_easy(_data->rows()[_row]);
+ int sd = _data->rows()[_row]->stream_id;
- emit removeTaskPlot(pid);
+ emit removeTaskPlot(sd, pid);
}
void KsQuickContextMenu::_removeCPUPlot()
{
- emit removeCPUPlot(_data->rows()[_row]->cpu);
+ emit removeCPUPlot(_data->rows()[_row]->stream_id, _data->rows()[_row]->cpu);
}
/**
@@ -275,10 +280,11 @@
* @param dm: The State machine of the Dual marker.
* @param parent: The parent of this widget.
*/
-KsRmPlotContextMenu::KsRmPlotContextMenu(KsDualMarkerSM *dm,
+KsRmPlotContextMenu::KsRmPlotContextMenu(KsDualMarkerSM *dm, int sd,
QWidget *parent)
: KsQuickMarkerMenu(dm, parent),
- _removePlotAction(this)
+ _removePlotAction(this),
+ _sd(sd)
{
addSection("Plots");
@@ -295,9 +301,9 @@
* @param cpu : CPU Id.
* @param parent: The parent of this widget.
*/
-KsRmCPUPlotMenu::KsRmCPUPlotMenu(KsDualMarkerSM *dm, int cpu,
+KsRmCPUPlotMenu::KsRmCPUPlotMenu(KsDualMarkerSM *dm, int sd, int cpu,
QWidget *parent)
-: KsRmPlotContextMenu(dm, parent)
+: KsRmPlotContextMenu(dm, sd, parent)
{
_removePlotAction.setText(QString("Remove [CPU %1]").arg(cpu));
}
@@ -309,9 +315,9 @@
* @param pid: Process Id.
* @param parent: The parent of this widget.
*/
-KsRmTaskPlotMenu::KsRmTaskPlotMenu(KsDualMarkerSM *dm, int pid,
+KsRmTaskPlotMenu::KsRmTaskPlotMenu(KsDualMarkerSM *dm, int sd, int pid,
QWidget *parent)
-: KsRmPlotContextMenu(dm, parent)
+: KsRmPlotContextMenu(dm, sd, parent)
{
kshark_context *kshark_ctx(nullptr);
QString descr("Remove [ ");
@@ -319,7 +325,7 @@
if (!kshark_instance(&kshark_ctx))
return;
- descr += tep_data_comm_from_pid(kshark_ctx->pevent, pid);
+ descr += tep_data_comm_from_pid(kshark_ctx->stream[_sd]->pevent, pid);
descr += "-";
descr += QString("%1").arg(pid);
descr += "] plot";
diff --git a/kernel-shark/src/KsQuickContextMenu.hpp b/kernel-shark/src/KsQuickContextMenu.hpp
index df8a65b..5976c17 100644
--- a/kernel-shark/src/KsQuickContextMenu.hpp
+++ b/kernel-shark/src/KsQuickContextMenu.hpp
@@ -29,7 +29,7 @@
/** Signal to deselect the active marker. */
void deselect();
-private:
+protected:
KsDualMarkerSM *_dm;
QAction _deselectAction;
@@ -45,22 +45,22 @@
public:
KsQuickContextMenu() = delete;
- KsQuickContextMenu(KsDataStore *data, size_t row,
- KsDualMarkerSM *dm,
+ KsQuickContextMenu(KsDualMarkerSM *dm,
+ KsDataStore *data, size_t row,
QWidget *parent = nullptr);
signals:
/** Signal to add a task plot. */
- void addTaskPlot(int);
+ void addTaskPlot(int sd, int pid);
/** Signal to add a CPU plot. */
- void addCPUPlot(int);
+ void addCPUPlot(int sd, int pid);
/** Signal to remove a task plot. */
- void removeTaskPlot(int);
+ void removeTaskPlot(int sd, int pid);
/** Signal to remove a CPU plot. */
- void removeCPUPlot(int);
+ void removeCPUPlot(int sd, int pid);
private:
void _hideTask();
@@ -108,6 +108,7 @@
QAction _removeTaskPlotAction;
QAction _clearAllFilters;
+
};
/**
@@ -118,7 +119,8 @@
public:
KsRmPlotContextMenu() = delete;
- KsRmPlotContextMenu(KsDualMarkerSM *dm, QWidget *parent = nullptr);
+ KsRmPlotContextMenu(KsDualMarkerSM *dm, int sd,
+ QWidget *parent = nullptr);
signals:
/** Signal to remove a plot. */
@@ -127,13 +129,16 @@
protected:
/** Menu action. */
QAction _removePlotAction;
+
+ /** . */
+ int _sd;
};
/**
* The KsQuickMarkerMenu class provides CPU Plot remove menus.
*/
struct KsRmCPUPlotMenu : public KsRmPlotContextMenu {
- KsRmCPUPlotMenu(KsDualMarkerSM *dm, int cpu,
+ KsRmCPUPlotMenu(KsDualMarkerSM *dm, int sd, int cpu,
QWidget *parent = nullptr);
};
@@ -141,7 +146,7 @@
* The KsQuickMarkerMenu class provides Task Plot remove menus.
*/
struct KsRmTaskPlotMenu : public KsRmPlotContextMenu {
- KsRmTaskPlotMenu(KsDualMarkerSM *dm, int pid,
+ KsRmTaskPlotMenu(KsDualMarkerSM *dm, int sd, int pid,
QWidget *parent = nullptr);
};
diff --git a/kernel-shark/src/KsSession.cpp b/kernel-shark/src/KsSession.cpp
index 9d86776..0ea3675 100644
--- a/kernel-shark/src/KsSession.cpp
+++ b/kernel-shark/src/KsSession.cpp
@@ -92,29 +92,32 @@
QString KsSession::getDataFile(kshark_context *kshark_ctx)
{
kshark_config_doc *file = kshark_config_alloc(KS_CONFIG_JSON);
- const char *file_str;
+ int sd;
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);
+ sd = kshark_import_trace_file(kshark_ctx, file);
+ if (sd)
+ return QString(kshark_ctx->stream[sd]->file);
return QString();
}
/**
- * @brief Save the configuration of the filters.
+ * @brief Save the configuration of the filters to file.
*
* @param kshark_ctx: Input location for context pointer.
+ * @param fileName: The name of the file.
*/
-void KsSession::saveFilters(kshark_context *kshark_ctx)
+void KsSession::saveFilters(kshark_context *kshark_ctx,
+ const QString &fileName)
{
- kshark_config_doc *filters =
- kshark_export_all_filters(kshark_ctx, KS_CONFIG_JSON);
+ kshark_config_doc *conf(nullptr);
- kshark_config_doc_add(_config, "Filters", filters);
+ kshark_export_all_dstreams(kshark_ctx, &conf);
+ kshark_save_config_file(fileName.toStdString().c_str(), conf);
+ kshark_free_config_doc(conf);
}
/**
@@ -123,25 +126,92 @@
* @param kshark_ctx: Input location for context pointer.
* @param data: Input location for KsDataStore object;
*/
-void KsSession::loadFilters(kshark_context *kshark_ctx, KsDataStore *data)
+void KsSession::loadFilters(kshark_context *kshark_ctx,
+ const QString &fileName,
+ KsDataStore *data)
{
- kshark_config_doc *filters = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jconf, *jall_stream, *jstream, *jdata, *jfile, *jfilters;
+ kshark_config_doc *conf =
+ kshark_open_config_file(fileName.toStdString().c_str(),
+ "kshark.config.filter");
+ int n, sd, *streamIds = kshark_all_streams(kshark_ctx);
+ bool doReload(false);
- if (!kshark_config_doc_get(_config, "Filters", filters))
+ if (!conf)
return;
- kshark_import_all_filters(kshark_ctx, filters);
+ if (conf->format != KS_CONFIG_JSON)
+ return;
- if (kshark_ctx->advanced_event_filter->filters)
+ jconf = KS_JSON_CAST(conf->conf_doc);
+
+ if (!json_object_object_get_ex(jconf, "data streams", &jall_stream))
+ return;
+
+ if (json_object_get_type(jall_stream) != json_type_array)
+ return;
+
+ n = json_object_array_length(jall_stream);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ for (int j = 0; j < n; ++j) {
+ char abs_path[FILENAME_MAX];
+ const char *file;
+
+ jstream = json_object_array_get_idx(jall_stream, j);
+ json_object_object_get_ex(jstream, "data", &jdata);
+ json_object_object_get_ex(jdata, "file", &jfile);
+ file = json_object_get_string(jfile);
+
+ if (!realpath(kshark_ctx->stream[sd]->file, abs_path))
+ continue;
+
+ if (strcmp(file, abs_path) == 0) {
+ json_object_object_get_ex(jstream,
+ "filters",
+ &jfilters);
+
+ kshark_config_doc *filters =
+ kshark_json_to_conf(jfilters);
+
+ kshark_import_all_filters(kshark_ctx,
+ sd, filters);
+ kshark_free_config_doc(filters);
+ }
+ }
+
+ if (kshark_ctx->stream[sd]->advanced_event_filter->filters)
+ doReload = true;
+ }
+
+ if (doReload)
data->reload();
else
- kshark_filter_entries(kshark_ctx, data->rows(), data->size());
-
- data->registerCPUCollections();
+ data->update();
emit data->updateWidgets(data);
}
+void KsSession::saveDataStreams(kshark_context *kshark_ctx)
+{
+ kshark_export_all_dstreams(kshark_ctx, &_config);
+}
+
+void KsSession::loadDataStreams(kshark_context *kshark_ctx, KsDataStore *data)
+{
+ bool ret;
+
+ ret = kshark_import_all_dstreams(kshark_ctx, _config,
+ data->rows_r(), data->size_r());
+
+ if (!ret) {
+ data->clear();
+ return;
+ }
+
+ data->registerCPUCollections();
+}
+
/**
* @brief Save the state of the table.
*
@@ -152,7 +222,7 @@
int64_t r = view.getTopRow();
topRow->conf_doc = json_object_new_int64(r);
- kshark_config_doc_add(_config, "ViewTop",topRow);
+ kshark_config_doc_add(_config, "ViewTop", topRow);
}
/**
@@ -309,10 +379,16 @@
*
* @param glw: Input location for the KsGLWidget widget.
*/
-void KsSession::saveGraphs(const KsGLWidget &glw)
+void KsSession::saveGraphs(kshark_context *kshark_ctx,
+ KsTraceGraph &graphs)
{
- _saveCPUPlots(glw._cpuList);
- _saveTaskPlots(glw._taskList);
+ int *streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ _saveCPUPlots(streamIds[i], graphs.glPtr());
+ _saveTaskPlots(streamIds[i], graphs.glPtr());
+ }
+
+ _saveComboPlots(graphs.glPtr());
}
/**
@@ -320,84 +396,199 @@
*
* @param graphs: Input location for the KsTraceGraph widget.
*/
-void KsSession::loadGraphs(KsTraceGraph *graphs)
+void KsSession::loadGraphs(kshark_context *kshark_ctx,
+ KsTraceGraph &graphs)
{
- graphs->cpuReDraw(_getCPUPlots());
- graphs->taskReDraw(_getTaskPlots());
-}
+ int sd, *streamIds = kshark_all_streams(kshark_ctx);
-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);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ graphs.cpuReDraw(sd, _getCPUPlots(sd));
+ graphs.taskReDraw(sd, _getTaskPlots(sd));
}
- cpuPlts->conf_doc = jcpus;
- kshark_config_doc_add(_config, "CPUPlots", cpuPlts);
+ QVector<QVector<int>> combos = _getComboPlots();
+ for (auto const &cp: combos) {
+ graphs.comboReDraw(0, cp);
+ }
}
-QVector<int> KsSession::_getCPUPlots()
+void KsSession::_savePlots(int sd, KsGLWidget *glw, bool cpu)
{
- kshark_config_doc *cpuPlts = kshark_config_alloc(KS_CONFIG_JSON);
- json_object *jcpus;
- QVector<int> cpus;
- size_t length;
+ kshark_config_doc *streamsConf = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jallStreams, *jstream, *jstreamId, *jplots;
+ QVector<int> plotIds;
+ int nStreams;
- if (!kshark_config_doc_get(_config, "CPUPlots", cpuPlts))
- return cpus;
+ if (cpu) {
+ plotIds = glw->_streamPlots[sd]._cpuList;
+ } else {
+ plotIds = glw->_streamPlots[sd]._taskList;
+ }
+
+ if (!kshark_config_doc_get(_config, "data streams", streamsConf) ||
+ streamsConf->format != KS_CONFIG_JSON)
+ return;
+
+ jallStreams = KS_JSON_CAST(streamsConf->conf_doc);
+ if (json_object_get_type(jallStreams) != json_type_array)
+ return;
+
+ nStreams = json_object_array_length(jallStreams);
+ for (int i = 0; i < nStreams; ++i) {
+ jstream = json_object_array_get_idx(jallStreams, i);
+ if (json_object_object_get_ex(jstream, "stream id", &jstreamId) &&
+ json_object_get_int(jstreamId) == sd)
+ break;
+
+ jstream = nullptr;
+ }
+
+ if (!jstream)
+ return;
+
+ jplots = json_object_new_array();
+ for (int i = 0; i < plotIds.count(); ++i) {
+ json_object *jcpu = json_object_new_int(plotIds[i]);
+ json_object_array_put_idx(jplots, i, jcpu);
+ }
+
+ if (cpu)
+ json_object_object_add(jstream, "CPUPlots", jplots);
+ else
+ json_object_object_add(jstream, "TaskPlots", jplots);
+}
+
+void KsSession::_saveCPUPlots(int sd, KsGLWidget *glw)
+{
+ _savePlots(sd, glw, true);
+}
+
+void KsSession::_saveTaskPlots(int sd, KsGLWidget *glw)
+{
+ _savePlots(sd, glw, false);
+}
+
+void KsSession::_saveComboPlots(KsGLWidget *glw)
+{
+ kshark_config_doc *combos = kshark_config_alloc(KS_CONFIG_JSON);
+ int var, nCombos = glw->_comboPlots.count();
+ json_object *jcombo, *jplots;
+
+ if (!nCombos)
+ return;
+
+ jplots = json_object_new_array();
+ for (int i = 0; i < nCombos; ++i) {
+ jcombo = json_object_new_array();
+
+ var = glw->_comboPlots[i]._hostStreamId;
+ json_object_array_put_idx(jcombo, 0, json_object_new_int(var));
+
+ var = glw->_comboPlots[i]._hostPid;
+ json_object_array_put_idx(jcombo, 1, json_object_new_int(var));
+
+ var = glw->_comboPlots[i]._guestStreamId;
+ json_object_array_put_idx(jcombo, 2, json_object_new_int(var));
+
+ var = glw->_comboPlots[i]._vcpu;
+ json_object_array_put_idx(jcombo, 3, json_object_new_int(var));
+
+ json_object_array_put_idx(jplots, i, jcombo);
+ }
+
+ combos->conf_doc = jplots;
+ kshark_config_doc_add(_config, "ComboPlots", combos);
+}
+
+QVector<int> KsSession::_getPlots(int sd, bool cpu)
+{
+ kshark_config_doc *streamsConf = kshark_config_alloc(KS_CONFIG_JSON);
+ json_object *jallStreams, *jstream, *jstreamId, *jplots;
+ int nStreams, nPlots, id;
+ const char *plotKey;
+ QVector<int> plots;
+
+ if (!kshark_config_doc_get(_config, "data streams", streamsConf) ||
+ streamsConf->format != KS_CONFIG_JSON)
+ return plots;
+
+ jallStreams = KS_JSON_CAST(streamsConf->conf_doc);
+ if (json_object_get_type(jallStreams) != json_type_array)
+ return plots;
+
+ nStreams = json_object_array_length(jallStreams);
+ for (int i = 0; i < nStreams; ++i) {
+ jstream = json_object_array_get_idx(jallStreams, i);
+ if (json_object_object_get_ex(jstream, "stream id", &jstreamId) &&
+ json_object_get_int(jstreamId) == sd)
+ break;
+
+ jstream = nullptr;
+ }
+
+ if (!jstream)
+ return plots;
+
+ if (cpu)
+ plotKey = "CPUPlots";
+ else
+ plotKey = "TaskPlots";
+
+ if (!json_object_object_get_ex(jstream, plotKey, &jplots) ||
+ json_object_get_type(jplots) != json_type_array)
+ return plots;
+
+ nPlots = json_object_array_length(jplots);
+ for (int i = 0; i < nPlots; ++i) {
+ id = json_object_get_int(json_object_array_get_idx(jplots, i));
+ plots.append(id);
+ }
+
+ return plots;
+}
+
+QVector<int> KsSession::_getCPUPlots(int sd)
+{
+ return _getPlots(sd, true);
+}
+
+QVector<int> KsSession::_getTaskPlots(int sd)
+{
+ return _getPlots(sd, false);
+}
+
+QVector<QVector<int>> KsSession::_getComboPlots()
+{
+ kshark_config_doc *combos = kshark_config_alloc(KS_CONFIG_JSON);
+ int nPlots, sdHost, sdGuest, pidHost, vcpu;
+ json_object *jplots, *jcombo;
+ QVector<QVector<int>> vec;
+
+ if (!kshark_config_doc_get(_config, "ComboPlots", combos))
+ return vec;
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);
+ jplots = KS_JSON_CAST(combos->conf_doc);
+ if (json_object_get_type(jplots) != json_type_array)
+ return vec;
+
+ nPlots = json_object_array_length(jplots);
+ for (int i = 0; i < nPlots; ++i) {
+ jcombo = json_object_array_get_idx(jplots, i);
+ if (json_object_get_type(jcombo) != json_type_array)
+ return vec;
+
+ sdHost = json_object_get_int(json_object_array_get_idx(jcombo, 0));
+ pidHost = json_object_get_int(json_object_array_get_idx(jcombo, 1));
+ sdGuest = json_object_get_int(json_object_array_get_idx(jcombo, 2));
+ vcpu = json_object_get_int(json_object_array_get_idx(jcombo, 3));
+
+ vec.append({sdHost, pidHost, sdGuest, vcpu});
}
}
- 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;
+ return vec;
}
/**
@@ -531,31 +722,31 @@
*/
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);
+// 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);
}
/**
@@ -566,35 +757,35 @@
*/
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);
+// 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);
}
diff --git a/kernel-shark/src/KsSession.hpp b/kernel-shark/src/KsSession.hpp
index b07c810..44ac2e1 100644
--- a/kernel-shark/src/KsSession.hpp
+++ b/kernel-shark/src/KsSession.hpp
@@ -49,13 +49,20 @@
void loadVisModel(KsGraphModel *model);
- void saveGraphs(const KsGLWidget &glw);
+ void saveGraphs(kshark_context *kshark_ctx,
+ KsTraceGraph &graphs);
- void loadGraphs(KsTraceGraph *graphs);
+ void loadGraphs(kshark_context *kshark_ctx,
+ KsTraceGraph &graphs);
- void saveFilters(kshark_context *kshark_ctx);
+ void saveFilters(kshark_context *kshark_ctx, const QString &fileName);
- void loadFilters(kshark_context *kshark_ctx, KsDataStore *data);
+ void loadFilters(kshark_context *kshark_ctx, const QString &fileName,
+ KsDataStore *data);
+
+ void saveDataStreams(kshark_context *kshark_ctx);
+
+ void loadDataStreams(kshark_context *kshark_ctx, KsDataStore *data);
void saveMainWindowSize(const QMainWindow &window);
@@ -86,13 +93,21 @@
json_object *_getMarkerJson();
- void _saveCPUPlots(const QVector<int> &cpus);
+ void _savePlots(int sd, KsGLWidget *glw, bool cpu);
- QVector<int> _getCPUPlots();
+ QVector<int> _getPlots(int sd, bool cpu);
- void _saveTaskPlots(const QVector<int> &tasks);
+ void _saveCPUPlots(int sd, KsGLWidget *glw);
- QVector<int> _getTaskPlots();
+ QVector<int> _getCPUPlots(int sd);
+
+ void _saveTaskPlots(int sd, KsGLWidget *glw);
+
+ QVector<int> _getTaskPlots(int sd);
+
+ void _saveComboPlots(KsGLWidget *glw);
+
+ QVector<QVector<int>> _getComboPlots();
bool _getMarker(const char* name, size_t *pos);
diff --git a/kernel-shark/src/KsTraceGraph.cpp b/kernel-shark/src/KsTraceGraph.cpp
index 6087e96..dd3f9bd 100644
--- a/kernel-shark/src/KsTraceGraph.cpp
+++ b/kernel-shark/src/KsTraceGraph.cpp
@@ -271,8 +271,9 @@
_keyPressed = false;
}
-void KsTraceGraph::_resetPointer(uint64_t ts, int cpu, int pid)
+void KsTraceGraph::_resetPointer(uint64_t ts, int sd, int cpu, int pid)
{
+ struct kshark_data_stream *stream;
uint64_t sec, usec;
QString pointer;
@@ -286,7 +287,11 @@
if (!kshark_instance(&kshark_ctx))
return;
- QString comm(tep_data_comm_from_pid(kshark_ctx->pevent, pid));
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return;
+
+ QString comm(tep_data_comm_from_pid(stream->pevent, pid));
comm.append("-");
comm.append(QString("%1").arg(pid));
_labelI1.setText(comm);
@@ -309,7 +314,7 @@
QString info(kshark_get_info_easy(e));
QString comm(kshark_get_task_easy(e));
QString pointer, elidedText;
- int labelWidth, width;
+ int labelWidth;
uint64_t sec, usec;
kshark_convert_nano(e->ts, &sec, &usec);
@@ -335,16 +340,7 @@
* The Info string is too long and cannot be displayed on the toolbar.
* Try to fit the text in the available space.
*/
- QFontMetrics metrix(_labelI5.font());
- width = labelWidth - FONT_WIDTH * 3;
- elidedText = metrix.elidedText(info, Qt::ElideRight, width);
-
- while(labelWidth < STRING_WIDTH(elidedText) + FONT_WIDTH * 5) {
- width -= FONT_WIDTH * 3;
- elidedText = metrix.elidedText(info, Qt::ElideRight, width);
- }
-
- _labelI5.setText(elidedText);
+ KsUtils::setElidedText(&_labelI5, info, Qt::ElideRight, labelWidth);
_labelI5.setVisible(true);
QCoreApplication::processEvents();
}
@@ -356,55 +352,44 @@
*/
void KsTraceGraph::markEntry(size_t row)
{
- int graph, cpuGrId, taskGrId;
-
- _glWindow.findGraphIds(*_data->rows()[row], &cpuGrId, &taskGrId);
+ int yPosVis(-1);
/*
* If a Task graph has been found, this Task graph will be
* visible. If no Task graph has been found, make visible
* the corresponding CPU graph.
*/
- if (taskGrId >= 0)
- graph = taskGrId;
- else
- graph = cpuGrId;
+ if (_mState->activeMarker()._mark.comboIsVisible())
+ yPosVis = _mState->activeMarker()._mark.comboY();
+ else if (_mState->activeMarker()._mark.taskIsVisible())
+ yPosVis = _mState->activeMarker()._mark.taskY();
+ else if (_mState->activeMarker()._mark.cpuIsVisible())
+ yPosVis = _mState->activeMarker()._mark.cpuY();
- _scrollArea.ensureVisible(0,
- _legendAxisX.height() +
- _glWindow.vMargin() +
- KS_GRAPH_HEIGHT / 2 +
- graph*(KS_GRAPH_HEIGHT + _glWindow.vSpacing()),
- 50,
- KS_GRAPH_HEIGHT / 2 + _glWindow.vSpacing() / 2);
+ if (yPosVis > 0)
+ _scrollArea.ensureVisible(0, yPosVis);
_glWindow.model()->jumpTo(_data->rows()[row]->ts);
- _mState->activeMarker().set(*_data,
- _glWindow.model()->histo(),
- row, cpuGrId, taskGrId);
+ _mState->activeMarker().set(*_data, _glWindow.model()->histo(),
+ row, _data->rows()[row]->stream_id);
_mState->updateMarkers(*_data, &_glWindow);
}
void KsTraceGraph::_markerReDraw()
{
- int cpuGrId, taskGrId;
size_t row;
if (_mState->markerA()._isSet) {
row = _mState->markerA()._pos;
- _glWindow.findGraphIds(*_data->rows()[row], &cpuGrId, &taskGrId);
- _mState->markerA().set(*_data,
- _glWindow.model()->histo(),
- row, cpuGrId, taskGrId);
+ _mState->markerA().set(*_data, _glWindow.model()->histo(),
+ row, _data->rows()[row]->stream_id);
}
if (_mState->markerB()._isSet) {
row = _mState->markerB()._pos;
- _glWindow.findGraphIds(*_data->rows()[row], &cpuGrId, &taskGrId);
- _mState->markerB().set(*_data,
- _glWindow.model()->histo(),
- row, cpuGrId, taskGrId);
+ _mState->markerB().set(*_data, _glWindow.model()->histo(),
+ row, _data->rows()[row]->stream_id);
}
}
@@ -413,9 +398,11 @@
*
* @param v: CPU ids to be plotted.
*/
-void KsTraceGraph::cpuReDraw(QVector<int> v)
+void KsTraceGraph::cpuReDraw(int sd, QVector<int> v)
{
- _glWindow._cpuList = v;
+ if (_glWindow._streamPlots.contains(sd))
+ _glWindow._streamPlots[sd]._cpuList = v;
+
_selfUpdate();
}
@@ -424,51 +411,72 @@
*
* @param v: Process ids of the tasks to be plotted.
*/
-void KsTraceGraph::taskReDraw(QVector<int> v)
+void KsTraceGraph::taskReDraw(int sd, QVector<int> v)
{
- _glWindow._taskList = v;
+ if (_glWindow._streamPlots.contains(sd))
+ _glWindow._streamPlots[sd]._taskList = v;
+
+ _selfUpdate();
+}
+
+void KsTraceGraph::comboReDraw(int sd, QVector<int> v)
+{
+ KsVirtComboPlot combo;
+
+ combo._hostStreamId = v[0];
+ combo._hostPid = v[1];
+ combo._guestStreamId = v[2];
+ combo._vcpu = v[3];
+ combo._hostBase = 0;
+ combo._vcpuBase = 0;
+
+// if (_glWindow._comboPlots.contains(combo))
+// return;
+
+ _glWindow._comboPlots.append(combo);
+
_selfUpdate();
}
/** Add (and plot) a CPU graph to the existing list of CPU graphs. */
-void KsTraceGraph::addCPUPlot(int cpu)
+void KsTraceGraph::addCPUPlot(int sd, int cpu)
{
- if (_glWindow._cpuList.contains(cpu))
+ if (_glWindow._streamPlots[sd]._cpuList.contains(cpu))
return;
- _glWindow._cpuList.append(cpu);
- qSort(_glWindow._cpuList);
+ _glWindow._streamPlots[sd]._cpuList.append(cpu);
+ qSort(_glWindow._streamPlots[sd]._cpuList);
_selfUpdate();
}
/** Add (and plot) a Task graph to the existing list of Task graphs. */
-void KsTraceGraph::addTaskPlot(int pid)
+void KsTraceGraph::addTaskPlot(int sd, int pid)
{
- if (_glWindow._taskList.contains(pid))
+ if (_glWindow._streamPlots[sd]._taskList.contains(pid))
return;
- _glWindow._taskList.append(pid);
- qSort(_glWindow._taskList);
+ _glWindow._streamPlots[sd]._taskList.append(pid);
+ qSort(_glWindow._streamPlots[sd]._taskList);
_selfUpdate();
}
/** Remove a CPU graph from the existing list of CPU graphs. */
-void KsTraceGraph::removeCPUPlot(int cpu)
+void KsTraceGraph::removeCPUPlot(int sd, int cpu)
{
- if (!_glWindow._cpuList.contains(cpu))
+ if (!_glWindow._streamPlots[sd]._cpuList.contains(cpu))
return;
- _glWindow._cpuList.removeAll(cpu);
+ _glWindow._streamPlots[sd]._cpuList.removeAll(cpu);
_selfUpdate();
}
/** Remove a Task graph from the existing list of Task graphs. */
-void KsTraceGraph::removeTaskPlot(int pid)
+void KsTraceGraph::removeTaskPlot(int sd, int pid)
{
- if (!_glWindow._taskList.contains(pid))
+ if (!_glWindow._streamPlots[sd]._taskList.contains(pid))
return;
- _glWindow._taskList.removeAll(pid);
+ _glWindow._streamPlots[sd]._taskList.removeAll(pid);
_selfUpdate();
}
@@ -544,7 +552,7 @@
{
QString graphLegends, graphName;
QVBoxLayout *layout;
- int width = 0;
+ int sd, width = 0;
if (_legendWindow.layout()) {
/*
@@ -565,28 +573,47 @@
layout->setAlignment(Qt::AlignTop);
layout->addSpacing(_glWindow.vMargin());
- auto lamMakeName = [&]() {
- QLabel *name = new QLabel(graphName);
-
+ auto lamMaxWidth = [&]() {
if (width < STRING_WIDTH(graphName))
width = STRING_WIDTH(graphName);
-
- name->setAlignment(Qt::AlignBottom);
- name->setStyleSheet("QLabel {background-color : white;}");
- name->setFixedHeight(KS_GRAPH_HEIGHT);
- layout->addWidget(name);
};
- for (auto const &cpu: _glWindow._cpuList) {
- graphName = QString("CPU %1").arg(cpu);
- lamMakeName();
+ auto lamMakeName = [&]() {
+ QVariant color = KsUtils::getStreamColor(sd);
+ QLabel *name = new QLabel(graphName);
+ QString styleSheet =
+ "background-color : " + color.toString() + ";";
+
+ name->setStyleSheet(styleSheet);
+ name->setFixedHeight(KS_GRAPH_HEIGHT);
+ layout->addWidget(name);
+ lamMaxWidth();
+ };
+
+ for (auto it = _glWindow._streamPlots.constBegin();
+ it != _glWindow._streamPlots.constEnd();
+ ++it) {
+ sd = it.key();
+ for (auto const &cpu: _glWindow._streamPlots[sd]._cpuList) {
+ graphName = QString(" CPU %1 ").arg(cpu);
+ lamMakeName();
+ }
+
+ for (auto const &pid: _glWindow._streamPlots[sd]._taskList) {
+ graphName =
+ QString(tep_data_comm_from_pid(_data->tep(sd), pid));
+ graphName.append(QString("-%1 ").arg(pid));
+ lamMakeName();
+ }
}
- for (auto const &pid: _glWindow._taskList) {
- graphName = QString(tep_data_comm_from_pid(_data->tep(),
- pid));
- graphName.append(QString("-%1").arg(pid));
- lamMakeName();
+ for (auto const &p: _glWindow._comboPlots) {
+ graphName = QString(" vCPU %1 \n\nHost-%2").arg(p._vcpu)
+ .arg(p._hostPid);
+ QLabel *name = new QLabel(graphName);
+ name->setFixedHeight(KS_GRAPH_HEIGHT * 2);
+ layout->addWidget(name);
+ lamMaxWidth();
}
_legendWindow.setLayout(layout);
@@ -718,7 +745,7 @@
void KsTraceGraph::_onCustomContextMenu(const QPoint &point)
{
KsQuickMarkerMenu *menu(nullptr);
- int cpu, pid;
+ int sd, cpu, pid;
size_t row;
bool found;
@@ -726,8 +753,8 @@
if (found) {
/* KernelShark entry has been found under the cursor. */
KsQuickContextMenu *entryMenu;
- menu = entryMenu = new KsQuickContextMenu(_data, row,
- _mState, this);
+ menu = entryMenu = new KsQuickContextMenu(_mState, _data, row,
+ this);
connect(entryMenu, &KsQuickContextMenu::addTaskPlot,
this, &KsTraceGraph::addTaskPlot);
@@ -741,34 +768,35 @@
connect(entryMenu, &KsQuickContextMenu::removeCPUPlot,
this, &KsTraceGraph::removeCPUPlot);
} else {
- cpu = _glWindow.getPlotCPU(point);
+ if (!_glWindow.getPlotInfo(point, &sd, &cpu, &pid))
+ return;
+
if (cpu >= 0) {
/*
* This is a CPU plot, but we do not have an entry
* under the cursor.
*/
KsRmCPUPlotMenu *rmMenu;
- menu = rmMenu = new KsRmCPUPlotMenu(_mState, cpu, this);
+ menu = rmMenu = new KsRmCPUPlotMenu(_mState, sd, cpu, this);
- auto lamRmPlot = [&cpu, this] () {
- removeCPUPlot(cpu);
+ auto lamRmPlot = [&sd, &cpu, this] () {
+ removeCPUPlot(sd, cpu);
};
connect(rmMenu, &KsRmPlotContextMenu::removePlot,
lamRmPlot);
}
- pid = _glWindow.getPlotPid(point);
if (pid >= 0) {
/*
* This is a Task plot, but we do not have an entry
* under the cursor.
*/
KsRmTaskPlotMenu *rmMenu;
- menu = rmMenu = new KsRmTaskPlotMenu(_mState, pid, this);
+ menu = rmMenu = new KsRmTaskPlotMenu(_mState, sd, pid, this);
- auto lamRmPlot = [&pid, this] () {
- removeTaskPlot(pid);
+ auto lamRmPlot = [&sd, &pid, this] () {
+ removeTaskPlot(sd, pid);
};
connect(rmMenu, &KsRmPlotContextMenu::removePlot,
diff --git a/kernel-shark/src/KsTraceGraph.hpp b/kernel-shark/src/KsTraceGraph.hpp
index c53258c..b786bc4 100644
--- a/kernel-shark/src/KsTraceGraph.hpp
+++ b/kernel-shark/src/KsTraceGraph.hpp
@@ -52,17 +52,19 @@
void markEntry(size_t);
- void cpuReDraw(QVector<int>);
+ void cpuReDraw(int sd, QVector<int>cpus);
- void taskReDraw(QVector<int>);
+ void taskReDraw(int sd, QVector<int> pids);
- void addCPUPlot(int);
+ void comboReDraw(int sd, QVector<int> v);
- void addTaskPlot(int);
+ void addCPUPlot(int sd, int cpu);
- void removeCPUPlot(int);
+ void addTaskPlot(int sd, int cpu);
- void removeTaskPlot(int);
+ void removeCPUPlot(int sd, int cpu);
+
+ void removeTaskPlot(int sd, int cpu);
void update(KsDataStore *data);
@@ -81,7 +83,6 @@
void deselect();
private:
-
void _zoomIn();
void _zoomOut();
@@ -96,7 +97,7 @@
void _stopUpdating();
- void _resetPointer(uint64_t ts, int cpu, int pid);
+ void _resetPointer(uint64_t ts, int sd, int cpu, int pid);
void _setPointerInfo(size_t);
diff --git a/kernel-shark/src/KsTraceViewer.cpp b/kernel-shark/src/KsTraceViewer.cpp
index 4e2c93e..1a0e9a2 100644
--- a/kernel-shark/src/KsTraceViewer.cpp
+++ b/kernel-shark/src/KsTraceViewer.cpp
@@ -245,7 +245,8 @@
* of the row number in the source model.
*/
size_t row = _proxyModel.mapRowFromSource(i.row());
- KsQuickContextMenu menu(_data, row, _mState, this);
+
+ KsQuickContextMenu menu(_mState, _data, row, this);
/*
* Note that this slot was connected to the
@@ -457,7 +458,7 @@
/** Switch the Dual marker. */
void KsTraceViewer::markSwitch()
{
- int row;
+ size_t row;
/* The state of the Dual marker has changed. Get the new active marker. */
DualMarkerState state = _mState->getState();
@@ -488,7 +489,7 @@
* The index in the source model is used to retrieve the value
* of the row number in the proxy model.
*/
- size_t row =_mState->getMarker(state)._pos;
+ row =_mState->getMarker(state)._pos;
QModelIndex index =
_proxyModel.mapFromSource(_model.index(row, 0));
@@ -558,20 +559,29 @@
void KsTraceViewer::_resizeToContents()
{
- int rows, columnSize;
+ int col, rows, columnSize;
_view.setVisible(false);
_view.resizeColumnsToContents();
_view.setVisible(true);
/*
- * Because of some unknown reason the first column doesn't get
+ * Because of some unknown reason some of the columns doesn't get
* resized properly by the code above. We will resize this
* column by hand.
*/
+ col = KsViewModel::TRACE_VIEW_STREAM_ID;
+ columnSize = STRING_WIDTH(_model.header()[col]) + FONT_WIDTH;
+ _view.setColumnWidth(col, columnSize);
+
+ col = KsViewModel::TRACE_VIEW_COL_CPU;
+ columnSize = STRING_WIDTH(_model.header()[col]) + FONT_WIDTH * 2;
+ _view.setColumnWidth(col, columnSize);
+
+ col = KsViewModel::TRACE_VIEW_COL_INDEX;
rows = _model.rowCount({});
columnSize = STRING_WIDTH(QString("%1").arg(rows)) + FONT_WIDTH;
- _view.setColumnWidth(0, columnSize);
+ _view.setColumnWidth(col, columnSize);
}
//! @cond Doxygen_Suppress
diff --git a/kernel-shark/src/KsTraceViewer.hpp b/kernel-shark/src/KsTraceViewer.hpp
index cf529ba..2176671 100644
--- a/kernel-shark/src/KsTraceViewer.hpp
+++ b/kernel-shark/src/KsTraceViewer.hpp
@@ -82,7 +82,7 @@
* This signal is used to re-emitted the addTaskPlot signal of the
* KsQuickContextMenu.
*/
- void addTaskPlot(int pid);
+ void addTaskPlot(int sd, int pid);
/**
* This signal is used to re-emitted the deselect signal of the
diff --git a/kernel-shark/src/KsUtils.cpp b/kernel-shark/src/KsUtils.cpp
index 6af0c66..49b8a3b 100644
--- a/kernel-shark/src/KsUtils.cpp
+++ b/kernel-shark/src/KsUtils.cpp
@@ -14,8 +14,12 @@
namespace KsUtils {
-/** @brief Get a sorted vector of Task's Pids. */
-QVector<int> getPidList()
+/**
+ * @brief Get a sorteg vector of Task's Pids.
+ *
+ * @param sd: Data stream identifier.
+ */
+QVector<int> getPidList(int sd)
{
kshark_context *kshark_ctx(nullptr);
int nTasks, *tempPids;
@@ -24,7 +28,7 @@
if (!kshark_instance(&kshark_ctx))
return pids;
- nTasks = kshark_get_task_pids(kshark_ctx, &tempPids);
+ nTasks = kshark_get_task_pids(kshark_ctx, sd, &tempPids);
for (int r = 0; r < nTasks; ++r) {
pids.append(tempPids[r]);
}
@@ -125,15 +129,37 @@
*
* @param kshark_ctx: Input location for the session context pointer.
* @param e: kshark_entry to be checked.
+ * @param sd: Data stream identifier.
* @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)
+ struct kshark_entry *e, int sd, int *cpu)
{
- return (e->cpu == cpu && (e->visible & KS_GRAPH_VIEW_FILTER_MASK));
+ return (e->cpu == *cpu &&
+ e->stream_id == sd &&
+ (e->visible & KS_GRAPH_VIEW_FILTER_MASK));
+}
+
+void setElidedText(QLabel* label, QString text,
+ enum Qt::TextElideMode mode,
+ int labelWidth)
+{
+ QFontMetrics metrix(label->font());
+ QString elidedText;
+ int textWidth;
+
+ textWidth = labelWidth - FONT_WIDTH * 3;
+ elidedText = metrix.elidedText(text, Qt::ElideRight, textWidth);
+
+ while(labelWidth < STRING_WIDTH(elidedText) + FONT_WIDTH * 5) {
+ textWidth -= FONT_WIDTH * 3;
+ elidedText = metrix.elidedText(text, mode, textWidth);
+ }
+
+ label->setText(elidedText);
}
}; // KsUtils
@@ -149,7 +175,6 @@
/** Create a default (empty) KsDataStore. */
KsDataStore::KsDataStore(QWidget *parent)
: QObject(parent),
- _tep(nullptr),
_rows(nullptr),
_dataSize(0)
{}
@@ -158,34 +183,101 @@
KsDataStore::~KsDataStore()
{}
-/** Load trace data for file. */
-void KsDataStore::loadDataFile(const QString &file)
+int KsDataStore::_openDataFile(kshark_context *kshark_ctx,
+ const QString &file)
{
- kshark_context *kshark_ctx(nullptr);
+ int sd;
- if (!kshark_instance(&kshark_ctx))
- return;
-
- clear();
-
- if (!kshark_open(kshark_ctx, file.toStdString().c_str())) {
- qCritical() << "ERROR Loading file " << file;
- return;
+ sd = kshark_open(kshark_ctx, file.toStdString().c_str());
+ if (sd < 0) {
+ qCritical() << "ERROR" << sd << "while loading file " << file;
+ return sd;
}
- _tep = kshark_ctx->pevent;
+ kshark_handle_all_plugins(kshark_ctx, sd, KSHARK_PLUGIN_UPDATE);
- if (kshark_ctx->event_handlers == nullptr)
- kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT);
- else
- kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_UPDATE);
+ return sd;
+}
- _dataSize = kshark_load_data_entries(kshark_ctx, &_rows);
+/** Load trace data for file. */
+int KsDataStore::loadDataFile(const QString &file)
+{
+ kshark_context *kshark_ctx(nullptr);
+ ssize_t n;
+ int sd;
+
+ if (!kshark_instance(&kshark_ctx))
+ return -EFAULT;
+
+ clear();
+ _unregisterCPUCollections();
+
+ sd = _openDataFile(kshark_ctx, file);
+ n = kshark_load_data_entries(kshark_ctx, sd, &_rows);
+ if (n < 0) {
+ kshark_close(kshark_ctx, sd);
+ return n;
+ }
+
+ _dataSize = n;
+ registerCPUCollections();
+
+ return sd;
+}
+
+/**
+ * @brief Append a trace data file to the data-set that is already loaded.
+ * The clock of the new data will be calibrated in order to be
+ * compatible with the clock of the prior data.
+ *
+ * @param file: Trace data file, to be append to the already loaded data.
+ * @param calib: Callback function providing the calibration of the clock of
+ * the associated data.
+ * @param argv: Array of arguments for the calibration function.
+ */
+int KsDataStore::appendDataFile(const QString &file, int64_t shift)
+{
+ kshark_context *kshark_ctx(nullptr);
+ struct kshark_entry **apndRows = NULL;
+ struct kshark_entry **mergedRows;
+ ssize_t nApnd = 0;
+ int sd;
+
+ if (!kshark_instance(&kshark_ctx))
+ return -EFAULT;
+
+ _unregisterCPUCollections();
+
+ sd = _openDataFile(kshark_ctx, file);
+
+ kshark_ctx->stream[sd]->calib = kshark_offset_calib;
+ kshark_ctx->stream[sd]->calib_array = new int64_t;
+ *(kshark_ctx->stream[sd]->calib_array) = shift;
+ kshark_ctx->stream[sd]->calib_array_size = 1;
+
+ nApnd = kshark_load_data_entries(kshark_ctx, sd, &apndRows);
+ if (nApnd < 0) {
+ kshark_close(kshark_ctx, sd);
+ return nApnd;
+ }
+
+ mergedRows = kshark_data_merge(_rows, _dataSize,
+ apndRows, nApnd);
+
+ free(_rows);
+ free(apndRows);
+
+ _dataSize += nApnd;
+ _rows = mergedRows;
+
+ registerCPUCollections();
+
+ return sd;
}
void KsDataStore::_freeData()
{
- if (_dataSize) {
+ if (_dataSize > 0) {
for (size_t r = 0; r < _dataSize; ++r)
free(_rows[r]);
@@ -206,8 +298,14 @@
_freeData();
- _dataSize = kshark_load_data_entries(kshark_ctx, &_rows);
- _tep = kshark_ctx->pevent;
+ if (kshark_ctx->n_streams == 0)
+ return;
+
+ _unregisterCPUCollections();
+
+ _dataSize = kshark_load_all_data_entries(kshark_ctx, &_rows);
+
+ registerCPUCollections();
emit updateWidgets(this);
}
@@ -217,11 +315,26 @@
{
kshark_context *kshark_ctx(nullptr);
- _freeData();
- _tep = nullptr;
+ if (!kshark_instance(&kshark_ctx))
+ return;
- if (kshark_instance(&kshark_ctx) && kshark_ctx->handle)
- kshark_close(kshark_ctx);
+ _freeData();
+ kshark_close_all(kshark_ctx);
+}
+
+/** Get the trace event parser for a given data stream. */
+tep_handle *KsDataStore::tep(int sd) const {
+ kshark_context *kshark_ctx(nullptr);
+ kshark_data_stream *stream;
+
+ if (!kshark_instance(&kshark_ctx))
+ return nullptr;
+
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (stream)
+ return stream->pevent;
+
+ return nullptr;
}
/** Update the visibility of the entries (filter). */
@@ -234,91 +347,107 @@
_unregisterCPUCollections();
- if (kshark_filter_is_set(kshark_ctx)) {
- kshark_filter_entries(kshark_ctx, _rows, _dataSize);
- emit updateWidgets(this);
- }
+ kshark_filter_all_entries(kshark_ctx, _rows, _dataSize);
registerCPUCollections();
+
+ emit updateWidgets(this);
}
/** Register a collection of visible entries for each CPU. */
void KsDataStore::registerCPUCollections()
{
+ qInfo() << "@ registerCPUCollections";
kshark_context *kshark_ctx(nullptr);
+ int *streamIds, nCPUs, sd;
- if (!kshark_instance(&kshark_ctx) ||
- !kshark_filter_is_set(kshark_ctx))
+ if (!kshark_instance(&kshark_ctx))
return;
- int nCPUs = tep_get_cpus(_tep);
- for (int cpu = 0; cpu < nCPUs; ++cpu) {
- kshark_register_data_collection(kshark_ctx,
- _rows, _dataSize,
- KsUtils::matchCPUVisible,
- cpu,
- 0);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+
+ nCPUs = tep_get_cpus(kshark_ctx->stream[sd]->pevent);
+ for (int cpu = 0; cpu < nCPUs; ++cpu) {
+ kshark_register_data_collection(kshark_ctx,
+ _rows, _dataSize,
+ KsUtils::matchCPUVisible,
+ sd, &cpu, 1,
+ 0);
+ }
}
+
+ free(streamIds);
}
void KsDataStore::_unregisterCPUCollections()
{
kshark_context *kshark_ctx(nullptr);
-
+ int *streamIds, nCPUs, sd;
+ qInfo() << "@@ unregisterCPUCollections";
if (!kshark_instance(&kshark_ctx))
return;
- int nCPUs = tep_get_cpus(_tep);
- for (int cpu = 0; cpu < nCPUs; ++cpu) {
- kshark_unregister_data_collection(&kshark_ctx->collections,
- KsUtils::matchCPUVisible,
- cpu);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
+ if (!kshark_filter_is_set(kshark_ctx, sd))
+ continue;
+
+ nCPUs = tep_get_cpus(kshark_ctx->stream[sd]->pevent);
+ for (int cpu = 0; cpu < nCPUs; ++cpu) {
+ kshark_unregister_data_collection(&kshark_ctx->collections,
+ KsUtils::matchCPUVisible,
+ sd, &cpu, 1);
+ }
}
+
+ free(streamIds);
}
-void KsDataStore::_applyIdFilter(int filterId, QVector<int> vec)
+void KsDataStore::_applyIdFilter(int filterId, QVector<int> vec, int sd)
{
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);
+ kshark_filter_clear(kshark_ctx, sd, KS_SHOW_EVENT_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, 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);
+ kshark_filter_clear(kshark_ctx, sd, KS_SHOW_TASK_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_HIDE_TASK_FILTER);
break;
case KS_SHOW_CPU_FILTER:
case KS_HIDE_CPU_FILTER:
- kshark_filter_clear(kshark_ctx, KS_SHOW_CPU_FILTER);
- kshark_filter_clear(kshark_ctx, KS_HIDE_CPU_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_SHOW_CPU_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_HIDE_CPU_FILTER);
break;
default:
return;
}
for (auto &&val: vec)
- kshark_filter_add_id(kshark_ctx, filterId, val);
+ kshark_filter_add_id(kshark_ctx, sd, filterId, val);
- if (!_tep)
+ if (!kshark_ctx->n_streams)
return;
_unregisterCPUCollections();
/*
- * If the advanced event filter is set, the data has to be reloaded,
+ * 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)
+ if (kshark_ctx->stream[sd]->advanced_event_filter->filters)
reload();
else
- kshark_filter_entries(kshark_ctx, _rows, _dataSize);
+ kshark_filter_stream_entries(kshark_ctx, sd, _rows, _dataSize);
registerCPUCollections();
@@ -326,61 +455,105 @@
}
/** Apply Show Task filter. */
-void KsDataStore::applyPosTaskFilter(QVector<int> vec)
+void KsDataStore::applyPosTaskFilter(int sd, QVector<int> vec)
{
- _applyIdFilter(KS_SHOW_TASK_FILTER, vec);
+ kshark_context *kshark_ctx(nullptr);
+ int nTasks, *pids;
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ nTasks = kshark_get_task_pids(kshark_ctx, sd, &pids);
+ free(pids);
+ if (vec.count() == nTasks)
+ return;
+
+ _applyIdFilter(KS_SHOW_TASK_FILTER, vec, sd);
}
/** Apply Hide Task filter. */
-void KsDataStore::applyNegTaskFilter(QVector<int> vec)
+void KsDataStore::applyNegTaskFilter(int sd, QVector<int> vec)
{
- _applyIdFilter(KS_HIDE_TASK_FILTER, vec);
+ if (!vec.count())
+ return;
+
+ _applyIdFilter(KS_HIDE_TASK_FILTER, vec, sd);
}
/** Apply Show Event filter. */
-void KsDataStore::applyPosEventFilter(QVector<int> vec)
+void KsDataStore::applyPosEventFilter(int sd, QVector<int> vec)
{
- _applyIdFilter(KS_SHOW_EVENT_FILTER, vec);
+ _applyIdFilter(KS_SHOW_EVENT_FILTER, vec, sd);
}
/** Apply Hide Event filter. */
-void KsDataStore::applyNegEventFilter(QVector<int> vec)
+void KsDataStore::applyNegEventFilter(int sd, QVector<int> vec)
{
- _applyIdFilter(KS_HIDE_EVENT_FILTER, vec);
+ if (!vec.count())
+ return;
+
+ _applyIdFilter(KS_HIDE_EVENT_FILTER, vec, sd);
}
/** Apply Show CPU filter. */
-void KsDataStore::applyPosCPUFilter(QVector<int> vec)
+void KsDataStore::applyPosCPUFilter(int sd, QVector<int> vec)
{
- _applyIdFilter(KS_SHOW_CPU_FILTER, vec);
+ kshark_context *kshark_ctx(nullptr);
+ kshark_data_stream *stream;
+ int nCPUs;
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return;
+
+ nCPUs = tep_get_cpus(stream->pevent);
+ if (vec.count() == nCPUs)
+ return;
+
+ _applyIdFilter(KS_SHOW_CPU_FILTER, vec, sd);
}
/** Apply Hide CPU filter. */
-void KsDataStore::applyNegCPUFilter(QVector<int> vec)
+void KsDataStore::applyNegCPUFilter(int sd, QVector<int> vec)
{
- _applyIdFilter(KS_HIDE_CPU_FILTER, vec);
+ if (!vec.count())
+ return;
+
+ _applyIdFilter(KS_HIDE_CPU_FILTER, vec, sd);
}
/** Disable all filters. */
void KsDataStore::clearAllFilters()
{
kshark_context *kshark_ctx(nullptr);
+ int *streamIds, sd;
- if (!kshark_instance(&kshark_ctx) || !_tep)
+ if (!kshark_instance(&kshark_ctx) || !kshark_ctx->n_streams)
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);
- kshark_filter_clear(kshark_ctx, KS_SHOW_CPU_FILTER);
- kshark_filter_clear(kshark_ctx, KS_HIDE_CPU_FILTER);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i) {
+ sd = streamIds[i];
- tep_filter_reset(kshark_ctx->advanced_event_filter);
+ kshark_filter_clear(kshark_ctx, sd, KS_SHOW_TASK_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_HIDE_TASK_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_SHOW_EVENT_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_HIDE_EVENT_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_SHOW_CPU_FILTER);
+ kshark_filter_clear(kshark_ctx, sd, KS_HIDE_CPU_FILTER);
+
+ tep_filter_reset(kshark_ctx->stream[sd]->advanced_event_filter);
+ }
+
kshark_clear_all_filters(kshark_ctx, _rows, _dataSize);
+ free(streamIds);
+
emit updateWidgets(this);
}
@@ -400,6 +573,16 @@
registerFromList(kshark_ctx);
}
+KsPluginManager::~KsPluginManager()
+{
+ kshark_context *kshark_ctx(nullptr);
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ unregisterFromList(kshark_ctx);
+}
+
/** Parse the plugin list declared in the CMake-generated header file. */
void KsPluginManager::_parsePluginList()
{
@@ -423,6 +606,7 @@
*/
void KsPluginManager::registerFromList(kshark_context *kshark_ctx)
{
+ qInfo() << "registerFromList" << _ksPluginList;
auto lamRegBuiltIn = [&kshark_ctx](const QString &plugin)
{
char *lib;
@@ -433,6 +617,7 @@
if (n <= 0)
return;
+ qInfo() << "reg" << lib;
kshark_register_plugin(kshark_ctx, lib);
free(lib);
};
@@ -443,13 +628,19 @@
kshark_register_plugin(kshark_ctx, lib.c_str());
};
- _forEachInList(_ksPluginList,
- _registeredKsPlugins,
- lamRegBuiltIn);
+ for (auto const &p: _ksPluginList)
+ lamRegBuiltIn(p);
- _forEachInList(_userPluginList,
- _registeredUserPlugins,
- lamRegUser);
+ for (auto const &p: _userPluginList)
+ lamRegUser(p);
+
+// _forEachInList(_ksPluginList,
+// _registeredKsPlugins,
+// lamRegBuiltIn);
+
+// _forEachInList(_userPluginList,
+// _registeredUserPlugins,
+// lamRegUser);
}
/**
@@ -468,6 +659,7 @@
if (n <= 0)
return;
+ qInfo() << "u_reg" << lib;
kshark_unregister_plugin(kshark_ctx, lib);
free(lib);
};
@@ -478,13 +670,19 @@
kshark_unregister_plugin(kshark_ctx, lib.c_str());
};
- _forEachInList(_ksPluginList,
- _registeredKsPlugins,
- lamUregBuiltIn);
+ for (auto const &p: _ksPluginList)
+ lamUregBuiltIn(p);
- _forEachInList(_userPluginList,
- _registeredUserPlugins,
- lamUregUser);
+ for (auto const &p: _userPluginList)
+ lamUregUser(p);
+
+// _forEachInList(_ksPluginList,
+// _registeredKsPlugins,
+// lamUregBuiltIn);
+
+// _forEachInList(_userPluginList,
+// _registeredUserPlugins,
+// lamUregUser);
}
/**
@@ -579,8 +777,8 @@
}
return;
- } else if (plugin.contains("/lib/plugin-" +
- _ksPluginList[i], Qt::CaseInsensitive)) {
+ } else if (plugin.contains("/lib/plugin-" + _ksPluginList[i],
+ Qt::CaseInsensitive)) {
/*
* The argument is the name of the library .so file.
*/
@@ -623,11 +821,33 @@
void KsPluginManager::unloadAll()
{
kshark_context *kshark_ctx(nullptr);
+ int *streamIds;
if (!kshark_instance(&kshark_ctx))
return;
- kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_CLOSE);
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i)
+ kshark_handle_all_plugins(kshark_ctx, streamIds[i],
+ KSHARK_PLUGIN_CLOSE);
+
+ unregisterFromList(kshark_ctx);
+
+ kshark_free_plugin_list(kshark_ctx->plugins);
+ kshark_ctx->plugins = nullptr;
+ kshark_free_event_handler_list(kshark_ctx->event_handlers);
+}
+
+/** Unload all plugins. */
+void KsPluginManager::unload(int sd)
+{
+ kshark_context *kshark_ctx(nullptr);
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ kshark_handle_all_plugins(kshark_ctx, sd, KSHARK_PLUGIN_CLOSE);
+
kshark_free_plugin_list(kshark_ctx->plugins);
kshark_ctx->plugins = nullptr;
kshark_free_event_handler_list(kshark_ctx->event_handlers);
@@ -639,14 +859,68 @@
*
* @param pluginIds: The indexes of the plugins to be loaded.
*/
-void KsPluginManager::updatePlugins(QVector<int> pluginIds)
+// void KsPluginManager::updatePlugins(QVector<int> pluginIds)
+// {
+// kshark_context *kshark_ctx(nullptr);
+//
+// if (!kshark_instance(&kshark_ctx))
+// return;
+//
+// auto lamRegisterPlugins = [&] (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.
+// */
+// lamRegisterPlugins(pluginIds);
+// return;
+// }
+//
+// /* Clean up all old plugins first. */
+// unloadAll();
+//
+// /* Now load. */
+// lamRegisterPlugins(pluginIds);
+// kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT);
+//
+// emit dataReload();
+// }
+/** @brief Update (change) the Plugins.
+ *
+ * @param pluginIds: The indexes of the plugins to be loaded.
+ */
+void KsPluginManager::updatePlugins(int sd, QVector<int> pluginIds)
{
kshark_context *kshark_ctx(nullptr);
+// int *streamIds;
if (!kshark_instance(&kshark_ctx))
return;
- auto register_plugins = [&] (QVector<int> ids)
+ auto lamRegisterPlugins = [&] (QVector<int> ids)
{
int nKsPlugins = _registeredKsPlugins.count();
@@ -663,10 +937,10 @@
else
_registeredUserPlugins[p - nKsPlugins] = true;
}
- registerFromList(kshark_ctx);
+// registerFromList(kshark_ctx);
};
- if (!kshark_ctx->pevent) {
+ if (!kshark_ctx->n_streams) {
kshark_free_plugin_list(kshark_ctx->plugins);
kshark_ctx->plugins = nullptr;
@@ -675,16 +949,35 @@
* plugins. Handling of the plugins will be done after
* we load a data file.
*/
- register_plugins(pluginIds);
+ lamRegisterPlugins(pluginIds);
return;
}
- /* Clean up all old plugins first. */
- unloadAll();
+ /* First clean up all old plugins associated with this data stream. */
+// unload(sd);
/* Now load. */
- register_plugins(pluginIds);
- kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT);
+ lamRegisterPlugins(pluginIds);
- emit dataReload();
+// kshark_handle_plugins(kshark_ctx, sd, KSHARK_PLUGIN_INIT);
+
+// streamIds = kshark_all_streams(kshark_ctx);
+// for (int i = 0; i < kshark_ctx->n_streams; ++i)
+// emit dataReload(streamIds[i]);
+// free(streamIds);
+}
+
+void KsPluginManager::updatePlugins_hack(int sd, QVector<int> pluginIds)
+{
+ kshark_context *kshark_ctx(nullptr);
+ struct kshark_plugin_list *plugin;
+
+ qInfo() << "updatePlugins_hack" << sd << pluginIds;
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ for (plugin = kshark_ctx->plugins; plugin; plugin = plugin->next)
+ kshark_plugin_add_stream(plugin, sd);
+
+ kshark_handle_all_plugins(kshark_ctx, sd, KSHARK_PLUGIN_UPDATE);
}
diff --git a/kernel-shark/src/KsUtils.hpp b/kernel-shark/src/KsUtils.hpp
index c8b5e88..bb0d650 100644
--- a/kernel-shark/src/KsUtils.hpp
+++ b/kernel-shark/src/KsUtils.hpp
@@ -82,7 +82,7 @@
namespace KsUtils {
-QVector<int> getPidList();
+QVector<int> getPidList(int sd);
QVector<int> getFilterIds(tracecmd_filter_id *filter);
@@ -110,7 +110,23 @@
}
bool matchCPUVisible(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int cpu);
+ struct kshark_entry *e, int sd, int *cpu);
+
+void setElidedText(QLabel* label, QString text,
+ enum Qt::TextElideMode mode,
+ int labelWidth);
+
+
+#define KS_STREAM_COLOR_LIGHTNESS 30
+
+inline QColor getStreamColor(int sd)
+{
+ QColor col(Qt::GlobalColor(Qt::red + sd));
+ col.setAlpha(KS_STREAM_COLOR_LIGHTNESS);
+
+ return col;
+}
+
}; // KsUtils
/** Identifier of the Dual Marker active state. */
@@ -131,36 +147,41 @@
~KsDataStore();
- void loadDataFile(const QString &file);
+ int loadDataFile(const QString &file);
+
+ int appendDataFile(const QString &file, int64_t shift);
void clear();
- /** Get the trace event parser. */
- tep_handle *tep() const {return _tep;}
+ tep_handle *tep(int sd) const;
- /** Get the trace data array.. */
+ /** Get the trace data array. */
struct kshark_entry **rows() const {return _rows;}
+ struct kshark_entry ***rows_r() {return &_rows;}
+
/** Get the size of the data array. */
size_t size() const {return _dataSize;}
+ size_t *size_r() {return &_dataSize;}
+
void reload();
void update();
void registerCPUCollections();
- void applyPosTaskFilter(QVector<int>);
+ void applyPosTaskFilter(int sd, QVector<int> vec);
- void applyNegTaskFilter(QVector<int>);
+ void applyNegTaskFilter(int sd, QVector<int> vec);
- void applyPosEventFilter(QVector<int>);
+ void applyPosEventFilter(int sd, QVector<int> vec);
- void applyNegEventFilter(QVector<int>);
+ void applyNegEventFilter(int sd, QVector<int> vec);
- void applyPosCPUFilter(QVector<int>);
+ void applyPosCPUFilter(int sd, QVector<int> vec);
- void applyNegCPUFilter(QVector<int>);
+ void applyNegCPUFilter(int sd, QVector<int> vec);
void clearAllFilters();
@@ -172,27 +193,30 @@
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;
+ int _openDataFile(kshark_context *kshark_ctx, const QString &file);
+
void _freeData();
+
void _unregisterCPUCollections();
- void _applyIdFilter(int filterId, QVector<int> vec);
+
+ void _applyIdFilter(int filterId, QVector<int> vec, int sd);
};
-/** A Plugin Manage class. */
+/** A Plugin Manager class. */
class KsPluginManager : public QObject
{
Q_OBJECT
public:
explicit KsPluginManager(QWidget *parent = nullptr);
+ ~KsPluginManager();
+
/** A list of available built-in plugins. */
QStringList _ksPluginList;
@@ -214,12 +238,14 @@
void addPlugins(const QStringList &fileNames);
void unloadAll();
+ void unload(int sd);
- void updatePlugins(QVector<int> pluginId);
+ void updatePlugins(int sd, QVector<int> pluginId);
+ void updatePlugins_hack(int sd, QVector<int> pluginIds);
signals:
/** This signal is emitted when a plugin is loaded or unloaded. */
- void dataReload();
+ void dataReload(int sd);
private:
void _parsePluginList();
diff --git a/kernel-shark/src/KsWidgetsLib.cpp b/kernel-shark/src/KsWidgetsLib.cpp
index ea02b5e..fe1a22d 100644
--- a/kernel-shark/src/KsWidgetsLib.cpp
+++ b/kernel-shark/src/KsWidgetsLib.cpp
@@ -10,12 +10,13 @@
*/
// KernelShark
-#include "libkshark.h"
-#include "KsUtils.hpp"
#include "KsCmakeDef.hpp"
#include "KsPlotTools.hpp"
#include "KsWidgetsLib.hpp"
+namespace KsWidgetsLib
+{
+
/**
* @brief Create KsProgressBar.
*
@@ -76,9 +77,6 @@
this->setLayout(&_layout);
}
-namespace KsWidgetsLib
-{
-
/**
* @brief Launch a File exists dialog. Use this function to ask the user
* before overwriting an existing file.
@@ -111,15 +109,19 @@
* @param name: The name of this widget.
* @param parent: The parent of this widget.
*/
-KsCheckBoxWidget::KsCheckBoxWidget(const QString &name, QWidget *parent)
+KsCheckBoxWidget::KsCheckBoxWidget(int sd, const QString &name,
+ QWidget *parent)
: QWidget(parent),
_tb(this),
+ _sd(sd),
_allCb("all", &_tb),
+ _allCbAction(nullptr),
_cbWidget(this),
_cbLayout(&_cbWidget),
_topLayout(this),
+ _stramLabel("", this),
_name(name),
- _nameLabel(name + ": ",&_tb)
+ _nameLabel(name + ": ", &_tb)
{
setWindowTitle(_name);
setMinimumHeight(SCREEN_HEIGHT / 2);
@@ -129,8 +131,11 @@
_cbWidget.setLayout(&_cbLayout);
+ _topLayout.addWidget(&_stramLabel);
+
_tb.addWidget(&_nameLabel);
- _tb.addWidget(&_allCb);
+ _allCbAction = _tb.addWidget(&_allCb);
+
_topLayout.addWidget(&_tb);
_topLayout.addWidget(&_cbWidget);
@@ -138,6 +143,7 @@
setLayout(&_topLayout);
_allCb.setCheckState(Qt::Checked);
+// setVisibleCbAll(false);
}
/**
@@ -218,15 +224,19 @@
* @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),
+KsCheckBoxDialog::KsCheckBoxDialog(QVector<KsCheckBoxWidget *> cbws, QWidget *parent)
+: QDialog(parent), _checkBoxWidgets(cbws),
_applyButton("Apply", this),
_cancelButton("Cancel", this)
{
int buttonWidth;
- setWindowTitle(cbw->name());
- _topLayout.addWidget(_checkBoxWidget);
+ if (!cbws.isEmpty())
+ setWindowTitle(cbws[0]->name());
+
+ for (auto const &w: _checkBoxWidgets)
+ _cbLayout.addWidget(w);
+ _topLayout.addLayout(&_cbLayout);
buttonWidth = STRING_WIDTH("--Cancel--");
_applyButton.setFixedWidth(buttonWidth);
@@ -256,16 +266,170 @@
void KsCheckBoxDialog::_applyPress()
{
- QVector<int> vec = _checkBoxWidget->getCheckedIds();
- emit apply(vec);
+ QVector<int> vec;
/*
* Disconnect _applyButton. This is done in order to protect
* against multiple clicks.
*/
disconnect(_applyButtonConnection);
+
+ for (auto const &w: _checkBoxWidgets) {
+ vec = w->getCheckedIds();
+ emit apply(w->sd(), vec);
+ }
}
+KsComboPlotDialog::KsComboPlotDialog(QWidget *parent)
+: _hostStreamLabel("Host data stream:"),
+ _guestStreamLabel("Guest data stream"),
+ _hostStreamComboBox(this),
+ _guestStreamComboBox(this),
+ _vcpuCheckBoxWidget(nullptr),
+ _hostCheckBoxWidget(nullptr),
+ _applyButton("Apply", this),
+ _cancelButton("Cancel", this)
+{
+ kshark_context *kshark_ctx(nullptr);
+ int *streamIds, buttonWidth;
+ int sdHost(0), sdGuest(1);
+ QStringList streamList;
+
+ auto lamAddLine = [&] {
+ QFrame* line = new QFrame();
+
+ line->setFrameShape(QFrame::HLine);
+ line->setFrameShadow(QFrame::Sunken);
+ _topLayout.addWidget(line);
+ };
+
+ setWindowTitle("Combo Plots");
+
+ if (!kshark_instance(&kshark_ctx) ||
+ kshark_ctx->n_streams < 2)
+ return;
+
+ streamIds = kshark_all_streams(kshark_ctx);
+ _hostStreamComboBox.addItem(QString::number(streamIds[0]));
+ for (int i = 1; i < kshark_ctx->n_streams; ++i) {
+ _hostStreamComboBox.addItem(QString::number(streamIds[i]));
+ _guestStreamComboBox.addItem(QString::number(streamIds[i]));
+ }
+
+ _streamMenuLayout.addWidget(&_hostStreamLabel, 0, 0);
+ _streamMenuLayout.addWidget(&_hostStreamComboBox, 0, 1);
+
+ _streamMenuLayout.addWidget(&_guestStreamLabel, 1, 0);
+ _streamMenuLayout.addWidget(&_guestStreamComboBox, 1, 1);
+
+ _topLayout.addLayout(&_streamMenuLayout);
+
+ lamAddLine();
+
+ _hostCheckBoxWidget = new KsTasksCheckBoxWidget(sdHost, true, this);
+ _hostCheckBoxWidget->setStream(QString(kshark_ctx->stream[sdHost]->file));
+ _hostCheckBoxWidget->setSingleSelection();
+ _hostCheckBoxWidget->setDefault(false);
+
+ _vcpuCheckBoxWidget = new KsCPUCheckBoxWidget(sdGuest, this);
+ _vcpuCheckBoxWidget->setStream(QString(kshark_ctx->stream[sdGuest]->file));
+ _vcpuCheckBoxWidget->setSingleSelection();
+ _vcpuCheckBoxWidget->setDefault(false);
+
+ _cbLayout.addWidget(_hostCheckBoxWidget);
+ _cbLayout.addWidget(_vcpuCheckBoxWidget);
+
+ _topLayout.addLayout(&_cbLayout);
+
+ 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, &KsComboPlotDialog::_applyPress);
+
+ connect(&_applyButton, &QPushButton::pressed,
+ this, &QWidget::close);
+
+ connect(&_cancelButton, &QPushButton::pressed,
+ this, &QWidget::close);
+
+ /*
+ * Using the old Signal-Slot syntax because QComboBox::currentIndexChanged
+ * has overloads.
+ */
+ connect(&_hostStreamComboBox, SIGNAL(currentIndexChanged(const QString &)),
+ this, SLOT(_hostStreamChanged(const QString &)));
+
+ connect(&_guestStreamComboBox, SIGNAL(currentIndexChanged(const QString &)),
+ this, SLOT(_guestStreamChanged(const QString &)));
+
+ setLayout(&_topLayout);
+}
+
+void KsComboPlotDialog::_applyPress()
+{
+ QVector<int> combo(4);
+
+ /*
+ * Disconnect _applyButton. This is done in order to protect
+ * against multiple clicks.
+ */
+ disconnect(_applyButtonConnection);
+
+ combo[0] = _hostStreamComboBox.currentText().toInt();
+ combo[1] = _hostCheckBoxWidget->getCheckedIds()[0];
+ combo[2] = _guestStreamComboBox.currentText().toInt();
+ combo[3] = _vcpuCheckBoxWidget->getCheckedIds()[0];
+
+ emit apply(-1, combo);
+}
+
+void KsComboPlotDialog::_hostStreamChanged(const QString &sdStr)
+{
+ qInfo() << "_hostStreamChanged";
+ kshark_context *kshark_ctx(nullptr);
+ int *streamIds, sdHost;
+ QStringList streamList;
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ sdHost = sdStr.toInt();
+ _guestStreamComboBox.clear();
+ streamIds = kshark_all_streams(kshark_ctx);
+ for (int i = 0; i < kshark_ctx->n_streams; ++i)
+ if (sdHost != streamIds[i])
+ _guestStreamComboBox.addItem(QString::number(streamIds[i]));
+}
+
+void KsComboPlotDialog::_guestStreamChanged(const QString &sdStr)
+{
+ qInfo() << "_guestStreamChanged";
+ kshark_context *kshark_ctx(nullptr);
+ int sdGuest;
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ sdGuest = sdStr.toInt();
+
+ delete _vcpuCheckBoxWidget;
+
+ _vcpuCheckBoxWidget = new KsCPUCheckBoxWidget(sdGuest, this);
+ _vcpuCheckBoxWidget->setDefault(false);
+ _cbLayout.addWidget(_vcpuCheckBoxWidget);
+}
/**
* @brief Create KsCheckBoxTable.
@@ -359,9 +523,9 @@
* @param name: The name of this widget.
* @param parent: The parent of this widget.
*/
-KsCheckBoxTableWidget::KsCheckBoxTableWidget(const QString &name,
+KsCheckBoxTableWidget::KsCheckBoxTableWidget(int sd, const QString &name,
QWidget *parent)
-: KsCheckBoxWidget(name, parent),
+: KsCheckBoxWidget(sd, name, parent),
_table(this)
{
connect(&_table, &KsCheckBoxTable::changeState,
@@ -514,9 +678,9 @@
* @param name: The name of this widget.
* @param parent: The parent of this widget.
*/
-KsCheckBoxTreeWidget::KsCheckBoxTreeWidget(const QString &name,
+KsCheckBoxTreeWidget::KsCheckBoxTreeWidget(int sd, const QString &name,
QWidget *parent)
-: KsCheckBoxWidget(name, parent),
+: KsCheckBoxWidget(sd, name, parent),
_tree(this)
{
connect(&_tree, &KsCheckBoxTree::verify,
@@ -614,24 +778,29 @@
/**
* @brief Create KsCPUCheckBoxWidget.
*
- * @param tep: Trace event parseer.
+ * @param sd: Data stream identifier.
* @param parent: The parent of this widget.
*/
-KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(struct tep_handle *tep,
- QWidget *parent)
-: KsCheckBoxTreeWidget("CPUs", parent)
+KsCPUCheckBoxWidget::KsCPUCheckBoxWidget(int sd, QWidget *parent)
+: KsCheckBoxTreeWidget(sd, "CPUs", parent)
{
int nCPUs(0), height(FONT_HEIGHT * 1.5);
+ kshark_context *kshark_ctx(nullptr);
+ kshark_data_stream *stream;
KsPlot::ColorTable colors;
QString style;
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
style = QString("QTreeView::item { height: %1 ;}").arg(height);
_tree.setStyleSheet(style);
_initTree();
- if (tep)
- nCPUs = tep_get_cpus(tep);
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (stream)
+ nCPUs = tep_get_cpus(stream->pevent);
_id.resize(nCPUs);
_cb.resize(nCPUs);
@@ -656,22 +825,107 @@
/**
* @brief Create KsEventsCheckBoxWidget.
*
- * @param tep: Trace event parseer.
+ * @param sd: Data stream identifier.
* @param parent: The parent of this widget.
*/
-KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(struct tep_handle *tep,
+// KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(int sd, QWidget *parent)
+// : KsCheckBoxTreeWidget(sd, "Events", parent)
+// {
+// QTreeWidgetItem *sysItem, *evtItem;
+// tep_event_format **events(nullptr);
+// kshark_context *kshark_ctx(nullptr);
+// kshark_data_stream *stream;
+// QString sysName, evtName;
+// int nEvts(0), i(0);
+//
+// if (!kshark_instance(&kshark_ctx))
+// return;
+//
+// stream = kshark_get_data_stream(kshark_ctx, sd);
+// if (stream) {
+// nEvts = tep_get_events_count(stream->pevent);
+// events = tep_list_events(stream->pevent, TEP_EVENT_SORT_SYSTEM);
+// }
+//
+// _initTree();
+// _id.resize(nEvts);
+// _cb.resize(nEvts);
+//
+// while (i < nEvts) {
+// sysName = events[i]->system;
+// sysItem = new QTreeWidgetItem;
+// sysItem->setText(0, sysName);
+// sysItem->setCheckState(0, Qt::Checked);
+// _tree.addTopLevelItem(sysItem);
+//
+// while (sysName == events[i]->system) {
+// evtName = 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] = events[i]->id;
+// _cb[i] = evtItem;
+//
+// if (++i == nEvts)
+// break;
+// }
+// }
+//
+// _tree.sortItems(0, Qt::AscendingOrder);
+// _adjustSize();
+// }
+
+KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(tep_handle *pevent,
QWidget *parent)
-: KsCheckBoxTreeWidget("Events", parent)
+: KsCheckBoxTreeWidget(-1, "Events", parent)
+{
+ tep_event **events;
+ int nEvts;
+
+ if (pevent) {
+ nEvts = tep_get_events_count(pevent);
+ events = tep_list_events(pevent,
+ TEP_EVENT_SORT_SYSTEM);
+ _makeItems(events, nEvts);
+ }
+}
+
+/**
+ * @brief Create KsEventsCheckBoxWidget.
+ *
+ * @param pevent: Page event used to parse the page.
+ * @param parent: The parent of this widget.
+ */
+KsEventsCheckBoxWidget::KsEventsCheckBoxWidget(int sd, QWidget *parent)
+: KsCheckBoxTreeWidget(sd, "Events", parent)
+{
+ kshark_context *kshark_ctx(nullptr);
+ kshark_data_stream *stream;
+ tep_event **events;
+ int nEvts(0);
+
+ if (!kshark_instance(&kshark_ctx))
+ return;
+
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (stream) {
+ nEvts = tep_get_events_count(stream->pevent);
+ events = tep_list_events(stream->pevent,
+ TEP_EVENT_SORT_SYSTEM);
+ _makeItems(events, nEvts);
+ }
+}
+
+void KsEventsCheckBoxWidget::_makeItems(tep_event **events, int nEvts)
{
QTreeWidgetItem *sysItem, *evtItem;
- tep_event **events(nullptr);
QString sysName, evtName;
- int nEvts(0), i(0);
-
- if (tep) {
- nEvts = tep_get_events_count(tep);
- events = tep_list_events(tep, TEP_EVENT_SORT_SYSTEM);
- }
+ int i(0);
_initTree();
_id.resize(nEvts);
@@ -719,16 +973,17 @@
/**
* @brief Create KsTasksCheckBoxWidget.
*
- * @param pevent: Page event used to parse the page.
+ * @param sd: Data stream identifier.
* @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)
+KsTasksCheckBoxWidget::KsTasksCheckBoxWidget(int sd, bool cond, QWidget *parent)
+: KsCheckBoxTableWidget(sd, "Tasks", parent),
+ _cond(cond)
{
kshark_context *kshark_ctx(nullptr);
QTableWidgetItem *pidItem, *comItem;
+ kshark_data_stream *stream;
KsPlot::ColorTable colors;
QStringList headers;
const char *comm;
@@ -737,12 +992,16 @@
if (!kshark_instance(&kshark_ctx))
return;
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return;
+
if (_cond)
headers << "Show" << "Pid" << "Task";
else
headers << "Hide" << "Pid" << "Task";
- _id = KsUtils::getPidList();
+ _id = KsUtils::getPidList(sd);
nTasks = _id.count();
_initTable(headers, nTasks);
colors = KsPlot::getTaskColorTable();
@@ -752,7 +1011,7 @@
pidItem = new QTableWidgetItem(tr("%1").arg(pid));
_table.setItem(i, 1, pidItem);
- comm = tep_data_comm_from_pid(kshark_ctx->pevent, pid);
+ comm = tep_data_comm_from_pid(stream->pevent, pid);
comItem = new QTableWidgetItem(tr(comm));
pidItem->setBackgroundColor(QColor(colors[pid].r(),
@@ -774,9 +1033,9 @@
* @param pluginList: A list of plugin names.
* @param parent: The parent of this widget.
*/
-KsPluginCheckBoxWidget::KsPluginCheckBoxWidget(QStringList pluginList,
+KsPluginCheckBoxWidget::KsPluginCheckBoxWidget(int sd, QStringList pluginList,
QWidget *parent)
-: KsCheckBoxTableWidget("Plugins", parent)
+: KsCheckBoxTableWidget(sd, "Plugins", parent)
{
QTableWidgetItem *nameItem, *infoItem;
QStringList headers;
diff --git a/kernel-shark/src/KsWidgetsLib.hpp b/kernel-shark/src/KsWidgetsLib.hpp
index 6f22374..e55e408 100644
--- a/kernel-shark/src/KsWidgetsLib.hpp
+++ b/kernel-shark/src/KsWidgetsLib.hpp
@@ -15,6 +15,13 @@
// Qt
#include <QtWidgets>
+// KernelShark
+#include "libkshark.h"
+#include "KsUtils.hpp"
+
+namespace KsWidgetsLib
+{
+
/**
* The KsProgressBar class provides a visualization of the progress of a
* running job.
@@ -66,9 +73,6 @@
/** The width of the KsMessageDialog widget. */
#define KS_MSG_DIALOG_WIDTH (SCREEN_WIDTH / 10)
-namespace KsWidgetsLib
-{
-
bool fileExistsDialog(QString fileName);
}; // KsWidgetsLib
@@ -81,7 +85,7 @@
{
Q_OBJECT
public:
- KsCheckBoxWidget(const QString &name = "",
+ KsCheckBoxWidget(int sd, const QString &name = "",
QWidget *parent = nullptr);
/** Get the name of the widget. */
@@ -95,19 +99,51 @@
return false;
}
+ void setVisibleCbAll(bool v) {_allCbAction->setVisible(v);}
+
void setDefault(bool);
void set(QVector<bool> v);
QVector<int> getCheckedIds();
+ /**
+ * Get the identifier of the Data stream for which the selection
+ * applies.
+ */
+ int sd() const {return _sd;}
+
+ void setStream(QString stream)
+ {
+ _streamName = stream;
+ KsUtils::setElidedText(&_stramLabel, _streamName,
+ Qt::ElideLeft, width());
+ QApplication::processEvents();
+ }
+
+ /**
+ * Reimplemented event handler used to update the geometry of the widget on
+ * resize events.
+ */
+ void resizeEvent(QResizeEvent* event)
+ {
+ KsUtils::setElidedText(&_stramLabel, _streamName,
+ Qt::ElideLeft, width());
+ QApplication::processEvents();
+ }
+
private:
QToolBar _tb;
protected:
+ /** Identifier of the Data stream for which the selection applies. */
+ int _sd;
+
/** The "all" checkboxe. */
QCheckBox _allCb;
+ QAction *_allCbAction;
+
/** A vector of Id numbers coupled to each checkboxe. */
QVector<int> _id;
@@ -120,6 +156,12 @@
/** The top level layout of this widget. */
QVBoxLayout _topLayout;
+ QString _streamName;
+ /**
+ * A label to show the name of the Data stream for which the selection
+ * applies. */
+ QLabel _stramLabel;
+
/** The name of this widget. */
QString _name;
@@ -146,20 +188,20 @@
public:
KsCheckBoxDialog() = delete;
- KsCheckBoxDialog(KsCheckBoxWidget *cbw, QWidget *parent = nullptr);
+ KsCheckBoxDialog(QVector<KsCheckBoxWidget *> cbws, QWidget *parent = nullptr);
signals:
/** Signal emitted when the "Apply" button is pressed. */
- void apply(QVector<int>);
+ void apply(int sd, QVector<int>);
private:
void _applyPress();
QVBoxLayout _topLayout;
- QHBoxLayout _buttonLayout;
+ QHBoxLayout _cbLayout, _buttonLayout;
- KsCheckBoxWidget *_checkBoxWidget;
+ QVector<KsCheckBoxWidget *> _checkBoxWidgets;
QPushButton _applyButton, _cancelButton;
@@ -199,9 +241,15 @@
{
Q_OBJECT
public:
- KsCheckBoxTableWidget(const QString &name = "",
+ KsCheckBoxTableWidget(int sd, const QString &name = "",
QWidget *parent = nullptr);
+ void setSingleSelection()
+ {
+ _table.setSelectionMode(QAbstractItemView::SingleSelection); // !!!!!!!!!!
+ setVisibleCbAll(false);
+ }
+
protected:
void _adjustSize();
@@ -260,9 +308,15 @@
public:
KsCheckBoxTreeWidget() = delete;
- KsCheckBoxTreeWidget(const QString &name = "",
+ KsCheckBoxTreeWidget(int sd, const QString &name = "",
QWidget *parent = nullptr);
+ void setSingleSelection()
+ {
+ _tree.setSelectionMode(QAbstractItemView::SingleSelection); // !!!!!!!!!!
+ setVisibleCbAll(false);
+ }
+
protected:
void _adjustSize();
@@ -290,6 +344,45 @@
void _verify();
};
+class KsComboPlotDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit KsComboPlotDialog(QWidget *parent = nullptr);
+
+signals:
+ /** Signal emitted when the "Apply" button is pressed. */
+ void apply(int sd, QVector<int>);
+
+private:
+ QVBoxLayout _topLayout;
+
+ QGridLayout _streamMenuLayout;
+
+ QHBoxLayout _cbLayout, _buttonLayout;
+
+ QLabel _hostStreamLabel, _guestStreamLabel;
+
+ QComboBox _hostStreamComboBox;
+
+ QComboBox _guestStreamComboBox;
+
+ KsCheckBoxTreeWidget *_vcpuCheckBoxWidget;
+
+ KsCheckBoxTableWidget *_hostCheckBoxWidget;
+
+ QPushButton _applyButton, _cancelButton;
+
+ QMetaObject::Connection _applyButtonConnection;
+
+ void _applyPress();
+
+private slots:
+ void _hostStreamChanged(const QString&);
+
+ void _guestStreamChanged(const QString&);
+};
+
/**
* The KsCPUCheckBoxWidget class provides a widget for selecting CPU plots to
* show.
@@ -298,8 +391,7 @@
{
KsCPUCheckBoxWidget() = delete;
- KsCPUCheckBoxWidget(struct tep_handle *pe,
- QWidget *parent = nullptr);
+ KsCPUCheckBoxWidget(int sd, QWidget *parent = nullptr);
};
/**
@@ -310,9 +402,7 @@
{
KsTasksCheckBoxWidget() = delete;
- KsTasksCheckBoxWidget(struct tep_handle *pe,
- bool cond = true,
- QWidget *parent = nullptr);
+ KsTasksCheckBoxWidget(int sd, bool cond, QWidget *parent = nullptr);
private:
/**
@@ -330,10 +420,14 @@
{
KsEventsCheckBoxWidget() = delete;
- KsEventsCheckBoxWidget(struct tep_handle *pe,
- QWidget *parent = nullptr);
+ KsEventsCheckBoxWidget(int sd, QWidget *parent = nullptr);
+
+ KsEventsCheckBoxWidget(tep_handle *pevent, QWidget *parent = nullptr);
void removeSystem(QString name);
+
+private:
+ void _makeItems(tep_event **events, int nEvts);
};
/**
@@ -343,7 +437,7 @@
{
KsPluginCheckBoxWidget() = delete;
- KsPluginCheckBoxWidget(QStringList pluginList,
+ KsPluginCheckBoxWidget(int sd, QStringList pluginList,
QWidget *parent = nullptr);
};
diff --git a/kernel-shark/src/libkshark-collection.c b/kernel-shark/src/libkshark-collection.c
index d2e4674..79e1a6c 100644
--- a/kernel-shark/src/libkshark-collection.c
+++ b/kernel-shark/src/libkshark-collection.c
@@ -75,7 +75,8 @@
size_t n_rows,
matching_condition_func cond,
int sd,
- int val,
+ int *values,
+ int n_val,
size_t margin)
{
struct kshark_entry_collection *col_ptr = NULL;
@@ -118,7 +119,7 @@
}
for (i = first + margin; i < end; ++i) {
- if (!cond(kshark_ctx, data[i], sd, val)) {
+ if (!cond(kshark_ctx, data[i], sd, values)) {
/*
* The entry is irrelevant for this collection.
* Do nothing.
@@ -148,7 +149,7 @@
}
} else if (good_data &&
data[i]->next &&
- !cond(kshark_ctx, data[i]->next, sd, val)) {
+ !cond(kshark_ctx, data[i]->next, sd, values)) {
/*
* Break the collection here. Add some margin data
* after the data of interest.
@@ -169,7 +170,7 @@
*/
if (i + margin >= j) {
for (;j < i + margin; ++j) {
- if (cond(kshark_ctx, data[j], sd, val)) {
+ if (cond(kshark_ctx, data[j], sd, values)) {
/*
* Good data has been found.
* Continue extending the
@@ -229,7 +230,10 @@
}
col_ptr->cond = cond;
- col_ptr->val = val;
+ col_ptr->n_val = n_val;
+ col_ptr->stream_id = sd;
+ col_ptr->values = malloc(n_val * sizeof(*col_ptr->values));
+ memcpy(col_ptr->values, values, n_val * sizeof(*col_ptr->values));
col_ptr->size = resume_count;
for (i = 0; i < col_ptr->size; ++i) {
@@ -484,7 +488,7 @@
0,
req_tmp->cond,
req_tmp->sd,
- req_tmp->val,
+ req_tmp->values,
req_tmp->vis_only,
req_tmp->vis_mask);
@@ -572,7 +576,7 @@
0,
req_tmp->cond,
req_tmp->sd,
- req_tmp->val,
+ req_tmp->values,
req_tmp->vis_only,
req_tmp->vis_mask);
@@ -709,6 +713,17 @@
return entry;
}
+static bool val_compare(int *val_a, int *val_b, size_t n_val)
+{
+ size_t i;
+
+ for (i = 0; i < n_val; ++i)
+ if (val_a[i] != val_b[i])
+ return false;
+
+ return true;
+}
+
/**
* @brief Search the list of Data collections and find the collection defined
* with a given Matching condition function and value.
@@ -724,13 +739,14 @@
struct kshark_entry_collection *
kshark_find_data_collection(struct kshark_entry_collection *col,
matching_condition_func cond,
- int sd, int val)
+ int sd, int *values, size_t n_val)
{
while (col) {
if (col->cond == cond &&
- col->sd == sd &&
- col->val == val)
- return col;
+ col->stream_id == sd &&
+ col->n_val == n_val &&
+ val_compare(col->values, values, n_val))
+ return col;
col = col->next;
}
@@ -758,6 +774,7 @@
{
free(col->resume_points);
free(col->break_points);
+ free(col->values);
free(col);
}
@@ -788,7 +805,7 @@
size_t n_rows,
matching_condition_func cond,
int sd,
- int val,
+ int *values, size_t n_val,
size_t margin)
{
struct kshark_entry_collection *col;
@@ -796,7 +813,7 @@
col = kshark_add_collection_to_list(kshark_ctx,
&kshark_ctx->collections,
data, n_rows,
- cond, sd, val,
+ cond, sd, values, n_val,
margin);
return col;
@@ -829,14 +846,15 @@
struct kshark_entry **data,
size_t n_rows,
matching_condition_func cond,
- int sd, int val,
+ int sd, int *values, size_t n_val,
size_t margin)
{
struct kshark_entry_collection *col;
col = kshark_data_collection_alloc(kshark_ctx, data,
0, n_rows,
- cond, sd, val,
+ cond, sd,
+ values, n_val,
margin);
if (col) {
@@ -861,15 +879,16 @@
*/
void kshark_unregister_data_collection(struct kshark_entry_collection **col,
matching_condition_func cond,
- int sd, int val)
+ int sd, int *values, size_t n_val)
{
struct kshark_entry_collection **last = col;
struct kshark_entry_collection *list;
for (list = *col; list; list = list->next) {
if (list->cond == cond &&
- list->sd == sd &&
- list->val == val) {
+ list->stream_id == sd &&
+ list->n_val == n_val &&
+ val_compare(list->values, values, n_val)) {
*last = list->next;
kshark_free_data_collection(list);
return;
diff --git a/kernel-shark/src/libkshark-configio.c b/kernel-shark/src/libkshark-configio.c
index c93aa05..76c54a8 100644
--- a/kernel-shark/src/libkshark-configio.c
+++ b/kernel-shark/src/libkshark-configio.c
@@ -332,7 +332,7 @@
return true;
fail:
- fprintf(stderr, "Failed to get config. document [%s]>.\n", key);
+ fprintf(stderr, "Failed to get config. document <%s>.\n", key);
return false;
}
@@ -896,6 +896,11 @@
}
}
+static int compare_ids(const void* a, const void* b)
+{
+ return ( *(int*)a - *(int*)b );
+}
+
static bool kshark_filter_array_to_json(struct tracecmd_filter_id *filter,
const char *filter_name,
struct json_object *jobj)
@@ -914,6 +919,8 @@
if (!ids)
return true;
+ qsort(ids, filter->count, sizeof(int), compare_ids);
+
/* Create a Json array and fill the Id values into it. */
jfilter_data = json_object_new_array();
if (!jfilter_data)
@@ -1338,6 +1345,60 @@
}
}
+static bool kshark_calib_array_from_json(struct kshark_context *kshark_ctx,
+ int sd, struct json_object *jobj)
+{
+ json_object *jcalib_argv, *jcalib;
+ int64_t *calib_argv = NULL;
+ int i, calib_length;
+
+ if (!json_object_object_get_ex(jobj, "calib. array", &jcalib_argv) ||
+ json_object_get_type(jcalib_argv) != json_type_array)
+ return false;
+
+ calib_length = json_object_array_length(jcalib_argv);
+ if (!calib_length)
+ return false;
+
+ calib_argv = calloc(calib_length, sizeof(*calib_argv));
+ for (i = 0; i < calib_length; ++i) {
+ jcalib = json_object_array_get_idx(jcalib_argv, i);
+ calib_argv[i] = json_object_get_int64(jcalib);
+ }
+
+ kshark_ctx->stream[sd]->calib = kshark_offset_calib;
+ kshark_ctx->stream[sd]->calib_array = calib_argv;
+ kshark_ctx->stream[sd]->calib_array_size = calib_length;
+
+ return true;
+}
+
+/**
+ * @brief Load from Configuration document the value of the time calibration
+ * constants into a Configuration document.
+ *
+ * @param kshark_ctx: Input location for session context pointer.
+ * @param sd: Data stream identifier.
+ * @param conf: Input location for the kshark_config_doc instance. Currently
+ * only Json format is supported. If NULL, a new Configuration
+ * document will be created.
+ *
+ * @returns True on success, otherwise False.
+ */
+bool kshark_import_calib_array(struct kshark_context *kshark_ctx, int sd,
+ struct kshark_config_doc *conf)
+{
+ switch (conf->format) {
+ case KS_CONFIG_JSON:
+ return kshark_calib_array_from_json(kshark_ctx, sd, conf->conf_doc);
+
+ default:
+ fprintf(stderr, "Document format %d not supported\n",
+ conf->format);
+ return false;
+ }
+}
+
static bool kshark_calib_array_to_json(struct kshark_context *kshark_ctx,
int sd, struct json_object *jobj)
{
@@ -1488,12 +1549,12 @@
/* Save a filter only if it contains Id values. */
ret = true;
if (filter_is_set(stream->show_task_filter))
- ret &= kshark_import_filter_array(stream->show_task_filter,
+ ret &= kshark_export_filter_array(stream->show_task_filter,
KS_SHOW_TASK_FILTER_NAME,
*conf);
if (filter_is_set(stream->hide_task_filter))
- ret &= kshark_import_filter_array(stream->hide_task_filter,
+ ret &= kshark_export_filter_array(stream->hide_task_filter,
KS_HIDE_TASK_FILTER_NAME,
*conf);
@@ -1760,6 +1821,8 @@
return NULL;
}
+
+
/**
* @brief Load Data Stream from a Configuration document.
*
@@ -1775,16 +1838,15 @@
* negative error code.
*/
int kshark_import_dstream(struct kshark_context *kshark_ctx,
- struct kshark_config_doc *conf,
+ struct kshark_config_doc *conf/*,
struct kshark_entry ***data_rows,
- size_t *data_size)
+ size_t *data_size*/)
{
struct kshark_config_doc *file_conf, *filter_conf;
bool ret = false;
int sd = -EFAULT;
- *data_size = 0;
-
+// *data_size = 0;
if (!kshark_type_check(conf, "kshark.config.stream"))
return sd;
@@ -1796,6 +1858,7 @@
kshark_config_doc_get(conf, "filters", filter_conf)) {
sd = kshark_import_trace_file(kshark_ctx, file_conf);
if (sd >= 0) {
+ kshark_import_calib_array(kshark_ctx, sd, conf);
ret = kshark_import_all_filters(kshark_ctx, sd,
filter_conf);
if (!ret) {
@@ -1803,8 +1866,11 @@
return -EFAULT;
}
- *data_size = kshark_load_data_entries(kshark_ctx, sd,
- data_rows);
+ kshark_handle_all_plugins(kshark_ctx, sd,
+ KSHARK_PLUGIN_UPDATE);
+
+// *data_size = kshark_load_data_entries(kshark_ctx, sd,
+// data_rows);
}
}
@@ -1827,6 +1893,9 @@
for (int i = 0; i < kshark_ctx->n_streams; ++i) {
dstream_conf = kshark_export_dstream(kshark_ctx, stream_ids[i],
KS_CONFIG_JSON);
+ if (!dstream_conf)
+ goto fail;
+
json_object_array_put_idx(jall_streams, i, dstream_conf->conf_doc);
/* Free only the kshark_config_doc object. */
@@ -1834,7 +1903,13 @@
}
json_object_object_add(jobj, "data streams", jall_streams);
+
return true;
+
+ fail:
+ json_object_put(jall_streams);
+
+ return false;
}
/**
@@ -1849,24 +1924,26 @@
* @returns True on success, otherwise False.
*/
bool kshark_export_all_dstreams(struct kshark_context *kshark_ctx,
- struct kshark_config_doc *conf)
+ struct kshark_config_doc **conf)
{
- switch (conf->format) {
+ if (!*conf)
+ *conf = kshark_filter_config_new(KS_CONFIG_JSON);
+
+ if (!*conf)
+ return false;
+
+ switch ((*conf)->format) {
case KS_CONFIG_JSON:
return kshark_export_all_dstreams_to_json(kshark_ctx,
- conf->conf_doc);
+ (*conf)->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
- conf->format);
+ (*conf)->format);
return false;
}
}
-static void __calib(struct kshark_entry *e, int64_t *atgv) {
- e->ts += atgv[0];
-}
-
static bool
kshark_import_all_dstreams_from_json(struct kshark_context *kshark_ctx,
struct json_object *jobj,
@@ -1874,72 +1951,31 @@
size_t *data_size)
{
struct kshark_config_doc dstream_conf;
- struct kshark_entry **stream_data_rows = NULL, **merged_data_rows;
- size_t stream_data_size = 0;
- json_object *jall_streams, *jstream, *jcalib_argv, *jcalib;
- int sd, i, j, length, calib_length;
- int64_t *calib_argv = NULL;
+ json_object *jall_streams, *jstream;
+ int sd, i, length;
if (!json_object_object_get_ex(jobj, "data streams", &jall_streams) ||
json_object_get_type(jall_streams) != json_type_array)
- goto fail;
+ return false;
length = json_object_array_length(jall_streams);
if (!length)
- goto fail;
+ return false;
dstream_conf.format = KS_CONFIG_JSON;
- jstream = json_object_array_get_idx(jall_streams, 0);
- dstream_conf.conf_doc = jstream;
- kshark_import_dstream(kshark_ctx, &dstream_conf, data_rows, data_size);
-
- for (i = 1; i < length; ++i) {
+ for (i = 0; i < length; ++i) {
jstream = json_object_array_get_idx(jall_streams, i);
-
- if (!json_object_object_get_ex(jstream, "calib. array", &jcalib_argv) ||
- json_object_get_type(jcalib_argv) != json_type_array)
- goto fail;
-
- calib_length = json_object_array_length(jcalib_argv);
- if (!calib_length)
- goto fail;
-
- calib_argv = calloc(calib_length, sizeof(*calib_argv));
- for (j = 0; j < calib_length; ++j) {
- jcalib = json_object_array_get_idx(jcalib_argv, j);
- calib_argv[j] = json_object_get_int64(jcalib);
- }
-
dstream_conf.conf_doc = jstream;
- sd = kshark_import_dstream(kshark_ctx, &dstream_conf,
- &stream_data_rows, &stream_data_size);
+ sd = kshark_import_dstream(kshark_ctx, &dstream_conf);
- merged_data_rows =
- kshark_data_merge(*data_rows, *data_size,
- stream_data_rows, stream_data_size,
- __calib, calib_argv);
-
- free(stream_data_rows);
- free(*data_rows);
-
- kshark_ctx->stream[sd]->calib_array = calib_argv;
- kshark_ctx->stream[sd]->calib_array_size = calib_length;
-
- stream_data_rows = *data_rows = NULL;
-
- *data_rows = merged_data_rows;
- *data_size += stream_data_size;
+ if (sd < 0)
+ return false;
}
+ *data_size = kshark_load_all_data_entries(kshark_ctx, data_rows);
+
return true;
-
- fail:
- free(*data_rows);
- free(calib_argv);
- *data_size = 0;
-
- return false;
}
/**
diff --git a/kernel-shark/src/libkshark-model.c b/kernel-shark/src/libkshark-model.c
index dc59d17..f056745 100644
--- a/kernel-shark/src/libkshark-model.c
+++ b/kernel-shark/src/libkshark-model.c
@@ -478,7 +478,6 @@
/* Set the new Lower Overflow bin. */
ksmodel_set_lower_edge(histo);
-
/*
* Copy the the mapping indexes of all overlaping bins starting from
* bin "0" of the new histo. Note that the number of overlaping bins
@@ -778,7 +777,7 @@
ksmodel_entry_front_request_alloc(struct kshark_trace_histo *histo,
int bin, bool vis_only,
matching_condition_func func,
- int sd, int val)
+ int sd, int *values)
{
size_t first, n;
@@ -790,7 +789,7 @@
first = ksmodel_first_index_at_bin(histo, bin);
return kshark_entry_request_alloc(first, n,
- func, sd, val,
+ func, sd, values,
vis_only, KS_GRAPH_VIEW_FILTER_MASK);
}
@@ -798,7 +797,7 @@
ksmodel_entry_back_request_alloc(struct kshark_trace_histo *histo,
int bin, bool vis_only,
matching_condition_func func,
- int sd, int val)
+ int sd, int *values)
{
size_t first, n;
@@ -810,7 +809,7 @@
first = ksmodel_last_index_at_bin(histo, bin);
return kshark_entry_request_alloc(first, n,
- func, sd, val,
+ func, sd, values,
vis_only, KS_GRAPH_VIEW_FILTER_MASK);
}
@@ -903,7 +902,7 @@
const struct kshark_entry *
ksmodel_get_entry_front(struct kshark_trace_histo *histo,
int bin, bool vis_only,
- matching_condition_func func, int sd, int val,
+ matching_condition_func func, int sd, int *values,
struct kshark_entry_collection *col,
ssize_t *index)
{
@@ -915,7 +914,7 @@
/* Set the position at the beginning of the bin and go forward. */
req = ksmodel_entry_front_request_alloc(histo, bin, vis_only,
- func, sd, val);
+ func, sd, values);
if (!req)
return NULL;
@@ -951,7 +950,7 @@
const struct kshark_entry *
ksmodel_get_entry_back(struct kshark_trace_histo *histo,
int bin, bool vis_only,
- matching_condition_func func, int sd, int val,
+ matching_condition_func func, int sd, int *values,
struct kshark_entry_collection *col,
ssize_t *index)
{
@@ -963,7 +962,7 @@
/* Set the position at the end of the bin and go backwards. */
req = ksmodel_entry_back_request_alloc(histo, bin, vis_only,
- func, sd, val);
+ func, sd, values);
if (!req)
return NULL;
@@ -1022,7 +1021,7 @@
return KS_EMPTY_BIN;
entry = ksmodel_get_entry_front(histo, bin, vis_only,
- kshark_match_cpu, sd, cpu,
+ kshark_match_cpu, sd, &cpu,
col, index);
return ksmodel_get_entry_pid(entry);
@@ -1056,7 +1055,7 @@
return KS_EMPTY_BIN;
entry = ksmodel_get_entry_back(histo, bin, vis_only,
- kshark_match_cpu, sd, cpu,
+ kshark_match_cpu, sd, &cpu,
col, index);
return ksmodel_get_entry_pid(entry);
@@ -1106,7 +1105,7 @@
return KS_EMPTY_BIN;
entry = ksmodel_get_entry_front(histo, bin, vis_only,
- kshark_match_pid, sd, pid,
+ kshark_match_pid, sd, &pid,
col,
index);
return ksmodel_get_entry_cpu(entry);
@@ -1140,7 +1139,7 @@
return KS_EMPTY_BIN;
entry = ksmodel_get_entry_back(histo, bin, vis_only,
- kshark_match_pid, sd, pid,
+ kshark_match_pid, sd, &pid,
col,
index);
@@ -1174,7 +1173,7 @@
/* Set the position at the beginning of the bin and go forward. */
req = ksmodel_entry_front_request_alloc(histo,
bin, true,
- kshark_match_cpu, sd, cpu);
+ kshark_match_cpu, sd, &cpu);
if (!req)
return false;
@@ -1228,7 +1227,7 @@
/* Set the position at the beginning of the bin and go forward. */
req = ksmodel_entry_front_request_alloc(histo,
bin, true,
- kshark_match_pid, sd, pid);
+ kshark_match_pid, sd, &pid);
if (!req)
return false;
@@ -1256,15 +1255,15 @@
}
static bool match_cpu_missed_events(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int sd, int cpu)
+ struct kshark_entry *e, int sd, int *cpu)
{
- return e->event_id == -EOVERFLOW && e->cpu == cpu && e->stream_id == sd;
+ return e->event_id == -EOVERFLOW && e->cpu == *cpu && e->stream_id == sd;
}
static bool match_pid_missed_events(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int sd, int pid)
+ struct kshark_entry *e, int sd, int *pid)
{
- return e->event_id == -EOVERFLOW && e->pid == pid && e->stream_id == sd;
+ return e->event_id == -EOVERFLOW && e->pid == *pid && e->stream_id == sd;
}
/**
@@ -1288,7 +1287,7 @@
ssize_t *index)
{
return ksmodel_get_entry_front(histo, bin, true,
- match_cpu_missed_events, sd, cpu,
+ match_cpu_missed_events, sd, &cpu,
col, index);
}
@@ -1313,6 +1312,6 @@
ssize_t *index)
{
return ksmodel_get_entry_front(histo, bin, true,
- match_pid_missed_events, sd, pid,
+ match_pid_missed_events, sd, &pid,
col, index);
}
diff --git a/kernel-shark/src/libkshark-model.h b/kernel-shark/src/libkshark-model.h
index dd9c6b2..3d81b0e 100644
--- a/kernel-shark/src/libkshark-model.h
+++ b/kernel-shark/src/libkshark-model.h
@@ -110,14 +110,14 @@
const struct kshark_entry *
ksmodel_get_entry_front(struct kshark_trace_histo *histo,
int bin, bool vis_only,
- matching_condition_func func, int sd, int val,
+ matching_condition_func func, int sd, int *values,
struct kshark_entry_collection *col,
ssize_t *index);
const struct kshark_entry *
ksmodel_get_entry_back(struct kshark_trace_histo *histo,
int bin, bool vis_only,
- matching_condition_func func, int sd, int val,
+ matching_condition_func func, int sd, int *values,
struct kshark_entry_collection *col,
ssize_t *index);
diff --git a/kernel-shark/src/libkshark-plugin.c b/kernel-shark/src/libkshark-plugin.c
index b1f31d5..ffa8541 100644
--- a/kernel-shark/src/libkshark-plugin.c
+++ b/kernel-shark/src/libkshark-plugin.c
@@ -150,10 +150,10 @@
* @param kshark_ctx: Input location for the session context pointer.
* @param file: The plugin object file to load.
*
- * @returns Zero on success, or a negative error code on failure.
+ * @returns The plugin object on success, or NULL on failure.
*/
-int kshark_register_plugin(struct kshark_context *kshark_ctx,
- const char *file)
+struct kshark_plugin_list *
+kshark_register_plugin(struct kshark_context *kshark_ctx, const char *file)
{
struct kshark_plugin_list *plugin = kshark_ctx->plugins;
struct stat st;
@@ -161,7 +161,7 @@
while (plugin) {
if (strcmp(plugin->file, file) == 0)
- return -EEXIST;
+ return NULL;
plugin = plugin->next;
}
@@ -169,19 +169,21 @@
ret = stat(file, &st);
if (ret < 0) {
fprintf(stderr, "plugin %s not found\n", file);
- return -ENODEV;
+ return NULL;
}
plugin = calloc(sizeof(struct kshark_plugin_list), 1);
if (!plugin) {
fprintf(stderr, "failed to allocate memory for plugin\n");
- return -ENOMEM;
+ return NULL;
}
+ plugin->streams = NULL;
+
if (asprintf(&plugin->file, "%s", file) <= 0) {
fprintf(stderr,
"failed to allocate memory for plugin file name");
- return -ENOMEM;
+ return NULL;
}
plugin->handle = dlopen(plugin->file, RTLD_NOW | RTLD_GLOBAL);
@@ -200,7 +202,7 @@
plugin->next = kshark_ctx->plugins;
kshark_ctx->plugins = plugin;
- return 0;
+ return plugin;
fail:
fprintf(stderr, "cannot load plugin '%s'\n%s\n",
@@ -213,7 +215,7 @@
free(plugin);
- return EFAULT;
+ return NULL;
}
/**
@@ -261,6 +263,79 @@
}
}
+struct kshark_plugin_list *
+kshark_find_plugin(struct kshark_plugin_list *plugins, const char *file)
+{
+ for (; plugins; plugins = plugins->next)
+ if (strcmp(plugins->file, file) == 0)
+ return plugins;
+
+ return NULL;
+}
+
+void kshark_plugin_add_stream(struct kshark_plugin_list *plugin, int sd)
+{
+ struct kshark_stream_list *stream;
+
+ /* First make sure that the Data Stream has not been added already. */
+ for (stream = plugin->streams; stream; stream = stream->next)
+ if (stream->stream_id == sd)
+ return;
+
+ /* Add the stream to the list. */
+ stream = malloc(sizeof(*stream));
+ stream->stream_id = sd;
+ stream->next = plugin->streams;
+ plugin->streams = stream;
+}
+
+void kshark_plugin_remove_stream(struct kshark_plugin_list *plugin, int sd)
+{
+ struct kshark_stream_list **stream;
+
+ for (stream = &plugin->streams; *stream; stream = &(*stream)->next) {
+ if ((*stream)->stream_id == sd) {
+ struct kshark_stream_list *this_stream;
+
+ this_stream = *stream;
+ *stream = this_stream->next;
+ free(this_stream);
+ }
+ }
+}
+
+int kshark_handle_plugin(struct kshark_context *kshark_ctx,
+ struct kshark_plugin_list *plugin,
+ int sd,
+ enum kshark_plugin_actions task_id)
+{
+ struct kshark_stream_list *stream;
+ int handler_count = 0;
+
+ for (stream = plugin->streams; stream; stream = stream->next) {
+ if (stream->stream_id == sd)
+ switch (task_id) {
+ case KSHARK_PLUGIN_INIT:
+ handler_count = plugin->init(kshark_ctx, sd);
+ break;
+
+ case KSHARK_PLUGIN_UPDATE:
+ plugin->close(kshark_ctx, sd);
+ handler_count = plugin->init(kshark_ctx, sd);
+ break;
+
+ case KSHARK_PLUGIN_CLOSE:
+ handler_count = plugin->close(kshark_ctx, sd);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return handler_count;
+}
+
/**
* @brief Use this function to initialize/update/deinitialize all registered
* plugins.
@@ -271,30 +346,33 @@
* @returns The number of successful added/removed plugin handlers on success,
* or a negative error code on failure.
*/
-int kshark_handle_plugins(struct kshark_context *kshark_ctx,
- enum kshark_plugin_actions task_id)
+int kshark_handle_all_plugins(struct kshark_context *kshark_ctx, int sd,
+ enum kshark_plugin_actions task_id)
{
struct kshark_plugin_list *plugin;
int handler_count = 0;
for (plugin = kshark_ctx->plugins; plugin; plugin = plugin->next) {
- switch (task_id) {
- case KSHARK_PLUGIN_INIT:
- handler_count += plugin->init(kshark_ctx);
- break;
+ handler_count +=
+ kshark_handle_plugin(kshark_ctx, plugin, sd, task_id);
- case KSHARK_PLUGIN_UPDATE:
- plugin->close(kshark_ctx);
- handler_count += plugin->init(kshark_ctx);
- break;
-
- case KSHARK_PLUGIN_CLOSE:
- handler_count += plugin->close(kshark_ctx);
- break;
-
- default:
- return -EINVAL;
- }
+// switch (task_id) {
+// case KSHARK_PLUGIN_INIT:
+// handler_count += plugin->init(kshark_ctx, sd);
+// break;
+//
+// case KSHARK_PLUGIN_UPDATE:
+// plugin->close(kshark_ctx, sd);
+// handler_count += plugin->init(kshark_ctx, sd);
+// break;
+//
+// case KSHARK_PLUGIN_CLOSE:
+// handler_count += plugin->close(kshark_ctx, sd);
+// break;
+//
+// default:
+// return -EINVAL;
+// }
}
return handler_count;
diff --git a/kernel-shark/src/libkshark-plugin.h b/kernel-shark/src/libkshark-plugin.h
index a39db29..4aad3a0 100644
--- a/kernel-shark/src/libkshark-plugin.h
+++ b/kernel-shark/src/libkshark-plugin.h
@@ -16,6 +16,9 @@
extern "C" {
#endif // __cplusplus
+// C
+#include <stdint.h>
+
// trace-cmd
#include "event-parse.h"
@@ -43,7 +46,7 @@
* A function type to be used when defining load/reload/unload plugin
* functions.
*/
-typedef int (*kshark_plugin_load_func)(struct kshark_context *);
+typedef int (*kshark_plugin_load_func)(struct kshark_context *, int);
struct kshark_trace_histo;
@@ -59,7 +62,7 @@
/** A function type to be used when defining plugin functions for drawing. */
typedef void
(*kshark_plugin_draw_handler_func)(struct kshark_cpp_argv *argv,
- int val, int draw_action);
+ int sd, int val, int draw_action);
/**
* A function type to be used when defining plugin functions for data
@@ -147,6 +150,15 @@
void kshark_free_event_handler_list(struct kshark_event_handler *handlers);
+/** Linked list of Data Stream identifiers. */
+struct kshark_stream_list {
+ /** Pointer to the next Data stream identifier. */
+ struct kshark_stream_list *next;
+
+ /** Data stream identifier. */
+ uint8_t stream_id;
+};
+
/** Linked list of plugins. */
struct kshark_plugin_list {
/** Pointer to the next Plugin. */
@@ -155,6 +167,9 @@
/** The plugin object file to load. */
char *file;
+ /** List of Data streams. */
+ struct kshark_stream_list *streams;
+
/** Plugin Event handler. */
void *handle;
@@ -165,16 +180,28 @@
kshark_plugin_load_func close;
};
-int kshark_register_plugin(struct kshark_context *kshark_ctx,
- const char *file);
+struct kshark_plugin_list *
+kshark_register_plugin(struct kshark_context *kshark_ctx, const char *file);
void kshark_unregister_plugin(struct kshark_context *kshark_ctx,
const char *file);
void kshark_free_plugin_list(struct kshark_plugin_list *plugins);
-int kshark_handle_plugins(struct kshark_context *kshark_ctx,
- enum kshark_plugin_actions task_id);
+struct kshark_plugin_list *
+kshark_find_plugin(struct kshark_plugin_list *plugins, const char *file);
+
+void kshark_plugin_add_stream(struct kshark_plugin_list *plugin, int sd);
+
+void kshark_plugin_remove_stream(struct kshark_plugin_list *plugin, int sd);
+
+int kshark_handle_plugin(struct kshark_context *kshark_ctx,
+ struct kshark_plugin_list *plugin,
+ int sd,
+ enum kshark_plugin_actions task_id);
+
+int kshark_handle_all_plugins(struct kshark_context *kshark_ctx, int sd,
+ enum kshark_plugin_actions task_id);
#ifdef __cplusplus
}
diff --git a/kernel-shark/src/libkshark.c b/kernel-shark/src/libkshark.c
index 84f2d86..780eb01 100644
--- a/kernel-shark/src/libkshark.c
+++ b/kernel-shark/src/libkshark.c
@@ -155,6 +155,7 @@
goto fail;
stream->file = NULL;
+ stream->calib = NULL;
stream->calib_array = NULL;
stream->calib_array_size = 0;
@@ -283,6 +284,7 @@
*/
int kshark_open(struct kshark_context *kshark_ctx, const char *file)
{
+ struct kshark_plugin_list *plugin;
int sd, rt;
sd = kshark_add_stream(kshark_ctx);
@@ -295,6 +297,9 @@
kshark_ctx->n_streams++;
+ for (plugin = kshark_ctx->plugins; plugin; plugin = plugin->next)
+ kshark_plugin_add_stream(plugin, sd);
+
return sd;
}
@@ -339,6 +344,7 @@
stream = kshark_get_data_stream(kshark_ctx, sd);
if (stream) {
+ kshark_handle_all_plugins(kshark_ctx, sd, KSHARK_PLUGIN_CLOSE);
kshark_stream_close(kshark_ctx->stream[sd]);
kshark_stream_free(kshark_ctx->stream[sd]);
kshark_ctx->stream[sd] = NULL;
@@ -354,26 +360,14 @@
}
/**
- * @brief Deinitialize kshark session. Should be called after closing all
- * open trace data files and before your application terminates.
+ * @brief Close all currently open trace data file and free the trace data handle.
*
- * @param kshark_ctx: Optional input location for session context pointer.
- * If it points to a context of a sessuin, that sessuin
- * will be deinitialize. If it points to NULL, it will
- * deinitialize the current session.
+ * @param kshark_ctx: Input location for the session context pointer.
*/
-void kshark_free(struct kshark_context *kshark_ctx)
+void kshark_close_all(struct kshark_context *kshark_ctx)
{
int i, *stream_ids, n_streams;
- if (kshark_ctx == NULL) {
- if (kshark_context_handler == NULL)
- return;
-
- kshark_ctx = kshark_context_handler;
- /* kshark_ctx_handler will be set to NULL below. */
- }
-
stream_ids = kshark_all_streams(kshark_ctx);
/*
@@ -385,10 +379,32 @@
kshark_close(kshark_ctx, stream_ids[i]);
free(stream_ids);
+}
+
+/**
+ * @brief Deinitialize kshark session. Should be called after closing all
+ * open trace data files and before your application terminates.
+ *
+ * @param kshark_ctx: Optional input location for session context pointer.
+ * If it points to a context of a sessuin, that sessuin
+ * will be deinitialize. If it points to NULL, it will
+ * deinitialize the current session.
+ */
+void kshark_free(struct kshark_context *kshark_ctx)
+{
+ if (kshark_ctx == NULL) {
+ if (kshark_context_handler == NULL)
+ return;
+
+ kshark_ctx = kshark_context_handler;
+ /* kshark_ctx_handler will be set to NULL below. */
+ }
+
+ kshark_close_all(kshark_ctx);
+
free(kshark_ctx->stream);
if (kshark_ctx->plugins) {
- kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_CLOSE);
kshark_free_plugin_list(kshark_ctx->plugins);
kshark_free_event_handler_list(kshark_ctx->event_handlers);
}
@@ -676,54 +692,50 @@
* stream->filter_mask. The value of the EVENT_VIEW flag in
* stream->filter_mask will be used instead.
*/
- int event_mask = kshark_ctx->filter_mask;
+ int event_mask = kshark_ctx->filter_mask & ~KS_GRAPH_VIEW_FILTER_MASK;
e->visible &= ~event_mask;
}
-/**
- * @brief This function loops over the array of entries specified by "data"
- * and "n_entries" and sets the "visible" fields of each entry
- * according to the criteria provided by the filters of the session's
- * context. The field "filter_mask" of the session's context is used to
- * control the level of visibility/invisibility of the entries which
- * are filtered-out.
- * WARNING: Do not use this function if the advanced filter is set.
- * Applying the advanced filter requires access to prevent_record,
- * hence the data has to be reloaded using kshark_load_data_entries().
- *
- * @param kshark_ctx: Input location for the session context pointer.
- * @param sd: Data stream identifier.
- * @param data: Input location for the trace data to be filtered.
- * @param n_entries: The size of the inputted data.
- */
-void kshark_filter_entries(struct kshark_context *kshark_ctx, int sd,
+static void filter_entries(struct kshark_context *kshark_ctx, int sd,
struct kshark_entry **data, size_t n_entries)
{
- struct kshark_data_stream *stream;
- int i;
+ struct kshark_data_stream *stream = NULL;
+ size_t i;
- stream = kshark_get_data_stream(kshark_ctx, sd);
- if (!stream)
- return;
+ if (sd >= 0) {
+ /* We will filter particular Data stream. */
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return;
- if (stream->advanced_event_filter->filters) {
- /* The advanced filter is set. */
- fprintf(stderr,
- "Failed to filter (sd = %i)!\n", sd);
- fprintf(stderr,
- "Reset the Advanced filter or reload the data.\n");
- return;
+ if (stream->advanced_event_filter->filters) {
+ /* The advanced filter is set. */
+ fprintf(stderr,
+ "Failed to filter (sd = %i)!\n", sd);
+ fprintf(stderr,
+ "Reset the Advanced filter or reload the data.\n");
+
+ return;
+ }
+
+ if (!kshark_filter_is_set(kshark_ctx, sd))
+ return;
}
- if (!kshark_filter_is_set(kshark_ctx, sd))
- return;
-
/* Apply only the Id filters. */
for (i = 0; i < n_entries; ++i) {
- /* Chack is the entry belongs to this stream. */
- if (data[i]->stream_id != sd)
- continue;
+ if (sd >= 0) {
+ /*
+ * We only filter particular stream. Chack is the entry
+ * belongs to this stream.
+ */
+ if (data[i]->stream_id != sd)
+ continue;
+ } else {
+ /* We filter all streams. */
+ stream = kshark_ctx->stream[data[i]->stream_id];
+ }
/* Start with and entry which is visible everywhere. */
data[i]->visible = 0xFF;
@@ -744,6 +756,50 @@
/**
* @brief This function loops over the array of entries specified by "data"
+ * and "n_entries" and sets the "visible" fields of each entry from a
+ * given Data stream according to the criteria provided by the filters
+ * of the session's context. The field "filter_mask" of the session's
+ * context is used to control the level of visibility/invisibility of
+ * the entries which are filtered-out.
+ * WARNING: Do not use this function if the advanced filter is set.
+ * Applying the advanced filter requires access to prevent_record,
+ * hence the data has to be reloaded using kshark_load_data_entries().
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param sd: Data stream identifier.
+ * @param data: Input location for the trace data to be filtered.
+ * @param n_entries: The size of the inputted data.
+ */
+void kshark_filter_stream_entries(struct kshark_context *kshark_ctx, int sd,
+ struct kshark_entry **data, size_t n_entries)
+{
+ if (sd >= 0)
+ filter_entries(kshark_ctx, sd, data, n_entries);
+}
+
+/**
+ * @brief This function loops over the array of entries specified by "data"
+ * and "n_entries" and sets the "visible" fields of each entry from
+ * all Data stream according to the criteria provided by the filters
+ * of the session's context. The field "filter_mask" of the session's
+ * context is used to control the level of visibility/invisibility of
+ * the entries which are filtered-out.
+ * WARNING: Do not use this function if the advanced filter is set.
+ * Applying the advanced filter requires access to prevent_record,
+ * hence the data has to be reloaded using kshark_load_data_entries().
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param data: Input location for the trace data to be filtered.
+ * @param n_entries: The size of the inputted data.
+ */
+void kshark_filter_all_entries(struct kshark_context *kshark_ctx,
+ struct kshark_entry **data, size_t n_entries)
+{
+ filter_entries(kshark_ctx, -1, data, n_entries);
+}
+
+/**
+ * @brief This function loops over the array of entries specified by "data"
* and "n_entries" and resets the "visible" fields of each entry to
* the default value of "0xFF" (visible everywhere).
*
@@ -941,6 +997,11 @@
entry = &temp_rec->entry;
missed_events_action(kshark_ctx, rec, entry);
+ if (stream->calib && stream->calib_array)
+ stream->calib(entry, stream->calib_array);
+
+ entry->stream_id = sd;
+
temp_next = &temp_rec->next;
++count;
@@ -952,6 +1013,9 @@
kshark_set_entry_values(stream, rec, entry);
entry->stream_id = sd;
+ if (stream->calib && stream->calib_array)
+ stream->calib(entry, stream->calib_array);
+
/* Execute all plugin-provided actions (if any). */
evt_handler = kshark_ctx->event_handlers;
while ((evt_handler = kshark_find_event_handler(evt_handler,
@@ -1100,6 +1164,7 @@
free_rec_list(rec_list, n_cpus, type);
*data_rows = rows;
+
return total;
fail_free:
@@ -1183,6 +1248,45 @@
return -ENOMEM;
}
+ssize_t kshark_load_all_data_entries(struct kshark_context *kshark_ctx,
+ struct kshark_entry ***data_rows)
+{
+ size_t data_size = 0;;
+ int i, *stream_ids, sd;
+
+ if (!kshark_ctx->n_streams)
+ return data_size;
+
+ stream_ids = kshark_all_streams(kshark_ctx);
+ sd = stream_ids[0];
+
+ data_size = kshark_load_data_entries(kshark_ctx, sd, data_rows);
+
+ for (i = 1; i < kshark_ctx->n_streams; ++i) {
+ struct kshark_entry **stream_data_rows = NULL;
+ struct kshark_entry **merged_data_rows;
+ size_t stream_data_size;
+
+ sd = stream_ids[i];
+ stream_data_size = kshark_load_data_entries(kshark_ctx, sd,
+ &stream_data_rows);
+
+ merged_data_rows =
+ kshark_data_merge(*data_rows, data_size,
+ stream_data_rows, stream_data_size);
+
+ free(stream_data_rows);
+ free(*data_rows);
+
+ stream_data_rows = *data_rows = NULL;
+
+ *data_rows = merged_data_rows;
+ data_size += stream_data_size;
+ }
+
+ return data_size;
+}
+
/**
* @brief A read of a record from a Data stream at a specific offset.
*
@@ -1742,9 +1846,9 @@
* Else false.
*/
bool kshark_match_pid(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int sd, int pid)
+ struct kshark_entry *e, int sd, int *pid)
{
- if (e->stream_id == sd && e->pid == pid)
+ if (e->stream_id == sd && e->pid == *pid)
return true;
return false;
@@ -1762,15 +1866,32 @@
* Else false.
*/
bool kshark_match_cpu(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int sd, int cpu)
+ struct kshark_entry *e, int sd, int *cpu)
{
- if (e->stream_id == sd && e->cpu == cpu)
+ if (e->stream_id == sd && e->cpu == *cpu)
return true;
return false;
}
/**
+ * @brief Simple Pid matching function to be user for data requests.
+ *
+ * @param kshark_ctx: Input location for the session context pointer.
+ * @param e: kshark_entry to be checked.
+ * @param sd: Data stream identifier.
+ * @param pid: Matching condition value.
+ *
+ * @returns True if the event Id of the entry matches the value of "event_id".
+ * Else false.
+ */
+bool kshark_match_event_id(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e, int sd, int *event_id)
+{
+ return e->stream_id == sd && e->event_id == *event_id;
+}
+
+/**
* @brief Create Data request. The request defines the properties of the
* requested kshark_entry.
*
@@ -1791,7 +1912,7 @@
*/
struct kshark_entry_request *
kshark_entry_request_alloc(size_t first, size_t n,
- matching_condition_func cond, int sd, int val,
+ matching_condition_func cond, int sd, int *values,
bool vis_only, int vis_mask)
{
struct kshark_entry_request *req = malloc(sizeof(*req));
@@ -1807,7 +1928,7 @@
req->n = n;
req->cond = cond;
req->sd = sd;
- req->val = val;
+ req->values = values;
req->vis_only = vis_only;
req->vis_mask = vis_mask;
@@ -1861,7 +1982,7 @@
*/
assert((inc > 0 && start < end) || (inc < 0 && start > end));
for (i = start; i != end; i += inc) {
- if (req->cond(kshark_ctx, data[i], req->sd, req->val)) {
+ if (req->cond(kshark_ctx, data[i], req->sd, req->values)) {
/*
* Data satisfying the condition has been found.
*/
@@ -1945,87 +2066,89 @@
return get_entry(req, data, index, req->first, end, -1);
}
+void kshark_offset_calib(struct kshark_entry *e, int64_t *atgv)
+{
+ e->ts += atgv[0];
+}
+
+void kshark_linear_clock_calib(struct kshark_entry *e, int64_t *atgv)
+{
+ e->ts = atgv[0] + e->ts * atgv[1];
+}
+
+
+static size_t copy_prior_data(struct kshark_entry **merged_data,
+ struct kshark_entry **prior_data,
+ size_t a_size,
+ uint64_t t)
+{
+ size_t mid, l = 0, h = a_size - 1;
+
+ /*
+ * After executing the BSEARCH macro, "l" will be the index of the last
+ * prior entry having timestamp < t and "h" will be the index of the
+ * first prior entry having timestamp >= t.
+ */
+ BSEARCH(h, l, prior_data[mid]->ts < t);
+
+ /*
+ * Copy all entries before "t" (in time).
+ */
+ memcpy(merged_data, prior_data, h * sizeof(*prior_data));
+
+ return h;
+}
+
/**
* @brief Merge two trace data streams.
*
- * @param prior_data: Input location for the prior trace data. The clock used
- * to record the prior data will be used by the merged data.
- * @param prior_size: The size of the prior trace data.
- * @param associated_data: Input location for the trace data to be merged to
- * the prior. The clock of the associated data will be
- * calibrated in order to be compatible with the clock
- * of the prior data.
- * @param associated_size: The size of the associated trace data.
- * @param calib: Callback function providing the calibration of the clock of
- * the associated data.
- * @param argv: Array of arguments for the calibration function.
+ * @param data_a: Input location for the prior trace data.
+ * @param a_size: The size of the prior trace data.
+ * @param data_b: Input location for the trace data to be merged to
+ * the prior.
+ * @param b_size: The size of the associated trace data.
*
* @returns Merged and sorted in time trace data. The user is responsible for
* freeing the elements of the outputted array.
*/
-struct kshark_entry **kshark_data_merge(struct kshark_entry **prior_data,
- size_t prior_size,
- struct kshark_entry **associated_data,
- size_t associated_size,
- time_calib_func calib,
- int64_t *argv)
+struct kshark_entry **kshark_data_merge(struct kshark_entry **data_a,
+ size_t a_size,
+ struct kshark_entry **data_b,
+ size_t b_size)
{
- size_t i = 0, prior_count = 0, assc_count = 0;
- size_t tot = prior_size + associated_size;
- size_t mid, l = 0, h = prior_size - 1;
+ size_t i = 0, a_count = 0, b_count = 0;
+ size_t tot = a_size + b_size, cpy_size;
struct kshark_entry **merged_data;
merged_data = calloc(tot, sizeof(*merged_data));
-
- /*
- * Calibrate the timestamp of the first entry of the associated data.
- */
- calib(associated_data[0], argv);
-
- if (prior_data[0]->ts < associated_data[0]->ts) {
- /*
- * After executing the BSEARCH macro, "l" will be the index of
- * the last prior entry having timestamp < associated_data[0]->ts
- * and "h" will be the index of the first prior entry having
- * timestamp >= associated_data[0]->ts.
- */
- BSEARCH(h, l, prior_data[mid]->ts < associated_data[0]->ts);
-
- /*
- * The prior data needs no time calibration. Copy all entries
- * before (in time) the first entry of the associated data.
- */
- memcpy(merged_data, prior_data, h * sizeof(*prior_data));
- i = prior_count = h;
+ if (data_a[0]->ts < data_b[0]->ts) {
+ i = a_count = copy_prior_data(merged_data, data_a,
+ a_size, data_b[0]->ts);
+ } else {
+ i = b_count = copy_prior_data(merged_data, data_b,
+ b_size, data_a[0]->ts);
}
for (; i < tot; ++i) {
- if (prior_data[prior_count]->ts <= associated_data[assc_count]->ts) {
- merged_data[i] = prior_data[prior_count++];
- if (prior_count == prior_size)
+ if (data_a[a_count]->ts <= data_b[b_count]->ts) {
+ merged_data[i] = data_a[a_count++];
+ if (a_count == a_size)
break;
} else {
- merged_data[i] = associated_data[assc_count++];
- if (assc_count == associated_size)
+ merged_data[i] = data_b[b_count++];
+ if (b_count == b_size)
break;
-
- /* Calibrate the timestamp of the following entry. */
- calib(associated_data[assc_count], argv);
}
}
- if (prior_count == prior_size && assc_count < associated_size) {
- /* Calibrate and copy the remaining associated data. */
- for (++i; i < tot; ++i) {
- merged_data[i] = associated_data[assc_count++];
- calib(merged_data[i], argv);
- }
- } else if (prior_count < prior_size && assc_count == associated_size) {
- /* Copy the remaining prior data. */
- ++i;
- memcpy(&merged_data[i], &prior_data[prior_count],
- (tot - i) * sizeof(*prior_data));
- }
+ /* Copy the remaining data. */
+ ++i;
+ cpy_size = (tot - i) * sizeof(*merged_data);
+
+ if (a_count == a_size && b_count < b_size)
+ memcpy(&merged_data[i], &data_b[b_count], cpy_size);
+ else if (a_count < a_size && b_count == b_size)
+ memcpy(&merged_data[i], &data_a[a_count], cpy_size);
return merged_data;
}
diff --git a/kernel-shark/src/libkshark.h b/kernel-shark/src/libkshark.h
index 05e3c47..c576655 100644
--- a/kernel-shark/src/libkshark.h
+++ b/kernel-shark/src/libkshark.h
@@ -87,6 +87,11 @@
int pid;
};
+/**
+ * Timestamp calibration function type. To be user for system clock calibration.
+ */
+typedef void (*time_calib_func) (struct kshark_entry *, int64_t *);
+
/** tructure representing a stream of trace data. */
struct kshark_data_stream {
/** Input handle for the trace data file. */
@@ -104,6 +109,9 @@
/** The size of the array of time calibration constants. */
size_t calib_array_size;
+ /** System clock calibration function. */
+ time_calib_func calib;
+
/** Hash table of task PIDs. */
struct kshark_task_list **tasks;
@@ -176,6 +184,9 @@
ssize_t kshark_load_data_entries(struct kshark_context *kshark_ctx, int sd,
struct kshark_entry ***data_rows);
+ssize_t kshark_load_all_data_entries(struct kshark_context *kshark_ctx,
+ struct kshark_entry ***data_rows);
+
ssize_t kshark_load_data_records(struct kshark_context *kshark_ctx, int sd,
struct tep_record ***data_rows);
@@ -184,6 +195,8 @@
void kshark_close(struct kshark_context *kshark_ctx, int sd);
+void kshark_close_all(struct kshark_context *kshark_ctx);
+
void kshark_free(struct kshark_context *kshark_ctx);
inline static struct kshark_data_stream *
@@ -300,9 +313,12 @@
bool kshark_filter_is_set(struct kshark_context *kshark_ctx, int sd);
-void kshark_filter_entries(struct kshark_context *kshark_ctx, int sd,
- struct kshark_entry **data,
- size_t n_entries);
+void kshark_filter_stream_entries(struct kshark_context *kshark_ctx, int sd,
+ struct kshark_entry **data,
+ size_t n_entries);
+
+void kshark_filter_all_entries(struct kshark_context *kshark_ctx,
+ struct kshark_entry **data, size_t n_entries);
void kshark_clear_all_filters(struct kshark_context *kshark_ctx,
struct kshark_entry **data,
@@ -338,10 +354,13 @@
size_t l, size_t h);
bool kshark_match_pid(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int sd, int pid);
+ struct kshark_entry *e, int sd, int *pid);
bool kshark_match_cpu(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int sd, int cpu);
+ struct kshark_entry *e, int sd, int *cpu);
+
+bool kshark_match_event_id(struct kshark_context *kshark_ctx,
+ struct kshark_entry *e, int sd, int *event_id);
/**
* Empty bin identifier.
@@ -359,7 +378,7 @@
/** Matching condition function type. To be user for data requests */
typedef bool (matching_condition_func)(struct kshark_context*,
struct kshark_entry*,
- int, int);
+ int, int*);
/**
* Data request structure, defining the properties of the required
@@ -387,7 +406,7 @@
/**
* Matching condition value, used by the Matching condition function.
*/
- int val;
+ int *values;
/** If true, a visible entry is requested. */
bool vis_only;
@@ -401,7 +420,7 @@
struct kshark_entry_request *
kshark_entry_request_alloc(size_t first, size_t n,
- matching_condition_func cond, int sd, int val,
+ matching_condition_func cond, int sd, int *values,
bool vis_only, int vis_mask);
void kshark_free_entry_request(struct kshark_entry_request *req);
@@ -416,22 +435,19 @@
struct kshark_entry **data,
ssize_t *index);
-/**
- * Timestamp calibration function type. To be user for merging data streams.
- */
-typedef void (*time_calib_func) (struct kshark_entry *, int64_t *);
+void kshark_offset_calib(struct kshark_entry *e, int64_t *atgv);
+
+void kshark_linear_clock_calib(struct kshark_entry *e, int64_t *atgv);
struct kshark_entry **kshark_data_merge(struct kshark_entry **prior_data,
size_t prior_size,
struct kshark_entry **associated_data,
- size_t associated_size,
- time_calib_func calib,
- int64_t *argv);
+ size_t associated_size);
/**
* Data collections are used to optimize the search for an entry having an
- * abstract property, defined by a Matching condition function and a value.
- * When a collection is processed, the data which is relevant for the
+ * abstract property, defined by a Matching condition function and an array of
+ * values. When a collection is processed, the data which is relevant for the
* collection is enclosed in "Data intervals", defined by pairs of "Resume" and
* "Break" points. It is guaranteed that the data outside of the intervals
* contains no entries satisfying the abstract matching condition. However, the
@@ -449,13 +465,15 @@
matching_condition_func *cond;
/** Data stream identifier. */
- int sd;
+ int stream_id;
/**
- * Matching condition value, used by the Matching condition finction
- * to define the collections.
+ * Array of matching condition values, used by the Matching condition
+ * finction to define the collection.
*/
- int val;
+ int *values;
+
+ int n_val;
/**
* Array of indexes defining the beginning of each individual data
@@ -478,23 +496,24 @@
struct kshark_entry **data,
size_t n_rows,
matching_condition_func cond,
- int sd, int val,
+ int sd, int *values, size_t n_val,
size_t margin);
struct kshark_entry_collection *
kshark_register_data_collection(struct kshark_context *kshark_ctx,
struct kshark_entry **data, size_t n_rows,
- matching_condition_func cond, int sd, int val,
+ matching_condition_func cond,
+ int sd, int *values, size_t n_val,
size_t margin);
void kshark_unregister_data_collection(struct kshark_entry_collection **col,
matching_condition_func cond,
- int sd, int val);
+ int sd, int *values, size_t n_val);
struct kshark_entry_collection *
kshark_find_data_collection(struct kshark_entry_collection *col,
matching_condition_func cond,
- int sd, int val);
+ int sd, int *values, size_t n_val);
void kshark_reset_data_collection(struct kshark_entry_collection *col);
@@ -684,12 +703,12 @@
enum kshark_config_formats format);
int kshark_import_dstream(struct kshark_context *kshark_ctx,
- struct kshark_config_doc *conf,
+ struct kshark_config_doc *conf/*,
struct kshark_entry ***data_rows,
- size_t *data_size);
+ size_t *data_size*/);
bool kshark_export_all_dstreams(struct kshark_context *kshark_ctx,
- struct kshark_config_doc *conf);
+ struct kshark_config_doc **conf);
bool kshark_import_all_dstreams(struct kshark_context *kshark_ctx,
struct kshark_config_doc *conf,
diff --git a/kernel-shark/src/plugins/CMakeLists.txt b/kernel-shark/src/plugins/CMakeLists.txt
index c9b5bdd..1fa2fc3 100644
--- a/kernel-shark/src/plugins/CMakeLists.txt
+++ b/kernel-shark/src/plugins/CMakeLists.txt
@@ -23,15 +23,15 @@
SOURCE sched_events.c SchedEvents.cpp)
list(APPEND PLUGIN_LIST "sched_events default") # This plugin will be loaded by default
-BUILD_PLUGIN(NAME rename_sched_events
- SOURCE rename_sched_events.c)
-list(APPEND PLUGIN_LIST "rename_sched_events") # This plugin isn't loaded by default
+# BUILD_PLUGIN(NAME rename_sched_events
+# SOURCE rename_sched_events.c)
+# list(APPEND PLUGIN_LIST "rename_sched_events") # This plugin isn't loaded by default
-BUILD_PLUGIN(NAME missed_events
- SOURCE missed_events.c MissedEvents.cpp)
-list(APPEND PLUGIN_LIST "missed_events default") # This plugin will be loaded by default
+# BUILD_PLUGIN(NAME missed_events
+# SOURCE missed_events.c MissedEvents.cpp)
+# list(APPEND PLUGIN_LIST "missed_events default") # This plugin will be loaded by default
-install(TARGETS sched_events missed_events
- LIBRARY DESTINATION ${_INSTALL_PREFIX}/lib/kshark/)
+#install(TARGETS sched_events missed_events
+# LIBRARY DESTINATION ${_INSTALL_PREFIX}/lib/kshark/)
set(PLUGINS ${PLUGIN_LIST} PARENT_SCOPE)
diff --git a/kernel-shark/src/plugins/MissedEvents.cpp b/kernel-shark/src/plugins/MissedEvents.cpp
index 05dfcb5..4d28c6c 100644
--- a/kernel-shark/src/plugins/MissedEvents.cpp
+++ b/kernel-shark/src/plugins/MissedEvents.cpp
@@ -86,7 +86,7 @@
static void pluginDraw(kshark_context *kshark_ctx,
KsCppArgV *argvCpp,
- int val, int draw_action)
+ int sd, int val, int draw_action)
{
int height = argvCpp->_graph->getHeight();
const kshark_entry *entry(nullptr);
@@ -97,12 +97,12 @@
for (int bin = 0; bin < nBins; ++bin) {
if (draw_action == KSHARK_PLUGIN_TASK_DRAW)
entry = ksmodel_get_task_missed_events(argvCpp->_histo,
- bin, val,
+ bin, sd, val,
nullptr,
&index);
if (draw_action == KSHARK_PLUGIN_CPU_DRAW)
entry = ksmodel_get_cpu_missed_events(argvCpp->_histo,
- bin, val,
+ bin, sd, val,
nullptr,
&index);
@@ -123,7 +123,7 @@
* @param draw_action: Draw action identifier.
*/
void draw_missed_events(kshark_cpp_argv *argv_c,
- int val, int draw_action)
+ int sd, int val, int draw_action)
{
kshark_context *kshark_ctx(NULL);
@@ -142,7 +142,7 @@
return;
try {
- pluginDraw(kshark_ctx, argvCpp, val, draw_action);
+ pluginDraw(kshark_ctx, argvCpp, sd, val, draw_action);
} catch (const std::exception &exc) {
std::cerr << "Exception in MissedEvents\n" << exc.what();
}
diff --git a/kernel-shark/src/plugins/SchedEvents.cpp b/kernel-shark/src/plugins/SchedEvents.cpp
index 8408657..63c120c 100644
--- a/kernel-shark/src/plugins/SchedEvents.cpp
+++ b/kernel-shark/src/plugins/SchedEvents.cpp
@@ -32,8 +32,6 @@
//! @endcond
-extern struct plugin_sched_context *plugin_sched_context_handler;
-
/** Sched Event identifier. */
enum class SchedEvent {
/** Sched Switch Event. */
@@ -48,7 +46,7 @@
kshark_trace_histo *histo,
kshark_entry_collection *col,
SchedEvent e,
- int pid,
+ int sd, int pid,
KsPlot::Graph *graph,
KsPlot::PlotObjList *shapes)
{
@@ -56,7 +54,7 @@
ssize_t indexClose(0), indexOpen(0), indexME(0);
std::function<void(int)> ifSchedBack;
KsPlot::Rectangle *rec = nullptr;
- int height = graph->getHeight() * .3;
+ int height = graph->height() * .3;
auto openBox = [&] (const KsPlot::Point &p)
{
@@ -108,11 +106,12 @@
* condition defined by kshark_match_pid.
*/
entryClose = ksmodel_get_entry_back(histo, bin, false,
- plugin_switch_match_entry_pid,
- pid, col, &indexClose);
+ plugin_switch_match_entry_pid,
+ sd, &pid, col, &indexClose);
entryME = ksmodel_get_task_missed_events(histo,
- bin, pid,
+ bin,
+ sd, pid,
col,
&indexME);
@@ -125,7 +124,7 @@
entryOpen =
ksmodel_get_entry_back(histo, bin, false,
plugin_switch_match_rec_pid,
- pid, col, &indexOpen);
+ sd, &pid, col, &indexOpen);
} else {
/*
@@ -136,13 +135,13 @@
entryOpen =
ksmodel_get_entry_back(histo, bin, false,
plugin_wakeup_match_rec_pid,
- pid,
+ sd, &pid,
col,
&indexOpen);
if (entryOpen) {
int cpu = ksmodel_get_cpu_back(histo, bin,
- pid,
+ sd, pid,
false,
col,
nullptr);
@@ -201,7 +200,7 @@
*/
static void secondPass(kshark_entry **data,
kshark_entry_collection *col,
- int pid)
+ int sd, int pid)
{
if (!col)
return;
@@ -219,7 +218,7 @@
kshark_entry_request *req =
kshark_entry_request_alloc(first, n,
plugin_switch_match_rec_pid,
- pid,
+ sd, &pid,
false,
KS_GRAPH_VIEW_FILTER_MASK);
@@ -255,7 +254,7 @@
* @param pid: Process Id.
* @param draw_action: Draw action identifier.
*/
-void plugin_draw(kshark_cpp_argv *argv_c, int pid, int draw_action)
+void plugin_draw(kshark_cpp_argv *argv_c, int sd, int pid, int draw_action)
{
plugin_sched_context *plugin_ctx;
kshark_context *kshark_ctx(NULL);
@@ -264,7 +263,7 @@
if (draw_action != KSHARK_PLUGIN_TASK_DRAW || pid == 0)
return;
- plugin_ctx = plugin_sched_context_handler;
+ plugin_ctx = get_sched_context(sd);
if (!plugin_ctx || !kshark_instance(&kshark_ctx))
return;
@@ -275,7 +274,7 @@
* coll = NULL.
*/
col = kshark_find_data_collection(plugin_ctx->collections,
- plugin_match_pid, pid);
+ plugin_match_pid, sd, &pid, 1);
if (!col) {
/*
* If a data collection for this task does not exist,
@@ -287,26 +286,27 @@
col = kshark_add_collection_to_list(kshark_ctx,
&plugin_ctx->collections,
data, size,
- plugin_match_pid, pid,
+ plugin_match_pid,
+ sd, &pid, 1,
KS_TASK_COLLECTION_MARGIN);
}
if (!tracecmd_filter_id_find(plugin_ctx->second_pass_hash, pid)) {
/* The second pass for this task is not done yet. */
- secondPass(argvCpp->_histo->data, col, pid);
+ secondPass(argvCpp->_histo->data, col, sd, pid);
tracecmd_filter_id_add(plugin_ctx->second_pass_hash, pid);
}
try {
pluginDraw(plugin_ctx, kshark_ctx,
argvCpp->_histo, col,
- SchedEvent::Wakeup, pid,
+ SchedEvent::Wakeup, sd, pid,
argvCpp->_graph, argvCpp->_shapes);
- pluginDraw(plugin_ctx, kshark_ctx,
- argvCpp->_histo, col,
- SchedEvent::Switch, pid,
- argvCpp->_graph, argvCpp->_shapes);
+// pluginDraw(plugin_ctx, kshark_ctx,
+// argvCpp->_histo, col,
+// SchedEvent::Switch, sd, pid,
+// argvCpp->_graph, argvCpp->_shapes);
} catch (const std::exception &exc) {
std::cerr << "Exception in SchedEvents\n" << exc.what();
}
diff --git a/kernel-shark/src/plugins/missed_events.c b/kernel-shark/src/plugins/missed_events.c
index cf652bf..cc41e22 100644
--- a/kernel-shark/src/plugins/missed_events.c
+++ b/kernel-shark/src/plugins/missed_events.c
@@ -19,10 +19,13 @@
{}
/** Load this plugin. */
-int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx)
+int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx, int sd)
{
+ printf("--> missed_events init %i\n", sd);
+
kshark_register_event_handler(&kshark_ctx->event_handlers,
KS_EVENT_OVERFLOW,
+ sd,
nop_action,
draw_missed_events);
@@ -30,10 +33,13 @@
}
/** Unload this plugin. */
-int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx)
+int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx, int sd)
{
+ printf("<-- missed_events close %i\n", sd);
+
kshark_unregister_event_handler(&kshark_ctx->event_handlers,
KS_EVENT_OVERFLOW,
+ sd,
nop_action,
draw_missed_events);
diff --git a/kernel-shark/src/plugins/missed_events.h b/kernel-shark/src/plugins/missed_events.h
index e05d79a..3777375 100644
--- a/kernel-shark/src/plugins/missed_events.h
+++ b/kernel-shark/src/plugins/missed_events.h
@@ -21,7 +21,7 @@
#endif
void draw_missed_events(struct kshark_cpp_argv *argv,
- int pid, int draw_action);
+ int sd, int pid, int draw_action);
#ifdef __cplusplus
}
diff --git a/kernel-shark/src/plugins/sched_events.c b/kernel-shark/src/plugins/sched_events.c
index d0fd15e..02b461d 100644
--- a/kernel-shark/src/plugins/sched_events.c
+++ b/kernel-shark/src/plugins/sched_events.c
@@ -21,7 +21,9 @@
#include "plugins/sched_events.h"
/** Plugin context instance. */
-struct plugin_sched_context *plugin_sched_context_handler = NULL;
+// struct plugin_sched_context *plugin_sched_context_handler = NULL;
+static struct plugin_sched_context *
+plugin_sched_context_handler[KS_MAX_NUM_STREAMS] = {NULL};
static bool define_wakeup_event(struct tep_handle *tep, const char *wakeup_name,
struct tep_event **wakeup_event,
@@ -50,34 +52,43 @@
free(plugin_ctx);
}
-static bool plugin_sched_init_context(struct kshark_context *kshark_ctx)
+struct plugin_sched_context *get_sched_context(int sd)
+{
+ return plugin_sched_context_handler[sd];
+}
+
+static bool plugin_sched_init_context(struct kshark_context *kshark_ctx,
+ int sd)
{
struct plugin_sched_context *plugin_ctx;
+ struct kshark_data_stream *stream;
struct tep_event *event;
bool wakeup_found;
- /* No context should exist when we initialize the plugin. */
- assert(plugin_sched_context_handler == NULL);
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream)
+ return false;
- plugin_sched_context_handler =
- calloc(1, sizeof(*plugin_sched_context_handler));
- if (!plugin_sched_context_handler) {
+ /* No context should exist when we initialize the plugin. */
+ assert(plugin_sched_context_handler[sd] == NULL);
+
+ plugin_ctx = calloc(1, sizeof(*plugin_ctx));
+ if (!plugin_ctx) {
fprintf(stderr,
"Failed to allocate memory for plugin_sched_context.\n");
return false;
}
- plugin_ctx = plugin_sched_context_handler;
- plugin_ctx->handle = kshark_ctx->handle;
- plugin_ctx->pevent = kshark_ctx->pevent;
+ plugin_ctx->handle = stream->handle;
+ plugin_ctx->pevent = stream->pevent;
plugin_ctx->collections = NULL;
event = tep_find_event_by_name(plugin_ctx->pevent,
"sched", "sched_switch");
if (!event) {
+ fprintf(stderr, "No sched_switch events in stream %i.\n", sd);
plugin_free_context(plugin_ctx);
plugin_sched_context_handler = NULL;
-
return false;
}
@@ -91,20 +102,20 @@
plugin_ctx->sched_switch_prev_state_field =
tep_find_field(event, "prev_state");
-
- wakeup_found = define_wakeup_event(kshark_ctx->pevent, "sched_wakeup",
+ wakeup_found = define_wakeup_event(stream->pevent, "sched_wakeup",
&plugin_ctx->sched_wakeup_event,
&plugin_ctx->sched_wakeup_pid_field);
- wakeup_found |= define_wakeup_event(kshark_ctx->pevent, "sched_wakeup_new",
- &plugin_ctx->sched_wakeup_new_event,
- &plugin_ctx->sched_wakeup_new_pid_field);
+ wakeup_found |= define_wakeup_event(stream->pevent, "sched_wakeup_new",
+ &plugin_ctx->sched_wakeup_new_event,
+ &plugin_ctx->sched_wakeup_new_pid_field);
- wakeup_found |= define_wakeup_event(kshark_ctx->pevent, "sched_waking",
- &plugin_ctx->sched_waking_event,
- &plugin_ctx->sched_waking_pid_field);
+ wakeup_found |= define_wakeup_event(stream->pevent, "sched_waking",
+ &plugin_ctx->sched_waking_event,
+ &plugin_ctx->sched_waking_pid_field);
plugin_ctx->second_pass_hash = tracecmd_filter_id_hash_alloc();
+ plugin_sched_context_handler[sd] = plugin_ctx;
return true;
}
@@ -114,10 +125,10 @@
*
* @param record: Input location for a sched_switch record.
*/
-int plugin_get_next_pid(struct tep_record *record)
+int plugin_get_next_pid(struct tep_record *record, int sd)
{
struct plugin_sched_context *plugin_ctx =
- plugin_sched_context_handler;
+ plugin_sched_context_handler[sd];
unsigned long long val;
int ret;
@@ -129,13 +140,15 @@
static void plugin_register_command(struct kshark_context *kshark_ctx,
struct tep_record *record,
- int pid)
+ int sd, int pid)
{
struct plugin_sched_context *plugin_ctx =
- plugin_sched_context_handler;
+ plugin_sched_context_handler[sd];
+ struct kshark_data_stream *stream;
const char *comm;
- if (!plugin_ctx->sched_switch_comm_field)
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream || !plugin_ctx->sched_switch_comm_field)
return;
comm = record->data + plugin_ctx->sched_switch_comm_field->offset;
@@ -144,21 +157,23 @@
* implemented as a wrapper function in libtracevent.
*/
- if (!tep_is_pid_registered(kshark_ctx->pevent, pid))
- tep_register_comm(kshark_ctx->pevent, comm, pid);
+ if (!tep_is_pid_registered(stream->pevent, pid))
+ tep_register_comm(stream->pevent, comm, pid);
}
-static int find_wakeup_pid(struct kshark_context *kshark_ctx, struct kshark_entry *e,
+int find_wakeup_pid(struct kshark_context *kshark_ctx, struct kshark_entry *e, int sd,
struct tep_event *wakeup_event, struct tep_format_field *pid_field)
{
+ struct kshark_data_stream *stream;
struct tep_record *record;
unsigned long long val;
int ret;
- if (!wakeup_event || e->event_id != wakeup_event->id)
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ if (!stream || !wakeup_event || e->event_id != wakeup_event->id)
return -1;
- record = tracecmd_read_at(kshark_ctx->handle, e->offset, NULL);
+ record = tracecmd_read_at(stream->handle, e->offset, NULL);
ret = tep_read_number_field(pid_field, record->data, &val);
free_record(record);
@@ -171,7 +186,7 @@
static bool wakeup_match_rec_pid(struct plugin_sched_context *plugin_ctx,
struct kshark_context *kshark_ctx,
struct kshark_entry *e,
- int pid)
+ int sd, int pid)
{
struct tep_event *wakeup_events[] = {
plugin_ctx->sched_waking_event,
@@ -186,7 +201,8 @@
int i, wakeup_pid = -1;
for (i = 0; i < sizeof(wakeup_events) / sizeof(wakeup_events[0]); i++) {
- wakeup_pid = find_wakeup_pid(kshark_ctx, e, wakeup_events[i], wakeup_fields[i]);
+ wakeup_pid = find_wakeup_pid(kshark_ctx, e, sd,
+ wakeup_events[i], wakeup_fields[i]);
if (wakeup_pid >= 0)
break;
}
@@ -210,15 +226,16 @@
*/
bool plugin_wakeup_match_rec_pid(struct kshark_context *kshark_ctx,
struct kshark_entry *e,
- int pid)
+ int sd, int *pid)
{
struct plugin_sched_context *plugin_ctx;
- plugin_ctx = plugin_sched_context_handler;
- if (!plugin_ctx)
+ plugin_ctx = plugin_sched_context_handler[sd];
+
+ if (e->stream_id != sd)
return false;
- return wakeup_match_rec_pid(plugin_ctx, kshark_ctx, e, pid);
+ return wakeup_match_rec_pid(plugin_ctx, kshark_ctx, e, sd, *pid);
}
/**
@@ -233,19 +250,20 @@
*/
bool plugin_switch_match_rec_pid(struct kshark_context *kshark_ctx,
struct kshark_entry *e,
- int pid)
+ int sd, int *pid)
{
struct plugin_sched_context *plugin_ctx;
unsigned long long val;
int ret, switch_pid = -1;
- plugin_ctx = plugin_sched_context_handler;
+ plugin_ctx = plugin_sched_context_handler[sd];
if (plugin_ctx->sched_switch_event &&
+ e->stream_id == sd &&
e->event_id == plugin_ctx->sched_switch_event->id) {
struct tep_record *record;
- record = tracecmd_read_at(kshark_ctx->handle, e->offset, NULL);
+ record = kshark_read_at(kshark_ctx, sd, e->offset);
ret = tep_read_number_field(plugin_ctx->sched_switch_prev_state_field,
record->data, &val);
@@ -255,7 +273,7 @@
free_record(record);
}
- if (switch_pid >= 0 && switch_pid == pid)
+ if (switch_pid >= 0 && switch_pid == *pid)
return true;
return false;
@@ -273,15 +291,16 @@
*/
bool plugin_switch_match_entry_pid(struct kshark_context *kshark_ctx,
struct kshark_entry *e,
- int pid)
+ int sd, int *pid)
{
struct plugin_sched_context *plugin_ctx;
- plugin_ctx = plugin_sched_context_handler;
+ plugin_ctx = plugin_sched_context_handler[sd];
if (plugin_ctx->sched_switch_event &&
e->event_id == plugin_ctx->sched_switch_event->id &&
- e->pid == pid)
+ e->stream_id == sd &&
+ e->pid == *pid)
return true;
return false;
@@ -299,69 +318,74 @@
* Otherwise false.
*/
bool plugin_match_pid(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int pid)
+ struct kshark_entry *e, int sd, int *pid)
{
- return plugin_switch_match_entry_pid(kshark_ctx, e, pid) ||
- plugin_switch_match_rec_pid(kshark_ctx, e, pid) ||
- plugin_wakeup_match_rec_pid(kshark_ctx, e, pid);
+ return plugin_switch_match_entry_pid(kshark_ctx, e, sd, pid) ||
+ plugin_switch_match_rec_pid(kshark_ctx, e, sd, pid) ||
+ plugin_wakeup_match_rec_pid(kshark_ctx, e, sd, pid);
}
static void plugin_sched_action(struct kshark_context *kshark_ctx,
struct tep_record *rec,
struct kshark_entry *entry)
{
- int pid = plugin_get_next_pid(rec);
+ int pid = plugin_get_next_pid(rec, entry->stream_id);
if (pid >= 0) {
entry->pid = pid;
- plugin_register_command(kshark_ctx, rec, entry->pid);
+ plugin_register_command(kshark_ctx, rec,
+ entry->stream_id,
+ entry->pid);
}
}
-static int plugin_sched_init(struct kshark_context *kshark_ctx)
+static int plugin_sched_init(struct kshark_context *kshark_ctx, int sd)
{
struct plugin_sched_context *plugin_ctx;
- if (!plugin_sched_init_context(kshark_ctx))
+ if (!plugin_sched_init_context(kshark_ctx, sd))
return 0;
- plugin_ctx = plugin_sched_context_handler;
+ plugin_ctx = plugin_sched_context_handler[sd];
kshark_register_event_handler(&kshark_ctx->event_handlers,
plugin_ctx->sched_switch_event->id,
+ sd,
plugin_sched_action,
plugin_draw);
return 1;
}
-static int plugin_sched_close(struct kshark_context *kshark_ctx)
+static int plugin_sched_close(struct kshark_context *kshark_ctx, int sd)
{
struct plugin_sched_context *plugin_ctx;
- if (!plugin_sched_context_handler)
+ plugin_ctx = plugin_sched_context_handler[sd];
+ if (!plugin_ctx)
return 0;
- plugin_ctx = plugin_sched_context_handler;
-
kshark_unregister_event_handler(&kshark_ctx->event_handlers,
plugin_ctx->sched_switch_event->id,
+ sd,
plugin_sched_action,
plugin_draw);
- plugin_free_context(plugin_ctx);
- plugin_sched_context_handler = NULL;
+ plugin_free_context(plugin_sched_context_handler[sd]);
+ plugin_sched_context_handler[sd] = NULL;
return 1;
}
/** Load this plugin. */
-int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx)
+int KSHARK_PLUGIN_INITIALIZER(struct kshark_context *kshark_ctx, int sd)
{
- return plugin_sched_init(kshark_ctx);
+ printf("--> sched init %i\n", sd);
+ return plugin_sched_init(kshark_ctx, sd);
}
/** Unload this plugin. */
-int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx)
+int KSHARK_PLUGIN_DEINITIALIZER(struct kshark_context *kshark_ctx, int sd)
{
- return plugin_sched_close(kshark_ctx);
+ printf("<-- sched close %i\n", sd);
+ return plugin_sched_close(kshark_ctx, sd);
}
diff --git a/kernel-shark/src/plugins/sched_events.h b/kernel-shark/src/plugins/sched_events.h
index dbc9963..96cc904 100644
--- a/kernel-shark/src/plugins/sched_events.h
+++ b/kernel-shark/src/plugins/sched_events.h
@@ -64,22 +64,25 @@
struct tracecmd_filter_id *second_pass_hash;
};
-int plugin_get_next_pid(struct tep_record *record);
+struct plugin_sched_context *get_sched_context(int sd);
+
+int plugin_get_next_pid(struct tep_record *record, int sd);
bool plugin_wakeup_match_rec_pid(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int pid);
+ struct kshark_entry *e, int sd, int *pid);
bool plugin_switch_match_rec_pid(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int pid);
+ struct kshark_entry *e, int sd, int *pid);
bool plugin_switch_match_entry_pid(struct kshark_context *kshark_ctx,
struct kshark_entry *e,
- int pid);
+ int sd, int *pid);
bool plugin_match_pid(struct kshark_context *kshark_ctx,
- struct kshark_entry *e, int pid);
+ struct kshark_entry *e, int sd, int *pid);
-void plugin_draw(struct kshark_cpp_argv *argv, int pid, int draw_action);
+void plugin_draw(struct kshark_cpp_argv *argv, int sd, int pid,
+ int draw_action);
#ifdef __cplusplus
}