linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com>
To: rostedt@goodmis.org
Cc: linux-trace-devel@vger.kernel.org
Subject: [PATCH] kernel-shark-2.alpha: Restructure KVMCombo plugin to use CPU mapping information from the trace files
Date: Thu,  9 Apr 2020 17:25:09 +0300	[thread overview]
Message-ID: <20200409142511.82228-3-tz.stoyanov@gmail.com> (raw)
In-Reply-To: <20200409142511.82228-1-tz.stoyanov@gmail.com>

From: Tzvetomir (VMware)  Stoyanov <tz.stoyanov@gmail.com>

In the upcoming trace-cmd 2.9, extra information about host and guest tracing
will be stored in the trace.dat files. Information about host CPU - guest vCPU
mapping will be saved in host trace file. This mapping is mandatory for KVMCombo
plugin. Currently, the mapping is extracted for the tracing data.
Getting the information from the trace files is more reliable and solves the use
case with more than one guest.

Signed-off-by: Tzvetomir (VMware)  Stoyanov <tz.stoyanov@gmail.com>
---
 src/plugins/KVMCombo.cpp | 203 ++++++++++++++++++++++-----------------
 src/plugins/KVMCombo.hpp |  14 +--
 2 files changed, 120 insertions(+), 97 deletions(-)

diff --git a/src/plugins/KVMCombo.cpp b/src/plugins/KVMCombo.cpp
index 1ae03aa..25c2331 100644
--- a/src/plugins/KVMCombo.cpp
+++ b/src/plugins/KVMCombo.cpp
@@ -69,10 +69,19 @@ KsVCPUCheckBoxWidget::KsVCPUCheckBoxWidget(QWidget *parent)
 	_initTree();
 }
 
-void KsVCPUCheckBoxWidget::update(int sdHost, VCPUVector vcpus)
+void KsVCPUCheckBoxWidget::update(int GuestId, GuestMap *gMap, GuestName *gName)
 {
-	int nVCPUs = vcpus.count();
 	KsPlot::ColorTable colors;
+	VCPUVector VCPUs;
+	HostPair Host;
+	int nVCPUs;
+
+	if (!gMap->contains(GuestId) || !gName->contains(GuestId))
+		return;
+
+	Host = gMap->value(GuestId);
+	VCPUs = Host.second;
+	nVCPUs = VCPUs.count();
 
 	_tree.clear();
 	_id.resize(nVCPUs);
@@ -80,9 +89,12 @@ void KsVCPUCheckBoxWidget::update(int sdHost, VCPUVector vcpus)
 	colors = KsPlot::getCPUColorTable();
 
 	for (int i = 0; i < nVCPUs; ++i) {
+		QString strCPU = QLatin1String("vCPU ") + QString::number(VCPUs.at(i).second);
+		strCPU += (QLatin1String("\t<") + gName->value(GuestId) + QLatin1Char('>'));
+
 		QTreeWidgetItem *cpuItem = new QTreeWidgetItem;
 		cpuItem->setText(0, "  ");
-		cpuItem->setText(1, QString("vCPU %1").arg(vcpus.at(i).second));
+		cpuItem->setText(1, strCPU);
 		cpuItem->setCheckState(0, Qt::Checked);
 		cpuItem->setBackgroundColor(0, QColor(colors[i].r(),
 						      colors[i].g(),
@@ -96,6 +108,65 @@ void KsVCPUCheckBoxWidget::update(int sdHost, VCPUVector vcpus)
 	setDefault(false);
 }
 
+static void getGuestMap(GuestMap *gMap, GuestName *gName)
+{
+	struct tracecmd_input *peer_handle = NULL;
+	struct kshark_data_stream *peer_stream;
+	struct tracecmd_input *guest_handle = NULL;
+	struct kshark_data_stream *guest_stream;
+	kshark_context *kshark_ctx(nullptr);
+	unsigned long long trace_id;
+	int ret;
+	const char *name;
+	int vcpu_count;
+	const int *cpu_pid;
+	int *streamIds;
+	int i, j, k;
+
+	if (!kshark_instance(&kshark_ctx))
+		return;
+
+	gMap->clear();
+	gName->clear();
+
+	streamIds = kshark_all_streams(kshark_ctx);
+	for (i = 0; i < kshark_ctx->n_streams; i++) {
+		guest_stream = kshark_get_data_stream(kshark_ctx, streamIds[i]);
+		if (!guest_stream || guest_stream->format != KS_TEP_DATA)
+			continue;
+		guest_handle = kshark_get_tep_input(guest_stream);
+		if (!guest_handle)
+			continue;
+		trace_id = tracecmd_get_traceid(guest_handle);
+		if (!trace_id)
+			continue;
+		for (j = 0; j < kshark_ctx->n_streams; j++) {
+			if (streamIds[i] == streamIds[j])
+				continue;
+			peer_stream = kshark_get_data_stream(kshark_ctx, streamIds[j]);
+			if (!peer_stream || peer_stream->format != KS_TEP_DATA)
+				continue;
+			peer_handle = kshark_get_tep_input(peer_stream);
+			if (!peer_handle)
+				continue;
+			ret = tracecmd_get_guest_cpumap(peer_handle, trace_id,
+							&name, &vcpu_count, &cpu_pid);
+			if (!ret) {
+				VCPUVector vcpus(vcpu_count);
+				for (k = 0; k < vcpu_count; k++) {
+					vcpus[k].first = cpu_pid[k];
+					vcpus[k].second = k;
+				}
+				gMap->insert(streamIds[i], QPair<int, VCPUVector>(streamIds[j], vcpus));
+				gName->insert(streamIds[i], QString(name));
+				break;
+			}
+		}
+	}
+
+	free(streamIds);
+}
+
 #define DIALOG_NAME	"KVM Combo plots"
 
 #define LABEL_WIDTH	(FONT_WIDTH * 50)
@@ -170,24 +241,29 @@ KsComboPlotDialog::KsComboPlotDialog(QWidget *parent)
 	setLayout(&_topLayout);
 }
 
-void KsComboPlotDialog::update(int sdHost, VCPUVector vcpus)
+void KsComboPlotDialog::update()
 {
 	kshark_context *kshark_ctx(nullptr);
-	int sd, *streamIds;
+	GuestMap::iterator i;
+	VCPUVector Vect;
+	HostPair hPair;
+	int sd;
+	int j;
 
 	if (!kshark_instance(&kshark_ctx))
 		return;
 
-	_sdHost = sdHost;
-	_vcpus = vcpus;
+	getGuestMap(&_guestMap, &_guestName);
+
+	hPair = _guestMap.begin().value();
 	KsUtils::setElidedText(&_hostFileLabel,
-			       kshark_ctx->stream[sdHost]->file,
+			       kshark_ctx->stream[hPair.first]->file,
 			       Qt::ElideLeft, LABEL_WIDTH);
 
-	streamIds = kshark_all_streams(kshark_ctx);
-	for (int i = 0; i < kshark_ctx->n_streams; ++i) {
-		sd = streamIds[i];
-		if (sd == sdHost)
+	_guestStreamComboBox.clear();
+	for (i = _guestMap.begin(); i != _guestMap.end(); ++i) {
+		sd = i.key();
+		if (sd >= kshark_ctx->n_streams)
 			continue;
 
 		_guestStreamComboBox.addItem(kshark_ctx->stream[sd]->file,
@@ -200,8 +276,8 @@ void KsComboPlotDialog::update(int sdHost, VCPUVector vcpus)
 				this,		&KsComboPlotDialog::_applyPress);
 	}
 
-	_vcpuTree.update(sdHost, vcpus);
-	free(streamIds);
+	sd = _guestStreamComboBox.currentData().toInt();
+	_vcpuTree.update(sd, &_guestMap, &_guestName);
 }
 
 void KsComboPlotDialog::_applyPress()
@@ -210,6 +286,18 @@ void KsComboPlotDialog::_applyPress()
 	QVector<int> allCombosVec;
 	KsComboPlot combo(2);
 	int nPlots(0);
+	VCPUVector VCPUs;
+	HostPair Host;
+	int GuestId;
+	int nVCPUs;
+
+	GuestId = _guestStreamComboBox.currentData().toInt();
+	if (!_guestMap.contains(GuestId))
+		return;
+
+	Host = _guestMap.value(GuestId);
+	VCPUs = Host.second;
+	nVCPUs = VCPUs.count();
 
 	/*
 	 * Disconnect _applyButton. This is done in order to protect
@@ -218,17 +306,20 @@ void KsComboPlotDialog::_applyPress()
 	disconnect(_applyButtonConnection);
 
 	for (auto const &i: cbVec) {
+		if (i >= nVCPUs)
+			continue;
+
 		allCombosVec.append(2);
 
-		combo[0]._streamId = _guestStreamComboBox.currentData().toInt();
-		combo[0]._id = _vcpus.at(i).second;
+		combo[0]._streamId = GuestId;
+		combo[0]._id = VCPUs.at(i).second;
 		combo[0]._type = KsPlot::KSHARK_CPU_DRAW |
 				 KsPlot::KSHARK_GUEST_DRAW;
 
 		combo[0] >> allCombosVec;
 
-		combo[1]._streamId = _sdHost;
-		combo[1]._id = _vcpus.at(i).first;
+		combo[1]._streamId = Host.first;
+		combo[1]._id = VCPUs.at(i).first;
 		combo[1]._type = KsPlot::KSHARK_TASK_DRAW |
 				 KsPlot::KSHARK_HOST_DRAW;
 
@@ -241,66 +332,8 @@ void KsComboPlotDialog::_applyPress()
 
 void KsComboPlotDialog::_guestStreamChanged(const QString &sdStr)
 {
-
-}
-
-static int getVCPU(plugin_kvm_context *plugin_ctx,
-		   kshark_trace_histo *histo,
-		   int sdHost, int pid)
-{
-	int values[2] = {plugin_ctx->vm_entry_id, pid};
-	const kshark_entry *entry;
-	unsigned long long vcpu;
-
-	for (int b = 0; b < histo->n_bins; ++b) {
-		entry = ksmodel_get_entry_front(histo,
-						b, false,
-						kshark_match_event_and_pid,
-						sdHost, values,
-						nullptr,
-						nullptr);
-		if (!entry)
-			continue;
-
-		if (kshark_read_event_field(entry, "vcpu_id", &vcpu) >= 0)
-			return vcpu;
-	}
-
-	return -1;
-}
-
-HostMap getVCPUPids(kshark_context *kshark_ctx, kshark_trace_histo *histo)
-{
-	int sd, n_vcpus, *streamIds, *pids;
-	plugin_kvm_context *plugin_ctx;
-	HostMap hMap;
-
-	streamIds = kshark_all_streams(kshark_ctx);
-	for (int i = 0; i < kshark_ctx->n_streams; ++i) {
-		sd = streamIds[i];
-		plugin_ctx = get_kvm_context(sd);
-		if (!plugin_ctx)
-			continue;
-
-		/* This stream contains KVM events. */
-		n_vcpus = plugin_ctx->vcpu_pids->count;
-		if (n_vcpus) {
-			VCPUVector vcpus(n_vcpus);
-			pids = kshark_hash_ids(plugin_ctx->vcpu_pids);
-			for (int j = 0; j < n_vcpus; ++j) {
-				vcpus[j].first = pids[j];
-				vcpus[j].second = getVCPU(plugin_ctx,
-							  histo,
-							  sd, pids[j]);
-			}
-
-			free(pids);
-			hMap[sd] = vcpus;
-		}
-	}
-
-	free(streamIds);
-	return hMap;
+	int GuestId = _guestStreamComboBox.currentData().toInt();
+	_vcpuTree.update(GuestId, &_guestMap, &_guestName);
 }
 
 KsComboPlotDialog dialog;
@@ -309,18 +342,11 @@ QMetaObject::Connection dialogConnection;
 static void showDialog(KsMainWindow *ks)
 {
 	kshark_context *kshark_ctx(nullptr);
-	kshark_trace_histo *histo;
-	VCPUVector vcpus;
-	HostMap hMap;
-	int sdHost;
 
 	if (!kshark_instance(&kshark_ctx))
 		return;
 
-	histo = ks->graphPtr()->glPtr()->model()->histo();
-	hMap = getVCPUPids(kshark_ctx, histo);
-
-	if (kshark_ctx->n_streams < 2 || hMap.count() != 1) {
+	if (kshark_ctx->n_streams < 2) {
 		QString err("Data from one Host and at least one Guest is required.");
 		QMessageBox msgBox;
 		msgBox.critical(nullptr, "Error", err);
@@ -328,10 +354,7 @@ static void showDialog(KsMainWindow *ks)
 		return;
 	}
 
-	sdHost = hMap.begin().key();
-	vcpus = hMap.begin().value();
-
-	dialog.update(sdHost, vcpus);
+	dialog.update();
 
 	if (!dialogConnection) {
 		dialogConnection =
diff --git a/src/plugins/KVMCombo.hpp b/src/plugins/KVMCombo.hpp
index b47f557..a343141 100644
--- a/src/plugins/KVMCombo.hpp
+++ b/src/plugins/KVMCombo.hpp
@@ -16,8 +16,9 @@
 #include "KsWidgetsLib.hpp"
 
 typedef QVector<QPair<int, int>> VCPUVector;
-
-typedef QMap<int, VCPUVector> HostMap;
+typedef QPair<int, VCPUVector> HostPair;
+typedef QMap<int, HostPair> GuestMap;
+typedef QMap<int, QString> GuestName;
 
 /**
  * The KsVCPUCheckBoxWidget class provides a widget for selecting CPU plots to
@@ -27,7 +28,7 @@ struct KsVCPUCheckBoxWidget : public KsWidgetsLib::KsCheckBoxTreeWidget
 {
 	explicit KsVCPUCheckBoxWidget(QWidget *parent = nullptr);
 
-	void update(int sdHost, VCPUVector vcpus);
+	void update(int GuestId, GuestMap *gMap, GuestName *gName);
 };
 
 /**
@@ -40,16 +41,15 @@ class KsComboPlotDialog : public QDialog
 public:
 	explicit KsComboPlotDialog(QWidget *parent = nullptr);
 
-	void update(int sdHost, VCPUVector vcpus);
+	void update();
 
 signals:
 	/** Signal emitted when the "Apply" button is pressed. */
 	void apply(int sd, QVector<int>);
 
 private:
-	int				_sdHost;
-
-	VCPUVector			_vcpus;
+	GuestMap			_guestMap;
+	GuestName			_guestName;
 
 	KsVCPUCheckBoxWidget		_vcpuTree;
 
-- 
2.25.1


  parent reply	other threads:[~2020-04-09 14:25 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-09 14:25 [PATCH] kernel-shark-2.alpha: Force trace-cmd.h to be used as plain C Tzvetomir Stoyanov (VMware)
2020-04-09 14:25 ` [PATCH] kernel-shark-2.alpha: Print the plugin's file name in case of loading error Tzvetomir Stoyanov (VMware)
2020-04-09 14:25 ` Tzvetomir Stoyanov (VMware) [this message]
2020-04-09 14:25 ` [PATCH] KernelShark: Adjust the width of marker buttons Tzvetomir Stoyanov (VMware)
2020-04-09 14:25 ` [PATCH v2] kernel-shark-2.alpha: Use new tracecmd APIs to open guest tracing file Tzvetomir Stoyanov (VMware)

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=20200409142511.82228-3-tz.stoyanov@gmail.com \
    --to=tz.stoyanov@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).