You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2013/07/31 14:38:17 UTC

[lucy-commits] git commit: refs/heads/master - Micro-benchmark for various types of method dispatch

Updated Branches:
  refs/heads/master 5959e9c81 -> 4f9384ae6


Micro-benchmark for various types of method dispatch


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/4f9384ae
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/4f9384ae
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/4f9384ae

Branch: refs/heads/master
Commit: 4f9384ae69503c2f899abcb3644971a8da546509
Parents: 5959e9c
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Wed Jul 31 14:37:30 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Wed Jul 31 14:37:30 2013 +0200

----------------------------------------------------------------------
 .../devel/benchmarks/method_dispatch/.gitignore |   3 +
 .../benchmarks/method_dispatch/Makefile.darwin  |  16 ++
 .../benchmarks/method_dispatch/Makefile.linux   |  16 ++
 .../devel/benchmarks/method_dispatch/dso.c      |  51 ++++++
 .../devel/benchmarks/method_dispatch/dso.h      |  18 ++
 .../devel/benchmarks/method_dispatch/exe.c      | 166 +++++++++++++++++++
 clownfish/devel/benchmarks/method_dispatch/oo.h |  24 +++
 7 files changed, 294 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/4f9384ae/clownfish/devel/benchmarks/method_dispatch/.gitignore
----------------------------------------------------------------------
diff --git a/clownfish/devel/benchmarks/method_dispatch/.gitignore b/clownfish/devel/benchmarks/method_dispatch/.gitignore
new file mode 100644
index 0000000..a82daf4
--- /dev/null
+++ b/clownfish/devel/benchmarks/method_dispatch/.gitignore
@@ -0,0 +1,3 @@
+dso.dylib
+dso.so
+exe

http://git-wip-us.apache.org/repos/asf/lucy/blob/4f9384ae/clownfish/devel/benchmarks/method_dispatch/Makefile.darwin
----------------------------------------------------------------------
diff --git a/clownfish/devel/benchmarks/method_dispatch/Makefile.darwin b/clownfish/devel/benchmarks/method_dispatch/Makefile.darwin
new file mode 100644
index 0000000..6ee18c5
--- /dev/null
+++ b/clownfish/devel/benchmarks/method_dispatch/Makefile.darwin
@@ -0,0 +1,16 @@
+CFLAGS = -std=gnu99 -Wextra -O2 -fomit-frame-pointer -DHAS_ALIAS
+
+all : bench
+
+dso.dylib : dso.c dso.h oo.h
+		gcc $(CFLAGS) -Wl,-alias,_thunk3,_Obj_Hello_THUNK -shared dso.c -o $@
+
+exe : exe.c dso.h oo.h dso.dylib
+		gcc $(CFLAGS) exe.c dso.dylib -o $@
+
+bench : exe
+		./exe
+
+clean :
+		rm -f dso.dylib exe
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/4f9384ae/clownfish/devel/benchmarks/method_dispatch/Makefile.linux
----------------------------------------------------------------------
diff --git a/clownfish/devel/benchmarks/method_dispatch/Makefile.linux b/clownfish/devel/benchmarks/method_dispatch/Makefile.linux
new file mode 100644
index 0000000..8938e60
--- /dev/null
+++ b/clownfish/devel/benchmarks/method_dispatch/Makefile.linux
@@ -0,0 +1,16 @@
+CFLAGS = -std=gnu99 -Wextra -O2 -fomit-frame-pointer
+
+all : bench
+
+dso.so : dso.c dso.h oo.h
+	gcc $(CFLAGS) -shared -fPIC dso.c -o $@
+
+exe : exe.c dso.h oo.h dso.so
+	gcc $(CFLAGS) -fPIE exe.c dso.so -o $@
+
+bench : exe
+	LD_LIBRARY_PATH=. ./exe
+
+clean :
+	rm -f dso.so exe
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/4f9384ae/clownfish/devel/benchmarks/method_dispatch/dso.c
----------------------------------------------------------------------
diff --git a/clownfish/devel/benchmarks/method_dispatch/dso.c b/clownfish/devel/benchmarks/method_dispatch/dso.c
new file mode 100644
index 0000000..2cb9f20
--- /dev/null
+++ b/clownfish/devel/benchmarks/method_dispatch/dso.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dso.h"
+
+static void Obj_hello(obj_t *obj);
+
+void thunk3(obj_t *obj);
+
+class_t *OBJ;
+size_t Obj_Hello_OFFSET;
+method_t Obj_Hello_THUNK_PTR;
+
+void
+bootstrap() {
+    size_t method_idx = 3;
+    size_t class_size = offsetof(class_t, vtable)
+                        + (method_idx + 1) * sizeof(method_t);
+
+    OBJ = (class_t*)calloc(1, class_size);
+
+    OBJ->name       = "Obj";
+    OBJ->class_size = class_size;
+
+    Obj_Hello_OFFSET = offsetof(class_t, vtable)
+                       + method_idx * sizeof(method_t);
+    OBJ->vtable[method_idx] = Obj_hello;
+    Obj_Hello_THUNK_PTR = thunk3;
+}
+
+obj_t*
+Obj_new() {
+    obj_t *self = (obj_t *)malloc(sizeof(obj_t));
+
+    self->refcount = 1;
+    self->klass    = OBJ;
+    self->value    = 0;
+
+    return self;
+}
+
+static void
+Obj_hello(obj_t *obj) {
+    ++obj->value;
+}
+
+void
+thunk3(obj_t *obj) {
+    obj->klass->vtable[3](obj);
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/4f9384ae/clownfish/devel/benchmarks/method_dispatch/dso.h
----------------------------------------------------------------------
diff --git a/clownfish/devel/benchmarks/method_dispatch/dso.h b/clownfish/devel/benchmarks/method_dispatch/dso.h
new file mode 100644
index 0000000..f69aaed
--- /dev/null
+++ b/clownfish/devel/benchmarks/method_dispatch/dso.h
@@ -0,0 +1,18 @@
+#ifndef DSO_H
+#define DSO_H
+
+#include "oo.h"
+
+extern class_t *OBJ;
+extern size_t Obj_Hello_OFFSET;
+extern method_t Obj_Hello_THUNK_PTR;
+#define Obj_Hello_FIXED_OFFSET (5 * sizeof(void*))
+
+void bootstrap();
+
+obj_t *Obj_new(void);
+
+void Obj_Hello_THUNK(obj_t *obj);
+
+#endif /* DSO_H */
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/4f9384ae/clownfish/devel/benchmarks/method_dispatch/exe.c
----------------------------------------------------------------------
diff --git a/clownfish/devel/benchmarks/method_dispatch/exe.c b/clownfish/devel/benchmarks/method_dispatch/exe.c
new file mode 100644
index 0000000..4e0b5d6
--- /dev/null
+++ b/clownfish/devel/benchmarks/method_dispatch/exe.c
@@ -0,0 +1,166 @@
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "dso.h"
+
+#define CPUFREQ    UINT64_C(2800000000)
+#define NOINLINE   __attribute__ ((noinline))
+uint64_t iterations;
+#define ITERATIONS iterations
+
+static inline method_t
+Obj_Hello_PTR(obj_t *obj) {
+    class_t *klass = obj->klass;
+    return *(method_t*)((char*)klass + Obj_Hello_OFFSET);
+}
+
+static inline void
+Obj_Hello(obj_t *obj) {
+    class_t *klass = obj->klass;
+    method_t method = *(method_t*)((char*)klass + Obj_Hello_OFFSET);
+    method(obj);
+}
+
+static inline void
+Obj_Hello_FIXED(obj_t *obj) {
+    class_t *klass = obj->klass;
+    method_t method = *(method_t*)((char*)klass + Obj_Hello_FIXED_OFFSET);
+    method(obj);
+}
+
+void
+loop_with_method_ptr(obj_t *obj) {
+    method_t method = Obj_Hello_PTR(obj);
+
+    for (uint64_t i = 0; i < ITERATIONS; ++i) {
+        method(obj);
+    }
+}
+
+void
+loop_with_wrapper(obj_t *obj) {
+    for (uint64_t i = 0; i < ITERATIONS; ++i) {
+        Obj_Hello(obj);
+    }
+}
+
+void
+loop_with_fixed_offset_wrapper(obj_t *obj) {
+    for (uint64_t i = 0; i < ITERATIONS; ++i) {
+        Obj_Hello_FIXED(obj);
+    }
+}
+
+#ifdef HAS_ALIAS
+void
+loop_with_thunk(obj_t *obj) {
+    for (uint64_t i = 0; i < ITERATIONS; ++i) {
+        Obj_Hello_THUNK(obj);
+    }
+}
+
+void
+loop_with_thunk_ptr(obj_t *obj) {
+    for (uint64_t i = 0; i < ITERATIONS; ++i) {
+        Obj_Hello_THUNK_PTR(obj);
+    }
+}
+#endif
+
+NOINLINE void
+single_call_with_wrapper(obj_t *obj) {
+    Obj_Hello(obj);
+}
+
+void
+call_with_wrapper(obj_t *obj) {
+    for (uint64_t i = 0; i < ITERATIONS; ++i) {
+        single_call_with_wrapper(obj);
+    }
+}
+
+#ifdef HAS_ALIAS
+NOINLINE void
+single_call_with_thunk(obj_t *obj) {
+    Obj_Hello_THUNK(obj);
+}
+
+void
+call_with_thunk_ptr(obj_t *obj) {
+    for (uint64_t i = 0; i < ITERATIONS; ++i) {
+        single_call_with_thunk(obj);
+    }
+}
+
+NOINLINE void
+single_call_with_thunk_ptr(obj_t *obj) {
+    Obj_Hello_THUNK_PTR(obj);
+}
+
+void
+call_with_thunk(obj_t *obj) {
+    for (uint64_t i = 0; i < ITERATIONS; ++i) {
+        single_call_with_thunk(obj);
+    }
+}
+#endif
+
+void
+loop_with_simulated_inline(obj_t *obj) {
+    for (uint64_t i = 0; i < ITERATIONS; ++i) {
+        obj->value++;
+    }
+}
+
+static void
+bench(method_t fn, const char *name) {
+    obj_t *obj = Obj_new();
+
+    struct timeval t0;
+    gettimeofday(&t0, NULL);
+
+    fn(obj);
+
+    struct timeval t1;
+    gettimeofday(&t1, NULL);
+
+    if (obj->value != ITERATIONS) {
+        fprintf(stderr, "Unexpected obj->value: %" PRIu64 "\n", obj->value);
+        abort();
+    }
+
+    uint64_t usec = (uint64_t)(t1.tv_sec - t0.tv_sec) * 1000000
+                    + (t1.tv_usec - t0.tv_usec);
+    printf("cycles/call with %s: %f\n", name,
+           ((double)usec * CPUFREQ) / (1000000.0 * ITERATIONS));
+}
+
+int
+main(int argc, char **argv) {
+    if (argc > 1) {
+        iterations = strtoll(argv[1], NULL, 10);
+    }
+    else {
+        iterations = UINT64_C(1000000000);
+    }
+    bootstrap();
+
+    bench(loop_with_method_ptr, "method ptr loop");
+    bench(loop_with_wrapper, "wrapper loop");
+    bench(loop_with_fixed_offset_wrapper, "fixed offset wrapper loop");
+#ifdef HAS_ALIAS
+    bench(loop_with_thunk, "thunk loop");
+    bench(loop_with_thunk_ptr, "thunk ptr loop");
+#endif
+    bench(call_with_wrapper, "wrapper");
+#ifdef HAS_ALIAS
+    bench(call_with_thunk, "thunk");
+    bench(call_with_thunk_ptr, "thunk ptr");
+#endif
+    bench(loop_with_simulated_inline, "simulated inline");
+
+    return 0;
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/4f9384ae/clownfish/devel/benchmarks/method_dispatch/oo.h
----------------------------------------------------------------------
diff --git a/clownfish/devel/benchmarks/method_dispatch/oo.h b/clownfish/devel/benchmarks/method_dispatch/oo.h
new file mode 100644
index 0000000..a08e843
--- /dev/null
+++ b/clownfish/devel/benchmarks/method_dispatch/oo.h
@@ -0,0 +1,24 @@
+#ifndef OO_H
+#define OO_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct class_t class_t;
+
+typedef struct obj_t {
+    size_t    refcount;
+    class_t  *klass;
+    uint64_t  value;
+} obj_t;
+
+typedef void (*method_t)(obj_t *obj);
+
+struct class_t {
+    char     *name;
+    size_t    class_size;
+    method_t  vtable[1];
+};
+
+#endif /* OO_H */
+