On Tue, May 17, 2022 at 2:56 AM Ilya Maximets <[email protected]> wrote:
>
> 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.
>
Makes no difference to me. Buckets will be calculated later anyway.

> >      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