Optimize wl_fixed_t to/from double conversion functions
authorKristian Høgsberg <krh@bitplanet.net>
Sat, 12 May 2012 03:36:20 +0000 (23:36 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Mon, 14 May 2012 13:36:38 +0000 (09:36 -0400)
src/connection.c
src/wayland-util.h
tests/Makefile.am
tests/fixed-benchmark.c [new file with mode: 0644]
tests/fixed-test.c [new file with mode: 0644]

index a888940..5b7965e 100644 (file)
@@ -853,7 +853,7 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
                        break;
                case 'f':
                        si = (int32_t) value->uint32;
-                       fprintf(stderr, "%f", (double) si / 256.0);
+                       fprintf(stderr, "%f", wl_fixed_to_double(si));
                        break;
                case 's':
                        fprintf(stderr, "\"%s\"", value->string);
index 8def7ee..fa5c6c5 100644 (file)
@@ -167,18 +167,32 @@ void *wl_array_add(struct wl_array *array, size_t size);
 void wl_array_copy(struct wl_array *array, struct wl_array *source);
 
 typedef int32_t wl_fixed_t;
-#define WL_FIXED_INVALID_VALUE ~0L
 
-static inline double wl_fixed_to_double(wl_fixed_t f)
+static inline double
+wl_fixed_to_double (wl_fixed_t f)
 {
-       return (double) f / 256.0;
-};
-static inline wl_fixed_t wl_fixed_from_double(double d)
+       union {
+               double d;
+               int64_t i;
+       } u;
+
+       u.i = ((1023LL + 44LL) << 52) + (1LL << 51) + f;
+
+       return u.d - (3LL << 43);
+}
+
+static inline wl_fixed_t
+wl_fixed_from_double(double d)
 {
-       if (d >= (1 << 23))
-               return WL_FIXED_INVALID_VALUE;
-       return (wl_fixed_t) round (d * 256.0);
-};
+       union {
+               double d;
+               int64_t i;
+       } u;
+
+       u.d = d + (3LL << (51 - 8));
+
+       return u.i;
+}
 
 static inline int wl_fixed_to_int(wl_fixed_t f)
 {
@@ -186,7 +200,7 @@ static inline int wl_fixed_to_int(wl_fixed_t f)
 }
 static inline wl_fixed_t wl_fixed_from_int(int i)
 {
-       return wl_fixed_from_double(i);
+       return i * 256;
 }
 
 #ifdef  __cplusplus
index 767919e..9fdf040 100644 (file)
@@ -6,12 +6,16 @@ TESTS =                                               \
        connection-test                         \
        event-loop-test                         \
        client-test                             \
-       os-wrappers-test
+       os-wrappers-test                        \
+       fixed-test
 
 check_PROGRAMS =                               \
        $(TESTS)                                \
        exec-fd-leak-checker
 
+noinst_PROGRAMS =                              \
+       fixed-benchmark
+
 test_runner_src = test-runner.c test-runner.h test-helpers.c
 
 sanity_test_SOURCES = sanity-test.c $(test_runner_src)
@@ -21,6 +25,9 @@ list_test_SOURCES = list-test.c $(test_runner_src)
 connection_test_SOURCES = connection-test.c $(test_runner_src)
 event_loop_test_SOURCES = event-loop-test.c $(test_runner_src)
 client_test_SOURCES = client-test.c $(test_runner_src)
+fixed_test_SOURCES = fixed-test.c $(test_runner_src)
+
+fixed_benchmark_SOURCES = fixed-benchmark.c
 
 os_wrappers_test_SOURCES =                     \
        os-wrappers-test.c                      \
diff --git a/tests/fixed-benchmark.c b/tests/fixed-benchmark.c
new file mode 100644 (file)
index 0000000..3f7aae3
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 "../src/wayland-private.h"
+
+volatile double global_d;
+
+static void
+magic_conversion(void)
+{
+       wl_fixed_t f;
+
+       for (f = 0; f < INT32_MAX; f++)
+               global_d = wl_fixed_to_double(f);
+}
+
+static void
+mul_conversion(void)
+{
+       wl_fixed_t f;
+
+       /* This will get optimized into multiplication by 1/256 */
+       for (f = 0; f < INT32_MAX; f++)
+               global_d = f / 256.0;
+}
+
+double factor = 256.0;
+
+static void
+div_conversion(void)
+{
+       wl_fixed_t f;
+
+       for (f = 0; f < INT32_MAX; f++)
+               global_d = f / 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("magic", magic_conversion);
+       benchmark("div", div_conversion);
+       benchmark("mul", mul_conversion);
+
+       return 0;
+}
diff --git a/tests/fixed-test.c b/tests/fixed-test.c
new file mode 100644 (file)
index 0000000..16fa5ff
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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 <assert.h>
+#include "../src/wayland-private.h"
+#include "test-runner.h"
+
+TEST(fixed_double_conversions)
+{
+       wl_fixed_t f;
+       double d;
+
+       d = 62.125;
+       f = wl_fixed_from_double(d);
+       fprintf(stderr, "double %lf to fixed %x\n", d, f);
+       assert(f == 0x3e20);
+
+       d = -1200.625;
+       f = wl_fixed_from_double(d);
+       fprintf(stderr, "double %lf to fixed %x\n", d, f);
+       assert(f == -0x4b0a0);
+
+       f = random();
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == f / 256.0);
+
+       f = 0x012030;
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == 288.1875);
+
+       f = 0x70000000;
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == f / 256);
+
+       f = -0x012030;
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == -288.1875);
+
+       f = 0x80000000;
+       d = wl_fixed_to_double(f);
+       fprintf(stderr, "fixed %x to double %lf\n", f, d);
+       assert(d == f / 256);
+}
+
+TEST(fixed_int_conversions)
+{
+       wl_fixed_t f;
+       int i;
+
+       i = 62;
+       f = wl_fixed_from_int(i);
+       assert(f == 62 * 256);
+
+       i = -2080;
+       f = wl_fixed_from_int(i);
+       assert(f == -2080 * 256);
+
+       f = 0x277013;
+       i = wl_fixed_to_int(f);
+       assert(i == 0x2770);
+
+       f = -0x5044;
+       i = wl_fixed_to_int(f);
+       assert(i == -0x50);
+}