bench: Modify benchmarks for a wider range of platforms
authorKazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
Mon, 24 Aug 2015 04:33:32 +0000 (13:33 +0900)
committerKazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
Fri, 28 Aug 2015 11:02:26 +0000 (20:02 +0900)
 - Add the new files bench.c and bench.h to implement a timer module.
 - Implement the module with clock_gettime(), mach_absolute_time(), or
   gettimeofday(), depending on a given platform.
 - Replace the time measurement code of the benchmark programs with the
   functions of the module.

Makefile.am
bench/bench.c [new file with mode: 0644]
bench/bench.h [new file with mode: 0644]
bench/compose.c
bench/key-proc.c
bench/rules.c
bench/rulescomp.c
configure.ac

index eae2b29..1d7ddaf 100644 (file)
@@ -250,8 +250,12 @@ check_PROGRAMS += $(TESTS)
 ##
 # Benchmarks
 ##
-
-BENCH_LDADD = $(TESTS_LDADD) $(RT_LIBS)
+check_LTLIBRARIES += libbench.la
+libbench_la_SOURCES = \
+       bench/bench.c \
+       bench/bench.h
+BENCH_LDADD  = libbench.la
+BENCH_LDADD += $(TESTS_LDADD) $(RT_LIBS)
 
 check_PROGRAMS += \
        bench/key-proc \
diff --git a/bench/bench.c b/bench/bench.c
new file mode 100644 (file)
index 0000000..9bb535c
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2015 Kazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
+ *                  Ran Benita <ran234@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#if defined(HAVE_CLOCK_GETTIME)
+#define USE_CLOCK_GETTIME
+#include <time.h>
+#elif defined(__MACH__) && __MACH__ == 1
+#define USE_MACH_ABSOLUTE_TIME
+#include <mach/mach_time.h>
+#else
+/* gettimeofday() - a last resort */
+#include <sys/time.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bench.h"
+
+static void
+set_bench_time(struct bench_time *dest, long seconds, long milliseconds)
+{
+    dest->seconds = seconds;
+    dest->milliseconds = milliseconds;
+}
+
+static void
+normalize_bench_time(struct bench_time *obj)
+{
+    if (obj->milliseconds >= 0) {
+        return;
+    }
+    obj->milliseconds += 1000000;
+    obj->seconds--;
+}
+
+void
+bench_timer_reset(struct bench_timer *self)
+{
+#if defined(USE_MACH_ABSOLUTE_TIME)
+    mach_timebase_info_data_t info;
+    if (mach_timebase_info(&info) == 0) {
+        self->scaling_factor = info.numer / info.denom;
+    }
+#endif
+    self->start.seconds = 0L;
+    self->start.milliseconds = 0L;
+    self->stop.seconds = 0L;
+    self->stop.milliseconds = 0L;
+}
+
+void
+bench_timer_start(struct bench_timer *self)
+{
+#if defined(USE_CLOCK_GETTIME)
+    struct timespec val;
+
+    (void)clock_gettime(CLOCK_MONOTONIC, &val);
+
+    /* With conversion from nanosecond to millisecond */
+    set_bench_time(&self->start, val.tv_sec, val.tv_nsec / 1000);
+#elif defined(USE_MACH_ABSOLUTE_TIME)
+    uint64_t val;
+
+    val = mach_absolute_time();
+
+    /* With conversion from nanosecond to millisecond */
+    set_bench_time(&self->start,
+                   self->scaling_factor * val / 1000000000,
+                   self->scaling_factor * val % 1000000000 / 1000);
+#else
+    struct timeval val;
+
+    (void)gettimeofday(&val, NULL);
+
+    set_bench_time(&self->start, val.tv_sec, val.tv_usec);
+#endif
+}
+
+void
+bench_timer_stop(struct bench_timer *self)
+{
+#if defined(USE_CLOCK_GETTIME)
+    struct timespec val;
+
+    (void)clock_gettime(CLOCK_MONOTONIC, &val);
+
+    /* With conversion from nanosecond to millisecond */
+    set_bench_time(&self->stop, val.tv_sec, val.tv_nsec / 1000);
+#elif defined(USE_MACH_ABSOLUTE_TIME)
+    uint64_t val;
+
+    val = mach_absolute_time();
+
+    /* With conversion from nanosecond to millisecond */
+    set_bench_time(&self->stop,
+                   self->scaling_factor * val / 1000000000,
+                   self->scaling_factor * val % 1000000000 / 1000);
+#else
+    struct timeval val;
+
+    (void)gettimeofday(&val, NULL);
+
+    set_bench_time(&self->stop, val.tv_sec, val.tv_usec);
+#endif
+}
+
+void
+bench_timer_get_elapsed_time(struct bench_timer *self, struct bench_time *result)
+{
+    result->seconds = self->stop.seconds - self->start.seconds;
+    result->milliseconds = self->stop.milliseconds - self->start.milliseconds;
+}
+
+char *
+bench_timer_get_elapsed_time_str(struct bench_timer *self)
+{
+    struct bench_time elapsed;
+    char *buf;
+
+    bench_timer_get_elapsed_time(self, &elapsed);
+    normalize_bench_time(&elapsed);
+    asprintf(&buf, "%ld.%06ld", elapsed.seconds, elapsed.milliseconds);
+
+    return buf;
+}
diff --git a/bench/bench.h b/bench/bench.h
new file mode 100644 (file)
index 0000000..5c1769e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2015 Kazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
+ *                  Ran Benita <ran234@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LIBXKBCOMMON_BENCH_H
+#define LIBXKBCOMMON_BENCH_H
+
+struct bench_time {
+    long seconds;
+    long milliseconds;
+};
+
+struct bench_timer {
+    struct bench_time start;
+    struct bench_time stop;
+#if defined(__MACH__) && __MACH__ == 1
+    uint64_t scaling_factor;
+#endif
+};
+
+void bench_timer_reset(struct bench_timer *self);
+
+void bench_timer_start(struct bench_timer *self);
+void bench_timer_stop(struct bench_timer *self);
+
+void bench_timer_get_elapsed_time(struct bench_timer *self, struct bench_time *result);
+/* It's caller's responsibility to release the returned string using free(). */
+char *bench_timer_get_elapsed_time_str(struct bench_timer *self);
+
+#endif /* LIBXKBCOMMON_BENCH_H */
index e2ded57..267b757 100644 (file)
@@ -26,6 +26,7 @@
 #include "xkbcommon/xkbcommon-compose.h"
 
 #include "../test/test.h"
+#include "bench.h"
 
 #define BENCHMARK_ITERATIONS 1000
 
@@ -33,10 +34,11 @@ int
 main(void)
 {
     struct xkb_context *ctx;
-    struct timespec start, stop, elapsed;
     char *path;
     FILE *file;
     struct xkb_compose_table *table;
+    struct bench_timer timer;
+    char *elapsed;
 
     ctx = test_get_context(CONTEXT_NO_FLAG);
     assert(ctx);
@@ -47,7 +49,9 @@ main(void)
     xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
     xkb_context_set_log_verbosity(ctx, 0);
 
-    clock_gettime(CLOCK_MONOTONIC, &start);
+    bench_timer_reset(&timer);
+
+    bench_timer_start(&timer);
     for (int i = 0; i < BENCHMARK_ITERATIONS; i++) {
         rewind(file);
         table = xkb_compose_table_new_from_file(ctx, file, "",
@@ -56,20 +60,15 @@ main(void)
         assert(table);
         xkb_compose_table_unref(table);
     }
-    clock_gettime(CLOCK_MONOTONIC, &stop);
+    bench_timer_stop(&timer);
 
     fclose(file);
     free(path);
 
-    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--;
-    }
-
-    fprintf(stderr, "compiled %d compose tables in %ld.%09lds\n",
-            BENCHMARK_ITERATIONS, elapsed.tv_sec, elapsed.tv_nsec);
+    elapsed = bench_timer_get_elapsed_time_str(&timer);
+    fprintf(stderr, "compiled %d compose tables in %ss\n",
+            BENCHMARK_ITERATIONS, elapsed);
+    free(elapsed);
 
     xkb_context_unref(ctx);
     return 0;
index 255f033..56b396a 100644 (file)
@@ -25,6 +25,7 @@
 #include <time.h>
 
 #include "../test/test.h"
+#include "bench.h"
 
 #define BENCHMARK_ITERATIONS 20000000
 
@@ -56,7 +57,8 @@ main(void)
     struct xkb_context *ctx;
     struct xkb_keymap *keymap;
     struct xkb_state *state;
-    struct timespec start, stop, elapsed;
+    struct bench_timer timer;
+    char *elapsed;
 
     ctx = test_get_context(0);
     assert(ctx);
@@ -73,19 +75,16 @@ main(void)
 
     srand(time(NULL));
 
-    clock_gettime(CLOCK_MONOTONIC, &start);
-    bench(state);
-    clock_gettime(CLOCK_MONOTONIC, &stop);
+    bench_timer_reset(&timer);
 
-    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--;
-    }
+    bench_timer_start(&timer);
+    bench(state);
+    bench_timer_stop(&timer);
 
-    fprintf(stderr, "ran %d iterations in %ld.%09lds\n",
-            BENCHMARK_ITERATIONS, elapsed.tv_sec, elapsed.tv_nsec);
+    elapsed = bench_timer_get_elapsed_time_str(&timer);
+    fprintf(stderr, "ran %d iterations in %ss\n",
+            BENCHMARK_ITERATIONS, elapsed);
+    free(elapsed);
 
     xkb_state_unref(state);
     xkb_keymap_unref(keymap);
index d92ed07..0dda7e3 100644 (file)
@@ -26,6 +26,7 @@
 #include "../test/test.h"
 #include "xkbcomp-priv.h"
 #include "rules.h"
+#include "bench.h"
 
 #define BENCHMARK_ITERATIONS 20000
 
@@ -33,12 +34,13 @@ int
 main(int argc, char *argv[])
 {
     struct xkb_context *ctx;
-    struct timespec start, stop, elapsed;
     int i;
     struct xkb_rule_names rmlvo = {
         "evdev", "pc105", "us,il", ",", "ctrl:nocaps,grp:menu_toggle",
     };
     struct xkb_component_names kccgst;
+    struct bench_timer timer;
+    char *elapsed;
 
     ctx = test_get_context(0);
     assert(ctx);
@@ -46,7 +48,9 @@ main(int argc, char *argv[])
     xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
     xkb_context_set_log_verbosity(ctx, 0);
 
-    clock_gettime(CLOCK_MONOTONIC, &start);
+    bench_timer_reset(&timer);
+
+    bench_timer_start(&timer);
     for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
         assert(xkb_components_from_rules(ctx, &rmlvo, &kccgst));
         free(kccgst.keycodes);
@@ -54,17 +58,12 @@ main(int argc, char *argv[])
         free(kccgst.compat);
         free(kccgst.symbols);
     }
-    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--;
-    }
+    bench_timer_stop(&timer);
 
-    fprintf(stderr, "processed %d rule files in %ld.%09lds\n",
-            BENCHMARK_ITERATIONS, elapsed.tv_sec, elapsed.tv_nsec);
+    elapsed = bench_timer_get_elapsed_time_str(&timer);
+    fprintf(stderr, "processed %d rule files in %ss\n",
+            BENCHMARK_ITERATIONS, elapsed);
+    free(elapsed);
 
     xkb_context_unref(ctx);
     return 0;
index 16f2bf5..650ccf3 100644 (file)
@@ -24,6 +24,7 @@
 #include <time.h>
 
 #include "../test/test.h"
+#include "bench.h"
 
 #define BENCHMARK_ITERATIONS 2500
 
@@ -32,7 +33,8 @@ main(int argc, char *argv[])
 {
     struct xkb_context *ctx;
     struct xkb_keymap *keymap;
-    struct timespec start, stop, elapsed;
+    struct bench_timer timer;
+    char *elapsed;
     int i;
 
     ctx = test_get_context(0);
@@ -41,23 +43,20 @@ main(int argc, char *argv[])
     xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
     xkb_context_set_log_verbosity(ctx, 0);
 
-    clock_gettime(CLOCK_MONOTONIC, &start);
+    bench_timer_reset(&timer);
+
+    bench_timer_start(&timer);
     for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
         keymap = test_compile_rules(ctx, "evdev", "evdev", "us", "", "");
         assert(keymap);
         xkb_keymap_unref(keymap);
     }
-    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--;
-    }
+    bench_timer_stop(&timer);
 
-    fprintf(stderr, "compiled %d keymaps in %ld.%09lds\n",
-            BENCHMARK_ITERATIONS, elapsed.tv_sec, elapsed.tv_nsec);
+    elapsed = bench_timer_get_elapsed_time_str(&timer);
+    fprintf(stderr, "compiled %d keymaps in %ss\n",
+            BENCHMARK_ITERATIONS, elapsed);
+    free(elapsed);
 
     xkb_context_unref(ctx);
     return 0;
index 57e3fde..671dca0 100644 (file)
@@ -109,6 +109,7 @@ AC_CHECK_LIB(rt, clock_gettime,
     [AC_SUBST(RT_LIBS, "-lrt")],
     [AC_SUBST(RT_LIBS, "")],
     [-lrt])
+AC_CHECK_FUNCS([clock_gettime])
 
 # Define a configuration option for the XKB config root
 xkb_base=`$PKG_CONFIG --variable=xkb_base xkeyboard-config`