Linux-Trace-Devel Archive on lore.kernel.org
 help / Atom feed
* [PATCH 0/2] Improve/debug the searching logic
@ 2019-01-04 20:06 Yordan Karadzhov
  2019-01-04 20:06 ` [PATCH 1/2] kernel-shark-qt: Avoid race condition when reading data Yordan Karadzhov
  2019-01-04 20:06 ` [PATCH 2/2] kernel-shark-qt: Implement State machine for searching in the data Yordan Karadzhov
  0 siblings, 2 replies; 3+ messages in thread
From: Yordan Karadzhov @ 2019-01-04 20:06 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel

Two patches aiming to resolve the known issues in the searching
inside the trace data.

Yordan Karadzhov (2):
  kernel-shark-qt: Avoid race condition when reading data
  kernel-shark-qt: Implement State machine for searching in the data

 kernel-shark-qt/src/CMakeLists.txt         |   2 +
 kernel-shark-qt/src/KsModels.cpp           |  70 ++++--
 kernel-shark-qt/src/KsModels.hpp           |  39 ++--
 kernel-shark-qt/src/KsSearchFSM.cpp        | 232 ++++++++++++++++++++
 kernel-shark-qt/src/KsSearchFSM.hpp        | 209 ++++++++++++++++++
 kernel-shark-qt/src/KsTraceViewer.cpp      | 241 +++++++--------------
 kernel-shark-qt/src/KsTraceViewer.hpp      |  32 ++-
 kernel-shark-qt/src/libkshark.c            |  74 ++++---
 kernel-shark-qt/src/libkshark.h            |   3 -
 kernel-shark-qt/src/plugins/sched_events.c |   6 +-
 10 files changed, 650 insertions(+), 258 deletions(-)
 create mode 100644 kernel-shark-qt/src/KsSearchFSM.cpp
 create mode 100644 kernel-shark-qt/src/KsSearchFSM.hpp

-- 
2.17.1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/2] kernel-shark-qt: Avoid race condition when reading data
  2019-01-04 20:06 [PATCH 0/2] Improve/debug the searching logic Yordan Karadzhov
@ 2019-01-04 20:06 ` Yordan Karadzhov
  2019-01-04 20:06 ` [PATCH 2/2] kernel-shark-qt: Implement State machine for searching in the data Yordan Karadzhov
  1 sibling, 0 replies; 3+ messages in thread
From: Yordan Karadzhov @ 2019-01-04 20:06 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel

We know that the data reading operations are not thread-safe.
A permanent solution for the problem is being worked on. For
the time being, this patch provides a naive temporary fix by
slapping mutexes all over the code, which will slow things down
a bit.

Signed-off-by: Yordan Karadzhov <ykaradzhov@vmware.com>
---
 kernel-shark-qt/src/libkshark.c            | 74 +++++++++++++---------
 kernel-shark-qt/src/libkshark.h            |  3 -
 kernel-shark-qt/src/plugins/sched_events.c |  6 +-
 3 files changed, 47 insertions(+), 36 deletions(-)

diff --git a/kernel-shark-qt/src/libkshark.c b/kernel-shark-qt/src/libkshark.c
index 598ea52..23dc813 100644
--- a/kernel-shark-qt/src/libkshark.c
+++ b/kernel-shark-qt/src/libkshark.c
@@ -960,31 +960,6 @@ ssize_t kshark_load_data_records(struct kshark_context *kshark_ctx,
 	return -ENOMEM;
 }
 
-/**
- * @brief A thread-safe read of a record from a specific offset.
- *
- * @param kshark_ctx: Input location for the session context pointer.
- * @param offset: the offset into the file to find the record.
- *
- * @returns The returned pevent_record must be freed.
- */
-struct tep_record *kshark_read_at(struct kshark_context *kshark_ctx,
-				  uint64_t offset)
-{
-	/*
-	 * Calling tracecmd_read_at() is not thread-safe. Use a mutex to
-	 * protect the access.
-	 */
-	pthread_mutex_lock(&kshark_ctx->input_mutex);
-
-	struct tep_record *data = tracecmd_read_at(kshark_ctx->handle,
-						      offset, NULL);
-
-	pthread_mutex_unlock(&kshark_ctx->input_mutex);
-
-	return data;
-}
-
 static const char *kshark_get_latency(struct tep_handle *pe,
 				      struct tep_record *record)
 {
@@ -1046,10 +1021,18 @@ int kshark_get_pid_easy(struct kshark_entry *entry)
 		/*
 		 * The entry has been touched by a plugin callback function.
 		 * Because of this we do not trust the value of "entry->pid".
+		 *
+		 * Currently the data reading operations are not thread-safe.
+		 * Use a mutex to protect the access.
 		 */
-		data = kshark_read_at(kshark_ctx, entry->offset);
+		pthread_mutex_lock(&kshark_ctx->input_mutex);
+
+		data = tracecmd_read_at(kshark_ctx->handle, entry->offset,
+					NULL);
 		pid = tep_data_pid(kshark_ctx->pevent, data);
 		free_record(data);
+
+		pthread_mutex_unlock(&kshark_ctx->input_mutex);
 	}
 
 	return pid;
@@ -1106,10 +1089,18 @@ const char *kshark_get_latency_easy(struct kshark_entry *entry)
 	if (entry->event_id < 0)
 		return NULL;
 
-	data = kshark_read_at(kshark_ctx, entry->offset);
+	/*
+	 * Currently the data reading operations are not thread-safe.
+	 * Use a mutex to protect the access.
+	 */
+	pthread_mutex_lock(&kshark_ctx->input_mutex);
+
+	data = tracecmd_read_at(kshark_ctx->handle, entry->offset, NULL);
 	lat = kshark_get_latency(kshark_ctx->pevent, data);
 	free_record(data);
 
+	pthread_mutex_unlock(&kshark_ctx->input_mutex);
+
 	return lat;
 }
 
@@ -1142,10 +1133,18 @@ int kshark_get_event_id_easy(struct kshark_entry *entry)
 		 * The entry has been touched by a plugin callback function.
 		 * Because of this we do not trust the value of
 		 * "entry->event_id".
+		 *
+		 * Currently the data reading operations are not thread-safe.
+		 * Use a mutex to protect the access.
 		 */
-		data = kshark_read_at(kshark_ctx, entry->offset);
+		pthread_mutex_lock(&kshark_ctx->input_mutex);
+
+		data = tracecmd_read_at(kshark_ctx->handle, entry->offset,
+					NULL);
 		event_id = tep_data_type(kshark_ctx->pevent, data);
 		free_record(data);
+
+		pthread_mutex_unlock(&kshark_ctx->input_mutex);
 	}
 
 	return (event_id == -1)? -EFAULT : event_id;
@@ -1184,7 +1183,14 @@ const char *kshark_get_event_name_easy(struct kshark_entry *entry)
 		}
 	}
 
+	/*
+	 * Currently the data reading operations are not thread-safe.
+	 * Use a mutex to protect the access.
+	 */
+	pthread_mutex_lock(&kshark_ctx->input_mutex);
 	event = tep_data_event_from_type(kshark_ctx->pevent, event_id);
+	pthread_mutex_unlock(&kshark_ctx->input_mutex);
+
 	if (event)
 		return event->name;
 
@@ -1223,8 +1229,13 @@ const char *kshark_get_info_easy(struct kshark_entry *entry)
 		}
 	}
 
-	data = kshark_read_at(kshark_ctx, entry->offset);
+	/*
+	 * Currently the data reading operations are not thread-safe.
+	 * Use a mutex to protect the access.
+	 */
+	pthread_mutex_lock(&kshark_ctx->input_mutex);
 
+	data = tracecmd_read_at(kshark_ctx->handle, entry->offset, NULL);
 	event_id = tep_data_type(kshark_ctx->pevent, data);
 	event = tep_data_event_from_type(kshark_ctx->pevent, event_id);
 	if (event)
@@ -1232,6 +1243,8 @@ const char *kshark_get_info_easy(struct kshark_entry *entry)
 
 	free_record(data);
 
+	pthread_mutex_unlock(&kshark_ctx->input_mutex);
+
 	return info;
 }
 
@@ -1315,7 +1328,8 @@ char* kshark_dump_entry(const struct kshark_entry *entry)
 		struct tep_event_format *event;
 		struct tep_record *data;
 
-		data = kshark_read_at(kshark_ctx, entry->offset);
+		data = tracecmd_read_at(kshark_ctx->handle, entry->offset,
+					NULL);
 
 		event = tep_data_event_from_type(kshark_ctx->pevent,
 						 entry->event_id);
diff --git a/kernel-shark-qt/src/libkshark.h b/kernel-shark-qt/src/libkshark.h
index 7d1edfc..a1b1f91 100644
--- a/kernel-shark-qt/src/libkshark.h
+++ b/kernel-shark-qt/src/libkshark.h
@@ -183,9 +183,6 @@ char* kshark_dump_custom_entry(struct kshark_context *kshark_ctx,
 			       const struct kshark_entry *entry,
 			       kshark_custom_info_func info_func);
 
-struct tep_record *kshark_read_at(struct kshark_context *kshark_ctx,
-				  uint64_t offset);
-
 /** Bit masks used to control the visibility of the entry after filtering. */
 enum kshark_filter_masks {
 	/**
diff --git a/kernel-shark-qt/src/plugins/sched_events.c b/kernel-shark-qt/src/plugins/sched_events.c
index 1500110..5409bc6 100644
--- a/kernel-shark-qt/src/plugins/sched_events.c
+++ b/kernel-shark-qt/src/plugins/sched_events.c
@@ -184,7 +184,7 @@ bool plugin_wakeup_match_rec_pid(struct kshark_context *kshark_ctx,
 
 	if (plugin_ctx->sched_wakeup_event &&
 	    e->event_id == plugin_ctx->sched_wakeup_event->id) {
-		record = kshark_read_at(kshark_ctx, e->offset);
+		record = tracecmd_read_at(kshark_ctx->handle, e->offset, NULL);
 
 		/* We only want those that actually woke up the task. */
 		ret = tep_read_number_field(plugin_ctx->sched_wakeup_success_field,
@@ -196,7 +196,7 @@ bool plugin_wakeup_match_rec_pid(struct kshark_context *kshark_ctx,
 
 	if (plugin_ctx->sched_wakeup_new_event &&
 	    e->event_id == plugin_ctx->sched_wakeup_new_event->id) {
-		record = kshark_read_at(kshark_ctx, e->offset);
+		record = tracecmd_read_at(kshark_ctx->handle, e->offset, NULL);
 
 		/* We only want those that actually woke up the task. */
 		ret = tep_read_number_field(plugin_ctx->sched_wakeup_new_success_field,
@@ -238,7 +238,7 @@ bool plugin_switch_match_rec_pid(struct kshark_context *kshark_ctx,
 	    e->event_id == plugin_ctx->sched_switch_event->id) {
 		struct tep_record *record;
 
-		record = kshark_read_at(kshark_ctx, e->offset);
+		record = tracecmd_read_at(kshark_ctx->handle, e->offset, NULL);
 		ret = tep_read_number_field(plugin_ctx->sched_switch_prev_state_field,
 					    record->data, &val);
 
-- 
2.17.1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 2/2] kernel-shark-qt: Implement State machine for searching in the data
  2019-01-04 20:06 [PATCH 0/2] Improve/debug the searching logic Yordan Karadzhov
  2019-01-04 20:06 ` [PATCH 1/2] kernel-shark-qt: Avoid race condition when reading data Yordan Karadzhov
@ 2019-01-04 20:06 ` Yordan Karadzhov
  1 sibling, 0 replies; 3+ messages in thread
From: Yordan Karadzhov @ 2019-01-04 20:06 UTC (permalink / raw)
  To: rostedt; +Cc: linux-trace-devel

This patch was originally motivated by the request to make it
possible to continue searching from the place when the search
has been stopped by the user. However because the implementation
of this feature made the original code quite messy (ugly), I
decided to reorganize the way the searching is controlled and
add a KsSearchFSM class that implements a Finite-State Machine
by following the "State" design pattern. KsSearchFSM class now
encapsulates the searching logic.

Signed-off-by: Yordan Karadzhov <ykaradzhov@vmware.com>
---
 kernel-shark-qt/src/CMakeLists.txt    |   2 +
 kernel-shark-qt/src/KsModels.cpp      |  70 +++++---
 kernel-shark-qt/src/KsModels.hpp      |  39 +++--
 kernel-shark-qt/src/KsSearchFSM.cpp   | 232 +++++++++++++++++++++++++
 kernel-shark-qt/src/KsSearchFSM.hpp   | 209 ++++++++++++++++++++++
 kernel-shark-qt/src/KsTraceViewer.cpp | 241 +++++++++-----------------
 kernel-shark-qt/src/KsTraceViewer.hpp |  32 ++--
 7 files changed, 603 insertions(+), 222 deletions(-)
 create mode 100644 kernel-shark-qt/src/KsSearchFSM.cpp
 create mode 100644 kernel-shark-qt/src/KsSearchFSM.hpp

diff --git a/kernel-shark-qt/src/CMakeLists.txt b/kernel-shark-qt/src/CMakeLists.txt
index 3eddaed..1e0a794 100644
--- a/kernel-shark-qt/src/CMakeLists.txt
+++ b/kernel-shark-qt/src/CMakeLists.txt
@@ -34,6 +34,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
     set (ks-guiLib_hdr  KsUtils.hpp
                         KsModels.hpp
                         KsGLWidget.hpp
+                        KsSearchFSM.hpp
                         KsDualMarker.hpp
                         KsWidgetsLib.hpp
                         KsTraceGraph.hpp
@@ -49,6 +50,7 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
                                                             KsModels.cpp
                                                             KsSession.cpp
                                                             KsGLWidget.cpp
+                                                            KsSearchFSM.cpp
                                                             KsDualMarker.cpp
                                                             KsWidgetsLib.cpp
                                                             KsTraceGraph.cpp
diff --git a/kernel-shark-qt/src/KsModels.cpp b/kernel-shark-qt/src/KsModels.cpp
index c8cc410..1b68143 100644
--- a/kernel-shark-qt/src/KsModels.cpp
+++ b/kernel-shark-qt/src/KsModels.cpp
@@ -48,33 +48,31 @@ void KsFilterProxyModel::setSource(KsViewModel *s)
 	_source = s;
 }
 
-void KsFilterProxyModel::_search(int column,
-				 const QString &searchText,
-				 condition_func cond,
-				 QList<int> *matchList,
-				 int first, int last,
-				 QProgressBar *pb,
-				 QLabel *l,
-				 bool notify)
+size_t KsFilterProxyModel::_search(int column,
+				   const QString &searchText,
+				   search_condition_func cond,
+				   QList<int> *matchList,
+				   int first, int last,
+				   QProgressBar *pb,
+				   QLabel *l,
+				   bool notify)
 {
-	int row, nRows(last - first + 1);
+	int index, row, nRows(last - first + 1);
 	int pbCount(1);
 	QString item;
 
-	_searchProgress = 0;
-
 	if (nRows > KS_PROGRESS_BAR_MAX)
-		pbCount = nRows / KS_PROGRESS_BAR_MAX;
+		pbCount = nRows / (KS_PROGRESS_BAR_MAX - _searchProgress);
 	else
 		_searchProgress = KS_PROGRESS_BAR_MAX - nRows;
 
 	/* Loop over the items of the proxy model. */
-	for (int r = first; r <= last; ++r) {
+	for (index = first; index <= last; ++index) {
 		/*
 		 * Use the index of the proxy model to retrieve the value
 		 * of the row number in the base model.
 		 */
-		row = mapRowFromSource(r);
+		row = mapRowFromSource(index);
 		item = _source->getValueStr(column, row);
 		if (cond(searchText, item))
 			matchList->append(row);
@@ -89,20 +87,25 @@ void KsFilterProxyModel::_search(int column,
 		}
 
 		/* Deal with the Progress bar of the seatch. */
-		if ((r - first) % pbCount == 0) {
+		if ((index - first) % pbCount == 0) {
 			if (notify) {
 				std::lock_guard<std::mutex> lk(_mutex);
 				++_searchProgress;
 				_pbCond.notify_one();
 			} else {
-				if (pb)
+				if (pb) {
 					pb->setValue(pb->value() + 1);
+					++_searchProgress;
+				}
+
 				if (l)
 					l->setText(QString(" %1").arg(matchList->count()));
 				QApplication::processEvents();
 			}
 		}
 	}
+
+	return index;
 }
 
 /** @brief Search the content of the table for a data satisfying an abstract
@@ -121,15 +124,40 @@ void KsFilterProxyModel::_search(int column,
  */
 size_t KsFilterProxyModel::search(int column,
 				  const QString &searchText,
-				  condition_func cond,
+				  search_condition_func cond,
 				  QList<int> *matchList,
 				  QProgressBar *pb,
 				  QLabel *l)
+{
+	int nRows = rowCount({});
+	_search(column, searchText, cond, matchList,
+		0, nRows - 1, pb, l, false);
+
+	return matchList->count();
+}
+
+/** @brief Search the content of the table for a data satisfying an abstract
+ *	   condition.
+ *
+ * @param sm: Input location for the Search State machine object.
+ * @param matchList: Output location for a list containing the row indexes of
+ *
+ * @returns The number of cells satisfying the matching condition.
+ */
+size_t KsFilterProxyModel::search(KsSearchFSM *sm, QList<int> *matchList)
 {
 	int nRows = rowCount({});
 
-	_search(column, searchText, cond, matchList, 0, nRows - 1,
-		pb, l, false);
+	sm->_lastRowSearched =
+		_search(sm->column(),
+			sm->searchText(),
+			sm->condition(),
+			matchList,
+			sm->_lastRowSearched + 1,
+			nRows - 1,
+			&sm->_searchProgBar,
+			&sm->_searchCountLabel,
+			false);
 
 	return matchList->count();
 }
@@ -152,7 +180,7 @@ size_t KsFilterProxyModel::search(int column,
  */
 QList<int> KsFilterProxyModel::searchMap(int column,
 					 const QString &searchText,
-					 condition_func cond,
+					 search_condition_func cond,
 					 int first,
 					 int last,
 					 bool notify)
@@ -325,7 +353,7 @@ void KsViewModel::update(KsDataStore *data)
  */
 size_t KsViewModel::search(int column,
 			   const QString &searchText,
-			   condition_func cond,
+			   search_condition_func cond,
 			   QList<size_t> *matchList)
 {
 	int nRows = rowCount({});
diff --git a/kernel-shark-qt/src/KsModels.hpp b/kernel-shark-qt/src/KsModels.hpp
index 08019e7..808c574 100644
--- a/kernel-shark-qt/src/KsModels.hpp
+++ b/kernel-shark-qt/src/KsModels.hpp
@@ -26,9 +26,7 @@
 // KernelShark
 #include "libkshark.h"
 #include "libkshark-model.h"
-
-/** Matching condition function type. To be user for searching. */
-typedef bool (*condition_func)(const QString &, const QString &);
+#include "KsSearchFSM.hpp"
 
 enum class DualMarkerState;
 
@@ -87,7 +85,7 @@ public:
 
 	size_t search(int column,
 		      const QString &searchText,
-		      condition_func cond,
+		      search_condition_func cond,
 		      QList<size_t> *matchList);
 
 	/** Table columns Identifiers. */
@@ -162,14 +160,16 @@ public:
 
 	size_t search(int column,
 		      const QString &searchText,
-		      condition_func cond,
+		      search_condition_func cond,
 		      QList<int> *matchList,
 		      QProgressBar *pb = nullptr,
 		      QLabel *l = nullptr);
 
+	size_t search(KsSearchFSM *sm, QList<int> *matchList);
+
 	QList<int> searchMap(int column,
 			     const QString  &searchText,
-			     condition_func  cond,
+			     search_condition_func  cond,
 			     int first,
 			     int last,
 			     bool notify);
@@ -183,9 +183,6 @@ public:
 		_searchStop = false;
 	}
 
-	/** Stop the serch for all threads. */
-	void searchStop() {_searchStop = true;}
-
 	/**
 	 * Use the "row" index in the Proxy model to retrieve the "row" index
 	 * in the source model.
@@ -196,6 +193,9 @@ public:
 		return this->data(this->index(r, 0)).toInt();
 	}
 
+	/** Get the source model. */
+	KsViewModel *source() {return _source;}
+
 	/**
 	 * A condition variable used to notify the main thread to update the
 	 * search progressbar.
@@ -205,24 +205,25 @@ public:
 	/** A mutex used by the condition variable. */
 	std::mutex		_mutex;
 
+	/** A flag used to stop the serch for all threads. */
+	bool			_searchStop;
+
 private:
 	int			_searchProgress;
 
-	bool			_searchStop;
-
 	/** Trace data array. */
 	kshark_entry		**_data;
 
 	KsViewModel	 	*_source;
 
-	void _search(int column,
-		     const QString &searchText,
-		     condition_func cond,
-		     QList<int> *matchList,
-		     int first, int last,
-		     QProgressBar *pb,
-		     QLabel *l,
-		     bool notify);
+	size_t _search(int column,
+		       const QString &searchText,
+		       search_condition_func cond,
+		       QList<int> *matchList,
+		       int first, int last,
+		       QProgressBar *pb,
+		       QLabel *l,
+		       bool notify);
 };
 
 /**
diff --git a/kernel-shark-qt/src/KsSearchFSM.cpp b/kernel-shark-qt/src/KsSearchFSM.cpp
new file mode 100644
index 0000000..4f01cc8
--- /dev/null
+++ b/kernel-shark-qt/src/KsSearchFSM.cpp
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+/**
+ *  @file    KsSearchFSM.cpp
+ *  @brief   Finite-state machine for searching in trace data.
+ */
+
+// KernelShark
+#include "KsSearchFSM.hpp"
+#include "KsUtils.hpp"
+#include "KsTraceViewer.hpp"
+#include "KsWidgetsLib.hpp"
+
+static bool notHaveCond(const QString &searchText, const QString &itemText)
+{
+	return !itemText.contains(searchText, Qt::CaseInsensitive);
+}
+
+static bool containsCond(const QString &searchText, const QString &itemText)
+{
+	return itemText.contains(searchText, Qt::CaseInsensitive);
+}
+
+static bool matchCond(const QString &searchText, const QString &itemText)
+{
+	return (itemText.compare(searchText, Qt::CaseInsensitive) == 0);
+}
+
+static bool noCond(const QString &searchText, const QString &itemText)
+{
+	return false;
+}
+
+/** Create a Finite-state machine for searching. */
+KsSearchFSM::KsSearchFSM(QWidget *parent)
+: _currentState(new NotDone),
+  _lastRowSearched(0),
+  _searchProgBar(parent),
+  _searchCountLabel("", parent),
+  _columnComboBox(parent),
+  _selectComboBox(parent),
+  _searchLineEdit(parent),
+  _prevButton("Prev", parent),
+  _nextButton("Next", parent),
+  _searchRestartButton(QIcon::fromTheme("media-playback-start"), "", parent),
+//   _searchStopButton(QIcon::fromTheme("media-playback-pause"), "", parent),
+  _searchStopButton(QIcon::fromTheme("process-stop"), "", parent),
+  _cond(nullptr),
+  _pbAction(nullptr),
+  _searchStopAction(nullptr),
+  _searchRestartAction(nullptr)
+{
+	int bWidth = FONT_WIDTH * 6;
+
+	_nextButton.setFixedWidth(bWidth);
+	_prevButton.setFixedWidth(bWidth);
+
+	_searchProgBar.setMaximumWidth(FONT_WIDTH * 10);
+	_searchProgBar.setRange(0, KS_PROGRESS_BAR_MAX);
+
+	_selectComboBox.addItem("contains");
+	_selectComboBox.addItem("full match");
+	_selectComboBox.addItem("does not have");
+	updateCondition();
+}
+
+/**
+ * Position all buttons and labels of the Finite-state machine for searching
+ * in a toolbar.
+ */
+void KsSearchFSM::placeInToolBar(QToolBar *tb)
+{
+	tb->addWidget(&_columnComboBox);
+	tb->addWidget(&_selectComboBox);
+	tb->addWidget(&_searchLineEdit);
+	tb->addSeparator();
+
+	tb->addWidget(&_nextButton);
+	tb->addWidget(&_prevButton);
+	tb->addSeparator();
+
+	_pbAction = tb->addWidget(&_searchProgBar);
+	_pbAction->setVisible(false);
+
+	tb->addWidget(&_searchCountLabel);
+
+	_searchStopAction = tb->addWidget(&_searchStopButton);
+	_searchStopAction->setVisible(false);
+
+	_searchRestartAction = tb->addWidget(&_searchRestartButton);
+	_searchRestartAction->setVisible(false);
+	tb->addSeparator();
+}
+
+/**
+ * Update the Matching condition function of the search according to the user
+ * input.
+ */
+void KsSearchFSM::updateCondition()
+{
+	int xSelect = _selectComboBox.currentIndex();
+
+	switch (xSelect) {
+	case Condition::Containes:
+		_cond = containsCond;
+		return;
+
+	case Condition::Match:
+		_cond = matchCond;
+		return;
+
+	case Condition::NotHave:
+		_cond = notHaveCond;
+		return;
+
+	default:
+		_cond = noCond;
+		return;
+	}
+}
+
+void KsSearchFSM ::_lockSearchPanel(bool lock)
+{
+	_columnComboBox.setEnabled(!lock);
+	_selectComboBox.setEnabled(!lock);
+	_searchLineEdit.setReadOnly(lock);
+	_prevButton.setEnabled(!lock);
+	_nextButton.setEnabled(!lock);
+// 	_graphFollowsCheckBox.setEnabled(!lock);
+}
+
+/** Act according to the provided input. */
+void NotDone::handleInput(KsSearchFSM* sm, sm_input_t input)
+{
+	switch(input) {
+	case sm_input_t::Start:
+		sm->_lastRowSearched = -1;
+		sm->lockSearchPanel();
+		sm->updateCondition();
+		sm->progressBarVisible(true);
+
+		if (sm->column() == KsViewModel::TRACE_VIEW_COL_INFO ||
+		    sm->column() == KsViewModel::TRACE_VIEW_COL_LAT)
+			sm->searchStopVisible(true);
+
+		sm->changeState(std::shared_ptr<InProgress>(new InProgress));
+		break;
+
+	case sm_input_t::Finish:
+		sm->changeState(std::shared_ptr<Done>(new Done));
+		break;
+
+	default:
+		/* Ignore the input. */
+		break;
+	}
+}
+
+/** Act according to the provided input. */
+void Paused::handleInput(KsSearchFSM* sm, sm_input_t input)
+{
+	switch(input) {
+	case sm_input_t::Start:
+		sm->lockSearchPanel();
+		sm->searchStopVisible(true);
+		sm->searchRestartVisible(false);
+		sm->changeState(std::shared_ptr<InProgress>(new InProgress));
+		break;
+
+	case sm_input_t::Change:
+		sm->_searchProgBar.setValue(0);
+		sm->_searchCountLabel.setText("");
+		sm->progressBarVisible(false);
+		sm->searchRestartVisible(false);
+		sm->changeState(std::shared_ptr<NotDone>(new NotDone));
+		break;
+
+	default:
+		/* Ignore the input. */
+		break;
+	}
+}
+
+/** Act according to the provided input. */
+void InProgress::handleInput(KsSearchFSM* sm, sm_input_t input)
+{
+	auto lamUnlock = [&sm] () {
+		sm->searchStopVisible(false);
+		sm->unlockSearchPanel();
+	};
+
+	switch(input) {
+	case sm_input_t::Stop:
+		lamUnlock();
+		sm->searchRestartVisible(true);
+		sm->changeState(std::shared_ptr<Paused>(new Paused));
+		break;
+
+	case sm_input_t::Finish:
+		lamUnlock();
+		sm->progressBarVisible(false);
+		sm->changeState(std::shared_ptr<Done>(new Done));
+		break;
+
+	default:
+		/* Ignore the input. */
+		break;
+	}
+}
+
+/** Act according to the provided input. */
+void Done::handleInput(KsSearchFSM* sm, sm_input_t i)
+{
+	switch(i) {
+	case sm_input_t::Change:
+		sm->_searchProgBar.setValue(0);
+		sm->progressBarVisible(false);
+		sm->_searchCountLabel.setText("");
+		sm->searchStopVisible(false);
+		sm->searchRestartVisible(false);
+		sm->changeState(std::shared_ptr<NotDone>(new NotDone));
+		break;
+
+	default:
+		/* Ignore the input. */
+		break;
+	}
+}
diff --git a/kernel-shark-qt/src/KsSearchFSM.hpp b/kernel-shark-qt/src/KsSearchFSM.hpp
new file mode 100644
index 0000000..2089912
--- /dev/null
+++ b/kernel-shark-qt/src/KsSearchFSM.hpp
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+
+/*
+ * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+/**
+ *  @file    KsSearchFSM.hpp
+ *  @brief   Finite-state machine for searching in trace data.
+ */
+
+#ifndef _KS_SEARCH_FSM_H
+#define _KS_SEARCH_FSM_H
+
+// C++11
+#include <memory>
+
+// Qt
+#include <QtWidgets>
+
+/** Matching condition function type. To be user for searching. */
+typedef bool (*search_condition_func)(const QString &, const QString &);
+
+/** State Identifiers of the Finite-state machine for searching. */
+enum class search_state_t
+{
+	/** Identifier of the "NotDone" state. */
+	NotDone_s = 0,
+
+	/** Identifier of the "InProgress" state. */
+	InProgress_s = 1,
+
+	/** Identifier of the "Paused" state. */
+	Paused_s = 2,
+
+	/** Identifier of the "Done" state. */
+	Done_s = 3
+};
+
+/** Inputs of the Finite-state machine for searching. */
+enum class sm_input_t
+{
+	Start = 0,
+	Stop = 1,
+	Finish = 2,
+	Change = 3
+};
+
+class KsSearchFSM;
+
+/**
+ * State provides a base class for the states of the Finite-state machine for
+ * searching.
+ */
+struct State
+{
+	/** Virtual destructor. */
+	virtual ~State() {}
+
+	/**
+	 * Act according to the provided input. This is a pure virtual
+	 * function.
+	 */
+	virtual void handleInput(KsSearchFSM* sm, sm_input_t i) = 0;
+
+	/**
+	 * Get the identifier of this state. This is a pure virtual function.
+	 */
+	virtual search_state_t id() = 0;
+};
+
+/** "NotDone" state. */
+struct NotDone : public State
+{
+	void handleInput(KsSearchFSM* sm, sm_input_t i) override;
+
+	search_state_t id() override {return search_state_t::NotDone_s;}
+};
+
+/** "InProgress" state. */
+struct InProgress : public State
+{
+	void handleInput(KsSearchFSM* sm, sm_input_t i) override;
+
+	/** Get the identifier of this state. */
+	search_state_t id() override {return search_state_t::InProgress_s;}
+};
+
+/** "Paused" state. */
+struct Paused : public State
+{
+	void handleInput(KsSearchFSM* sm, sm_input_t i) override;
+
+	/** Get the identifier of this state. */
+	search_state_t id() override {return search_state_t::Paused_s;}
+};
+
+/** "Done" state. */
+struct Done : public State
+{
+	void handleInput(KsSearchFSM* sm, sm_input_t i) override;
+
+	/** Get the identifier of this state. */
+	search_state_t id() override {return search_state_t::Done_s;}
+};
+
+/** Finite-state machine for searching. */
+class KsSearchFSM : public QWidget
+{
+	Q_OBJECT
+public:
+	explicit KsSearchFSM(QWidget *parent = nullptr);
+
+	void placeInToolBar(QToolBar *tb);
+
+	/** Act according to the provided input. */
+	void handleInput(sm_input_t input)
+	{
+		_currentState->handleInput(this, input);
+	}
+
+	/** Switch the state. */
+	void changeState(std::shared_ptr<State> newState)
+	{
+		_currentState = newState;
+	}
+
+	/** Get the identifier of the Current state. */
+	search_state_t getState() const {return _currentState->id();}
+
+	/** Get the data column to search in. */
+	int column() const {return _columnComboBox.currentIndex();}
+
+	/** Get the Matching condition function. */
+	search_condition_func condition() const {return _cond;}
+
+	/** Get the text to search for. */
+	QString searchText() const {return _searchLineEdit.text();}
+
+	/** Set the value of the Search Progress Bar. */
+	void setProgress(int v) {_searchProgBar.setValue(v);}
+
+	/** Increment the value of the Search Progress Bar. */
+	void incrementProgress()
+	{
+		_searchProgBar.setValue(_searchProgBar.value() + 1);
+	}
+
+	void updateCondition();
+
+	/** Disable the user searching input (lock the panel). */
+	void lockSearchPanel() {_lockSearchPanel(true);}
+
+	/** Enable the user searching input (unlock the panel). */
+	void unlockSearchPanel() {_lockSearchPanel(false);}
+
+	/** Set the visibility of the Search Progress Bar. */
+	void progressBarVisible(bool v) {_pbAction->setVisible(v);}
+
+	/** Set the visibility of the Search Stop button. */
+	void searchStopVisible(bool v) {_searchStopAction->setVisible(v);}
+
+	/** Set the visibility of the Search Restart button. */
+	void searchRestartVisible(bool v) {_searchRestartAction->setVisible(v);}
+
+	/** Current State of the Finite-state machine for searching. */
+	std::shared_ptr<State>	_currentState;
+
+	/**
+	 * Last row, tested for matching. To be used when restarting the
+	 * search.
+	 */
+	ssize_t		_lastRowSearched;
+
+//! @cond Doxygen_Suppress
+
+	QProgressBar	_searchProgBar;
+
+	QLabel		_searchCountLabel;
+
+	QComboBox	_columnComboBox;
+
+	QComboBox	_selectComboBox;
+
+	QLineEdit	_searchLineEdit;
+
+	QPushButton	_prevButton, _nextButton;
+
+	QPushButton	_searchRestartButton, _searchStopButton;
+
+//! @endcond
+
+private:
+
+	search_condition_func	_cond;
+
+	QAction		*_pbAction, *_searchStopAction, *_searchRestartAction;
+
+	void _lockSearchPanel(bool lock);
+
+	enum Condition
+	{
+		Containes = 0,
+		Match = 1,
+		NotHave = 2
+	};
+};
+
+#endif
diff --git a/kernel-shark-qt/src/KsTraceViewer.cpp b/kernel-shark-qt/src/KsTraceViewer.cpp
index f02fbbb..369c78e 100644
--- a/kernel-shark-qt/src/KsTraceViewer.cpp
+++ b/kernel-shark-qt/src/KsTraceViewer.cpp
@@ -46,7 +46,6 @@ void KsTableView::scrollTo(const QModelIndex &index, ScrollHint hint)
 	QTableView::scrollTo(index, hint);
 }
 
-
 /** Create a default (empty) Trace viewer widget. */
 KsTraceViewer::KsTraceViewer(QWidget *parent)
 : QWidget(parent),
@@ -57,23 +56,12 @@ KsTraceViewer::KsTraceViewer(QWidget *parent)
   _toolbar(this),
   _labelSearch("Search: Column", this),
   _labelGrFollows("Graph follows  ", this),
-  _columnComboBox(this),
-  _selectComboBox(this),
-  _searchLineEdit(this),
-  _prevButton("Prev", this),
-  _nextButton("Next", this),
-  _searchStopButton(QIcon::fromTheme("process-stop"), "", this),
-  _pbAction(nullptr),
+  _searchFSM(this),
   _graphFollowsCheckBox(this),
-  _searchProgBar(this),
-  _searchCountLabel("", this),
-  _searchDone(false),
   _graphFollows(true),
   _mState(nullptr),
   _data(nullptr)
 {
-	int bWidth;
-
 	this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
 
 	/* Make a search toolbar. */
@@ -82,71 +70,51 @@ KsTraceViewer::KsTraceViewer(QWidget *parent)
 
 	/* On the toolbar make two Combo boxes for the search settings. */
 	_toolbar.addWidget(&_labelSearch);
-	_columnComboBox.addItems(_tableHeader);
+	_searchFSM._columnComboBox.addItems(_tableHeader);
 
 	/*
 	 * Using the old Signal-Slot syntax because
 	 * QComboBox::currentIndexChanged has overloads.
 	 */
-	connect(&_columnComboBox,	SIGNAL(currentIndexChanged(int)),
-		this,			SLOT(_searchEdit(int)));
-
-	_toolbar.addWidget(&_columnComboBox);
-
-	_selectComboBox.addItem("contains");
-	_selectComboBox.addItem("full match");
-	_selectComboBox.addItem("does not have");
+	connect(&_searchFSM._columnComboBox,	SIGNAL(currentIndexChanged(int)),
+		this,				SLOT(_searchEdit(int)));
 
 	/*
 	 * Using the old Signal-Slot syntax because
 	 * QComboBox::currentIndexChanged has overloads.
 	 */
-	connect(&_selectComboBox,	SIGNAL(currentIndexChanged(int)),
-		this,			SLOT(_searchEdit(int)));
-
-	_toolbar.addWidget(&_selectComboBox);
+	connect(&_searchFSM._selectComboBox,	SIGNAL(currentIndexChanged(int)),
+		this,				SLOT(_searchEdit(int)));
 
 	/* On the toolbar, make a Line edit field for search. */
-	_searchLineEdit.setMaximumWidth(FONT_WIDTH * 20);
-
-	connect(&_searchLineEdit,	&QLineEdit::returnPressed,
-		this,			&KsTraceViewer::_search);
+	_searchFSM._searchLineEdit.setMaximumWidth(FONT_WIDTH * 20);
 
-	connect(&_searchLineEdit,	&QLineEdit::textEdited,
-		this,			&KsTraceViewer::_searchEditText);
+	connect(&_searchFSM._searchLineEdit,	&QLineEdit::returnPressed,
+		this,				&KsTraceViewer::_search);
 
-	_toolbar.addWidget(&_searchLineEdit);
-	_toolbar.addSeparator();
+	connect(&_searchFSM._searchLineEdit,	&QLineEdit::textEdited,
+		this,				&KsTraceViewer::_searchEditText);
 
 	/* On the toolbar, add Prev & Next buttons. */
-	bWidth = FONT_WIDTH * 6;
-
-	_nextButton.setFixedWidth(bWidth);
-	_toolbar.addWidget(&_nextButton);
-	connect(&_nextButton,	&QPushButton::pressed,
-		this,		&KsTraceViewer::_next);
-
-	_prevButton.setFixedWidth(bWidth);
-	_toolbar.addWidget(&_prevButton);
-	connect(&_prevButton,	&QPushButton::pressed,
-		this,		&KsTraceViewer::_prev);
-
-	_toolbar.addSeparator();
-	_searchProgBar.setMaximumWidth(FONT_WIDTH * 10);
-	_searchProgBar.setRange(0, 200);
-	_pbAction = _toolbar.addWidget(&_searchProgBar);
-	_pbAction->setVisible(false);
-	_toolbar.addWidget(&_searchCountLabel);
-	_searchStopAction = _toolbar.addWidget(&_searchStopButton);
-	_searchStopAction->setVisible(false);
-	connect(&_searchStopButton,	&QPushButton::pressed,
-		this,			&KsTraceViewer::_searchStop);
+	connect(&_searchFSM._nextButton,	&QPushButton::pressed,
+		this,				&KsTraceViewer::_next);
+
+	connect(&_searchFSM._prevButton,	&QPushButton::pressed,
+		this,				&KsTraceViewer::_prev);
+
+
+	connect(&_searchFSM._searchStopButton,	&QPushButton::pressed,
+		this,				&KsTraceViewer::_searchStop);
+
+	connect(&_searchFSM._searchRestartButton,	&QPushButton::pressed,
+		this,				&KsTraceViewer::_searchContinue);
+
+	_searchFSM.placeInToolBar(&_toolbar);
 
 	/*
 	 * On the toolbar, make a Check box for connecting the search pannel
 	 * to the Graph widget.
 	 */
-	_toolbar.addSeparator();
 	_toolbar.addWidget(&_graphFollowsCheckBox);
 	_toolbar.addWidget(&_labelGrFollows);
 	_graphFollowsCheckBox.setCheckState(Qt::Checked);
@@ -238,10 +206,8 @@ void KsTraceViewer::reset()
 
 void KsTraceViewer::_searchReset()
 {
-	_searchProgBar.setValue(0);
-	_searchCountLabel.setText("");
+	_searchFSM.handleInput(sm_input_t::Change);
 	_proxyModel.searchReset();
-	_searchDone = false;
 }
 
 /** Get the index of the first (top) visible row. */
@@ -320,88 +286,26 @@ void KsTraceViewer::_graphFollowsChanged(int state)
 {
 	_graphFollows = (bool) state;
 
-	if (_graphFollows && _searchDone)
+	if (_graphFollows && _searchDone())
 		emit select(*_it); // Send a signal to the Graph widget.
 }
 
-static bool notHaveCond(const QString &searchText, const QString &itemText)
-{
-	return !itemText.contains(searchText, Qt::CaseInsensitive);
-}
-
-static bool containsCond(const QString &searchText, const QString &itemText)
-{
-	return itemText.contains(searchText, Qt::CaseInsensitive);
-}
-
-static bool matchCond(const QString &searchText, const QString &itemText)
-{
-	return (itemText.compare(searchText, Qt::CaseInsensitive) == 0);
-}
-
-void KsTraceViewer::_lockSearchPanel(bool lock)
-{
-	_columnComboBox.setEnabled(!lock);
-	_selectComboBox.setEnabled(!lock);
-	_searchLineEdit.setReadOnly(lock);
-	_prevButton.setEnabled(!lock);
-	_nextButton.setEnabled(!lock);
-	_graphFollowsCheckBox.setEnabled(!lock);
-}
-
 void KsTraceViewer::_search()
 {
-	if (!_searchDone) {
+	if (!_searchDone()) {
 		/*
 		 * The search is not done. This means that the search settings
 		 * have been modified since the last time we searched.
 		 */
-		int xColumn, xSelect;
-		QString xText;
-
-		/* Disable the user input until the search is done. */
-		_lockSearchPanel(true);
-
 		_matchList.clear();
-		xText = _searchLineEdit.text();
-		if (xText.isEmpty()) {
-			/*
-			 * No text is provided by the user. Most probably this
-			 * is an accidental key press. Just reenable the input.
-			 */
-			_lockSearchPanel(false);
-			return;
-		}
-
-		xColumn = _columnComboBox.currentIndex();
-		xSelect = _selectComboBox.currentIndex();
-
-		switch (xSelect) {
-			case Condition::Containes:
-				_searchItems(xColumn, xText, &containsCond);
-				break;
-
-			case Condition::Match:
-				_searchItems(xColumn, xText, &matchCond);
-				break;
-
-			case Condition::NotHave:
-				_searchItems(xColumn, xText, &notHaveCond);
-				break;
-
-			default:
-				break;
-		}
+		_searchItems();
 
 		if (!_matchList.empty()) {
-			this->showRow(*_it, true);
+			showRow(*_it, true);
 
 			if (_graphFollows)
 				emit select(*_it); // Send a signal to the Graph widget.
 		}
-
-		/* Enable the user input. */
-		_lockSearchPanel(false);
 	} else {
 		/*
 		 * If the search is done, pressing "Enter" is equivalent
@@ -413,13 +317,13 @@ void KsTraceViewer::_search()
 
 void KsTraceViewer::_next()
 {
-	if (!_searchDone) {
+	if (!_searchDone()) {
 		_search();
 		return;
 	}
 
 	if (!_matchList.empty()) { // Items have been found.
-		int row = _getSelectedDataRow();
+		int row = selectedRow();
 		/*
 		 * The iterator can only be at the selected row or if the
 		 * selected row is not a match at the first matching row after
@@ -427,7 +331,7 @@ void KsTraceViewer::_next()
 		 */
 		if (*_it == row) {
 			++_it; // Move the iterator.
-			if (_it == _matchList.end() ) {
+			if (_it == _matchList.end()) {
 				/*
 				 * This is the last item of the list.
 				 * Go back to the beginning.
@@ -448,7 +352,7 @@ void KsTraceViewer::_next()
 
 void KsTraceViewer::_prev()
 {
-	if (!_searchDone) {
+	if (!_searchDone()) {
 		_search();
 		return;
 	}
@@ -474,6 +378,7 @@ void KsTraceViewer::_prev()
 void KsTraceViewer::_updateSearchCount()
 {
 	int index, total;
+	QString countText;
 
 	if (_matchList.isEmpty())
 		return;
@@ -481,14 +386,20 @@ void KsTraceViewer::_updateSearchCount()
 	index = _it - _matchList.begin();
 	total =_matchList.count();
 
-	_searchCountLabel.setText(QString(" %1 / %2").arg(index).arg(total));
+	countText = QString(" %1 / %2").arg(index + 1).arg(total);
+	_searchFSM._searchCountLabel.setText(countText);
 }
 
 void KsTraceViewer::_searchStop()
 {
-	_searchStopAction->setVisible(false);
-	_proxyModel.searchStop();
-	_lockSearchPanel(false);
+	_proxyModel._searchStop = true;
+	_searchFSM.handleInput(sm_input_t::Stop);
+}
+
+void KsTraceViewer::_searchContinue()
+{
+	_proxyModel._searchStop = false;
+	_searchItems();
 }
 
 void KsTraceViewer::_clicked(const QModelIndex& i)
@@ -499,7 +410,7 @@ void KsTraceViewer::_clicked(const QModelIndex& i)
 	 */
 	size_t row = _proxyModel.mapRowFromSource(i.row());
 
-	if (_searchDone && _matchList.count()) {
+	if (_searchDone() && _matchList.count()) {
 		_setSearchIterator(row);
 		_updateSearchCount();
 	}
@@ -594,7 +505,7 @@ void KsTraceViewer::markSwitch()
 		_view.clearSelection();
 	}
 
-	row = _getSelectedDataRow();
+	row = selectedRow();
 	if (row >= 0) {
 		_setSearchIterator(row);
 		_updateSearchCount();
@@ -634,7 +545,7 @@ void KsTraceViewer::resizeEvent(QResizeEvent* event)
 void KsTraceViewer::keyReleaseEvent(QKeyEvent *event)
 {
 	if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) {
-		int row = _getSelectedDataRow();
+		int row = selectedRow();
 		if (row >= 0)
 			emit select(row); // Send a signal to the Graph widget.
 
@@ -668,52 +579,52 @@ void KsTraceViewer::_resizeToContents()
 
 //! @endcond
 
-size_t KsTraceViewer::_searchItems(int column,
-				   const QString &searchText,
-				   condition_func cond)
+size_t KsTraceViewer::_searchItems()
 {
+	int column = _searchFSM._columnComboBox.currentIndex();
+	QString searchText = _searchFSM._searchLineEdit.text();
 	int count, dataRow;
 
-	_pbAction->setVisible(true);
+	if (searchText.isEmpty()) {
+		/*
+		 * No text is provided by the user. Most probably this
+		 * is an accidental key press. */
+		return 0;
+	}
 
 	if (_proxyModel.rowCount({}) < KS_SEARCH_SHOW_PROGRESS_MIN) {
 		/*
 		 * This is a small data-set. Do a single-threaded search
 		 * without showing the progress.
 		 */
-		_proxyModel.search(column, searchText, cond, &_matchList,
+		_proxyModel.search(column, searchText, _searchFSM.condition(), &_matchList,
 				   nullptr, nullptr);
 	} else {
-		_searchStopAction->setVisible(true);
+		_searchFSM.handleInput(sm_input_t::Start);
 
 		if (column == KsViewModel::TRACE_VIEW_COL_INFO ||
-		    column == KsViewModel::TRACE_VIEW_COL_LAT) {
-			_proxyModel.search(column, searchText,
-					   cond, &_matchList,
-					   &_searchProgBar,
-					   &_searchCountLabel);
-		} else {
-			_searchItemsMapReduce(column, searchText, cond);
-		}
-
-		_searchStopAction->setVisible(false);
+		    column == KsViewModel::TRACE_VIEW_COL_LAT)
+			_proxyModel.search(&_searchFSM, &_matchList);
+		else
+			_searchItemsMapReduce(column, searchText, _searchFSM.condition());
 	}
 
 	count = _matchList.count();
-
-	_pbAction->setVisible(false);
-	_searchDone = true;
+	_searchFSM.handleInput(sm_input_t::Finish);
 
 	if (count == 0) // No items have been found. Do nothing.
 		return 0;
 
-	dataRow = _getSelectedDataRow();
+	dataRow = selectedRow();
 	if (dataRow >= 0) {
 		_view.clearSelection();
 		_setSearchIterator(dataRow);
+		showRow(*_it, true);
+
+		if (_graphFollows)
+			emit select(*_it); // Send a signal to the Graph widget.
 	} else {
 		/* Move the iterator to the beginning of the match list. */
-		_view.clearSelection();
 		_it = _matchList.begin();
 	}
 
@@ -747,7 +658,7 @@ void KsTraceViewer::_setSearchIterator(int row)
 
 void KsTraceViewer::_searchItemsMapReduce(int column,
 					  const QString &searchText,
-					  condition_func cond)
+					  search_condition_func cond)
 {
 	int nThreads = std::thread::hardware_concurrency();
 	std::vector<QPair<int, int>> ranges(nThreads);
@@ -763,9 +674,9 @@ void KsTraceViewer::_searchItemsMapReduce(int column,
 	};
 
 	auto lamSearchReduce = [&] (QList<int> &resultList,
-				  const QList<int> &mapList) {
+				    const QList<int> &mapList) {
 		resultList << mapList;
-		_searchProgBar.setValue(_searchProgBar.value() + 1);
+		_searchFSM.incrementProgress();
 	};
 
 	for (auto &r: ranges) {
@@ -785,7 +696,7 @@ void KsTraceViewer::_searchItemsMapReduce(int column,
 	while (_proxyModel.searchProgress() < KS_PROGRESS_BAR_MAX - nThreads) {
 		std::unique_lock<std::mutex> lk(_proxyModel._mutex);
 		_proxyModel._pbCond.wait(lk);
-		_searchProgBar.setValue(_proxyModel.searchProgress());
+		_searchFSM.setProgress(_proxyModel.searchProgress());
 		QApplication::processEvents();
 	}
 
@@ -793,7 +704,11 @@ void KsTraceViewer::_searchItemsMapReduce(int column,
 		lamSearchReduce(_matchList, m.get());
 }
 
-int KsTraceViewer::_getSelectedDataRow()
+/**
+ * Get the currently selected row. If no row is selected the function
+ * returns -1.
+ */
+int KsTraceViewer::selectedRow()
 {
 	QItemSelectionModel *sm = _view.selectionModel();
 	int dataRow = -1;
diff --git a/kernel-shark-qt/src/KsTraceViewer.hpp b/kernel-shark-qt/src/KsTraceViewer.hpp
index a8c1fe6..f59f5df 100644
--- a/kernel-shark-qt/src/KsTraceViewer.hpp
+++ b/kernel-shark-qt/src/KsTraceViewer.hpp
@@ -18,6 +18,7 @@
 // KernelShark
 #include "KsUtils.hpp"
 #include "KsModels.hpp"
+#include "KsSearchFSM.hpp"
 #include "KsDualMarker.hpp"
 
 /**
@@ -67,6 +68,8 @@ public:
 
 	void clearSelection();
 
+	int selectedRow();
+
 	void update(KsDataStore *data);
 
 signals:
@@ -100,24 +103,10 @@ private:
 
 	QLabel		_labelSearch, _labelGrFollows;
 
-	QComboBox	_columnComboBox;
-
-	QComboBox	_selectComboBox;
-
-	QLineEdit	_searchLineEdit;
-
-	QPushButton	_prevButton, _nextButton, _searchStopButton;
-
-	QAction		*_pbAction, *_searchStopAction;
+	KsSearchFSM	_searchFSM;
 
 	QCheckBox	_graphFollowsCheckBox;
 
-	QProgressBar	_searchProgBar;
-
-	QLabel		_searchCountLabel;
-
-	bool		_searchDone;
-
 	bool		_graphFollows;
 
 	QList<int>		_matchList;
@@ -139,11 +128,10 @@ private:
 
 	void _resizeToContents();
 
-	size_t _searchItems(int column, const QString &searchText,
-			    condition_func cond);
+	size_t _searchItems();
 
 	void _searchItemsMapReduce(int column, const QString &searchText,
-				   condition_func cond);
+				   search_condition_func cond);
 
 	void _searchEditText(const QString &);
 
@@ -161,13 +149,19 @@ private:
 
 	void _searchStop();
 
+	void _searchContinue();
+
 	void _clicked(const QModelIndex& i);
 
 	void _onCustomContextMenu(const QPoint &);
 
 	void _setSearchIterator(int row);
 
-	int _getSelectedDataRow();
+	bool _searchDone()
+	{
+		return _searchFSM.getState() == search_state_t::Done_s ||
+		       _searchFSM.getState() == search_state_t::Paused_s;
+	}
 
 private slots:
 	void _searchEdit(int);
-- 
2.17.1

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, back to index

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-04 20:06 [PATCH 0/2] Improve/debug the searching logic Yordan Karadzhov
2019-01-04 20:06 ` [PATCH 1/2] kernel-shark-qt: Avoid race condition when reading data Yordan Karadzhov
2019-01-04 20:06 ` [PATCH 2/2] kernel-shark-qt: Implement State machine for searching in the data Yordan Karadzhov

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 linux-trace-devel@archiver.kernel.org
	public-inbox-index linux-trace-devel


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