lguest: Adaptive timeout

Since the correct timeout value varies, use a heuristic which adjusts
the timeout depending on how many packets we've seen.  This gives
slightly worse results, but doesn't need tweaking when GSO is
introduced.

500 usec	19.1887		xmit 561141 recv 1 timeout 559657
Dynamic (278)	20.1974		xmit 214510 recv 5 timeout 214491 usec 278

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 Documentation/lguest/lguest.c |   16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff -r 2247883cb9d3 Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c	Mon Jul 14 14:38:23 2008 +1000
+++ b/Documentation/lguest/lguest.c	Mon Jul 14 16:22:25 2008 +1000
@@ -84,6 +84,7 @@ static unsigned long guest_limit, guest_
 static unsigned long guest_limit, guest_max;
 /* The pipe for signal hander to write to. */
 static int timeoutpipe[2];
+static unsigned int timeout_usec = 500;
 
 /* a per-cpu variable indicating whose vcpu is currently running */
 static unsigned int __thread cpu_id;
@@ -862,9 +863,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\n",
+				printf("network xmit %u recv %u timeout %u usec %u\n",
 				       net_xmit_notify, net_recv_notify,
-				       net_timeout);
+				       net_timeout, timeout_usec);
 				exit(2);
 			}
 			abort->count = 0;
@@ -904,7 +905,7 @@ static void block_vq(struct virtqueue *v
 	itm.it_interval.tv_sec = 0;
 	itm.it_interval.tv_usec = 0;
 	itm.it_value.tv_sec = 0;
-	itm.it_value.tv_usec = 750;
+	itm.it_value.tv_usec = timeout_usec;
 
 	setitimer(ITIMER_REAL, &itm, NULL);
 }
@@ -921,6 +922,7 @@ 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;
 
 	if (!timeout)
 		net_xmit_notify++;
@@ -941,6 +943,14 @@ static void handle_net_output(int fd, st
 	/* Block further kicks and set up a timer if we saw anything. */
 	if (!timeout && num)
 		block_vq(vq);
+
+	if (timeout) {
+		if (num < last_timeout_num)
+			timeout_usec += 10;
+		else if (timeout_usec > 1)
+			timeout_usec--;
+		last_timeout_num = num;
+	}
 }
 
 /* This is where we handle a packet coming in from the tun device to our
