aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation/lguest/lguest.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2009-06-13 00:27:11 -0400
committerRusty Russell <rusty@rustcorp.com.au>2009-06-12 08:57:11 -0400
commit38bc2b8c56a2e212bbd19de7cf9976dcc7bf9953 (patch)
tree26071dbb540926c329ece0ab4d4425807021b5c8 /Documentation/lguest/lguest.c
parent5dac051bc6030963181b69faddd9e0ad04f85fa8 (diff)
lguest: implement deferred interrupts in example Launcher
Rather than sending an interrupt on every buffer, we only send an interrupt when we're about to wait for the Guest to send us a new one. The console input and network input still send interrupts manually, but the block device, network and console output queues can simply rely on this logic to send interrupts to the Guest at the right time. The patch is cluttered by moving trigger_irq() higher in the code. In practice, two factors make this optimization less interesting: (1) we often only get one input at a time, even for networking, (2) triggering an interrupt rapidly tends to get coalesced anyway. Before: Secs RxIRQS TxIRQs 1G TCP Guest->Host: 3.72 32784 32771 1M normal pings: 99 1000004 995541 100,000 1k pings (-l 120): 5 49510 49058 After: 1G TCP Guest->Host: 3.69 32809 32769 1M normal pings: 99 1000004 996196 100,000 1k pings (-l 120): 5 52435 52361 (Note the interrupt count on 100k pings goes *up*: see next patch). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'Documentation/lguest/lguest.c')
-rw-r--r--Documentation/lguest/lguest.c41
1 files changed, 22 insertions, 19 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index 5470b8ed2149..84c471b07c27 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -551,6 +551,21 @@ static unsigned next_desc(struct virtqueue *vq, unsigned int i)
551 return next; 551 return next;
552} 552}
553 553
554/* This actually sends the interrupt for this virtqueue */
555static void trigger_irq(struct virtqueue *vq)
556{
557 unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
558
559 /* If they don't want an interrupt, don't send one, unless empty. */
560 if ((vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
561 && lg_last_avail(vq) != vq->vring.avail->idx)
562 return;
563
564 /* Send the Guest an interrupt tell them we used something up. */
565 if (write(lguest_fd, buf, sizeof(buf)) != 0)
566 err(1, "Triggering irq %i", vq->config.irq);
567}
568
554/* This looks in the virtqueue and for the first available buffer, and converts 569/* This looks in the virtqueue and for the first available buffer, and converts
555 * it to an iovec for convenient access. Since descriptors consist of some 570 * it to an iovec for convenient access. Since descriptors consist of some
556 * number of output then some number of input descriptors, it's actually two 571 * number of output then some number of input descriptors, it's actually two
@@ -567,6 +582,9 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
567 while (last_avail == vq->vring.avail->idx) { 582 while (last_avail == vq->vring.avail->idx) {
568 u64 event; 583 u64 event;
569 584
585 /* OK, tell Guest about progress up to now. */
586 trigger_irq(vq);
587
570 /* Nothing new? Wait for eventfd to tell us they refilled. */ 588 /* Nothing new? Wait for eventfd to tell us they refilled. */
571 if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event)) 589 if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event))
572 errx(1, "Event read failed?"); 590 errx(1, "Event read failed?");
@@ -631,21 +649,6 @@ static void add_used(struct virtqueue *vq, unsigned int head, int len)
631 vq->vring.used->idx++; 649 vq->vring.used->idx++;
632} 650}
633 651
634/* This actually sends the interrupt for this virtqueue */
635static void trigger_irq(struct virtqueue *vq)
636{
637 unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
638
639 /* If they don't want an interrupt, don't send one, unless empty. */
640 if ((vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
641 && lg_last_avail(vq) != vq->vring.avail->idx)
642 return;
643
644 /* Send the Guest an interrupt tell them we used something up. */
645 if (write(lguest_fd, buf, sizeof(buf)) != 0)
646 err(1, "Triggering irq %i", vq->config.irq);
647}
648
649/* And here's the combo meal deal. Supersize me! */ 652/* And here's the combo meal deal. Supersize me! */
650static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len) 653static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len)
651{ 654{
@@ -730,7 +733,7 @@ static void console_output(struct virtqueue *vq)
730 err(1, "Write to stdout gave %i", len); 733 err(1, "Write to stdout gave %i", len);
731 iov_consume(iov, out, len); 734 iov_consume(iov, out, len);
732 } 735 }
733 add_used_and_trigger(vq, head, 0); 736 add_used(vq, head, 0);
734} 737}
735 738
736/* 739/*
@@ -754,7 +757,7 @@ static void net_output(struct virtqueue *vq)
754 errx(1, "Input buffers in net output queue?"); 757 errx(1, "Input buffers in net output queue?");
755 if (writev(net_info->tunfd, iov, out) < 0) 758 if (writev(net_info->tunfd, iov, out) < 0)
756 errx(1, "Write to tun failed?"); 759 errx(1, "Write to tun failed?");
757 add_used_and_trigger(vq, head, 0); 760 add_used(vq, head, 0);
758} 761}
759 762
760/* This is where we handle packets coming in from the tun device to our 763/* This is where we handle packets coming in from the tun device to our
@@ -1422,7 +1425,7 @@ static void blk_request(struct virtqueue *vq)
1422 if (out->type & VIRTIO_BLK_T_BARRIER) 1425 if (out->type & VIRTIO_BLK_T_BARRIER)
1423 fdatasync(vblk->fd); 1426 fdatasync(vblk->fd);
1424 1427
1425 add_used_and_trigger(vq, head, wlen); 1428 add_used(vq, head, wlen);
1426} 1429}
1427 1430
1428/*L:198 This actually sets up a virtual block device. */ 1431/*L:198 This actually sets up a virtual block device. */
@@ -1496,7 +1499,7 @@ static void rng_input(struct virtqueue *vq)
1496 } 1499 }
1497 1500
1498 /* Tell the Guest about the new input. */ 1501 /* Tell the Guest about the new input. */
1499 add_used_and_trigger(vq, head, totlen); 1502 add_used(vq, head, totlen);
1500} 1503}
1501 1504
1502/* And this creates a "hardware" random number device for the Guest. */ 1505/* And this creates a "hardware" random number device for the Guest. */