win-pvdrivers

changeset 896:d7c96703155f

Limit the amount of work done in Dpc. Again. Initial testing seems to show negligible performance hit and dpc latency is reduced.
author James Harper <james.harper@bendigoit.com.au>
date Thu Mar 24 13:25:16 2011 +1100 (2011-03-24)
parents 26fcdb535a0a
children 0b3220aea661
files xennet/xennet_rx.c
line diff
     1.1 --- a/xennet/xennet_rx.c	Thu Mar 24 13:09:42 2011 +1100
     1.2 +++ b/xennet/xennet_rx.c	Thu Mar 24 13:25:16 2011 +1100
     1.3 @@ -156,6 +156,7 @@ XenNet_FillRing(struct xennet_info *xi)
     1.4  }
     1.5  
     1.6  LONG total_allocated_packets = 0;
     1.7 +LONG dpc_limit_hit = 0;
     1.8  LARGE_INTEGER last_print_time;
     1.9  
    1.10  /* lock free */
    1.11 @@ -191,7 +192,7 @@ put_packet_on_freelist(struct xennet_inf
    1.12    if ((int)total_allocated_packets < 0 || (current_time.QuadPart - last_print_time.QuadPart) / 10000 > 1000)
    1.13    {
    1.14      last_print_time.QuadPart = current_time.QuadPart;
    1.15 -    KdPrint(("total_allocated_packets = %d, rx_outstanding = %d, rx_pb_outstanding = %d, rx_pb_free = %d\n", total_allocated_packets, xi->rx_outstanding, rx_pb_outstanding, xi->rx_pb_free));
    1.16 +    KdPrint(("total_allocated_packets = %d, rx_outstanding = %d, dpc_limit_hit = %d, rx_pb_outstanding = %d, rx_pb_free = %d\n", total_allocated_packets, xi->rx_outstanding, dpc_limit_hit, rx_pb_outstanding, xi->rx_pb_free));
    1.17    }
    1.18  }
    1.19  
    1.20 @@ -284,7 +285,9 @@ XenNet_MakePacket(struct xennet_info *xi
    1.21      if (!pi->curr_buffer || !pi->curr_pb)
    1.22      {
    1.23        KdPrint((__DRIVER_NAME "     out of buffers for packet\n"));
    1.24 +      KdPrint((__DRIVER_NAME "     out_remaining = %d, curr_buffer = %p, curr_pb = %p\n", out_remaining, pi->curr_buffer, pi->curr_pb));
    1.25        // TODO: free some stuff or we'll leak
    1.26 +      /* unchain buffers then free packet */
    1.27        return NULL;
    1.28      }
    1.29      NdisQueryBufferOffset(pi->curr_buffer, &in_buffer_offset, &in_buffer_length);
    1.30 @@ -620,7 +623,8 @@ XenNet_RxQueueDpcSynchronized(PVOID cont
    1.31  /* We limit the number of packets per interrupt so that acks get a chance
    1.32  under high rx load. The DPC is immediately re-scheduled */
    1.33  /* this isn't actually done right now */
    1.34 -#define MAX_BUFFERS_PER_INTERRUPT 256
    1.35 +#define MAXIMUM_PACKETS_PER_INTERRUPT 32
    1.36 +#define MAXIMUM_DATA_PER_INTERRUPT (MAXIMUM_PACKETS_PER_INTERRUPT * 1500)
    1.37  
    1.38  // Called at DISPATCH_LEVEL
    1.39  static VOID
    1.40 @@ -633,6 +637,8 @@ XenNet_RxBufferCheck(PKDPC dpc, PVOID co
    1.41    PNDIS_PACKET packets[MAXIMUM_PACKETS_PER_INDICATE];
    1.42    ULONG packet_count = 0;
    1.43    ULONG buffer_count = 0;
    1.44 +  ULONG packet_data = 0;
    1.45 +  ULONG interim_packet_data = 0;
    1.46    struct netif_extra_info *ei;
    1.47    USHORT id;
    1.48    int more_to_do = FALSE;
    1.49 @@ -683,7 +689,7 @@ XenNet_RxBufferCheck(PKDPC dpc, PVOID co
    1.50      prod = xi->rx.sring->rsp_prod;
    1.51      KeMemoryBarrier(); /* Ensure we see responses up to 'prod'. */
    1.52  
    1.53 -    for (cons = xi->rx.rsp_cons; cons != prod; cons++)
    1.54 +    for (cons = xi->rx.rsp_cons; cons != prod && packet_count < MAXIMUM_PACKETS_PER_INTERRUPT && packet_data < MAXIMUM_DATA_PER_INTERRUPT; cons++)
    1.55      {
    1.56        id = (USHORT)(cons & (NET_RX_RING_SIZE - 1));
    1.57        page_buf = xi->rx_ring_pbs[id];
    1.58 @@ -725,10 +731,16 @@ XenNet_RxBufferCheck(PKDPC dpc, PVOID co
    1.59        {
    1.60          more_data_flag = (BOOLEAN)(page_buf->rsp.flags & NETRXF_more_data);
    1.61          extra_info_flag = (BOOLEAN)(page_buf->rsp.flags & NETRXF_extra_info);
    1.62 +        interim_packet_data += page_buf->rsp.status;
    1.63        }
    1.64        
    1.65        if (!extra_info_flag && !more_data_flag)
    1.66 +      {
    1.67          last_buf = page_buf;
    1.68 +        packet_count++;
    1.69 +        packet_data += interim_packet_data;
    1.70 +        interim_packet_data = 0;
    1.71 +      }
    1.72        buffer_count++;
    1.73      }
    1.74      xi->rx.rsp_cons = cons;
    1.75 @@ -736,6 +748,9 @@ XenNet_RxBufferCheck(PKDPC dpc, PVOID co
    1.76      /* Give netback more buffers */
    1.77      XenNet_FillRing(xi);
    1.78  
    1.79 +    if (packet_count >= MAXIMUM_PACKETS_PER_INTERRUPT || packet_data >= MAXIMUM_DATA_PER_INTERRUPT)
    1.80 +      break;
    1.81 +
    1.82      more_to_do = RING_HAS_UNCONSUMED_RESPONSES(&xi->rx);
    1.83      if (!more_to_do)
    1.84      {
    1.85 @@ -757,16 +772,21 @@ XenNet_RxBufferCheck(PKDPC dpc, PVOID co
    1.86  
    1.87    KeReleaseSpinLockFromDpcLevel(&xi->rx_lock);
    1.88  
    1.89 -#if 0
    1.90 -do this on a timer or something during packet manufacture
    1.91 -  if (buffer_count >= MAX_BUFFERS_PER_INTERRUPT)
    1.92 +  if (packet_count >= MAXIMUM_PACKETS_PER_INTERRUPT || packet_data >= MAXIMUM_DATA_PER_INTERRUPT)
    1.93    {
    1.94      /* fire again immediately */
    1.95 -    KdPrint((__DRIVER_NAME "     Dpc Duration Exceeded\n"));
    1.96 +    //KdPrint((__DRIVER_NAME "     Dpc Duration Exceeded\n"));
    1.97 +    dpc_limit_hit++;
    1.98 +    /* we want the Dpc on the end of the queue. By definition we are already on the right CPU so we know the Dpc queue will be run immediately */
    1.99 +    KeSetImportanceDpc(&xi->rx_dpc, MediumImportance);
   1.100      KeInsertQueueDpc(&xi->rx_dpc, NULL, NULL);
   1.101      //xi->vectors.EvtChn_Sync(xi->vectors.context, XenNet_RxQueueDpcSynchronized, xi);
   1.102    }
   1.103 -#endif
   1.104 +  else
   1.105 +  {
   1.106 +    /* make sure the Dpc queue is run immediately next interrupt */
   1.107 +    KeSetImportanceDpc(&xi->rx_dpc, HighImportance);
   1.108 +  }
   1.109  
   1.110    /* make packets out of the buffers */
   1.111    page_buf = head_buf;