virtualization.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC V2 0/4] Adding tracepoints to vhost/net
@ 2014-03-21  9:41 Jason Wang
  2014-03-21  9:41 ` [PATCH RFC V2 1/4] vhost: introduce queue_index for tracing Jason Wang
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Jason Wang @ 2014-03-21  9:41 UTC (permalink / raw)
  To: mst, kvm, virtio-dev, virtualization, netdev, linux-kernel

Recent debugging on vhost net zerocopy shows the need of
tracepoints. So to help in vhost{net} debugging and performance
analyzing, the following series adding basic tracepoints to
vhost. Operations of both vhost and vhost_net were traced in current
implementation.

A top-like satistics displaying script were introduced to help the
troubleshooting:
vhost statistics

 vhost_virtio_update_used_idx               1215215       0
 vhost_virtio_get_vq_desc                   1215215       0
 vhost_work_queue_wakeup                     986808       0
 vhost_virtio_signal                         811601       0
 vhost_net_tx                                611457       0
 vhost_net_rx                                603758       0
 vhost_net_tx(datacopy)                      601903       0
 vhost_work_queue_wakeup(rx_net)             565081       0
 vhost_virtio_signal(rx)                     461603       0
 vhost_work_queue_wakeup(tx_kick)            421718       0
 vhost_virtio_update_avail_event             417346       0
 vhost_virtio_signal(tx)                     349998       0
 vhost_work_queue_coalesce                    39384       0
 vhost_work_queue_coalesce(rx_net)            38677       0
 vhost_net_tx(zerocopy)                        9554       0
 vhost_work_queue_coalesce(tx_kick)             707       0
 vhost_work_queue_wakeup(rx_kick)                 9       0

TODO:
- performance test
- finalize which should be traced

Reference:
- V1: https://lkml.org/lkml/2012/4/9/478

Jason Wang (4):
  vhost: introduce queue_index for tracing
  vhost: basic tracepoints
  vhost_net: add basic tracepoints for vhost_net
  tools: virtio: add a top-like utility for displaying vhost satistics

 drivers/vhost/net.c       |   7 +
 drivers/vhost/net_trace.h |  53 +++++++
 drivers/vhost/trace.h     | 175 ++++++++++++++++++++++
 drivers/vhost/vhost.c     |  14 +-
 drivers/vhost/vhost.h     |   3 +
 tools/virtio/vhost_stat   | 375 ++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 626 insertions(+), 1 deletion(-)
 create mode 100644 drivers/vhost/net_trace.h
 create mode 100644 drivers/vhost/trace.h
 create mode 100755 tools/virtio/vhost_stat

-- 
1.8.3.2

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

* [PATCH RFC V2 1/4] vhost: introduce queue_index for tracing
  2014-03-21  9:41 [PATCH RFC V2 0/4] Adding tracepoints to vhost/net Jason Wang
@ 2014-03-21  9:41 ` Jason Wang
  2014-03-21  9:41 ` [PATCH RFC V2 2/4] vhost: basic tracepoints Jason Wang
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Jason Wang @ 2014-03-21  9:41 UTC (permalink / raw)
  To: mst, kvm, virtio-dev, virtualization, netdev, linux-kernel

Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 drivers/vhost/net.c   | 1 +
 drivers/vhost/vhost.h | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index a0fa5de..85d666c 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -708,6 +708,7 @@ static int vhost_net_open(struct inode *inode, struct file *f)
 		n->vqs[i].done_idx = 0;
 		n->vqs[i].vhost_hlen = 0;
 		n->vqs[i].sock_hlen = 0;
+		n->vqs[i].vq.queue_index = i;
 	}
 	vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX);
 
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 35eeb2a..6e36416 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -96,6 +96,9 @@ struct vhost_virtqueue {
 	/* Last used index value we have signalled on */
 	bool signalled_used_valid;
 
+	/* Queue index used for tracing */
+	u16 queue_index;
+
 	/* Log writes to used structure. */
 	bool log_used;
 	u64 log_addr;
-- 
1.8.3.2

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

* [PATCH RFC V2 2/4] vhost: basic tracepoints
  2014-03-21  9:41 [PATCH RFC V2 0/4] Adding tracepoints to vhost/net Jason Wang
  2014-03-21  9:41 ` [PATCH RFC V2 1/4] vhost: introduce queue_index for tracing Jason Wang
@ 2014-03-21  9:41 ` Jason Wang
  2014-03-21  9:41 ` [PATCH RFC V2 3/4] vhost_net: add basic tracepoints for vhost_net Jason Wang
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Jason Wang @ 2014-03-21  9:41 UTC (permalink / raw)
  To: mst, kvm, virtio-dev, virtualization, netdev, linux-kernel

To help for the performance optimizations and debugging, this patch tracepoints
for vhost. Two kinds of activities were traced: virtio and vhost work
queuing/wakeup.

Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 drivers/vhost/net.c   |   1 +
 drivers/vhost/trace.h | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/vhost/vhost.c |  14 +++-
 3 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 drivers/vhost/trace.h

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 85d666c..7353204 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -1,3 +1,4 @@
+
 /* Copyright (C) 2009 Red Hat, Inc.
  * Author: Michael S. Tsirkin <mst@redhat.com>
  *
diff --git a/drivers/vhost/trace.h b/drivers/vhost/trace.h
new file mode 100644
index 0000000..e380942
--- /dev/null
+++ b/drivers/vhost/trace.h
@@ -0,0 +1,175 @@
+#if !defined(_TRACE_VHOST_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_VHOST_H
+
+#include <linux/tracepoint.h>
+#include "vhost.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vhost
+
+/*
+ * Tracepoint for updating used flag.
+ */
+TRACE_EVENT(vhost_virtio_update_used_flags,
+	TP_PROTO(struct vhost_virtqueue *vq),
+	TP_ARGS(vq),
+
+	TP_STRUCT__entry(
+		__field(struct vhost_virtqueue *, vq)
+                __field(u16, queue_index)
+		__field(u16, used_flags)
+	),
+
+	TP_fast_assign(
+		__entry->vq = vq;
+                __entry->queue_index = vq->queue_index;
+		__entry->used_flags = vq->used_flags;
+	),
+
+	TP_printk("vhost update used flag %x to vq %d notify %s",
+		  __entry->used_flags, __entry->queue_index,
+		  (__entry->used_flags & VRING_USED_F_NO_NOTIFY) ?
+		  "disabled" : "enabled")
+);
+
+/*
+ * Tracepoint for updating avail event.
+ */
+TRACE_EVENT(vhost_virtio_update_avail_event,
+	TP_PROTO(struct vhost_virtqueue *vq),
+	TP_ARGS(vq),
+
+	TP_STRUCT__entry(
+		__field(struct vhost_virtqueue *, vq)
+		__field(u16, queue_index)
+		__field(u16, avail_idx)
+	),
+
+	TP_fast_assign(
+		__entry->vq = vq;
+		__entry->queue_index = vq->queue_index;
+		__entry->avail_idx = vq->avail_idx;
+	),
+
+	TP_printk("vhost update avail event %u(%u) for vq %d",
+		  __entry->avail_idx, __entry->avail_idx %
+		  __entry->vq->num, __entry->queue_index)
+);
+
+/*
+ * Tracepoint for updating used index.
+ */
+TRACE_EVENT(vhost_virtio_update_used_idx,
+	TP_PROTO(struct vhost_virtqueue *vq),
+	TP_ARGS(vq),
+
+	TP_STRUCT__entry(
+		__field(struct vhost_virtqueue *, vq)
+		__field(u16, queue_index)
+		__field(u16, used_idx)
+	),
+
+	TP_fast_assign(
+		__entry->vq = vq;
+		__entry->queue_index = vq->queue_index;
+		__entry->used_idx = vq->last_used_idx;
+	),
+
+	TP_printk("vhost update used index %u(%u) for vq %d",
+		  __entry->used_idx, __entry->used_idx %
+		  __entry->vq->num, __entry->queue_index)
+);
+
+/*
+ * Tracepoint for processing descriptor.
+ */
+TRACE_EVENT(vhost_virtio_get_vq_desc,
+	TP_PROTO(struct vhost_virtqueue *vq, unsigned int index,
+		 unsigned out, unsigned int in),
+	TP_ARGS(vq, index, out, in),
+
+	TP_STRUCT__entry(
+		__field(struct vhost_virtqueue *, vq)
+		__field(u16, queue_index)
+		__field(unsigned int, head)
+		__field(unsigned int, out)
+		__field(unsigned int, in)
+                __field(u16, last_avail_idx)
+	),
+
+	TP_fast_assign(
+		__entry->vq = vq;
+		__entry->queue_index = vq->queue_index;
+		__entry->head = index;
+		__entry->out = out;
+		__entry->in = in;
+                __entry->last_avail_idx = vq->last_avail_idx;
+	),
+
+	TP_printk("vhost get vq %d desc last avail index %u(%u), "
+                  "head %u out %u in %u",
+		  __entry->queue_index,
+		  __entry->last_avail_idx,
+                  __entry->last_avail_idx % __entry->vq->num,
+                  __entry->head, __entry->out, __entry->in)
+);
+
+/*
+ * Tracepoint for signal guest.
+ */
+TRACE_EVENT(vhost_virtio_signal,
+	TP_PROTO(struct vhost_virtqueue *vq),
+	TP_ARGS(vq),
+
+	TP_STRUCT__entry(
+		__field(u16, queue_index)
+	),
+
+	TP_fast_assign(
+		__entry->queue_index = vq->queue_index;
+	),
+
+	TP_printk("vhost signal vq %d", __entry->queue_index)
+);
+
+DECLARE_EVENT_CLASS(vhost_work_template,
+	TP_PROTO(struct vhost_work *work),
+	TP_ARGS(work),
+
+	TP_STRUCT__entry(
+		__field(void *, function)
+	),
+
+	TP_fast_assign(
+		__entry->function = work->fn;
+	),
+
+        TP_printk("%pf", __entry->function)
+);
+
+DEFINE_EVENT(vhost_work_template, vhost_work_queue_wakeup,
+	TP_PROTO(struct vhost_work *work),
+	TP_ARGS(work));
+
+DEFINE_EVENT(vhost_work_template, vhost_work_queue_coalesce,
+	TP_PROTO(struct vhost_work *work),
+	TP_ARGS(work));
+
+DEFINE_EVENT(vhost_work_template, vhost_poll_start,
+	TP_PROTO(struct vhost_work *work),
+	TP_ARGS(work));
+
+DEFINE_EVENT(vhost_work_template, vhost_poll_stop,
+	TP_PROTO(struct vhost_work *work),
+	TP_ARGS(work));
+
+#endif /* _TRACE_VHOST_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/vhost
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
+
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 78987e4..7cf3d6e 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -28,6 +28,8 @@
 #include <linux/module.h>
 
 #include "vhost.h"
+#define CREATE_TRACE_POINTS
+#include "trace.h"
 
 enum {
 	VHOST_MEMORY_MAX_NREGIONS = 64,
@@ -45,6 +47,7 @@ static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
 	poll = container_of(pt, struct vhost_poll, table);
 	poll->wqh = wqh;
 	add_wait_queue(wqh, &poll->wait);
+	trace_vhost_poll_start(&poll->work);
 }
 
 static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
@@ -114,6 +117,7 @@ void vhost_poll_stop(struct vhost_poll *poll)
 		remove_wait_queue(poll->wqh, &poll->wait);
 		poll->wqh = NULL;
 	}
+	trace_vhost_poll_stop(&poll->work);
 }
 EXPORT_SYMBOL_GPL(vhost_poll_stop);
 
@@ -163,8 +167,10 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
 		work->queue_seq++;
 		spin_unlock_irqrestore(&dev->work_lock, flags);
 		wake_up_process(dev->worker);
+		trace_vhost_work_queue_wakeup(work);
 	} else {
 		spin_unlock_irqrestore(&dev->work_lock, flags);
+		trace_vhost_work_queue_coalesce(work);
 	}
 }
 EXPORT_SYMBOL_GPL(vhost_work_queue);
@@ -1008,6 +1014,7 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq)
 		if (vq->log_ctx)
 			eventfd_signal(vq->log_ctx, 1);
 	}
+	trace_vhost_virtio_update_used_flags(vq);
 	return 0;
 }
 
@@ -1027,6 +1034,7 @@ static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event)
 		if (vq->log_ctx)
 			eventfd_signal(vq->log_ctx, 1);
 	}
+	trace_vhost_virtio_update_avail_event(vq);
 	return 0;
 }
 
@@ -1311,6 +1319,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
 		}
 	} while ((i = next_desc(&desc)) != -1);
 
+	trace_vhost_virtio_get_vq_desc(vq, head, *out_num, *in_num);
 	/* On success, increment avail index. */
 	vq->last_avail_idx++;
 
@@ -1405,6 +1414,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
 		vq_err(vq, "Failed to increment used idx");
 		return -EFAULT;
 	}
+	trace_vhost_virtio_update_used_idx(vq);
 	if (unlikely(vq->log_used)) {
 		/* Log used index update. */
 		log_write(vq->log_base,
@@ -1457,8 +1467,10 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
 	/* Signal the Guest tell them we used something up. */
-	if (vq->call_ctx && vhost_notify(dev, vq))
+	if (vq->call_ctx && vhost_notify(dev, vq)) {
 		eventfd_signal(vq->call_ctx, 1);
+		trace_vhost_virtio_signal(vq);
+	}
 }
 EXPORT_SYMBOL_GPL(vhost_signal);
 
-- 
1.8.3.2

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

* [PATCH RFC V2 3/4] vhost_net: add basic tracepoints for vhost_net
  2014-03-21  9:41 [PATCH RFC V2 0/4] Adding tracepoints to vhost/net Jason Wang
  2014-03-21  9:41 ` [PATCH RFC V2 1/4] vhost: introduce queue_index for tracing Jason Wang
  2014-03-21  9:41 ` [PATCH RFC V2 2/4] vhost: basic tracepoints Jason Wang
@ 2014-03-21  9:41 ` Jason Wang
  2014-03-21  9:41 ` [PATCH RFC V2 4/4] tools: virtio: add a top-like utility for displaying vhost satistics Jason Wang
       [not found] ` <1395394913-19548-5-git-send-email-jasowang@redhat.com>
  4 siblings, 0 replies; 7+ messages in thread
From: Jason Wang @ 2014-03-21  9:41 UTC (permalink / raw)
  To: mst, kvm, virtio-dev, virtualization, netdev, linux-kernel

To help performance analyze and debugging, this patch introduces
tracepoints for vhost_net. Two tracepoints were introduced, packets
sending and receiving.

Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 drivers/vhost/net.c       |  5 +++++
 drivers/vhost/net_trace.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)
 create mode 100644 drivers/vhost/net_trace.h

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 7353204..8ac83a9 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -30,6 +30,9 @@
 
 #include "vhost.h"
 
+#define CREATE_TRACE_POINTS
+#include "net_trace.h"
+
 static int experimental_zcopytx = 1;
 module_param(experimental_zcopytx, int, 0444);
 MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;"
@@ -444,6 +447,7 @@ static void handle_tx(struct vhost_net *net)
 		if (err != len)
 			pr_debug("Truncated TX packet: "
 				 " len %d != %zd\n", err, len);
+		trace_vhost_net_tx(zcopy_used, len);
 		if (!zcopy_used)
 			vhost_add_used_and_signal(&net->dev, vq, head, 0);
 		else
@@ -620,6 +624,7 @@ static void handle_rx(struct vhost_net *net)
 			vhost_discard_vq_desc(vq, headcount);
 			continue;
 		}
+		trace_vhost_net_rx(sock_len);
 		if (unlikely(vhost_hlen) &&
 		    memcpy_toiovecend(nvq->hdr, (unsigned char *)&hdr, 0,
 				      vhost_hlen)) {
diff --git a/drivers/vhost/net_trace.h b/drivers/vhost/net_trace.h
new file mode 100644
index 0000000..a99a799
--- /dev/null
+++ b/drivers/vhost/net_trace.h
@@ -0,0 +1,53 @@
+#if !defined(_TRACE_VHOST_NET_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_VHOST_NET_H
+
+#include <linux/tracepoint.h>
+#include "vhost.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vhost_net
+
+TRACE_EVENT(vhost_net_tx,
+	TP_PROTO(bool zerocopy, int len),
+	TP_ARGS(zerocopy, len),
+
+	TP_STRUCT__entry(
+		__field(bool, zerocopy)
+		__field(int, len)
+	),
+
+	TP_fast_assign(
+		__entry->zerocopy = zerocopy;
+		__entry->len = len;
+	),
+
+	TP_printk("vhost_net send packet mode %s length %d\n",
+		__entry->zerocopy ? "zerocopy" : "datacopy",
+		__entry->len)
+);
+
+TRACE_EVENT(vhost_net_rx,
+	TP_PROTO(int len),
+	TP_ARGS(len),
+
+	TP_STRUCT__entry(
+		__field(int, len)
+	),
+
+	TP_fast_assign(
+		__entry->len = len;
+	),
+
+	TP_printk("vhost_net receive packet length %d\n",
+		__entry->len)
+);
+
+#endif /* _TRACE_VHOST_NET_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/vhost
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE net_trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
-- 
1.8.3.2

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

* [PATCH RFC V2 4/4] tools: virtio: add a top-like utility for displaying vhost satistics
  2014-03-21  9:41 [PATCH RFC V2 0/4] Adding tracepoints to vhost/net Jason Wang
                   ` (2 preceding siblings ...)
  2014-03-21  9:41 ` [PATCH RFC V2 3/4] vhost_net: add basic tracepoints for vhost_net Jason Wang
@ 2014-03-21  9:41 ` Jason Wang
       [not found] ` <1395394913-19548-5-git-send-email-jasowang@redhat.com>
  4 siblings, 0 replies; 7+ messages in thread
From: Jason Wang @ 2014-03-21  9:41 UTC (permalink / raw)
  To: mst, kvm, virtio-dev, virtualization, netdev, linux-kernel

This patch adds simple python to display vhost satistics of vhost, the codes
were based on kvm_stat script from qemu. As work function has been recored,
filters could be used to distinguish which kinds of work are being executed or
queued:

vhost statistics

 vhost_virtio_update_used_idx               1215215       0
 vhost_virtio_get_vq_desc                   1215215       0
 vhost_work_queue_wakeup                     986808       0
 vhost_virtio_signal                         811601       0
 vhost_net_tx                                611457       0
 vhost_net_rx                                603758       0
 vhost_net_tx(datacopy)                      601903       0
 vhost_work_queue_wakeup(rx_net)             565081       0
 vhost_virtio_signal(rx)                     461603       0
 vhost_work_queue_wakeup(tx_kick)            421718       0
 vhost_virtio_update_avail_event             417346       0
 vhost_virtio_signal(tx)                     349998       0
 vhost_work_queue_coalesce                    39384       0
 vhost_work_queue_coalesce(rx_net)            38677       0
 vhost_net_tx(zerocopy)                        9554       0
 vhost_work_queue_coalesce(tx_kick)             707       0
 vhost_work_queue_wakeup(rx_kick)                 9       0

Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 tools/virtio/vhost_stat | 375 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 375 insertions(+)
 create mode 100755 tools/virtio/vhost_stat

diff --git a/tools/virtio/vhost_stat b/tools/virtio/vhost_stat
new file mode 100755
index 0000000..398fd4a
--- /dev/null
+++ b/tools/virtio/vhost_stat
@@ -0,0 +1,375 @@
+#!/usr/bin/python
+#
+# top-like utility for displaying vhost statistics
+#
+# Copyright 2012 Red Hat, Inc.
+#
+# Modified from kvm_stat from qemu
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+import curses
+import sys, os, time, optparse
+
+work_types = {
+    "handle_rx_kick" : "rx_kick",
+    "handle_tx_kick" : "tx_kick",
+    "handle_rx_net" : "rx_net",
+    "handle_tx_net" : "tx_net",
+    "vhost_attach_cgroups_work": "cg_attach"
+    }
+
+addr = {}
+
+kallsyms = file("/proc/kallsyms").readlines()
+for kallsym in kallsyms:
+    entry = kallsym.split()
+    if entry[2] in work_types.keys():
+        addr["0x%s" % entry[0]] = work_types[entry[2]]
+
+copy_modes = {
+    1 : 'zerocopy',
+    0 : 'datacopy',
+}
+
+vqs = {
+    1 : 'rx',
+    0 : 'tx',
+}
+
+filters = {
+    'vhost_work_queue_wakeup': ('function', addr),
+    'vhost_work_queue_coalesce' : ('function', addr),
+    'vhost_poll_start' : ('function', addr),
+    'vhost_poll_stop' : ('function', addr),
+    'vhost_net_tx' : ('zerocopy', copy_modes),
+    'vhost_virtio_signal' : ('queue_index', vqs),
+}
+
+def invert(d):
+    return dict((x[1], x[0]) for x in d.iteritems())
+
+for f in filters:
+    filters[f] = (filters[f][0], invert(filters[f][1]))
+
+import ctypes, struct, array
+
+libc = ctypes.CDLL('libc.so.6')
+syscall = libc.syscall
+class perf_event_attr(ctypes.Structure):
+    _fields_ = [('type', ctypes.c_uint32),
+                ('size', ctypes.c_uint32),
+                ('config', ctypes.c_uint64),
+                ('sample_freq', ctypes.c_uint64),
+                ('sample_type', ctypes.c_uint64),
+                ('read_format', ctypes.c_uint64),
+                ('flags', ctypes.c_uint64),
+                ('wakeup_events', ctypes.c_uint32),
+                ('bp_type', ctypes.c_uint32),
+                ('bp_addr', ctypes.c_uint64),
+                ('bp_len', ctypes.c_uint64),
+                ]
+def _perf_event_open(attr, pid, cpu, group_fd, flags):
+    return syscall(298, ctypes.pointer(attr), ctypes.c_int(pid),
+                   ctypes.c_int(cpu), ctypes.c_int(group_fd),
+                   ctypes.c_long(flags))
+
+PERF_TYPE_HARDWARE              = 0
+PERF_TYPE_SOFTWARE              = 1
+PERF_TYPE_TRACEPOINT            = 2
+PERF_TYPE_HW_CACHE              = 3
+PERF_TYPE_RAW                   = 4
+PERF_TYPE_BREAKPOINT            = 5
+
+PERF_SAMPLE_IP                  = 1 << 0
+PERF_SAMPLE_TID                 = 1 << 1
+PERF_SAMPLE_TIME                = 1 << 2
+PERF_SAMPLE_ADDR                = 1 << 3
+PERF_SAMPLE_READ                = 1 << 4
+PERF_SAMPLE_CALLCHAIN           = 1 << 5
+PERF_SAMPLE_ID                  = 1 << 6
+PERF_SAMPLE_CPU                 = 1 << 7
+PERF_SAMPLE_PERIOD              = 1 << 8
+PERF_SAMPLE_STREAM_ID           = 1 << 9
+PERF_SAMPLE_RAW                 = 1 << 10
+
+PERF_FORMAT_TOTAL_TIME_ENABLED  = 1 << 0
+PERF_FORMAT_TOTAL_TIME_RUNNING  = 1 << 1
+PERF_FORMAT_ID                  = 1 << 2
+PERF_FORMAT_GROUP               = 1 << 3
+
+import re
+
+sys_tracing = '/sys/kernel/debug/tracing'
+
+class Group(object):
+    def __init__(self, cpu):
+        self.events = []
+        self.group_leader = None
+        self.cpu = cpu
+    def add_event(self, name, event_set, tracepoint, filter = None):
+        self.events.append(Event(group = self,
+                                 name = name, event_set = event_set,
+                                 tracepoint = tracepoint, filter = filter))
+        if len(self.events) == 1:
+            self.file = os.fdopen(self.events[0].fd)
+    def read(self):
+        bytes = 8 * (1 + len(self.events))
+        fmt = 'xxxxxxxx' + 'q' * len(self.events)
+        return dict(zip([event.name for event in self.events],
+                        struct.unpack(fmt, self.file.read(bytes))))
+
+class Event(object):
+    def __init__(self, group, name, event_set, tracepoint, filter = None):
+        self.name = name
+        attr = perf_event_attr()
+        attr.type = PERF_TYPE_TRACEPOINT
+        attr.size = ctypes.sizeof(attr)
+        id_path = os.path.join(sys_tracing, 'events', event_set,
+                               tracepoint, 'id')
+        id = int(file(id_path).read())
+        attr.config = id
+        attr.sample_type = (PERF_SAMPLE_RAW
+                            | PERF_SAMPLE_TIME
+                            | PERF_SAMPLE_CPU)
+        attr.sample_period = 1
+        attr.read_format = PERF_FORMAT_GROUP
+        group_leader = -1
+        if group.events:
+            group_leader = group.events[0].fd
+        fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0)
+        if fd == -1:
+            raise Exception('perf_event_open failed')
+        if filter:
+            import fcntl
+            fcntl.ioctl(fd, 0x40082406, filter)
+        self.fd = fd
+    def enable(self):
+        import fcntl
+        fcntl.ioctl(self.fd, 0x00002400, 0)
+    def disable(self):
+        import fcntl
+        fcntl.ioctl(self.fd, 0x00002401, 0)
+
+class TracepointProvider(object):
+    def __init__(self, event_set):
+        path = os.path.join(sys_tracing, 'events', event_set)
+        self.event_set = event_set
+        fields = [f
+                  for f in os.listdir(path)
+                  if os.path.isdir(os.path.join(path, f))]
+        extra = []
+        for f in fields:
+            if f in filters:
+                subfield, values = filters[f]
+                for name, number in values.iteritems():
+                    # kvm_exit(MMIO)
+                    extra.append(f + '(' + name + ')')
+        fields += extra
+        self._setup(fields)
+        self.select(fields)
+    def fields(self):
+        return self._fields
+    def _setup(self, _fields):
+        self._fields = _fields
+        cpure = r'cpu([0-9]+)'
+        self.cpus = [int(re.match(cpure, x).group(1))
+                     for x in os.listdir('/sys/devices/system/cpu')
+                     if re.match(cpure, x)]
+        import resource
+        nfiles = len(self.cpus) * 1000
+        resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles))
+        events = []
+        self.group_leaders = []
+        for cpu in self.cpus:
+            group = Group(cpu)
+            for name in _fields:
+                tracepoint = name
+                filter = None
+                # for field like kvm_exit(MMIO)
+                m = re.match(r'(.*)\((.*)\)', name)
+                if m:
+                    tracepoint, sub = m.groups()
+                    filter = '%s==%s\0' % (filters[tracepoint][0],
+                                           filters[tracepoint][1][sub])
+                event = group.add_event(name, event_set = self.event_set,
+                                        tracepoint = tracepoint,
+                                        filter = filter)
+            self.group_leaders.append(group)
+    def select(self, fields):
+        for group in self.group_leaders:
+            for event in group.events:
+                if event.name in fields:
+                    event.enable()
+                else:
+                    event.disable()
+    def read(self):
+        from collections import defaultdict
+        ret = defaultdict(int)
+        for group in self.group_leaders:
+            for name, val in group.read().iteritems():
+                ret[name] += val
+        return ret
+
+class Stats:
+    def __init__(self, providers, fields = None):
+        self.providers = providers
+        self.fields_filter = fields
+        self._update()
+    def _update(self):
+        def wanted(key):
+            import re
+            if not self.fields_filter:
+                return True
+            return re.match(self.fields_filter, key) is not None
+        self.values = {}
+        for provider in self.providers:
+            for key in provider.fields():
+                if wanted(key):
+                    self.values[key] = None
+            provider.select(self.values.keys())
+    def set_fields_filter(self, fields_filter):
+        self.fields_filter = fields_filter
+        self._update()
+    def get(self):
+        for provider in self.providers:
+            new = provider.read()
+            for key in provider.fields():
+                oldval = self.values.get(key, (0, 0))
+                newval = new[key]
+                newdelta = None
+                if oldval is not None:
+                    newdelta = newval - oldval[0]
+                self.values[key] = (newval, newdelta)
+        return self.values
+
+if not os.access('/sys/kernel/debug', os.F_OK):
+    print 'Please enable CONFIG_DEBUG_FS in your kernel'
+    sys.exit(1)
+if not os.access('/sys/module/vhost_net', os.F_OK):
+    print 'Please make sure vhost_net module are loaded'
+    sys.exit(1)
+
+label_width = 40
+number_width = 10
+
+def tui(screen, stats):
+    curses.use_default_colors()
+    curses.noecho()
+    drilldown = False
+    fields_filter = stats.fields_filter
+    def update_drilldown():
+        if not fields_filter:
+            if drilldown:
+                stats.set_fields_filter(None)
+            else:
+                stats.set_fields_filter(r'^[^\(]*$')
+    update_drilldown()
+    def refresh(sleeptime):
+        screen.erase()
+        screen.addstr(0, 0, 'vhost statistics')
+        row = 2
+        s = stats.get()
+        def sortkey(x):
+            if s[x][1]:
+                return (-s[x][1], -s[x][0])
+            else:
+                return (0, -s[x][0])
+        for key in sorted(s.keys(), key = sortkey):
+            if row >= screen.getmaxyx()[0]:
+                break
+            values = s[key]
+            if not values[0] and not values[1]:
+                break
+            col = 1
+            screen.addstr(row, col, key)
+            col += label_width
+            screen.addstr(row, col, '%10d' % (values[0],))
+            col += number_width
+            if values[1] is not None:
+                screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
+            row += 1
+        screen.refresh()
+
+    sleeptime = 0.25
+    while True:
+        refresh(sleeptime)
+        curses.halfdelay(int(sleeptime * 10))
+        sleeptime = 3
+        try:
+            c = screen.getkey()
+            if c == 'x':
+                drilldown = not drilldown
+                update_drilldown()
+            if c == 'q':
+                break
+        except KeyboardInterrupt:
+            break
+        except curses.error:
+            continue
+
+def batch(stats):
+    s = stats.get()
+    time.sleep(1)
+    s = stats.get()
+    for key in sorted(s.keys()):
+        values = s[key]
+        print '%-22s%10d%10d' % (key, values[0], values[1])
+
+def log(stats):
+    keys = sorted(stats.get().iterkeys())
+    def banner():
+        for k in keys:
+            print '%10s' % k[0:9],
+        print
+    def statline():
+        s = stats.get()
+        for k in keys:
+            print ' %9d' % s[k][1],
+        print
+    line = 0
+    banner_repeat = 20
+    while True:
+        time.sleep(1)
+        if line % banner_repeat == 0:
+            banner()
+        statline()
+        line += 1
+
+options = optparse.OptionParser()
+options.add_option('-1', '--once', '--batch',
+                   action = 'store_true',
+                   default = False,
+                   dest = 'once',
+                   help = 'run in batch mode for one second',
+                   )
+options.add_option('-l', '--log',
+                   action = 'store_true',
+                   default = False,
+                   dest = 'log',
+                   help = 'run in logging mode (like vmstat)',
+                   )
+options.add_option('-f', '--fields',
+                   action = 'store',
+                   default = None,
+                   dest = 'fields',
+                   help = 'fields to display (regex)',
+                   )
+(options, args) = options.parse_args(sys.argv)
+
+try:
+    provider = [TracepointProvider('vhost'), TracepointProvider('vhost_net')]
+except:
+    print "Could not initialize tracepoint"
+    sys.exit(1)
+
+stats = Stats(provider, fields = options.fields)
+
+if options.log:
+    log(stats)
+elif not options.once:
+    import curses.wrapper
+    curses.wrapper(tui, stats)
+else:
+    batch(stats)
-- 
1.8.3.2

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

* Re: [PATCH RFC V2 4/4] tools: virtio: add a top-like utility for displaying vhost satistics
       [not found] ` <1395394913-19548-5-git-send-email-jasowang@redhat.com>
@ 2014-04-10  9:27   ` Fam Zheng
       [not found]   ` <20140410092702.GJ22890@T430.nay.redhat.com>
  1 sibling, 0 replies; 7+ messages in thread
From: Fam Zheng @ 2014-04-10  9:27 UTC (permalink / raw)
  To: Jason Wang; +Cc: virtio-dev, kvm, mst, netdev, linux-kernel, virtualization

On Fri, 03/21 17:41, Jason Wang wrote:
> This patch adds simple python to display vhost satistics of vhost, the codes
> were based on kvm_stat script from qemu. As work function has been recored,
> filters could be used to distinguish which kinds of work are being executed or
> queued:
> 
> vhost statistics
> 
>  vhost_virtio_update_used_idx               1215215       0
>  vhost_virtio_get_vq_desc                   1215215       0
>  vhost_work_queue_wakeup                     986808       0
>  vhost_virtio_signal                         811601       0
>  vhost_net_tx                                611457       0
>  vhost_net_rx                                603758       0
>  vhost_net_tx(datacopy)                      601903       0
>  vhost_work_queue_wakeup(rx_net)             565081       0
>  vhost_virtio_signal(rx)                     461603       0
>  vhost_work_queue_wakeup(tx_kick)            421718       0
>  vhost_virtio_update_avail_event             417346       0
>  vhost_virtio_signal(tx)                     349998       0
>  vhost_work_queue_coalesce                    39384       0
>  vhost_work_queue_coalesce(rx_net)            38677       0
>  vhost_net_tx(zerocopy)                        9554       0
>  vhost_work_queue_coalesce(tx_kick)             707       0
>  vhost_work_queue_wakeup(rx_kick)                 9       0
> 
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
>  tools/virtio/vhost_stat | 375 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 375 insertions(+)
>  create mode 100755 tools/virtio/vhost_stat
> 
> diff --git a/tools/virtio/vhost_stat b/tools/virtio/vhost_stat
> new file mode 100755
> index 0000000..398fd4a
> --- /dev/null
> +++ b/tools/virtio/vhost_stat
> @@ -0,0 +1,375 @@
> +#!/usr/bin/python
> +#
> +# top-like utility for displaying vhost statistics
> +#
> +# Copyright 2012 Red Hat, Inc.

Should it be 2014?

Fam

<snip>

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

* Re: [PATCH RFC V2 4/4] tools: virtio: add a top-like utility for displaying vhost satistics
       [not found]   ` <20140410092702.GJ22890@T430.nay.redhat.com>
@ 2014-04-11  3:04     ` Jason Wang
  0 siblings, 0 replies; 7+ messages in thread
From: Jason Wang @ 2014-04-11  3:04 UTC (permalink / raw)
  To: Fam Zheng; +Cc: virtio-dev, kvm, mst, netdev, linux-kernel, virtualization

On Thu, 2014-04-10 at 17:27 +0800, Fam Zheng wrote:
> On Fri, 03/21 17:41, Jason Wang wrote:
> > This patch adds simple python to display vhost satistics of vhost, the codes
> > were based on kvm_stat script from qemu. As work function has been recored,
> > filters could be used to distinguish which kinds of work are being executed or
> > queued:
> > 
> > vhost statistics
> > 
> >  vhost_virtio_update_used_idx               1215215       0
> >  vhost_virtio_get_vq_desc                   1215215       0
> >  vhost_work_queue_wakeup                     986808       0
> >  vhost_virtio_signal                         811601       0
> >  vhost_net_tx                                611457       0
> >  vhost_net_rx                                603758       0
> >  vhost_net_tx(datacopy)                      601903       0
> >  vhost_work_queue_wakeup(rx_net)             565081       0
> >  vhost_virtio_signal(rx)                     461603       0
> >  vhost_work_queue_wakeup(tx_kick)            421718       0
> >  vhost_virtio_update_avail_event             417346       0
> >  vhost_virtio_signal(tx)                     349998       0
> >  vhost_work_queue_coalesce                    39384       0
> >  vhost_work_queue_coalesce(rx_net)            38677       0
> >  vhost_net_tx(zerocopy)                        9554       0
> >  vhost_work_queue_coalesce(tx_kick)             707       0
> >  vhost_work_queue_wakeup(rx_kick)                 9       0
> > 
> > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > ---
> >  tools/virtio/vhost_stat | 375 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 375 insertions(+)
> >  create mode 100755 tools/virtio/vhost_stat
> > 
> > diff --git a/tools/virtio/vhost_stat b/tools/virtio/vhost_stat
> > new file mode 100755
> > index 0000000..398fd4a
> > --- /dev/null
> > +++ b/tools/virtio/vhost_stat
> > @@ -0,0 +1,375 @@
> > +#!/usr/bin/python
> > +#
> > +# top-like utility for displaying vhost statistics
> > +#
> > +# Copyright 2012 Red Hat, Inc.
> 
> Should it be 2014?
> 
> Fam
> 
> <snip>

Yes it should, thanks for pointing this out.

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

end of thread, other threads:[~2014-04-11  3:04 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-21  9:41 [PATCH RFC V2 0/4] Adding tracepoints to vhost/net Jason Wang
2014-03-21  9:41 ` [PATCH RFC V2 1/4] vhost: introduce queue_index for tracing Jason Wang
2014-03-21  9:41 ` [PATCH RFC V2 2/4] vhost: basic tracepoints Jason Wang
2014-03-21  9:41 ` [PATCH RFC V2 3/4] vhost_net: add basic tracepoints for vhost_net Jason Wang
2014-03-21  9:41 ` [PATCH RFC V2 4/4] tools: virtio: add a top-like utility for displaying vhost satistics Jason Wang
     [not found] ` <1395394913-19548-5-git-send-email-jasowang@redhat.com>
2014-04-10  9:27   ` Fam Zheng
     [not found]   ` <20140410092702.GJ22890@T430.nay.redhat.com>
2014-04-11  3:04     ` Jason Wang

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).