[PATCH weston v2 12/21] Introduce a 'double fixed' data type abstraction

Jonas Ådahl jadahl at gmail.com
Wed May 13 03:26:33 PDT 2015


The 'double fixed' value type is a fixed point data type implemented as
two signed 32 bit integers. It is intended to be sent over the wire and
used when wl_fixed_t is not detailed enough.

Two helper functions are introduced: wl_double_fixed_to_double and
wl_double_fixed_from_double that can be used for conversion.

The type is implemented by separating the integral part from the
fractional part, storing them in individual signed 32 bit integers.

Converting to a double could be implemented with:

	double = integral + fraction / 2147483648

Converting to a double could be implemented with:

	integral = integral part of double
	fraction = fractional part of double * 2147483648

The implementation provided in this patch is slightly faster than the
above methods, but assumes that the IEEE 754 double-precision binary
floating-point format is used internally. It is based on the wl_fixed_t
conversion functions from wayland-util.h.

Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---
 Makefile.am                    |   6 +++
 shared/util.h                  |  57 +++++++++++++++++++++
 tests/double-fixed-benchmark.c | 110 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 173 insertions(+)
 create mode 100644 shared/util.h
 create mode 100644 tests/double-fixed-benchmark.c

diff --git a/Makefile.am b/Makefile.am
index 2f16fac..0a30cb4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -990,6 +990,7 @@ noinst_PROGRAMS +=			\
 	$(shared_tests)			\
 	$(weston_tests)			\
 	$(ivi_tests)			\
+	double-fixed-benchmark		\
 	matrix-test
 
 test_module_ldflags = \
@@ -1102,6 +1103,11 @@ matrix_test_SOURCES =				\
 matrix_test_CPPFLAGS = -DUNIT_TEST
 matrix_test_LDADD = -lm -lrt
 
+double_fixed_benchmark_SOURCES =		\
+	tests/double-fixed-benchmark.c		\
+	shared/util.h
+double_fixed_benchmark_LDADD = -lm
+
 if ENABLE_IVI_SHELL
 module_tests += 				\
 	ivi-layout-internal-test.la		\
diff --git a/shared/util.h b/shared/util.h
new file mode 100644
index 0000000..97a6f9b
--- /dev/null
+++ b/shared/util.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef WESTON_SHARED_UTIL_H
+#define WESTON_SHARED_UTIL_H
+
+#include <math.h>
+
+static inline double
+wl_double_fixed_to_double(int32_t i, int32_t f)
+{
+        union {
+                double d;
+                int64_t i;
+        } u;
+
+        u.i = ((1023LL + (52LL - 31LL)) << 52) +  (1LL << 51) + f;
+
+        return i + (u.d - (3LL << (52 - 32)));
+}
+
+static inline void
+wl_double_fixed_from_double(double d, int32_t *i, int32_t *f)
+{
+        double integral;
+        union {
+                double d;
+                int64_t i;
+        } u;
+
+        u.d = modf(d, &integral) + (3LL << (51 - 31));
+
+        *i = integral;
+        *f = u.i;
+}
+
+#endif /* WESTON_SHARED_UTIL_H */
diff --git a/tests/double-fixed-benchmark.c b/tests/double-fixed-benchmark.c
new file mode 100644
index 0000000..e4e5685
--- /dev/null
+++ b/tests/double-fixed-benchmark.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include <stdint.h>
+#include "shared/util.h"
+
+volatile double global_d;
+
+static void
+noop_conversion(void)
+{
+	int32_t fp;
+
+	union {
+		int64_t i;
+		double d;
+	} u;
+
+	for (fp = 0; fp < INT32_MAX; fp++) {
+		u.i = fp;
+		global_d = u.d;
+	}
+}
+
+static void
+magic_conversion(void)
+{
+	int32_t fp;
+
+	for (fp = 0; fp < INT32_MAX; fp++) {
+		global_d = wl_double_fixed_to_double(fp, fp);
+	}
+}
+
+static void
+mul_conversion(void)
+{
+	int32_t fp;
+
+	for (fp = 0; fp < INT32_MAX; fp++) {
+		global_d = fp + fp / 2147483648.0;
+	}
+}
+
+double factor = 2147483648.0;
+
+static void
+div_conversion(void)
+{
+	int32_t fp;
+
+	for (fp = 0; fp < INT32_MAX; fp++) {
+		global_d = fp + fp / factor;
+	}
+}
+
+static void
+benchmark(const char *s, void (*f)(void))
+{
+	struct timespec start, stop, elapsed;
+
+	clock_gettime(CLOCK_MONOTONIC, &start);
+	f();
+	clock_gettime(CLOCK_MONOTONIC, &stop);
+
+	elapsed.tv_sec = stop.tv_sec - start.tv_sec;
+	elapsed.tv_nsec = stop.tv_nsec - start.tv_nsec;
+	if (elapsed.tv_nsec < 0) {
+		elapsed.tv_nsec += 1000000000;
+		elapsed.tv_sec--;
+	}
+	printf("benchmarked %s:\t%ld.%09lds\n",
+	       s, elapsed.tv_sec, elapsed.tv_nsec);
+}
+
+int
+main(int argc, char *argv[])
+{
+	benchmark("noop", noop_conversion);
+	benchmark("magic", magic_conversion);
+	benchmark("div", div_conversion);
+	benchmark("mul", mul_conversion);
+
+	return 0;
+}
-- 
2.1.4



More information about the wayland-devel mailing list