>> I was looking through the bhyve code and noticed an obvious
>> easy (if trivial) code improvement.
>>
>> Tested "standalone" rather than inside bhyve (with both gcc and
>> clang, on FreeBSD 9.0).
>
>  Thanks; I'll apply it.
>
>> Not sure where/how diffs should go, so I figured I would send this
>> here as a test. :-)
>
>  This is as good a place as any :)
>
>later,
>
>Peter.

I looked at the svn commit and there's a glitch...

I only sent you one file (pci_virtio_block.c) of the two (not
having realized the code was duplicated in pci_virtio_net.c).  You
applied the change to both files but missed something:

        Index: pci_virtio_block.c
        ===================================================================
        --- pci_virtio_block.c  (revision 247865)
        +++ pci_virtio_block.c  (revision 247871)
        @@ -164,14 +164,19 @@
         static int
         hq_num_avail(struct vring_hqueue *hq)
         {
        -       int ndesc;
        +       uint16_t ndesc;

This change (to use uint16_t) is important.
 
        -       if (*hq->hq_avail_idx >= hq->hq_cur_aidx)
        -               ndesc = *hq->hq_avail_idx - hq->hq_cur_aidx;
        -       else
        -               ndesc = UINT16_MAX - hq->hq_cur_aidx + 
*hq->hq_avail_idx + 1;
        +       /*
        +        * We're just computing (a-b) in GF(216).

(minor: this should read "2 caret 16" or maybe "2**16", presumably
some mail software ate it?)

        +        *
        +        * The only glitch here is that in standard C,
        +        * uint16_t promotes to (signed) int when int has
        +        * more than 16 bits (pretty much always now), so
        +        * we have to force it back to unsigned.
        +        */
        +       ndesc = (unsigned)*hq->hq_avail_idx - (unsigned)hq->hq_cur_aidx;

The trick here is that if, e.g., avail is 3 and cur is 29,
we get 3 - 29 = 0xffffffe6, which should be considered "the
same as" 65510.  The original calculation did (via the else
half):

    ndesc = UINT16_MAX - hq->hq_cur_aidx + *hq->hq_avail_idx + 1
          = 65535 - 29 + 3 + 1

which is 65510.  The new one computes (in 32-bit unsigned)
0xffffffe6 but then assigns the result to a 16-bit unsigned
temporary (i.e., ndesc), chopping off the unwanted high bits
and resulting in 0xffe6 = 65510.

        -       assert(ndesc >= 0 && ndesc <= hq->hq_size);
        +       assert(ndesc <= hq->hq_size);
         
                return (ndesc);
         }

        Index: pci_virtio_net.c
        ===================================================================
        --- pci_virtio_net.c    (revision 247865)
        +++ pci_virtio_net.c    (revision 247871)
        @@ -172,12 +172,17 @@
         {
                int ndesc;

Uh oh, here we (still) have a regular plain "int"...

        -       if (*hq->hq_avail_idx >= hq->hq_cur_aidx)
        -               ndesc = *hq->hq_avail_idx - hq->hq_cur_aidx;
        -       else
        -               ndesc = UINT16_MAX - hq->hq_cur_aidx + 
*hq->hq_avail_idx + 1;
        +       /*
        +        * We're just computing (a-b) in GF(216).
        +        *
        +        * The only glitch here is that in standard C,
        +        * uint16_t promotes to (signed) int when int has
        +        * more than 16 bits (pretty much always now), so
        +        * we have to force it back to unsigned.
        +        */
        +       ndesc = (unsigned)*hq->hq_avail_idx - (unsigned)hq->hq_cur_aidx;

This time we'll do something like "3 - 29" in unsigned and get
0xffffffe6 as before, but then stick that in a (32 bit) int and
believe it means -26.

        -       assert(ndesc >= 0 && ndesc <= hq->hq_size);
        +       assert(ndesc <= hq->hq_size);

Without the >= 0 part of the assert, we'll miss the underflow
since ndesc is signed, and hq_size is uint16_t and will widen
to (plain signed) int here.

(Of course it's more typical to have, e.g., not 3 and 29 but
0xfffc = 65532 and 24, where the subtraction will produce
-65508 when we wanted 28.  I'd have to look closely at the
rest of the code to see what happens after that.)

                return (ndesc);
         }

The comment might be misleading -- the trick is to compute the
result in two steps, first in GF(2**{anything >= 16}), then
*reduce* it (via assigment to uint16_t) to GF(2**16).  (I used
"**" this time instead of ^, just to be different :-) )

Chris
_______________________________________________
freebsd-virtualization@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-virtualization
To unsubscribe, send any mail to 
"freebsd-virtualization-unsubscr...@freebsd.org"

Reply via email to