diff --git a/repos/libports/run/memcpy.run b/repos/libports/run/memcpy.run
new file mode 100644
index 0000000000..ec345adfe8
--- /dev/null
+++ b/repos/libports/run/memcpy.run
@@ -0,0 +1,76 @@
+if { [get_cmd_switch --autopilot] } {
+ if {[have_include "power_on/qemu"]} {
+ puts "\nRun script does not support Qemu.\n"
+ exit 0
+ }
+}
+
+build "core init test/memcpy"
+
+create_boot_directory
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image {
+ core init test-memcpy
+ ld.lib.so libc.lib.so vfs.lib.so
+}
+
+append qemu_args " -nographic "
+
+proc run_test {name serial_id} {
+ run_genode_until "start $name.*\n" 20 $serial_id
+ set t1 [clock milliseconds]
+ run_genode_until "finished $name.*\n" 180 $serial_id
+ set t2 [clock milliseconds]
+ return [expr {$t2 - $t1}]
+}
+
+run_genode_until "Memcpy testsuite started.*\n" 60
+set serial_id [output_spawn_id]
+set byte_dur [run_test "bytewise memcpy" $serial_id]
+set genode_dur [run_test "Genode memcpy" $serial_id]
+set libc_cpy_dur [run_test "libc memcpy" $serial_id]
+set libc_set_dur [run_test "libc memset" $serial_id]
+set uncached_wr_dur [run_test "Genode memcpy" $serial_id]
+set uncached_rd_dur [run_test "Genode memcpy" $serial_id]
+puts "bytewise: copied 8 GB in $byte_dur milliseconds ([expr {8192000 / $byte_dur}] MiB/sec)"
+puts "memcpy: copied 8 GB in $genode_dur milliseconds ([expr {8192000 / $genode_dur}] MiB/sec)"
+puts "libc memcpy: copied 8 GB in $libc_cpy_dur milliseconds ([expr {8192000 / $libc_cpy_dur}] MiB/sec)"
+puts "libc memset: copied 8 GB in $libc_set_dur milliseconds ([expr {8192000 / $libc_set_dur}] MiB/sec)"
+puts "memcpy (uncached write): copied 8 GB in $uncached_wr_dur milliseconds ([expr {8192000 / $uncached_wr_dur}] MiB/sec)"
+puts "memcpy (uncached read): copied 8 GB in $uncached_rd_dur milliseconds ([expr {8192000 / $uncached_rd_dur}] MiB/sec)"
+exit 0
+
+#
+# Linux baseline measurements
+#
+
+# Raspberry Pi 1
+# bytewise memcpy: copied 8388608 KiB in 93390210 usecs (87 MiB/sec)
+# libc memcpy: copied 8388608 KiB in 6238602 usecs (1313 MiB/sec)
+# libc memset: copied 8388608 KiB in 6023324 usecs (1360 MiB/sec)
diff --git a/repos/libports/src/test/memcpy/linux/Makefile b/repos/libports/src/test/memcpy/linux/Makefile
new file mode 100644
index 0000000000..ec714bf749
--- /dev/null
+++ b/repos/libports/src/test/memcpy/linux/Makefile
@@ -0,0 +1,7 @@
+INC_DIR = $(PWD)/..
+
+memcpy: main.cc $(INC_DIR)/memcpy.h
+ g++ -I$(INC_DIR) -O2 -Wall -Wextra -Weffc++ -std=gnu++11 $< -o $@
+
+clean:
+ rm -f *~ memcpy
diff --git a/repos/libports/src/test/memcpy/linux/main.cc b/repos/libports/src/test/memcpy/linux/main.cc
new file mode 100644
index 0000000000..b8872f33dd
--- /dev/null
+++ b/repos/libports/src/test/memcpy/linux/main.cc
@@ -0,0 +1,85 @@
+#include
+#include
+
+#include "memcpy.h"
+
+struct Duration { unsigned long usecs; };
+
+
+struct Time
+{
+ timespec _timespec { 0, 0 };
+
+ Time()
+ {
+ clock_gettime(CLOCK_REALTIME, &_timespec);
+ }
+
+ Time(timespec timespec) : _timespec(timespec) { }
+
+ void print() const
+ {
+ printf("secs=%ld nsecs=%ld\n",
+ (long)_timespec.tv_sec, (long)_timespec.tv_nsec);
+ }
+
+ static Duration duration(Time t1, Time t2)
+ {
+ auto usecs = [&] (timespec ts) {
+ return 1000UL*1000UL*((unsigned long)ts.tv_sec % 1000UL)
+ + (unsigned long)ts.tv_nsec/1000UL; };
+
+ return Duration { usecs(t2._timespec) - usecs(t1._timespec) };
+ }
+};
+
+
+struct Test {
+
+ Time s { };
+
+ void start() { }
+
+ void finished()
+ {
+ Time e;
+ Duration duration = Time::duration(s, e);
+
+ printf("copied %ld KiB in %ld usecs ",
+ (unsigned long)TOTAL_MEM_KB, duration.usecs);
+ printf("(%ld MiB/sec)\n", (unsigned long)
+ ((float)(TOTAL_MEM_KB/1024)/((float)duration.usecs/1000000)));
+ }
+};
+
+
+struct Bytewise_test : Test
+{
+ void copy(void *dst, const void *src, size_t size) {
+ bytewise_memcpy(dst, src, size); }
+};
+
+
+struct Libc_memcpy_test : Test
+{
+ void copy(void *dst, const void *src, size_t size) {
+ memcpy(dst, src, size); }
+};
+
+
+struct Libc_memset_test : Test
+{
+ void copy(void *dst, const void *, size_t size) {
+ memset(dst, 0, size); }
+};
+
+
+int main(int, char**)
+{
+ printf("bytewise memcpy test:\n");
+ memcpy_test();
+ printf("libc memcpy test:\n");
+ memcpy_test();
+ printf("libc memset test:\n");
+ memcpy_test();
+}
diff --git a/repos/libports/src/test/memcpy/main.cc b/repos/libports/src/test/memcpy/main.cc
new file mode 100644
index 0000000000..13484e60f9
--- /dev/null
+++ b/repos/libports/src/test/memcpy/main.cc
@@ -0,0 +1,66 @@
+#include
+#include
+
+#include
+#include
+#include
+
+#include "memcpy.h"
+
+using Genode::log;
+
+struct Bytewise_test {
+
+ void start() { log("start bytewise memcpy"); }
+ void finished() { log("finished bytewise memcpy"); }
+
+ void copy(void *dst, const void *src, size_t size) {
+ bytewise_memcpy(dst, src, size); }
+};
+
+struct Genode_cpy_test {
+
+ void start() { log("start Genode memcpy"); }
+ void finished() { log("finished Genode memcpy"); }
+
+ void copy(void *dst, const void *src, size_t size) {
+ Genode::memcpy(dst, src, size); }
+};
+
+struct Libc_cpy_test {
+
+ void start() { log("start libc memcpy"); }
+ void finished() { log("finished libc memcpy"); }
+
+ void copy(void *dst, const void *src, size_t size) {
+ memcpy(dst, src, size); }
+};
+
+struct Libc_set_test {
+
+ void start() { log("start libc memset"); }
+ void finished() { log("finished libc memset"); }
+
+ void copy(void *dst, const void *, size_t size) {
+ memset(dst, 0, size); }
+};
+
+void Libc::Component::construct(Libc::Env &env)
+{
+ log("Memcpy testsuite started");
+
+ memcpy_test();
+ memcpy_test();
+ memcpy_test();
+ memcpy_test();
+
+ Genode::Attached_ram_dataspace uncached_ds(env.ram(), env.rm(),
+ BUF_SIZE, Genode::UNCACHED);
+
+ memcpy_test(uncached_ds.local_addr(),
+ nullptr, BUF_SIZE);
+ memcpy_test(nullptr, uncached_ds.local_addr(),
+ BUF_SIZE);
+
+ log("Memcpy testsuite finished");
+}
diff --git a/repos/libports/src/test/memcpy/memcpy.h b/repos/libports/src/test/memcpy/memcpy.h
new file mode 100644
index 0000000000..5d453a47dd
--- /dev/null
+++ b/repos/libports/src/test/memcpy/memcpy.h
@@ -0,0 +1,50 @@
+#include
+#include
+#include
+
+enum {
+ BUF_SIZE = 8UL*1024UL*1024UL,
+ ITERATION = 1024UL,
+ TOTAL_MEM_KB = BUF_SIZE / 1024 * ITERATION,
+};
+
+
+template
+void memcpy_test(void * dst = nullptr, void * src = nullptr,
+ size_t size = BUF_SIZE)
+{
+ void * const from_buf = src ? src : malloc(size);
+ void * const to_buf = dst ? dst : malloc(size);
+
+ Test test;
+ test.start();
+
+ for (unsigned i = 0; i < ITERATION; i++)
+ test.copy(to_buf, from_buf, BUF_SIZE);
+
+ test.finished();
+
+ if (!src) free(from_buf);
+ if (!dst) free(to_buf);
+}
+
+
+static inline void *bytewise_memcpy(void *dst, const void *src, size_t size)
+{
+ char *d = (char *)dst, *s = (char *)src;
+
+ /* copy eight byte chunks */
+ for (size_t i = size >> 3; i > 0; i--, *d++ = *s++,
+ *d++ = *s++,
+ *d++ = *s++,
+ *d++ = *s++,
+ *d++ = *s++,
+ *d++ = *s++,
+ *d++ = *s++,
+ *d++ = *s++);
+
+ /* copy left over */
+ for (size_t i = 0; i < (size & 0x7); i++, *d++ = *s++);
+
+ return dst;
+}
diff --git a/repos/libports/src/test/memcpy/target.mk b/repos/libports/src/test/memcpy/target.mk
new file mode 100644
index 0000000000..0f56d703a4
--- /dev/null
+++ b/repos/libports/src/test/memcpy/target.mk
@@ -0,0 +1,3 @@
+TARGET = test-memcpy
+SRC_CC = main.cc
+LIBS += libc