diff --git a/repos/os/run/ahci.run b/repos/os/run/ahci.run
deleted file mode 100644
index c30925e6c2..0000000000
--- a/repos/os/run/ahci.run
+++ /dev/null
@@ -1,141 +0,0 @@
-if {![have_spec x86] && ![have_spec platform_arndale]} {
- puts "\nThe AHCI driver supports x86 architecture and Arndale only\n"
- exit 0
-}
-
-#
-# Build
-#
-
-set build_components { core init drivers/timer drivers/ahci test/blk/cli }
-
-lappend_if [have_spec acpi] build_components drivers/acpi
-lappend_if [have_spec pci] build_components drivers/pci
-lappend_if [have_spec pci] build_components drivers/pci/device_pd
-lappend_if [have_spec platform_arndale] build_components drivers/platform
-
-build $build_components
-
-create_boot_directory
-
-#
-# Generate config
-#
-
-set config {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
-
-append_if [have_spec platform_arndale] config {
-
-
-
- }
-
-append_if [have_spec acpi] config {
-
-
-
-
-
-
-
-
-
-
-
- }
-
-append_if [expr ![have_spec acpi] && [have_spec pci]] config {
-
-
-
- }
-
-append config {
-
-
-
- }
-
-append_if [have_spec acpi] config {
- }
-
-append config {
-
-
-
-
-
-
-
- }
-
-append_if [have_spec acpi] config {
- }
-
-append config {
-
-
-
-
-
-
-
-
-
-
-}
-
-install_config $config
-
-#
-# Boot modules
-#
-
-set boot_modules { core init timer ahci test-blk-cli }
-
-lappend_if [have_spec pci] boot_modules pci_drv
-lappend_if [have_spec acpi] boot_modules acpi_drv
-lappend_if [have_spec nova] boot_modules pci_device_pd
-lappend_if [have_spec platform_arndale] boot_modules platform_drv
-
-build_boot_image $boot_modules
-
-#
-# Qemu
-#
-
-set disk_image "bin/block.img"
-
-append qemu_args " -m 64 -nographic "
-append qemu_args " -drive id=disk,file=$disk_image,if=none -device ahci,id=ahci -device ide-drive,drive=disk,bus=ahci.0 -boot d"
-
-if { [file exists $disk_image] == 0 } then {
- # create random block device file
- puts "creating disk image \"$disk_image\""
- catch {
- exec dd if=/dev/urandom of=$disk_image bs=512 count=20480
- }
-}
-
-#
-# Test
-#
-
-run_genode_until "Tests finished successfully.*\n" 50
diff --git a/repos/os/run/ahci_bench.run b/repos/os/run/ahci_bench.run
index cc67e7ba8a..5f2fd5b840 100644
--- a/repos/os/run/ahci_bench.run
+++ b/repos/os/run/ahci_bench.run
@@ -1,18 +1,6 @@
-#
-# Select benchmark layer
-#
-# 0: driver internal
-# 1: native Genode app
-# 2: native Genode app with partition manager
-#
-set layer 0
-
-# driver-internal benchmark is special
-if {[expr ($layer == 0)] && ![have_spec platform_arndale]} {
- puts "Driver-internal benchmark (layer 0) only supported on Arndale."
- exit 0
-}
+set mke2fs [check_installed mke2fs]
+set dd [check_installed dd]
#
# Build
@@ -22,24 +10,24 @@ set build_components {
drivers/timer
drivers/ahci
drivers/platform
+ test/blk/bench
}
-lappend_if [expr ($layer == 1 || $layer == 2)] build_components test/block_bench
-lappend_if [expr ($layer == 2)] build_components server/part_blk
-
lappend_if [have_spec acpi] build_components drivers/acpi
-lappend_if [have_spec pci] build_components drivers/pci/device_pd
lappend_if [have_spec pci] build_components drivers/pci
build $build_components
+#
+# Build EXT2-file-system image
+#
+catch { exec $dd if=/dev/zero of=bin/ext2.raw bs=1M count=16 }
+catch { exec $mke2fs -F bin/ext2.raw }
create_boot_directory
#
-# Config
+# Generate config
#
-
-# basic config for all layers
set config {
@@ -56,13 +44,13 @@ set config {
-
+
- }
-
+
+}
append_if [expr ![have_spec acpi] && ![have_spec pci]] config {
@@ -71,75 +59,56 @@ append_if [expr ![have_spec acpi] && ![have_spec pci]] config {
append_if [have_spec acpi] config {
-
+
-
- }
+
+
+
+
+
+}
append_if [expr ![have_spec acpi] && [have_spec pci]] config {
- }
-
-# start driver internal bench with layer 0
-append_if [expr $layer == 0] config {
-
-
-
- }
-
-# start part_blk with layer 2
-append_if [expr $layer == 2] config {
-
-
-
-
-
-
-
-
+
}
-# start normal AHCI driver and bench app with layer 1 or 2
-append_if [expr ($layer == 1 || $layer == 2)] config {
-
-
- }
-
-append_if [expr ($layer == 1 || $layer == 2) && [have_spec acpi]] config {
-
-
-
- }
-
-append_if [expr ($layer == 1 || $layer == 2)] config {
-
-
- }
-
-# if layer is 2 route block requests of bench app to part_blk
-append_if [expr $layer == 2] config {
-
-
-
- }
-
-# end start node of bench app if layer 1 or 2
-append_if [expr ($layer == 1 || $layer == 2)] config {
- }
-
-# end config
append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
install_config $config
@@ -147,20 +116,18 @@ install_config $config
#
# Boot modules
#
-
-set boot_modules { core init timer }
+set boot_modules { core init timer ahci_drv test-blk-bench libc.lib.so
+ ld.lib.so }
lappend_if [expr ![have_spec acpi] && ![have_spec pci]] boot_modules platform_drv
lappend_if [have_spec pci] boot_modules pci_drv
-lappend_if [have_spec pci] boot_modules pci_device_pd
+lappend_if [have_spec nova] boot_modules pci_device_pd
lappend_if [have_spec acpi] boot_modules acpi_drv
-lappend_if [expr ($layer == 0)] boot_modules ahci_bench
-lappend_if [expr ($layer == 1 || $layer == 2)] boot_modules ahci
-lappend_if [expr ($layer == 1 || $layer == 2)] boot_modules test-block_bench
-lappend_if [expr ($layer == 2)] boot_modules part_blk
-
build_boot_image $boot_modules
-run_genode_until forever
+append qemu_args " -nographic -m 256 "
+append qemu_args " -drive id=disk,file=bin/ext2.raw,if=none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -boot d"
+append qemu_args " -drive id=cd,file=[run_dir]/../ahci_bench.iso,if=none,media=cdrom -device ide-cd,drive=cd,bus=ahci.1"
+run_genode_until "Done\n" 100
diff --git a/repos/os/src/test/blk/bench/main.cc b/repos/os/src/test/blk/bench/main.cc
new file mode 100644
index 0000000000..95b8aa23e9
--- /dev/null
+++ b/repos/os/src/test/blk/bench/main.cc
@@ -0,0 +1,158 @@
+#include
+#include
+#include
+#include
+
+#include
+
+using namespace Genode;
+
+enum {
+ TEST_WRITE = false,
+ TEST_SIZE = 1024 * 1024 * 1024,
+ REQUEST_SIZE = 8 * 512,
+ TX_BUFFER = Block::Session::TX_QUEUE_SIZE * REQUEST_SIZE
+};
+
+
+namespace Test {
+ class Throughput;
+ struct Main;
+}
+
+
+class Test::Throughput
+{
+ private:
+
+ Allocator_avl _alloc{env()->heap() };
+ Block::Connection _session { &_alloc, TX_BUFFER };
+ Timer::Connection _timer;
+
+ Signal_rpc_member _disp_ack;
+ Signal_rpc_member _disp_submit;
+ bool _read_done = false;
+ bool _write_done = false;
+
+ unsigned long _start = 0;
+ unsigned long _stop = 0;
+ size_t _bytes = 0;
+ Block::sector_t _current = 0;
+
+ size_t _blk_size;
+ Block::sector_t _blk_count;
+
+ void _submit()
+ {
+ static size_t count = REQUEST_SIZE / _blk_size;
+
+ try {
+ while (_session.tx()->ready_to_submit()) {
+ Block::Packet_descriptor p(
+ _session.tx()->alloc_packet(REQUEST_SIZE),
+ !_read_done ? Block::Packet_descriptor::READ : Block::Packet_descriptor::WRITE,
+ _current, count);
+
+ _session.tx()->submit_packet(p);
+
+ /* increment for next read */
+ _current += count;
+ if (_current + count >= _blk_count)
+ _current = 0;
+ }
+ } catch (...) { }
+ }
+
+ void _ready_to_submit(unsigned)
+ {
+ _submit();
+ }
+
+ void _ack_avail(unsigned)
+ {
+ while (_session.tx()->ack_avail()) {
+
+ Block::Packet_descriptor p = _session.tx()->get_acked_packet();
+ if (!p.succeeded())
+ PERR("Packet error: block: %llu count: %zu", p.block_number(), p.block_count());
+
+ if (!_read_done || (_read_done && p.operation() == Block::Packet_descriptor::WRITE))
+ _bytes += p.size();
+
+ _session.tx()->release_packet(p);
+ }
+
+ if (_bytes >= TEST_SIZE) {
+ _finish();
+ return;
+ }
+
+ _submit();
+ }
+
+ void _finish()
+ {
+ if (_read_done && (_write_done || !TEST_WRITE))
+ return;
+
+ _stop = _timer.elapsed_ms();
+ ::printf("%s %zu KB in %lu ms (%.02f MB/s)\n",
+ !_read_done ? "Read" : "Wrote",
+ _bytes / 1024, _stop - _start,
+ ((double)_bytes / (1024 * 1024)) / ((double)(_stop - _start) / 1000));
+
+
+ /* start write */
+ if (!_read_done ) {
+ _read_done = true;
+ _start = _timer.elapsed_ms();
+ _bytes = 0;
+ _current = 0;
+ if (TEST_WRITE)
+ _submit();
+ else
+ ::printf("Done\n");
+ } else if (!_write_done && TEST_WRITE) {
+ _write_done = true;
+ ::printf("Done\n");
+ }
+ }
+
+ public:
+
+ Throughput(Server::Entrypoint &ep)
+ : _disp_ack(ep, *this, &Throughput::_ack_avail),
+ _disp_submit(ep, *this, &Throughput::_ready_to_submit)
+ {
+ _session.tx_channel()->sigh_ack_avail(_disp_ack);
+ _session.tx_channel()->sigh_ready_to_submit(_disp_submit);
+
+ Block::Session::Operations blk_ops;
+ _session.info(&_blk_count, &_blk_size, &blk_ops);
+
+ PWRN("block count %llu size %zu", _blk_count, _blk_size);
+ PINF("read/write %u KB ...", TEST_SIZE / 1024);
+ _start = _timer.elapsed_ms();
+ _submit();
+ }
+};
+
+
+struct Test::Main
+{
+ Main(Server::Entrypoint &ep)
+ {
+ new (env()->heap()) Throughput(ep);
+ }
+};
+
+
+namespace Server {
+ char const *name() { return "block_bench_ep"; };
+ size_t stack_size() { return 2*1024*sizeof(long); }
+
+ void construct(Entrypoint &ep)
+ {
+ static Test::Main server(ep);
+ }
+}
diff --git a/repos/os/src/test/blk/bench/target.mk b/repos/os/src/test/blk/bench/target.mk
new file mode 100644
index 0000000000..cfb1b61bb0
--- /dev/null
+++ b/repos/os/src/test/blk/bench/target.mk
@@ -0,0 +1,3 @@
+TARGET = test-blk-bench
+SRC_CC = main.cc
+LIBS = base server libc