Adam Litke
2009-Nov-30  16:14 UTC
virtio: Add memory statistics reporting to the balloon driver (V4)
Changes since V3:
 - Do not do endian conversions as they will be done in the host
 - Report stats that reference a quantity of memory in bytes
 - Minor coding style updates
Changes since V2:
 - Increase stat field size to 64 bits
 - Report all sizes in kb (not pages)
 - Drop anon_pages stat and fix endianness conversion
Changes since V1:
 - Use a virtqueue instead of the device config space
When using ballooning to manage overcommitted memory on a host, a system for
guests to communicate their memory usage to the host can provide information
that will minimize the impact of ballooning on the guests.  The current method
employs a daemon running in each guest that communicates memory statistics to a
host daemon at a specified time interval.  The host daemon aggregates this
information and inflates and/or deflates balloons according to the level of
host memory pressure.  This approach is effective but overly complex since a
daemon must be installed inside each guest and coordinated to communicate with
the host.  A simpler approach is to collect memory statistics in the virtio
balloon driver and communicate them directly to the hypervisor.
This patch enables the guest-side support by adding stats collection and
reporting to the virtio balloon driver.
Signed-off-by: Adam Litke <agl at us.ibm.com>
Cc: Rusty Russell <rusty at rustcorp.com.au>
Cc: Anthony Liguori <anthony at codemonkey.ws>
Cc: virtualization at lists.linux-foundation.org
Cc: linux-kernel at vger.kernel.org
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 200c22f..f4c8cd8 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -29,7 +29,7 @@
 struct virtio_balloon
 {
 	struct virtio_device *vdev;
-	struct virtqueue *inflate_vq, *deflate_vq;
+	struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
 
 	/* Where the ballooning thread waits for config to change. */
 	wait_queue_head_t config_change;
@@ -50,6 +50,9 @@ struct virtio_balloon
 	/* The array of pfns we tell the Host about. */
 	unsigned int num_pfns;
 	u32 pfns[256];
+
+	/* Memory statistics */
+	struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
 };
 
 static struct virtio_device_id id_table[] = {
@@ -155,6 +158,61 @@ static void leak_balloon(struct virtio_balloon *vb, size_t
num)
 	}
 }
 
+static inline void update_stat(struct virtio_balloon *vb, int idx,
+				__le16 tag, __le64 val)
+{
+	BUG_ON(idx >= VIRTIO_BALLOON_S_NR);
+	vb->stats[idx].tag = tag;
+	vb->stats[idx].val = val;
+}
+
+#define pages_to_bytes(x) ((x) << PAGE_SHIFT)
+static void update_balloon_stats(struct virtio_balloon *vb)
+{
+	unsigned long events[NR_VM_EVENT_ITEMS];
+	struct sysinfo i;
+	int idx = 0;
+
+	all_vm_events(events);
+	si_meminfo(&i);
+
+	update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_IN,
+				pages_to_bytes(events[PSWPIN]));
+	update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_OUT,
+				pages_to_bytes(events[PSWPOUT]));
+	update_stat(vb, idx++, VIRTIO_BALLOON_S_MAJFLT, events[PGMAJFAULT]);
+	update_stat(vb, idx++, VIRTIO_BALLOON_S_MINFLT, events[PGFAULT]);
+	update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMFREE,
+				pages_to_bytes(i.freeram));
+	update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMTOT,
+				pages_to_bytes(i.totalram));
+}
+
+/*
+ * While most virtqueues communicate guest-initiated requests to the
hypervisor,
+ * the stats queue operates in reverse.  The driver initializes the virtqueue
+ * with a single buffer.  From that point forward, all conversations consist of
+ * a hypervisor request (a call to this function) which directs us to refill
+ * the virtqueue with a fresh stats buffer.
+ */
+static void stats_ack(struct virtqueue *vq)
+{
+	struct virtio_balloon *vb;
+	unsigned int len;
+	struct scatterlist sg;
+
+	vb = vq->vq_ops->get_buf(vq, &len);
+	if (!vb)
+		return;
+
+	update_balloon_stats(vb);
+
+	sg_init_one(&sg, vb->stats, sizeof(vb->stats));
+	if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
+		BUG();
+	vq->vq_ops->kick(vq);
+}
+
 static void virtballoon_changed(struct virtio_device *vdev)
 {
 	struct virtio_balloon *vb = vdev->priv;
@@ -205,10 +263,10 @@ static int balloon(void *_vballoon)
 static int virtballoon_probe(struct virtio_device *vdev)
 {
 	struct virtio_balloon *vb;
-	struct virtqueue *vqs[2];
-	vq_callback_t *callbacks[] = { balloon_ack, balloon_ack };
-	const char *names[] = { "inflate", "deflate" };
-	int err;
+	struct virtqueue *vqs[3];
+	vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_ack };
+	const char *names[] = { "inflate", "deflate",
"stats" };
+	int err, nvqs;
 
 	vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
 	if (!vb) {
@@ -221,13 +279,28 @@ static int virtballoon_probe(struct virtio_device *vdev)
 	init_waitqueue_head(&vb->config_change);
 	vb->vdev = vdev;
 
-	/* We expect two virtqueues. */
-	err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+	/* We expect two virtqueues: inflate and deflate,
+	 * and optionally stat. */
+	nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
+	err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
 	if (err)
 		goto out_free_vb;
 
 	vb->inflate_vq = vqs[0];
 	vb->deflate_vq = vqs[1];
+	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
+		struct scatterlist sg;
+		vb->stats_vq = vqs[2];
+
+		/*
+		 * Prime this virtqueue with one buffer so the hypervisor can
+		 * use it to signal us later.
+		 */
+		sg_init_one(&sg, vb->stats, sizeof vb->stats);
+		if (vb->stats_vq->vq_ops->add_buf(vb->stats_vq, &sg, 1, 0,
vb) < 0)
+			BUG();
+		vb->stats_vq->vq_ops->kick(vb->stats_vq);
+	}
 
 	vb->thread = kthread_run(balloon, vb, "vballoon");
 	if (IS_ERR(vb->thread)) {
@@ -265,7 +338,10 @@ static void virtballoon_remove(struct virtio_device *vdev)
 	kfree(vb);
 }
 
-static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
+static unsigned int features[] = {
+	VIRTIO_BALLOON_F_MUST_TELL_HOST,
+	VIRTIO_BALLOON_F_STATS_VQ,
+};
 
 static struct virtio_driver virtio_balloon = {
 	.feature_table = features,
diff --git a/include/linux/virtio_balloon.h b/include/linux/virtio_balloon.h
index 09d7300..92d3550 100644
--- a/include/linux/virtio_balloon.h
+++ b/include/linux/virtio_balloon.h
@@ -6,6 +6,7 @@
 
 /* The feature bitmap for virtio balloon */
 #define VIRTIO_BALLOON_F_MUST_TELL_HOST	0 /* Tell before reclaiming pages */
+#define VIRTIO_BALLOON_F_STATS_VQ	1 /* Memory Stats virtqueue */
 
 /* Size of a PFN in the balloon interface. */
 #define VIRTIO_BALLOON_PFN_SHIFT 12
@@ -17,4 +18,19 @@ struct virtio_balloon_config
 	/* Number of pages we've actually got in balloon. */
 	__le32 actual;
 };
+
+#define VIRTIO_BALLOON_S_SWAP_IN  0   /* Amount of memory swapped in */
+#define VIRTIO_BALLOON_S_SWAP_OUT 1   /* Amount of memory swapped out */
+#define VIRTIO_BALLOON_S_MAJFLT   2   /* Number of major faults */
+#define VIRTIO_BALLOON_S_MINFLT   3   /* Number of minor faults */
+#define VIRTIO_BALLOON_S_MEMFREE  4   /* Total amount of free memory */
+#define VIRTIO_BALLOON_S_MEMTOT   5   /* Total amount of memory */
+#define VIRTIO_BALLOON_S_NR       6
+
+struct virtio_balloon_stat
+{
+	u16 tag;
+	u64 val;
+} __attribute__((packed));
+
 #endif /* _LINUX_VIRTIO_BALLOON_H */
-- 
Thanks,
Adam
Rusty Russell
2009-Dec-01  02:24 UTC
virtio: Add memory statistics reporting to the balloon driver (V4)
On Tue, 1 Dec 2009 02:44:15 am Adam Litke wrote:> Changes since V3:OK, I applied this. And here's the fixes I applied afterwards (to save YA round trip: please ack and I'll fold them together) virtio: balloon fixes 1) Tag and val args to update_stat() are no longer __le. 2) pages_to_bytes() should promote to u64 so we don't truncate. 3) Fix two checkpatch.pl warnings. Signed-off-by: Rusty Russell <rusty at rustcorp.com.au> --- drivers/virtio/virtio_balloon.c | 8 +++++--- include/linux/virtio_balloon.h | 3 +-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -158,14 +158,15 @@ static void leak_balloon(struct virtio_b } static inline void update_stat(struct virtio_balloon *vb, int idx, - __le16 tag, __le64 val) + u16 tag, u64 val) { BUG_ON(idx >= VIRTIO_BALLOON_S_NR); vb->stats[idx].tag = tag; vb->stats[idx].val = val; } -#define pages_to_bytes(x) ((x) << PAGE_SHIFT) +#define pages_to_bytes(x) ((u64)(x) << PAGE_SHIFT) + static void update_balloon_stats(struct virtio_balloon *vb) { unsigned long events[NR_VM_EVENT_ITEMS]; @@ -296,7 +297,8 @@ static int virtballoon_probe(struct virt * use it to signal us later. */ sg_init_one(&sg, vb->stats, sizeof vb->stats); - if (vb->stats_vq->vq_ops->add_buf(vb->stats_vq, &sg, 1, 0, vb) < 0) + if (vb->stats_vq->vq_ops->add_buf(vb->stats_vq, + &sg, 1, 0, vb) < 0) BUG(); vb->stats_vq->vq_ops->kick(vb->stats_vq); } diff --git a/include/linux/virtio_balloon.h b/include/linux/virtio_balloon.h --- a/include/linux/virtio_balloon.h +++ b/include/linux/virtio_balloon.h @@ -28,8 +28,7 @@ struct virtio_balloon_config #define VIRTIO_BALLOON_S_MEMTOT 5 /* Total amount of memory */ #define VIRTIO_BALLOON_S_NR 6 -struct virtio_balloon_stat -{ +struct virtio_balloon_stat { u16 tag; u64 val; } __attribute__((packed));
Avi Kivity
2009-Dec-01  14:56 UTC
virtio: Add memory statistics reporting to the balloon driver (V4)
On 11/30/2009 06:14 PM, Adam Litke wrote:> Changes since V3: > - Do not do endian conversions as they will be done in the host > - Report stats that reference a quantity of memory in bytes > - Minor coding style updates > > Changes since V2: > - Increase stat field size to 64 bits > - Report all sizes in kb (not pages) > - Drop anon_pages stat and fix endianness conversion > > Changes since V1: > - Use a virtqueue instead of the device config space > > When using ballooning to manage overcommitted memory on a host, a system for > guests to communicate their memory usage to the host can provide information > that will minimize the impact of ballooning on the guests. The current method > employs a daemon running in each guest that communicates memory statistics to a > host daemon at a specified time interval. The host daemon aggregates this > information and inflates and/or deflates balloons according to the level of > host memory pressure. This approach is effective but overly complex since a > daemon must be installed inside each guest and coordinated to communicate with > the host. A simpler approach is to collect memory statistics in the virtio > balloon driver and communicate them directly to the hypervisor. > > This patch enables the guest-side support by adding stats collection and > reporting to the virtio balloon driver. > >What about a spec update? Did that happen and I just missed it? -- error compiling committee.c: too many arguments to function
Adam Litke
2009-Dec-01  15:05 UTC
virtio: Add memory statistics reporting to the balloon driver (V4)
On Tue, 2009-12-01 at 16:56 +0200, Avi Kivity wrote:> What about a spec update? Did that happen and I just missed it?Yes it did. I forgot to update this patch leader note with the link: http://ozlabs.org/~rusty/virtio-spec/virtio-spec-0.8.2.pdf -- Thanks, Adam
Avi Kivity
2009-Dec-01  15:53 UTC
virtio: Add memory statistics reporting to the balloon driver (V4)
On 12/01/2009 05:05 PM, Adam Litke wrote:> On Tue, 2009-12-01 at 16:56 +0200, Avi Kivity wrote: > >> What about a spec update? Did that happen and I just missed it? >> > Yes it did. I forgot to update this patch leader note with the link: > http://ozlabs.org/~rusty/virtio-spec/virtio-spec-0.8.2.pdf >Great, thanks. -- error compiling committee.c: too many arguments to function
Apparently Analagous Threads
- virtio: Add memory statistics reporting to the balloon driver (V4)
- virtio: Add memory statistics reporting to the balloon driver (V3)
- virtio: Add memory statistics reporting to the balloon driver (V3)
- virtio: Add memory statistics reporting to the balloon driver (V2)
- virtio: Add memory statistics reporting to the balloon driver (V2)