Do we have to use the ATOMIC(long long) syntax, or can we use
atomic_ullong for most of the struct variable definitions?  If we have
to use the former, there should be a comment explaining why.

In dp_netdev_flow_used() I don't think we need to read the time and do
a MAX.  time_msec() is monotonic, so just writing the value should be
fine.

There should be a comment in dp_netdev_flow_used() explaining why we
do updates the way we do.

Alternatively, the patch might benefit from a "relaxed add" helper
local to dpif_netdev which does a relaxed read, add, relaxed write.

Acked-by: Ethan Jackson <et...@nicira.com>


On Wed, Apr 1, 2015 at 9:20 AM, Daniele Di Proietto
<diproiet...@vmware.com> wrote:
> A read operation from a non atomic shared value (without external
> locking) can return incorrect values.  Using the atomic semantics
> prevents this from happening.
>
> However:
> * No memory barriers are used.  We don't need that kind of consistency
>   for statistics (we use relaxed operations).
> * The updates are not atomic, just the loads and stores.  This is ok
>   because there's a single writer.
>
> Suggested-by: Ethan Jackson <et...@nicira.com>
> Signed-off-by: Daniele Di Proietto <diproiet...@vmware.com>
> ---
>  lib/dpif-netdev.c | 69 
> ++++++++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 50 insertions(+), 19 deletions(-)
>
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index b5cfdcb..a882e9c 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -239,10 +239,10 @@ struct dp_netdev_port {
>
>  /* Contained by struct dp_netdev_flow's 'stats' member.  */
>  struct dp_netdev_flow_stats {
> -    long long int used;             /* Last used time, in monotonic msecs. */
> -    long long int packet_count;     /* Number of packets matched. */
> -    long long int byte_count;       /* Number of bytes matched. */
> -    uint16_t tcp_flags;             /* Bitwise-OR of seen tcp_flags values. 
> */
> +    ATOMIC(long long) used;         /* Last used time, in monotonic msecs. */
> +    ATOMIC(long long) packet_count; /* Number of packets matched. */
> +    ATOMIC(long long) byte_count;   /* Number of bytes matched. */
> +    ATOMIC(uint16_t) tcp_flags;     /* Bitwise-OR of seen tcp_flags values. 
> */
>  };
>
>  /* A flow in 'dp_netdev_pmd_thread's 'flow_table'.
> @@ -338,7 +338,7 @@ static void dp_netdev_actions_free(struct 
> dp_netdev_actions *);
>  /* Contained by struct dp_netdev_pmd_thread's 'stats' member.  */
>  struct dp_netdev_pmd_stats {
>      /* Indexed by DP_STAT_*. */
> -    unsigned long long int n[DP_N_STATS];
> +    ATOMIC(unsigned long long) n[DP_N_STATS];
>  };
>
>  /* PMD: Poll modes drivers.  PMD accesses devices via polling to eliminate
> @@ -754,10 +754,15 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct 
> dpif_dp_stats *stats)
>
>      stats->n_flows = stats->n_hit = stats->n_missed = stats->n_lost = 0;
>      CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
> +        unsigned long long n;
>          stats->n_flows += cmap_count(&pmd->flow_table);
> -        stats->n_hit += pmd->stats.n[DP_STAT_HIT];
> -        stats->n_missed += pmd->stats.n[DP_STAT_MISS];
> -        stats->n_lost += pmd->stats.n[DP_STAT_LOST];
> +
> +        atomic_read_relaxed(&pmd->stats.n[DP_STAT_HIT], &n);
> +        stats->n_hit += n;
> +        atomic_read_relaxed(&pmd->stats.n[DP_STAT_MISS], &n);
> +        stats->n_missed += n;
> +        atomic_read_relaxed(&pmd->stats.n[DP_STAT_LOST], &n);
> +        stats->n_lost += n;
>      }
>      stats->n_masks = UINT32_MAX;
>      stats->n_mask_hit = UINT64_MAX;
> @@ -1545,13 +1550,23 @@ dp_netdev_pmd_find_flow(const struct 
> dp_netdev_pmd_thread *pmd,
>  }
>
>  static void
> -get_dpif_flow_stats(const struct dp_netdev_flow *netdev_flow,
> +get_dpif_flow_stats(const struct dp_netdev_flow *netdev_flow_,
>                      struct dpif_flow_stats *stats)
>  {
> -    stats->n_packets = netdev_flow->stats.packet_count;
> -    stats->n_bytes = netdev_flow->stats.byte_count;
> -    stats->used = netdev_flow->stats.used;
> -    stats->tcp_flags = netdev_flow->stats.tcp_flags;
> +    struct dp_netdev_flow *netdev_flow;
> +    long long n;
> +    uint16_t flags;
> +
> +    netdev_flow = CONST_CAST(struct dp_netdev_flow *, netdev_flow_);
> +
> +    atomic_read_relaxed(&netdev_flow->stats.packet_count, &n);
> +    stats->n_packets = n;
> +    atomic_read_relaxed(&netdev_flow->stats.byte_count, &n);
> +    stats->n_bytes = n;
> +    atomic_read_relaxed(&netdev_flow->stats.used, &n);
> +    stats->used = n;
> +    atomic_read_relaxed(&netdev_flow->stats.tcp_flags, &flags);
> +    stats->tcp_flags = flags;
>  }
>
>  /* Converts to the dpif_flow format, using 'key_buf' and 'mask_buf' for
> @@ -2678,19 +2693,35 @@ static void
>  dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow, int cnt, int size,
>                      uint16_t tcp_flags)
>  {
> -    long long int now = time_msec();
> +    long long n, now = time_msec();
> +    uint16_t flags;
>
> -    netdev_flow->stats.used = MAX(now, netdev_flow->stats.used);
> -    netdev_flow->stats.packet_count += cnt;
> -    netdev_flow->stats.byte_count += size;
> -    netdev_flow->stats.tcp_flags |= tcp_flags;
> +    atomic_read_relaxed(&netdev_flow->stats.used, &n);
> +    n = MAX(now, n);
> +    atomic_store_relaxed(&netdev_flow->stats.used, n);
> +
> +    atomic_read_relaxed(&netdev_flow->stats.packet_count, &n);
> +    n += cnt;
> +    atomic_store_relaxed(&netdev_flow->stats.packet_count, n);
> +
> +    atomic_read_relaxed(&netdev_flow->stats.byte_count, &n);
> +    n += size;
> +    atomic_store_relaxed(&netdev_flow->stats.byte_count, n);
> +
> +    atomic_read_relaxed(&netdev_flow->stats.tcp_flags, &flags);
> +    flags |= tcp_flags;
> +    atomic_store_relaxed(&netdev_flow->stats.tcp_flags, flags);
>  }
>
>  static void
>  dp_netdev_count_packet(struct dp_netdev_pmd_thread *pmd,
>                         enum dp_stat_type type, int cnt)
>  {
> -    pmd->stats.n[type] += cnt;
> +    unsigned long long n;
> +
> +    atomic_read_relaxed(&pmd->stats.n[type], &n);
> +    n += cnt;
> +    atomic_store_relaxed(&pmd->stats.n[type], n);
>  }
>
>  static int
> --
> 2.1.4
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to