linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Yordan Karadzhov (VMware)" <y.karadz@gmail.com>
To: rostedt@goodmis.org
Cc: linux-trace-devel@vger.kernel.org,
	"Yordan Karadzhov (VMware)" <y.karadz@gmail.com>
Subject: [PATCH v2 6/6] kernel-shark: Optimize the logic of the filtering menus
Date: Mon, 30 Mar 2020 19:06:52 +0300	[thread overview]
Message-ID: <20200330160652.28424-7-y.karadz@gmail.com> (raw)
In-Reply-To: <20200330160652.28424-1-y.karadz@gmail.com>

The logic of the menus is optimized to automatically decide whether is
more efficient to use positive (show only) or negative (do not show)
ID filter. Note that there is no difference between using positive or
negative filters in terms of performance, because the IDs of each filter
are stored in a hash table, hence the checks are made in constant time.
The motivation is just to keep the configuration of the filters as
simple as possible, in particular when we want this configuration to be
saved and later restored from the Session. The patch also fixes the
problem of negative filters set from the Quick Context menu not being
shown in the main filtering menus.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 kernel-shark/src/KsMainWindow.cpp | 193 ++++++++++++++++++++----------
 kernel-shark/src/KsMainWindow.hpp |   9 ++
 2 files changed, 142 insertions(+), 60 deletions(-)

diff --git a/kernel-shark/src/KsMainWindow.cpp b/kernel-shark/src/KsMainWindow.cpp
index 9b5fc2d..1f56645 100644
--- a/kernel-shark/src/KsMainWindow.cpp
+++ b/kernel-shark/src/KsMainWindow.cpp
@@ -594,42 +594,127 @@ void KsMainWindow::_graphFilterSync(int state)
 	_data.update();
 }
 
+void KsMainWindow::_presetCBWidget(tracecmd_filter_id *showFilter,
+				   tracecmd_filter_id *hideFilter,
+				   KsCheckBoxWidget *cbw)
+{
+	if (!kshark_this_filter_is_set(showFilter) &&
+	    !kshark_this_filter_is_set(hideFilter)) {
+		/*
+		 * No filter is set currently. All CheckBoxes of the Widget
+		 * will be checked.
+		 */
+		cbw->setDefault(true);
+	} else {
+		QVector<int> ids = cbw->getIds();
+		QVector<bool>  status;
+		int n = ids.count();
+		bool show, hide;
+
+		if (kshark_this_filter_is_set(showFilter)) {
+			/*
+			 * The "show only" filter is set. The default status
+			 * of all CheckBoxes will be "unchecked".
+			 */
+			status = QVector<bool>(n, false);
+			for (int i = 0; i < n; ++i) {
+				show = !!tracecmd_filter_id_find(showFilter,
+							         ids[i]);
+
+				hide = !!tracecmd_filter_id_find(hideFilter,
+							         ids[i]);
+
+				if (show && !hide) {
+					/*
+					 * Both "show" and "hide" define this
+					 * Id as visible. Set the status of
+					 * its CheckBoxes to "checked".
+					 */
+					status[i] = true;
+				}
+			}
+		} else {
+			/*
+			 * Only the "do not show" filter is set. The default
+			 * status of all CheckBoxes will be "checked".
+			 */
+			status = QVector<bool>(n, true);
+			for (int i = 0; i < n; ++i) {
+				hide = !!tracecmd_filter_id_find(hideFilter,
+							         ids[i]);
+
+				if (hide)
+					status[i] = false;
+			}
+		}
+
+		cbw->set(status);
+	}
+}
+
+void KsMainWindow::_applyFilter(QVector<int> all, QVector<int> show,
+				std::function<void(QVector<int>)> posFilter,
+				std::function<void(QVector<int>)> negFilter)
+{
+	if (show.count() < all.count() / 2) {
+		posFilter(show);
+	} else {
+		/*
+		 * It is more efficiant to apply negative (do not show) filter.
+		 */
+		QVector<int> diff;
+
+		/*
+		 * The Ids may not be sorted, because in the widgets the items
+		 * are shown sorted by name. Get those Ids sorted first.
+		 */
+		std::sort(all.begin(), all.end());
+		std::sort(show.begin(), show.end());
+
+		/*
+		 * The IDs of the "do not show" filter are given by the
+		 * difference between "all" Ids and the Ids of the "show only"
+		 * filter.
+		 */
+		std::set_difference(all.begin(), all.end(),
+				    show.begin(), show.end(),
+				    std::inserter(diff, diff.begin()));
+
+		negFilter(diff);
+	}
+}
+
+/* Quiet warnings over documenting simple structures */
+//! @cond Doxygen_Suppress
+
+#define LAMDA_FILTER(method) [=] (QVector<int> vec) {method(vec);}
+
+//! @endcond
+
 void KsMainWindow::_showEvents()
 {
 	kshark_context *kshark_ctx(nullptr);
 	KsCheckBoxWidget *events_cb;
 	KsCheckBoxDialog *dialog;
+	QVector<bool> v;
 
 	if (!kshark_instance(&kshark_ctx))
 		return;
 
 	events_cb = new KsEventsCheckBoxWidget(_data.tep(), this);
 	dialog = new KsCheckBoxDialog(events_cb, this);
+	_presetCBWidget(kshark_ctx->show_event_filter,
+		        kshark_ctx->hide_event_filter,
+		        events_cb);
+
+	auto lamFilter = [=] (QVector<int> show) {
+		QVector<int> all = KsUtils::getEventIdList();
+		_applyFilter(all, show,
+			     LAMDA_FILTER(_data.applyPosEventFilter),
+			     LAMDA_FILTER(_data.applyNegEventFilter));
+	};
 
-	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);
-
-		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);
-	}
-
-	connect(dialog,		&KsCheckBoxDialog::apply,
-		&_data,		&KsDataStore::applyPosEventFilter);
+	connect(dialog,		&KsCheckBoxDialog::apply, lamFilter);
 
 	dialog->show();
 }
@@ -639,32 +724,25 @@ void KsMainWindow::_showTasks()
 	kshark_context *kshark_ctx(nullptr);
 	KsCheckBoxWidget *tasks_cbd;
 	KsCheckBoxDialog *dialog;
+	QVector<bool> v;
 
 	if (!kshark_instance(&kshark_ctx))
 		return;
 
 	tasks_cbd = new KsTasksCheckBoxWidget(_data.tep(), true, this);
 	dialog = new KsCheckBoxDialog(tasks_cbd, this);
+	_presetCBWidget(kshark_ctx->show_task_filter,
+			kshark_ctx->hide_task_filter,
+			tasks_cbd);
+
+	auto lamFilter = [=] (QVector<int> show) {
+		QVector<int> all = KsUtils::getEventIdList();
+		_applyFilter(all, show,
+			     LAMDA_FILTER(_data.applyPosTaskFilter),
+			     LAMDA_FILTER(_data.applyNegTaskFilter));
+	};
 
-	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);
-
-		for (int i = 0; i < nPids; ++i) {
-			if (tracecmd_filter_id_find(kshark_ctx->show_task_filter,
-						    pids[i]))
-				v[i] = true;
-		}
-
-		tasks_cbd->set(v);
-	}
-
-	connect(dialog,		&KsCheckBoxDialog::apply,
-		&_data,		&KsDataStore::applyPosTaskFilter);
+	connect(dialog,		&KsCheckBoxDialog::apply, lamFilter);
 
 	dialog->show();
 }
@@ -674,30 +752,25 @@ void KsMainWindow::_showCPUs()
 	kshark_context *kshark_ctx(nullptr);
 	KsCheckBoxWidget *cpu_cbd;
 	KsCheckBoxDialog *dialog;
+	QVector<bool> v;
 
 	if (!kshark_instance(&kshark_ctx))
 		return;
 
 	cpu_cbd = new KsCPUCheckBoxWidget(_data.tep(), this);
 	dialog = new KsCheckBoxDialog(cpu_cbd, this);
+	_presetCBWidget(kshark_ctx->show_cpu_filter,
+			kshark_ctx->hide_cpu_filter,
+			cpu_cbd);
+
+	auto lamFilter = [=] (QVector<int> show) {
+		QVector<int> all = KsUtils::getEventIdList();
+		_applyFilter(all, show,
+			     LAMDA_FILTER(_data.applyPosCPUFilter),
+			     LAMDA_FILTER(_data.applyNegCPUFilter));
+	};
 
-	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);
-
-		for (int i = 0; i < nCPUs; ++i) {
-			if (tracecmd_filter_id_find(kshark_ctx->show_cpu_filter, i))
-				v[i] = true;
-		}
-
-		cpu_cbd->set(v);
-	}
-
-	connect(dialog,		&KsCheckBoxDialog::apply,
-		&_data,		&KsDataStore::applyPosCPUFilter);
+	connect(dialog,		&KsCheckBoxDialog::apply, lamFilter);
 
 	dialog->show();
 }
diff --git a/kernel-shark/src/KsMainWindow.hpp b/kernel-shark/src/KsMainWindow.hpp
index 59030e4..997ea54 100644
--- a/kernel-shark/src/KsMainWindow.hpp
+++ b/kernel-shark/src/KsMainWindow.hpp
@@ -19,6 +19,7 @@
 // KernelShark
 #include "KsTraceViewer.hpp"
 #include "KsTraceGraph.hpp"
+#include "KsWidgetsLib.hpp"
 #include "KsSession.hpp"
 #include "KsUtils.hpp"
 
@@ -177,6 +178,14 @@ private:
 
 	void _graphFilterSync(int state);
 
+	void _presetCBWidget(tracecmd_filter_id *showFilter,
+			     tracecmd_filter_id *hideFilter,
+			     KsCheckBoxWidget *cbw);
+
+	void _applyFilter(QVector<int> all, QVector<int> show,
+			  std::function<void(QVector<int>)> posFilter,
+			  std::function<void(QVector<int>)> negFilter);
+
 	void _showEvents();
 
 	void _showTasks();
-- 
2.20.1


      parent reply	other threads:[~2020-03-30 16:07 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-30 16:06 [PATCH v2 0/6] kernel-shark: Optimize the logic of the filtering menus Yordan Karadzhov (VMware)
2020-03-30 16:06 ` [PATCH v2 1/6] kernel-shark: Add method for checking if a given ID filter is set Yordan Karadzhov (VMware)
2020-03-30 16:06 ` [PATCH v2 2/6] kernel-shark: Fix bug in bool kshark_export_all_cpu_filters() Yordan Karadzhov (VMware)
2020-03-30 16:06 ` [PATCH v2 3/6] kernel-shark: Add two helper methods to KsUtils Yordan Karadzhov (VMware)
2020-03-30 16:06 ` [PATCH v2 4/6] kernel-shark: Add getIds() to class KsCheckBoxWidget Yordan Karadzhov (VMware)
2020-03-30 16:06 ` [PATCH v2 5/6] kernel-shark: Remove unused methods from KsMainWindow class Yordan Karadzhov (VMware)
2020-03-30 16:06 ` Yordan Karadzhov (VMware) [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200330160652.28424-7-y.karadz@gmail.com \
    --to=y.karadz@gmail.com \
    --cc=linux-trace-devel@vger.kernel.org \
    --cc=rostedt@goodmis.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).