Linux-Trace-Devel Archive on lore.kernel.org
 help / color / 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 5/5] kernel-shark: Optimize the logic of the filtering menus
Date: Thu, 19 Mar 2020 16:10:31 +0200
Message-ID: <20200319141031.3774-6-y.karadz@gmail.com> (raw)
In-Reply-To: <20200319141031.3774-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 | 184 +++++++++++++++++++++++-------
 kernel-shark/src/KsMainWindow.hpp |  12 ++
 2 files changed, 156 insertions(+), 40 deletions(-)

diff --git a/kernel-shark/src/KsMainWindow.cpp b/kernel-shark/src/KsMainWindow.cpp
index 9b5fc2d..aed28a8 100644
--- a/kernel-shark/src/KsMainWindow.cpp
+++ b/kernel-shark/src/KsMainWindow.cpp
@@ -594,114 +594,218 @@ void KsMainWindow::_graphFilterSync(int state)
 	_data.update();
 }
 
+QVector<bool> KsMainWindow::_getFilterCbStatus(tracecmd_filter_id *showFilter,
+					       tracecmd_filter_id *hideFilter,
+					       QVector<int> ids)
+{
+	QVector<bool> v;
+
+	if (!kshark_this_filter_is_set(showFilter) &&
+	    !kshark_this_filter_is_set(hideFilter)) {
+		return v;
+	} else {
+		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".
+			 */
+			v = 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".
+					 */
+					v[i] = true;
+				}
+			}
+		} else { // Only hide filter is set.
+			v = QVector<bool>(n, true);
+			for (int i = 0; i < n; ++i) {
+				hide = !!tracecmd_filter_id_find(hideFilter,
+								 ids[i]);
+
+				if (hide)
+					v[i] = false;
+			}
+		}
+	}
+
+	return v;
+}
+
+QVector<int> KsMainWindow::_revertFilterIds(QVector<int> all, QVector<int> vec)
+{
+	QVector<int> diff;
+
+	/*
+	 * The Ids may not be sorted, becausein in the widgets the items are
+	 * shown sorted by name. Get those Ids sorted first.
+	 */
+	std::sort(vec.begin(), vec.end());
+
+	/*
+	 * The IDs of the "do not show" filter are given by the difference
+	 * between "all Ids" and the "show only" filter.
+	 */
+	std::set_difference(all.begin(), all.end(),
+			    vec.begin(), vec.end(),
+			    std::inserter(diff, diff.begin()));
+
+	return diff;
+}
+
 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);
+	v = _getFilterCbStatus(kshark_ctx->show_event_filter,
+			       kshark_ctx->hide_event_filter,
+			       KsUtils::getEventIdList(TEP_EVENT_SORT_SYSTEM));
 
-	if (!kshark_ctx->show_event_filter ||
-	    !kshark_ctx->show_event_filter->count) {
+	if (v.count() == 0) {
 		events_cb->setDefault(true);
 	} else {
 		/*
-		 * The event filter contains IDs. Make this visible in the
-		 * CheckBox Widget.
+		 * Some of the event filters 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);
+		this,		&KsMainWindow::_applyEventFilter);
 
 	dialog->show();
 }
 
+void KsMainWindow::_applyEventFilter(QVector<int> showEvents)
+{
+	QVector<int> allEvents = KsUtils::getEventIdList();
+
+	if (showEvents.count() < allEvents.count() / 2) {
+		_data.applyPosEventFilter(showEvents);
+	} else {
+		/*
+		 * It is more efficiant to apply negative (do not show) filter.
+		 */
+		QVector<int> diff = _revertFilterIds(allEvents, showEvents);
+		_data.applyNegEventFilter(diff);
+	}
+}
+
 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);
+	v = _getFilterCbStatus(kshark_ctx->show_task_filter,
+			       kshark_ctx->hide_task_filter,
+			       KsUtils::getPidList());
 
-	if (!kshark_ctx->show_task_filter ||
-	    !kshark_ctx->show_task_filter->count) {
+	if (v.count() == 0) {
 		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;
-		}
-
+		/*
+		 * Some of the task filters contains PIDs. Make this visible
+		 * in the CheckBox Widget.
+		 */
 		tasks_cbd->set(v);
 	}
 
 	connect(dialog,		&KsCheckBoxDialog::apply,
-		&_data,		&KsDataStore::applyPosTaskFilter);
+		this,		&KsMainWindow::_applyTaskFilter);
 
 	dialog->show();
 }
 
+void KsMainWindow::_applyTaskFilter(QVector<int> showPids)
+{
+	QVector<int> allPids = KsUtils::getPidList();
+
+	if (showPids.count() <  allPids.count() / 2) {
+		_data.applyPosTaskFilter(showPids);
+	} else {
+		/*
+		 * It is more efficiant to apply negative (do not show) filter.
+		 */
+		QVector<int> diff = _revertFilterIds(allPids, showPids);
+		_data.applyNegTaskFilter(diff);
+	}
+}
+
 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);
+	v = _getFilterCbStatus(kshark_ctx->show_cpu_filter,
+			       kshark_ctx->hide_cpu_filter,
+			       KsUtils::getCPUList());
 
-	if (!kshark_ctx->show_cpu_filter ||
-	    !kshark_ctx->show_cpu_filter->count) {
+	if (v.count() == 0) {
 		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;
-		}
-
+		/*
+		 * Some of the CPU filters contains IDs. Make this visible
+		 * in the CheckBox Widget.
+		 */
 		cpu_cbd->set(v);
 	}
 
 	connect(dialog,		&KsCheckBoxDialog::apply,
-		&_data,		&KsDataStore::applyPosCPUFilter);
+		this,		&KsMainWindow::_applyCPUFilter);
 
 	dialog->show();
 }
 
+void KsMainWindow::_applyCPUFilter(QVector<int> showCPUs)
+{
+	QVector<int> allCPUs = KsUtils::getCPUList();
+
+	if (showCPUs.count() < allCPUs.count() / 2) {
+		_data.applyPosCPUFilter(showCPUs);
+	} else {
+		/*
+		 * It is more efficiant to apply negative (do not show) filter.
+		 */
+		QVector<int> diff = _revertFilterIds(allCPUs, showCPUs);
+		_data.applyNegCPUFilter(diff);
+	}
+}
+
 void KsMainWindow::_advancedFiltering()
 {
 	KsAdvFilteringDialog *dialog;
diff --git a/kernel-shark/src/KsMainWindow.hpp b/kernel-shark/src/KsMainWindow.hpp
index 59030e4..ecfc12c 100644
--- a/kernel-shark/src/KsMainWindow.hpp
+++ b/kernel-shark/src/KsMainWindow.hpp
@@ -177,6 +177,18 @@ private:
 
 	void _graphFilterSync(int state);
 
+	QVector<bool> _getFilterCbStatus(tracecmd_filter_id *showFilter,
+					 tracecmd_filter_id *hideFilter,
+					 QVector<int> ids);
+
+	QVector<int> _revertFilterIds(QVector<int> all, QVector<int> vec);
+
+	void _applyEventFilter(QVector<int> showEvents);
+
+	void _applyTaskFilter(QVector<int> showPids);
+
+	void _applyCPUFilter(QVector<int> showCPUs);
+
 	void _showEvents();
 
 	void _showTasks();
-- 
2.20.1


      parent reply index

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-19 14:10 [PATCH 0/5] " Yordan Karadzhov (VMware)
2020-03-19 14:10 ` [PATCH 1/5] kernel-shark: Add method for checking if a given ID filter is set Yordan Karadzhov (VMware)
2020-03-19 14:10 ` [PATCH 2/5] kernel-shark: Fix bug in bool kshark_export_all_cpu_filters() Yordan Karadzhov (VMware)
2020-03-19 14:10 ` [PATCH 3/5] kernel-shark: Add two helper methods to KsUtils Yordan Karadzhov (VMware)
2020-03-19 14:10 ` [PATCH 4/5] kernel-shark: Remove unused methods from KsMainWindow class Yordan Karadzhov (VMware)
2020-03-19 14:10 ` 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=20200319141031.3774-6-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

Linux-Trace-Devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-trace-devel/0 linux-trace-devel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-trace-devel linux-trace-devel/ https://lore.kernel.org/linux-trace-devel \
		linux-trace-devel@vger.kernel.org
	public-inbox-index linux-trace-devel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-trace-devel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git