On 3/9/22 15:19, Wan Junjie wrote:
> When several pmd threads race for the meter lock, the time 'now' each pmd 
> runs will
> have no guarantee in the order they really happen.
> 
> For example, pmd A runs meter at time x, and pmd B runs meter at time x+1. 
> However
> if pmd B get the lock and run meter first, meter->used will be assgined to 
> x+1, and
> then pmd A would run with delta_t equal to 0, the calculation for buckets is 
> good now.
> But pmd A will set meter->used to x, move the the time back a little.
> 
> If pmd B or other pmd runs it again, it will get a delta_t greater than it 
> should be
> and buckets is bigger than we expect. With really high thoughput and more 
> than four
> pmd threads, the deviation here will grow up very high.
> 
> This fix makes sure the time will only be added up.
> 
> Signed-off-by: Wan Junjie <[email protected]>
> ---
>  lib/dpif-netdev.c | 13 ++++++-------
>  1 file changed, 6 insertions(+), 7 deletions(-)
> 
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index 3acf5512a..26b584579 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -7160,8 +7160,7 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct 
> dp_packet_batch *packets_,
>      struct dp_meter *meter;
>      struct dp_meter_band *band;
>      struct dp_packet *packet;
> -    long long int long_delta_t; /* msec */
> -    uint32_t delta_t; /* msec */
> +    long long int long_delta_t, delta_t;
>      const size_t cnt = dp_packet_batch_size(packets_);
>      uint32_t bytes, volume;
>      int exceeded_band[NETDEV_MAX_BURST];
> @@ -7184,7 +7183,7 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct 
> dp_packet_batch *packets_,
>  
>      ovs_mutex_lock(&meter->lock);
>      /* All packets will hit the meter at the same time. */
> -    long_delta_t = now / 1000 - meter->used / 1000; /* msec */
> +    long_delta_t = now - meter->used;
>  
>      if (long_delta_t < 0) {
>          /* This condition means that we have several threads fighting for a
> @@ -7196,11 +7195,11 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct 
> dp_packet_batch *packets_,
>  
>      /* Make sure delta_t will not be too large, so that bucket will not
>       * wrap around below. */
> -    delta_t = (long_delta_t > (long long int)meter->max_delta_t)
> -        ? meter->max_delta_t : (uint32_t)long_delta_t;
> +    delta_t = (long_delta_t > (long long int)meter->max_delta_t * 1000)
> +        ? (meter->max_delta_t * 1000) : long_delta_t;
>  
>      /* Update meter stats. */
> -    meter->used = now;
> +    meter->used += long_delta_t;

Maybe it's easier to just move the assignment to the 'else'
branch of the (long_delta_t < 0) condition?  Seems cleaner
to me this way.

>      meter->packet_count += cnt;
>      bytes = 0;
>      DP_PACKET_BATCH_FOR_EACH (i, packet, packets_) {
> @@ -7228,7 +7227,7 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct 
> dp_packet_batch *packets_,
>          band = &meter->bands[m];
>          max_bucket_size = band->burst_size * 1000ULL;
>          /* Update band's bucket. */
> -        band->bucket += (uint64_t) delta_t * band->rate;
> +        band->bucket += (delta_t * band->rate / 1000);
>          if (band->bucket > max_bucket_size) {
>              band->bucket = max_bucket_size;
>          }

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to