test for measuring memcpy throughput (fix #3016)

This commit is contained in:
Norman Feske 2018-09-19 16:00:28 +02:00 committed by Christian Helmuth
parent c2d85ff554
commit f21493272d
6 changed files with 287 additions and 0 deletions

View File

@ -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 {
<config>
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route> <any-service> <parent/> </any-service> </default-route>
<default caps="200"/>
<start name="test-memcpy">
<resource name="RAM" quantum="32M"/>
<config>
<vfs> <dir name="dev"> <log/> <null/> </dir> </vfs>
<libc stdout="/dev/log" stderr="/dev/log" socket="/socket"/>
</config>
</start>
</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)

View File

@ -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

View File

@ -0,0 +1,85 @@
#include <time.h>
#include <string.h>
#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<Bytewise_test>();
printf("libc memcpy test:\n");
memcpy_test<Libc_memcpy_test>();
printf("libc memset test:\n");
memcpy_test<Libc_memset_test>();
}

View File

@ -0,0 +1,66 @@
#include <stdio.h>
#include <string.h>
#include <base/attached_ram_dataspace.h>
#include <libc/component.h>
#include <util/string.h>
#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<Bytewise_test>();
memcpy_test<Genode_cpy_test>();
memcpy_test<Libc_cpy_test>();
memcpy_test<Libc_set_test>();
Genode::Attached_ram_dataspace uncached_ds(env.ram(), env.rm(),
BUF_SIZE, Genode::UNCACHED);
memcpy_test<Genode_cpy_test>(uncached_ds.local_addr<void>(),
nullptr, BUF_SIZE);
memcpy_test<Genode_cpy_test>(nullptr, uncached_ds.local_addr<void>(),
BUF_SIZE);
log("Memcpy testsuite finished");
}

View File

@ -0,0 +1,50 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
enum {
BUF_SIZE = 8UL*1024UL*1024UL,
ITERATION = 1024UL,
TOTAL_MEM_KB = BUF_SIZE / 1024 * ITERATION,
};
template <typename Test>
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;
}

View File

@ -0,0 +1,3 @@
TARGET = test-memcpy
SRC_CC = main.cc
LIBS += libc