Acked-by: Justin Pettit <jpet...@nicira.com>

On Sep 24, 2013, at 10:17 AM, Ben Pfaff <b...@nicira.com> wrote:

> The hmap code has for a long time incremented a counter when a hash bucket
> grew to have many entries.  This can let a developer know that some hash
> function is performing poorly, but doesn't give any hint as to which one.
> This commit improves the situation by adding rate-limited debug logging
> that points out a particular line of code as the source of the poor hash
> behavior.  It should make issues easier to track down.
> 
> Bug #19926.
> CC: Keith Amidon <ke...@nicira.com>
> Signed-off-by: Ben Pfaff <b...@nicira.com>
> ---
> lib/hmap.c |   38 ++++++++++++++++++++++++++++----------
> lib/hmap.h |   31 +++++++++++++++++++++++--------
> 2 files changed, 51 insertions(+), 18 deletions(-)
> 
> diff --git a/lib/hmap.c b/lib/hmap.c
> index f15e72c..a559a77 100644
> --- a/lib/hmap.c
> +++ b/lib/hmap.c
> @@ -21,6 +21,9 @@
> #include "coverage.h"
> #include "random.h"
> #include "util.h"
> +#include "vlog.h"
> +
> +VLOG_DEFINE_THIS_MODULE(hmap);
> 
> COVERAGE_DEFINE(hmap_pathological);
> COVERAGE_DEFINE(hmap_expand);
> @@ -85,7 +88,7 @@ hmap_moved(struct hmap *hmap)
> }
> 
> static void
> -resize(struct hmap *hmap, size_t new_mask)
> +resize(struct hmap *hmap, size_t new_mask, const char *where)
> {
>     struct hmap tmp;
>     size_t i;
> @@ -109,7 +112,10 @@ resize(struct hmap *hmap, size_t new_mask)
>             count++;
>         }
>         if (count > 5) {
> +            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10);
>             COVERAGE_INC(hmap_pathological);
> +            VLOG_DBG_RL(&rl, "%s: %d nodes in bucket (%zu nodes, %zu 
> buckets)",
> +                        where, count, hmap->n, hmap->mask + 1);
>         }
>     }
>     hmap_swap(hmap, &tmp);
> @@ -136,38 +142,50 @@ calc_mask(size_t capacity)
>     return mask;
> }
> 
> -/* Expands 'hmap', if necessary, to optimize the performance of searches. */
> +/* Expands 'hmap', if necessary, to optimize the performance of searches.
> + *
> + * ('where' is used in debug logging.  Commonly one would use hmap_expand() 
> to
> + * automatically provide the caller's source file and line number for
> + * 'where'.) */
> void
> -hmap_expand(struct hmap *hmap)
> +hmap_expand_at(struct hmap *hmap, const char *where)
> {
>     size_t new_mask = calc_mask(hmap->n);
>     if (new_mask > hmap->mask) {
>         COVERAGE_INC(hmap_expand);
> -        resize(hmap, new_mask);
> +        resize(hmap, new_mask, where);
>     }
> }
> 
> -/* Shrinks 'hmap', if necessary, to optimize the performance of iteration. */
> +/* Shrinks 'hmap', if necessary, to optimize the performance of iteration.
> + *
> + * ('where' is used in debug logging.  Commonly one would use hmap_shrink() 
> to
> + * automatically provide the caller's source file and line number for
> + * 'where'.) */
> void
> -hmap_shrink(struct hmap *hmap)
> +hmap_shrink_at(struct hmap *hmap, const char *where)
> {
>     size_t new_mask = calc_mask(hmap->n);
>     if (new_mask < hmap->mask) {
>         COVERAGE_INC(hmap_shrink);
> -        resize(hmap, new_mask);
> +        resize(hmap, new_mask, where);
>     }
> }
> 
> /* Expands 'hmap', if necessary, to optimize the performance of searches when
>  * it has up to 'n' elements.  (But iteration will be slow in a hash map whose
> - * allocated capacity is much higher than its current number of nodes.)  */
> + * allocated capacity is much higher than its current number of nodes.)
> + *
> + * ('where' is used in debug logging.  Commonly one would use hmap_reserve() 
> to
> + * automatically provide the caller's source file and line number for
> + * 'where'.) */
> void
> -hmap_reserve(struct hmap *hmap, size_t n)
> +hmap_reserve_at(struct hmap *hmap, size_t n, const char *where)
> {
>     size_t new_mask = calc_mask(n);
>     if (new_mask > hmap->mask) {
>         COVERAGE_INC(hmap_reserve);
> -        resize(hmap, new_mask);
> +        resize(hmap, new_mask, where);
>     }
> }
> 
> diff --git a/lib/hmap.h b/lib/hmap.h
> index ab7d3ae..76a73ac 100644
> --- a/lib/hmap.h
> +++ b/lib/hmap.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2008, 2009, 2010, 2012 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -78,14 +78,24 @@ static inline size_t hmap_count(const struct hmap *);
> static inline bool hmap_is_empty(const struct hmap *);
> 
> /* Adjusting capacity. */
> -void hmap_expand(struct hmap *);
> -void hmap_shrink(struct hmap *);
> -void hmap_reserve(struct hmap *, size_t capacity);
> +void hmap_expand_at(struct hmap *, const char *where);
> +#define hmap_expand(HMAP) hmap_expand_at(HMAP, SOURCE_LOCATOR)
> +
> +void hmap_shrink_at(struct hmap *, const char *where);
> +#define hmap_shrink(HMAP) hmap_shrink_at(HMAP, SOURCE_LOCATOR)
> +
> +void hmap_reserve_at(struct hmap *, size_t capacity, const char *where);
> +#define hmap_reserve(HMAP, CAPACITY) \
> +    hmap_reserve_at(HMAP, CAPACITY, SOURCE_LOCATOR)
> 
> /* Insertion and deletion. */
> +static inline void hmap_insert_at(struct hmap *, struct hmap_node *,
> +                                  size_t hash, const char *where);
> +#define hmap_insert(HMAP, NODE, HASH) \
> +    hmap_insert_at(HMAP, NODE, HASH, SOURCE_LOCATOR)
> +
> static inline void hmap_insert_fast(struct hmap *,
>                                     struct hmap_node *, size_t hash);
> -static inline void hmap_insert(struct hmap *, struct hmap_node *, size_t 
> hash);
> static inline void hmap_remove(struct hmap *, struct hmap_node *);
> 
> void hmap_node_moved(struct hmap *, struct hmap_node *, struct hmap_node *);
> @@ -199,13 +209,18 @@ hmap_insert_fast(struct hmap *hmap, struct hmap_node 
> *node, size_t hash)
> }
> 
> /* Inserts 'node', with the given 'hash', into 'hmap', and expands 'hmap' if
> - * necessary to optimize search performance. */
> + * necessary to optimize search performance.
> + *
> + * ('where' is used in debug logging.  Commonly one would use hmap_insert() 
> to
> + * automatically provide the caller's source file and line number for
> + * 'where'.) */
> static inline void
> -hmap_insert(struct hmap *hmap, struct hmap_node *node, size_t hash)
> +hmap_insert_at(struct hmap *hmap, struct hmap_node *node, size_t hash,
> +               const char *where)
> {
>     hmap_insert_fast(hmap, node, hash);
>     if (hmap->n / 2 > hmap->mask) {
> -        hmap_expand(hmap);
> +        hmap_expand_at(hmap, where);
>     }
> }
> 
> -- 
> 1.7.10.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