diff --git a/repos/os/run/fb_bench.run b/repos/os/run/fb_bench.run
new file mode 100644
index 0000000000..8ee7c6276b
--- /dev/null
+++ b/repos/os/run/fb_bench.run
@@ -0,0 +1,89 @@
+#
+# Build
+#
+
+if {[have_spec hw_odroid_xu]} {
+ puts "Run script not supported for this platform."; exit 0 }
+
+set build_components { core init test/fb_bench drivers/framebuffer drivers/timer }
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+append_platform_drv_build_components
+
+build $build_components
+
+create_boot_directory
+
+#
+# Generate config
+#
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_if [have_spec sdl] config {
+
+
+
+
+
+
+ }
+
+append_platform_drv_config
+
+append_if [have_spec framebuffer] config {
+
+
+
+ }
+
+append config {
+
+
+
+}
+
+install_config $config
+
+#
+# Boot modules
+#
+
+# generic modules
+set boot_modules {
+ core init timer
+ test-fb_bench
+}
+
+# platform-specific modules
+append_platform_drv_boot_modules
+
+lappend_if [have_spec sdl] boot_modules fb_sdl
+lappend_if [have_spec framebuffer] boot_modules fb_drv
+
+build_boot_image $boot_modules
+
+run_genode_until forever
+
diff --git a/repos/os/src/test/fb_bench/main.cc b/repos/os/src/test/fb_bench/main.cc
new file mode 100644
index 0000000000..6039f7b250
--- /dev/null
+++ b/repos/os/src/test/fb_bench/main.cc
@@ -0,0 +1,138 @@
+/*
+ * \brief Framebuffer throughput test
+ * \author Norman Feske
+ * \date 2015-06-05
+ */
+
+/*
+ * Copyright (C) 2012-2014 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+static unsigned long now_ms()
+{
+ static Timer::Connection timer;
+ return timer.elapsed_ms();
+}
+
+
+int main(int argc, char **argv)
+{
+ using namespace Genode;
+
+ printf("--- test-fb_bench started ---\n");
+
+ static Framebuffer::Connection fb;
+
+ static Attached_dataspace fb_ds(fb.dataspace());
+ static Framebuffer::Mode const fb_mode = fb.mode();
+
+ /*
+ * Allocate two memory buffers as big as the framebuffer.
+ */
+ char *src_buf[2];
+ for (unsigned i = 0; i < 2; i++)
+ src_buf[i] = (char *)env()->heap()->alloc(fb_ds.size());
+
+ /* duration of individual test, in milliseconds */
+ unsigned long duration_ms = 2000;
+
+ printf("byte-wise memcpy from RAM to RAM...\n");
+ {
+ unsigned long transferred_kib = 0;
+ unsigned long const start_ms = now_ms();
+
+ for (; now_ms() - start_ms < duration_ms;) {
+ memcpy(src_buf[0], src_buf[1], fb_ds.size());
+ transferred_kib += fb_ds.size() / 1024;
+ }
+
+ unsigned long const end_ms = now_ms();
+
+ printf("-> %ld MiB/sec\n",
+ (transferred_kib)/(end_ms - start_ms));
+ }
+
+ /*
+ * Fill one memory buffer with white pixels.
+ */
+ memset(src_buf[1], ~0, fb_ds.size());
+
+ printf("byte-wise memcpy from RAM to framebuffer...\n");
+ {
+ unsigned long transferred_kib = 0;
+ unsigned long const start_ms = now_ms();
+
+ for (unsigned i = 0; now_ms() - start_ms < duration_ms; i++) {
+ memcpy(fb_ds.local_addr(), src_buf[i % 2], fb_ds.size());
+ transferred_kib += fb_ds.size() / 1024;
+ }
+
+ unsigned long const end_ms = now_ms();
+
+ printf("-> %ld MiB/sec\n",
+ (transferred_kib)/(end_ms - start_ms));
+ }
+
+ /*
+ * Blitting via the blit library from RAM to framebuffer
+ */
+ printf("copy via blit library from RAM to framebuffer...\n");
+ {
+ unsigned long transferred_kib = 0;
+ unsigned long const start_ms = now_ms();
+
+ /* line width in bytes */
+ unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
+ unsigned const h = fb_mode.height();
+
+ for (unsigned i = 0; now_ms() - start_ms < duration_ms; i++) {
+ blit(src_buf[i % 2], w, fb_ds.local_addr(), w, w, h);
+
+ transferred_kib += (w*h) / 1024;
+ }
+
+ unsigned long const end_ms = now_ms();
+
+ printf("-> %ld MiB/sec\n",
+ (transferred_kib)/(end_ms - start_ms));
+ }
+
+ /*
+ * Unaligned blitting via the blit library from RAM to framebuffer
+ */
+ printf("unaligned copy via blit library from RAM to framebuffer...\n");
+ {
+ unsigned long transferred_kib = 0;
+ unsigned long const start_ms = now_ms();
+
+ /* line width in bytes */
+ unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
+ unsigned const h = fb_mode.height();
+
+ for (unsigned i = 0; now_ms() - start_ms < duration_ms; i++) {
+ blit(src_buf[i % 2] + 2, w, fb_ds.local_addr() + 2, w, w - 2, h);
+
+ transferred_kib += (w*h) / 1024;
+ }
+
+ unsigned long const end_ms = now_ms();
+
+ printf("-> %ld MiB/sec\n",
+ (transferred_kib)/(end_ms - start_ms));
+ }
+
+ printf("--- test-fb_bench finished ---\n");
+ return 0;
+}
diff --git a/repos/os/src/test/fb_bench/target.mk b/repos/os/src/test/fb_bench/target.mk
new file mode 100644
index 0000000000..1ce75df66a
--- /dev/null
+++ b/repos/os/src/test/fb_bench/target.mk
@@ -0,0 +1,3 @@
+TARGET = test-fb_bench
+SRC_CC = main.cc
+LIBS = base blit