Make use of __builtin_clz if available which should optimize ofputil_version_bitmap_scanr() by replacing a loop with a single CLZ instruction when available.
I'm unsure if this approach is worth it or not. But a similar approach could be taken to use ffs() in bitmap_scan(). Signed-off-by: Simon Horman <ho...@verge.net.au> --- configure.ac | 1 + lib/ofp-util.c | 19 ------------------- lib/ofp-util.h | 12 +++++++++++- lib/util.c | 21 +++++++++++++++++++++ lib/util.h | 9 +++++++++ m4/openvswitch.m4 | 16 ++++++++++++++++ 6 files changed, 58 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index 32940a5..7f9fffb 100644 --- a/configure.ac +++ b/configure.ac @@ -76,6 +76,7 @@ OVS_CHECK_GROFF OVS_CHECK_BRCOMPAT OVS_CHECK_GNU_MAKE OVS_CHECK_CACHE_TIME +OVS_CHECK___BUILTIN_CLZ OVS_ENABLE_OPTION([-Wall]) OVS_ENABLE_OPTION([-Wno-sign-compare]) diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 1639f9c..107661e 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -1077,25 +1077,6 @@ ofputil_version_bitmap_set_range1(size_t start, size_t end) return new; } -/* Scans 'ovb'. Returns the bit offset of the highest-numbered bit set to 1, - * or VERSION_BITMAP_W if all of the bits are set to 0. */ -size_t -ofputil_version_bitmap_scanr(uint32_t bitmap) -{ - /* N.B: When using GCC 3.4 or newer this may be made - * faster using __builtin_clz() - */ - size_t i = VERSION_BITMAP_W - 1; - - do { - if (ofputil_version_bitmap_is_set(bitmap, i)) { - return i; - } - } while (i--); - - return VERSION_BITMAP_W; -} - /* Find the number of bits in 'ovb' that are set to one. */ size_t ofputil_version_bitmap_count_set(uint32_t bitmap) diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 8dd1389..04501e6 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -130,9 +130,19 @@ ofputil_version_bitmap_is_set(uint32_t bitmap, size_t offset) } uint32_t ofputil_version_bitmap_set_range1(size_t start, size_t end); -size_t ofputil_version_bitmap_scanr(uint32_t bitmap); size_t ofputil_version_bitmap_count_set(uint32_t bitmap); +/* Scans 'ovb'. Returns the bit offset of the highest-numbered bit set to 1, + * or VERSION_BITMAP_W if all of the bits are set to 0. */ +static inline size_t +ofputil_version_bitmap_scanr(uint32_t bitmap) +{ + if (!bitmap) + return VERSION_BITMAP_W; + BUILD_ASSERT(sizeof bitmap == sizeof(unsigned int)); + return VERSION_BITMAP_W - 1 - clz(bitmap); +} + void ofputil_format_version_bitmap(struct ds *msg, uint32_t bitmap); void ofputil_format_version_bitmap_names(struct ds *msg, uint32_t bitmap); diff --git a/lib/util.c b/lib/util.c index c90d556..f25f66b 100644 --- a/lib/util.c +++ b/lib/util.c @@ -1149,3 +1149,24 @@ bitwise_get(const void *src, unsigned int src_len, n_bits); return ntohll(value); } + +#ifndef HAVE___BUILTIN_CLZ +#define UINT_BITS (sizeof(unsigned int) * 8) + +/* Returns the number of leading 0-bits in x + * x must be non-zero */ +int clz(unsigned int x) +{ + size_t i = UINT_BITS - 1; + + assert(x); + + do { + if (x & (1u << i)) { + return UINT_BITS - i - 1; + } + } while (i--); + + return UINT_BITS; +} +#endif diff --git a/lib/util.h b/lib/util.h index a1f4bd7..91d4c1a 100644 --- a/lib/util.h +++ b/lib/util.h @@ -287,6 +287,15 @@ void bitwise_put(uint64_t value, uint64_t bitwise_get(const void *src, unsigned int src_len, unsigned int src_ofs, unsigned int n_bits); +#ifdef HAVE___BUILTIN_CLZ +static inline int clz(unsigned int x) +{ + return __builtin_clz(x); +} +#else +int clz(unsigned int x); +#endif + #ifdef __cplusplus } #endif diff --git a/m4/openvswitch.m4 b/m4/openvswitch.m4 index 7469011..ae761b5 100644 --- a/m4/openvswitch.m4 +++ b/m4/openvswitch.m4 @@ -193,6 +193,22 @@ AC_DEFUN([OVS_CHECK_MALLOC_HOOKS], __free_hook in <malloc.h>.]) fi]) +dnl Checks for __builtin_clz +AC_DEFUN([OVS_CHECK___BUILTIN_CLZ], + [AC_CACHE_CHECK( + [whether __builtin_clz is provided], + [ovs_cv___builtin_clz], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [], + [return __builtin_clz(1);])], + [ovs_cv___builtin_clz=yes], + [ovs_cv___builtin_clz=no])]) + if test $ovs_cv___builtin_clz = yes; then + AC_DEFINE([HAVE___BUILTIN_CLZ], [1], + [Define to 1 if you have __builtin_clz]) + fi]) + dnl Checks for valgrind/valgrind.h. AC_DEFUN([OVS_CHECK_VALGRIND], [AC_CHECK_HEADERS([valgrind/valgrind.h])]) -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev