|
|
9119d9 |
From b5bba7ab59381434ebf03bedd9ff4b22696b7384 Mon Sep 17 00:00:00 2001
|
|
|
9119d9 |
Message-Id: <b5bba7ab59381434ebf03bedd9ff4b22696b7384@dist-git>
|
|
|
9119d9 |
From: Pavel Hrdina <phrdina@redhat.com>
|
|
|
9119d9 |
Date: Tue, 25 Nov 2014 10:52:58 +0100
|
|
|
9119d9 |
Subject: [PATCH] internal: add macro to round value to the next closest power
|
|
|
9119d9 |
of 2
|
|
|
9119d9 |
|
|
|
9119d9 |
There are two special cases, if the input number is 0 or the number is
|
|
|
9119d9 |
larger then 2^31 (for 32bit unsigned int). For the special cases the
|
|
|
9119d9 |
return value is 0 because they cannot be rounded.
|
|
|
9119d9 |
|
|
|
9119d9 |
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
|
|
|
9119d9 |
(cherry picked from commit ff28ebf13622ec3667f63fc0c0c22698331ced4b)
|
|
|
9119d9 |
|
|
|
9119d9 |
I had to add the gnulib function 'count_leading_zeros' manually because
|
|
|
9119d9 |
we don't update the gnulib downstream.
|
|
|
9119d9 |
|
|
|
9119d9 |
Conflicts:
|
|
|
9119d9 |
bootstrap.conf - removed count-leading-zeros as we don't update
|
|
|
9119d9 |
the gnulib
|
|
|
9119d9 |
src/util/virutil.h - add count_leading_zeros by hand from gnulib
|
|
|
9119d9 |
module
|
|
|
9119d9 |
|
|
|
9119d9 |
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1076098
|
|
|
9119d9 |
|
|
|
9119d9 |
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
|
|
|
9119d9 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
9119d9 |
---
|
|
|
9119d9 |
src/internal.h | 6 +++++
|
|
|
9119d9 |
src/util/virutil.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
9119d9 |
tests/utiltest.c | 39 +++++++++++++++++++++++++++++++++
|
|
|
9119d9 |
3 files changed, 109 insertions(+)
|
|
|
9119d9 |
|
|
|
9119d9 |
diff --git a/src/internal.h b/src/internal.h
|
|
|
9119d9 |
index f6a88b2..09d8277 100644
|
|
|
9119d9 |
--- a/src/internal.h
|
|
|
9119d9 |
+++ b/src/internal.h
|
|
|
9119d9 |
@@ -382,6 +382,12 @@
|
|
|
9119d9 |
/* round up value to the closest multiple of size */
|
|
|
9119d9 |
# define VIR_ROUND_UP(value, size) (VIR_DIV_UP(value, size) * (size))
|
|
|
9119d9 |
|
|
|
9119d9 |
+/* Round up to the next closest power of 2. It will return rounded number or 0
|
|
|
9119d9 |
+ * for 0 or number more than 2^31 (for 32bit unsigned int). */
|
|
|
9119d9 |
+# define VIR_ROUND_UP_POWER_OF_TWO(value) \
|
|
|
9119d9 |
+ ((value) > 0 && (value) <= 1U << (sizeof(unsigned int) * 8 - 1) ? \
|
|
|
9119d9 |
+ 1U << (sizeof(unsigned int) * 8 - count_leading_zeros((value) - 1)) : 0)
|
|
|
9119d9 |
+
|
|
|
9119d9 |
|
|
|
9119d9 |
/* Specific error values for use in forwarding programs such as
|
|
|
9119d9 |
* virt-login-shell; these values match what GNU env does. */
|
|
|
9119d9 |
diff --git a/src/util/virutil.h b/src/util/virutil.h
|
|
|
9119d9 |
index 105c519..ae49aef 100644
|
|
|
9119d9 |
--- a/src/util/virutil.h
|
|
|
9119d9 |
+++ b/src/util/virutil.h
|
|
|
9119d9 |
@@ -244,4 +244,68 @@ VIR_ENUM_DECL(virTristateSwitch)
|
|
|
9119d9 |
|
|
|
9119d9 |
unsigned int virGetListenFDs(void);
|
|
|
9119d9 |
|
|
|
9119d9 |
+/* Borrow the code to count-leading-zeroes from gnulib LGPLv2+
|
|
|
9119d9 |
+ * count-leading-zeroes.h. */
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+/* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN,
|
|
|
9119d9 |
+ expand to code that computes the number of leading zeros of the local
|
|
|
9119d9 |
+ variable 'x' of type TYPE (an unsigned integer type) and return it
|
|
|
9119d9 |
+ from the current function. */
|
|
|
9119d9 |
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
|
|
9119d9 |
+# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \
|
|
|
9119d9 |
+ return x ? BUILTIN (x) : CHAR_BIT * sizeof x;
|
|
|
9119d9 |
+#elif _MSC_VER
|
|
|
9119d9 |
+# pragma intrinsic _BitReverse
|
|
|
9119d9 |
+# pragma intrinsic _BitReverse64
|
|
|
9119d9 |
+# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \
|
|
|
9119d9 |
+ do \
|
|
|
9119d9 |
+ { \
|
|
|
9119d9 |
+ unsigned long result; \
|
|
|
9119d9 |
+ return MSC_BUILTIN (&result, x) ? result : CHAR_BIT * sizeof x; \
|
|
|
9119d9 |
+ } \
|
|
|
9119d9 |
+ while (0)
|
|
|
9119d9 |
+#else
|
|
|
9119d9 |
+# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \
|
|
|
9119d9 |
+ do \
|
|
|
9119d9 |
+ { \
|
|
|
9119d9 |
+ int count; \
|
|
|
9119d9 |
+ unsigned int leading_32; \
|
|
|
9119d9 |
+ if (! x) \
|
|
|
9119d9 |
+ return CHAR_BIT * sizeof x; \
|
|
|
9119d9 |
+ for (count = 0; \
|
|
|
9119d9 |
+ (leading_32 = ((x >> (sizeof (TYPE) * CHAR_BIT - 32)) \
|
|
|
9119d9 |
+ & 0xffffffffU), \
|
|
|
9119d9 |
+ count < CHAR_BIT * sizeof x - 32 && !leading_32); \
|
|
|
9119d9 |
+ count += 32) \
|
|
|
9119d9 |
+ x = x << 31 << 1; \
|
|
|
9119d9 |
+ return count + count_leading_zeros_32 (leading_32); \
|
|
|
9119d9 |
+ } \
|
|
|
9119d9 |
+ while (0)
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+/* Compute and return the number of leading zeros in X,
|
|
|
9119d9 |
+ where 0 < X < 2**32. */
|
|
|
9119d9 |
+static inline int
|
|
|
9119d9 |
+count_leading_zeros_32 (unsigned int x)
|
|
|
9119d9 |
+{
|
|
|
9119d9 |
+ /* http://graphics.stanford.edu/~seander/bithacks.html */
|
|
|
9119d9 |
+ static const char de_Bruijn_lookup[32] = {
|
|
|
9119d9 |
+ 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
|
|
|
9119d9 |
+ 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
|
|
|
9119d9 |
+ };
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ x |= x >> 1;
|
|
|
9119d9 |
+ x |= x >> 2;
|
|
|
9119d9 |
+ x |= x >> 4;
|
|
|
9119d9 |
+ x |= x >> 8;
|
|
|
9119d9 |
+ x |= x >> 16;
|
|
|
9119d9 |
+ return de_Bruijn_lookup[((x * 0x07c4acddU) & 0xffffffffU) >> 27];
|
|
|
9119d9 |
+}
|
|
|
9119d9 |
+#endif
|
|
|
9119d9 |
+/* Compute and return the number of leading zeros in X. */
|
|
|
9119d9 |
+static inline int
|
|
|
9119d9 |
+count_leading_zeros (unsigned int x)
|
|
|
9119d9 |
+{
|
|
|
9119d9 |
+ COUNT_LEADING_ZEROS (__builtin_clz, _BitScanReverse, unsigned int);
|
|
|
9119d9 |
+}
|
|
|
9119d9 |
+
|
|
|
9119d9 |
#endif /* __VIR_UTIL_H__ */
|
|
|
9119d9 |
diff --git a/tests/utiltest.c b/tests/utiltest.c
|
|
|
9119d9 |
index 89e82aa..8274ed0 100644
|
|
|
9119d9 |
--- a/tests/utiltest.c
|
|
|
9119d9 |
+++ b/tests/utiltest.c
|
|
|
9119d9 |
@@ -144,6 +144,44 @@ testParseVersionString(const void *data ATTRIBUTE_UNUSED)
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
+struct testRoundData {
|
|
|
9119d9 |
+ unsigned int input;
|
|
|
9119d9 |
+ unsigned int output;
|
|
|
9119d9 |
+};
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+static struct testRoundData roundData[] = {
|
|
|
9119d9 |
+ { 0, 0 },
|
|
|
9119d9 |
+ { 1, 1 },
|
|
|
9119d9 |
+ { 1000, 1024 },
|
|
|
9119d9 |
+ { 1024, 1024 },
|
|
|
9119d9 |
+ { 1025, 2048 },
|
|
|
9119d9 |
+ { UINT_MAX, 0 },
|
|
|
9119d9 |
+};
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+static int
|
|
|
9119d9 |
+testRoundValueToPowerOfTwo(const void *data ATTRIBUTE_UNUSED)
|
|
|
9119d9 |
+{
|
|
|
9119d9 |
+ unsigned int result;
|
|
|
9119d9 |
+ size_t i;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ for (i = 0; i < ARRAY_CARDINALITY(roundData); i++) {
|
|
|
9119d9 |
+ result = VIR_ROUND_UP_POWER_OF_TWO(roundData[i].input);
|
|
|
9119d9 |
+ if (roundData[i].output != result) {
|
|
|
9119d9 |
+ if (virTestGetDebug() > 0) {
|
|
|
9119d9 |
+ fprintf(stderr, "\nInput number [%u]\n", roundData[i].input);
|
|
|
9119d9 |
+ fprintf(stderr, "Expected number [%u]\n", roundData[i].output);
|
|
|
9119d9 |
+ fprintf(stderr, "Actual number [%u]\n", result);
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ return -1;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ return 0;
|
|
|
9119d9 |
+}
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+
|
|
|
9119d9 |
|
|
|
9119d9 |
static int
|
|
|
9119d9 |
mymain(void)
|
|
|
9119d9 |
@@ -163,6 +201,7 @@ mymain(void)
|
|
|
9119d9 |
DO_TEST(IndexToDiskName);
|
|
|
9119d9 |
DO_TEST(DiskNameToIndex);
|
|
|
9119d9 |
DO_TEST(ParseVersionString);
|
|
|
9119d9 |
+ DO_TEST(RoundValueToPowerOfTwo);
|
|
|
9119d9 |
|
|
|
9119d9 |
return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
--
|
|
|
9119d9 |
2.1.3
|
|
|
9119d9 |
|