diff mbox series

[v2,21/23] kernel-shark-qt: Add Record dialog to KS GUI.

Message ID 20181016155232.5257-22-ykaradzhov@vmware.com (mailing list archive)
State Accepted
Headers show
Series Add Qt-based GUI for KernelShark | expand

Commit Message

Yordan Karadzhov Oct. 16, 2018, 3:53 p.m. UTC
A Record dialog is added to the Tools menu of the KernelShark GUI.
The Record dialog can be used only after installing the project
(sudo make install).

Signed-off-by: Yordan Karadzhov <ykaradzhov@vmware.com>
---
 kernel-shark-qt/src/KsMainWindow.cpp | 128 +++++++++++++++++++++++++++
 kernel-shark-qt/src/KsMainWindow.hpp |  22 +++++
 2 files changed, 150 insertions(+)
diff mbox series

Patch

diff --git a/kernel-shark-qt/src/KsMainWindow.cpp b/kernel-shark-qt/src/KsMainWindow.cpp
index b9fb587..b3cbc3b 100644
--- a/kernel-shark-qt/src/KsMainWindow.cpp
+++ b/kernel-shark-qt/src/KsMainWindow.cpp
@@ -28,6 +28,7 @@ 
 #include "libkshark.h"
 #include "KsCmakeDef.hpp"
 #include "KsMainWindow.hpp"
+#include "KsCaptureDialog.hpp"
 #include "KsAdvFilteringDialog.hpp"
 
 /** Create KernelShark Main window. */
@@ -39,6 +40,8 @@  KsMainWindow::KsMainWindow(QWidget *parent)
   _graph(this),
   _mState(this),
   _plugins(this),
+  _capture(this),
+  _captureLocalServer(this),
   _openAction("Open", this),
   _restorSessionAction("Restor Last Session", this),
   _importSessionAction("Import Session", this),
@@ -56,6 +59,7 @@  KsMainWindow::KsMainWindow(QWidget *parent)
   _cpuSelectAction("CPUs", this),
   _taskSelectAction("Tasks", this),
   _pluginsAction("Plugins", this),
+  _captureAction("Record", this),
   _colorAction(this),
   _colSlider(this),
   _colorPhaseSlider(Qt::Horizontal, this),
@@ -67,6 +71,7 @@  KsMainWindow::KsMainWindow(QWidget *parent)
 	setWindowTitle("Kernel Shark");
 	_createActions();
 	_createMenus();
+	_initCapture();
 
 	_splitter.addWidget(&_graph);
 	_splitter.addWidget(&_view);
@@ -215,6 +220,13 @@  void KsMainWindow::_createActions()
 	connect(&_pluginsAction,	&QAction::triggered,
 		this,			&KsMainWindow::_pluginSelect);
 
+	_captureAction.setIcon(QIcon::fromTheme("media-record"));
+	_captureAction.setShortcut(tr("Ctrl+R"));
+	_captureAction.setStatusTip("Capture trace data");
+
+	connect(&_captureAction,	&QAction::triggered,
+		this,			&KsMainWindow::_record);
+
 	_colorPhaseSlider.setMinimum(20);
 	_colorPhaseSlider.setMaximum(180);
 	_colorPhaseSlider.setValue(KsPlot::Color::getRainbowFrequency() * 100);
@@ -321,6 +333,7 @@  void KsMainWindow::_createMenus()
 	/* Tools menu */
 	tools = menuBar()->addMenu("Tools");
 	tools->addAction(&_pluginsAction);
+	tools->addAction(&_captureAction);
 	tools->addSeparator();
 	tools->addAction(&_colorAction);
 	tools->addAction(&_fullScreenModeAction);
@@ -690,6 +703,29 @@  void KsMainWindow::_pluginSelect()
 	dialog->show();
 }
 
+void KsMainWindow::_record()
+{
+#ifndef DO_AS_ROOT
+
+	QErrorMessage *em = new QErrorMessage(this);
+	QString message;
+
+	message = "Record is currently not supported.";
+	message += " Install \"pkexec\" and then do:<br>";
+	message += " cd build <br> sudo ./cmake_uninstall.sh <br>";
+	message += " ./cmake_clean.sh <br> cmake .. <br> make <br>";
+	message += " sudo make install";
+
+	em->showMessage(message);
+	qCritical() << "ERROR: " << message;
+
+	return;
+
+#endif
+
+	_capture.start();
+}
+
 void KsMainWindow::_setColorPhase(int f)
 {
 	KsPlot::Color::setRainbowFrequency(f / 100.);
@@ -895,6 +931,98 @@  void KsMainWindow::loadSession(const QString &fileName)
 	_colorPhaseSlider.setValue(_session.getColorScheme() * 100);
 }
 
+void KsMainWindow::_initCapture()
+{
+#ifdef DO_AS_ROOT
+
+	_capture.setProgram("kshark-su-record");
+
+	connect(&_capture,	&QProcess::started,
+		this,		&KsMainWindow::_captureStarted);
+
+	/*
+	 * Using the old Signal-Slot syntax because QProcess::finished has
+	 * overloads.
+	 */
+	connect(&_capture,	SIGNAL(finished(int, QProcess::ExitStatus)),
+		this,		SLOT(_captureFinished(int, QProcess::ExitStatus)));
+
+	connect(&_capture,	&QProcess::errorOccurred,
+		this,		&KsMainWindow::_captureError);
+
+	connect(&_captureLocalServer,	&QLocalServer::newConnection,
+		this,			&KsMainWindow::_readSocket);
+
+#endif
+}
+
+void KsMainWindow::_captureStarted()
+{
+	_captureLocalServer.listen("KSCapture");
+}
+
+void KsMainWindow::_captureFinished(int exit, QProcess::ExitStatus st)
+{
+	QProcess *capture = (QProcess *)sender();
+
+	_captureLocalServer.close();
+
+	if (exit != 0 || st != QProcess::NormalExit) {
+		QString message = "Capture process failed:<br>";
+
+		message += capture->errorString();
+		message += "<br>Try doing:<br> sudo make install";
+
+		_error(message, "captureFinishedErr", false, false);
+	}
+}
+
+void KsMainWindow::_captureError(QProcess::ProcessError error)
+{
+	QProcess *capture = (QProcess *)sender();
+	QString message = "Capture process failed:<br>";
+
+	message += capture->errorString();
+	message += "<br>Try doing:<br> sudo make install";
+
+	_error(message, "captureFinishedErr", false, false);
+}
+
+void KsMainWindow::_readSocket()
+{
+	QLocalSocket *socket;
+	quint32 blockSize;
+	QString fileName;
+
+	auto lamSocketError = [&](QString message)
+	{
+		message = "ERROR from Local Server: " + message;
+		_error(message, "readSocketErr", false, false);
+	};
+
+	socket = _captureLocalServer.nextPendingConnection();
+	if (!socket) {
+		lamSocketError("Pending connectio not found!");
+		return;
+	}
+
+	QDataStream in(socket);
+	socket->waitForReadyRead();
+	if (socket->bytesAvailable() < (int)sizeof(quint32)) {
+		lamSocketError("Message size is corrupted!");
+		return;
+	};
+
+	in >> blockSize;
+	if (socket->bytesAvailable() < blockSize || in.atEnd()) {
+		lamSocketError("Message is corrupted!");
+		return;
+	}
+
+	in >> fileName;
+	loadDataFile(fileName);
+}
+
 void KsMainWindow::_splitterMoved(int pos, int index)
 {
 	_session.saveSplitterSize(_splitter);
diff --git a/kernel-shark-qt/src/KsMainWindow.hpp b/kernel-shark-qt/src/KsMainWindow.hpp
index 6e3f864..0e14c80 100644
--- a/kernel-shark-qt/src/KsMainWindow.hpp
+++ b/kernel-shark-qt/src/KsMainWindow.hpp
@@ -14,6 +14,7 @@ 
 
 // Qt
 #include <QMainWindow>
+#include <QLocalServer>
 
 // KernelShark
 #include "KsTraceViewer.hpp"
@@ -81,6 +82,12 @@  private:
 	/** Plugin manager. */
 	KsPluginManager	_plugins;
 
+	/** The process used to record trace data. */
+	QProcess	_capture;
+
+	/** Local Server used for comunucation with the Capture process. */
+	QLocalServer	_captureLocalServer;
+
 	// File menu.
 	QAction		_openAction;
 
@@ -119,6 +126,8 @@  private:
 	// Tools menu.
 	QAction		_pluginsAction;
 
+	QAction		_captureAction;
+
 	QWidgetAction	_colorAction;
 
 	QWidget		_colSlider;
@@ -166,6 +175,8 @@  private:
 
 	void _pluginSelect();
 
+	void _record();
+
 	void _setColorPhase(int);
 
 	void _fullScreenMode();
@@ -174,18 +185,29 @@  private:
 
 	void _contents();
 
+	void _captureStarted();
+
+	void _captureError(QProcess::ProcessError error);
+
+	void _readSocket();
+
 	void _splitterMoved(int pos, int index);
 
 	void _createActions();
 
 	void _createMenus();
 
+	void _initCapture();
+
 	void _updateSession();
 
 	inline void _resizeEmpty() {resize(SCREEN_WIDTH * .5, FONT_HEIGHT * 3);}
 
 	void _error(const QString &text, const QString &errCode,
 		    bool resize, bool unloadPlugins);
+
+private slots:
+	void _captureFinished(int, QProcess::ExitStatus);
 };
 
 #endif // _KS_MAINWINDOW_H