lguest: Debugging patch for lguest network performance
---
 Documentation/lguest/lguest.c |   72 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 65 insertions(+), 7 deletions(-)

diff -r 21d535aa168d Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c	Thu Aug 28 11:52:27 2008 +1000
+++ b/Documentation/lguest/lguest.c	Thu Aug 28 17:07:50 2008 +1000
@@ -173,6 +173,8 @@ struct virtqueue
 	/* Is this blocked awaiting a timer? */
 	bool blocked;
 };
+
+static unsigned int net_xmit_notify, net_recv_notify, net_recv_notify, net_timeout;
 
 /* Remember the arguments to the program so we can "reboot" */
 static char **main_args;
@@ -810,6 +812,8 @@ struct console_abort
 	struct timeval start;
 };
 
+static int last_timeout_num;
+
 /* This is the routine which handles console input (ie. stdin). */
 static bool handle_console_input(int fd, struct device *dev)
 {
@@ -866,6 +870,9 @@ static bool handle_console_input(int fd,
 				/* Just in case Waker is blocked in BREAK, send
 				 * unbreak now. */
 				write(fd, args, sizeof(args));
+				printf("network xmit %u recv %u timeout %u usec %u last_timeout_num %u\n",
+				       net_xmit_notify, net_recv_notify,
+				       net_timeout, timeout_usec, last_timeout_num);
 				exit(2);
 			}
 			abort->count = 0;
@@ -885,6 +892,8 @@ static void handle_console_output(int fd
 	unsigned int head, out, in;
 	int len;
 	struct iovec iov[vq->vring.num];
+
+	net_xmit_notify++;
 
 	/* Keep getting output buffers from the Guest until we run out. */
 	while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
@@ -913,6 +922,15 @@ static void block_vq(struct virtqueue *v
 	setitimer(ITIMER_REAL, &itm, NULL);
 }
 
+static struct {
+	bool timeout;
+	u16 num_iovecs;
+	u16 timeout_usec;
+	u16 total_iovec_length;
+	u16 last_num_iovecs;
+} stats[1000];
+static int stats_idx;
+
 /*
  * The Network
  *
@@ -925,7 +943,6 @@ static void handle_net_output(int fd, st
 	unsigned int head, out, in, num = 0;
 	int len;
 	struct iovec iov[vq->vring.num];
-	static int last_timeout_num;
 
 	/* Keep getting output buffers from the Guest until we run out. */
 	while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
@@ -935,12 +952,51 @@ static void handle_net_output(int fd, st
 		if (len < 0)
 			err(1, "Writing network packet to tun");
 		add_used_and_trigger(fd, vq, head, len);
-		num++;
+		num += out;
+		stats[stats_idx].num_iovecs++;
+		stats[stats_idx].total_iovec_length += out;
 	}
 
 	/* Block further kicks and set up a timer if we saw anything. */
-	if (!timeout && num)
-		block_vq(vq);
+	if (!timeout && num) {
+		stats[stats_idx].timeout_usec = timeout_usec;
+		if (vq->vring.used->flags & VRING_USED_F_NO_NOTIFY) {
+			/* We're already blocked.  This implies the timeout is
+			 * too long, and we got pinged when the ring filled. */
+			timeout_usec -= timeout_usec / 8;
+		} else
+			block_vq(vq);
+	}
+
+	stats[stats_idx].timeout = timeout;
+	stats[stats_idx].last_num_iovecs = last_timeout_num;
+	stats_idx++;
+	if (stats_idx == 1000)
+		stats_idx = 0;
+
+	if (stats_idx == 1000) {
+		unsigned long args[] = { LHREQ_BREAK, 0 };
+		unsigned int i;
+		for (i = 0; i < 1000; i++) {
+			char str[30];
+			if (stats[i].timeout)
+				sprintf(str, "T:%u/%u vs %u",
+					stats[i].total_iovec_length,
+					stats[i].num_iovecs,
+					stats[i].last_num_iovecs);
+			else
+				sprintf(str, "%u/%u usec %u",
+					stats[i].total_iovec_length,
+					stats[i].num_iovecs,
+					stats[i].timeout_usec);
+			printf("%-19s", str);
+			if (i % 4 == 3)
+				printf("\n");
+		}
+		close(waker_fds.pipe[1]);
+		write(fd, args, sizeof(args));
+		exit(3);
+	}
 
 	/* We never quite know how long should we wait before we check the
 	 * queue again for more packets.  We start at 500 microseconds, and if
@@ -948,9 +1004,10 @@ static void handle_net_output(int fd, st
 	 * too small and increase it by 10 microseconds.  Otherwise, we drop it
 	 * by one microsecond every time.  It seems to work well enough. */
 	if (timeout) {
-		if (num) {
-			if (num < last_timeout_num)
-				timeout_usec += 10;
+		net_timeout++;
+		if (1) {
+			if (num <= last_timeout_num)
+				timeout_usec++;
 			else if (timeout_usec > 1)
 				timeout_usec--;
 		}
@@ -1011,6 +1068,7 @@ static void enable_fd(int fd, struct vir
 
 static void net_enable_fd(int fd, struct virtqueue *vq, bool timeout)
 {
+	net_recv_notify++;
 	/* We don't need to know again when Guest refills receive buffer. */
 	vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
 	enable_fd(fd, vq, timeout);
