diff --git a/os/run/ahci_bench.run b/os/run/ahci_bench.run new file mode 100644 index 000000000..745fd28b8 --- /dev/null +++ b/os/run/ahci_bench.run @@ -0,0 +1,66 @@ +# +# Build +# + +build { + core init + drivers/timer + drivers/ahci + drivers/platform +} + +create_boot_directory + + +# +# Config +# + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + + +# +# Boot modules +# + +build_boot_image { + core init + timer + platform_drv + ahci_bench +} + +run_genode_until forever + +# vi: set ft=tcl : diff --git a/os/src/drivers/ahci/exynos5/bench/main.cc b/os/src/drivers/ahci/exynos5/bench/main.cc new file mode 100644 index 000000000..1cd89091f --- /dev/null +++ b/os/src/drivers/ahci/exynos5/bench/main.cc @@ -0,0 +1,193 @@ +/* + * \brief SATA benchmark for Exynos5 platform + * \author Martin Stein + * \date 2012-06-05 + */ + +/* + * Copyright (C) 2012-2013 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 + +/* local includes */ +#include + + +struct Operation +{ + virtual void operator () (Block::Driver &driver, + Genode::addr_t block_number, + Genode::size_t block_count, + Genode::addr_t buffer_phys, + char *buffer_virt) = 0; +}; + + +/* + * \param total_size total number of bytes to read + * \param request_size number of bytes per request + */ +static void run_benchmark(Block::Driver &driver, + Timer::Session &timer, + char *buffer_virt, + Genode::addr_t buffer_phys, + Genode::size_t buffer_size, + Genode::size_t request_size, + Operation &operation) +{ + using namespace Genode; + + /* + * The goal is to get a test that took 2 s < time < 2.3 s, + * thus we start with count = 32 and then adjust the count + * for a retry if the test time is not in range. + */ + unsigned bytes = 64 * request_size; + unsigned ms = 0; + while (1) + { + /* calculate test parameters */ + if (bytes > buffer_size) { + PERR("undersized buffer %u, need %u", buffer_size, bytes); + while (1) ; + } + size_t num_requests = bytes / request_size; + + /* do measurement */ + size_t const time_before_ms = timer.elapsed_ms(); + for (size_t i = 0; i < num_requests; i++) + { + size_t const block_count = request_size / driver.block_size(); + addr_t const block_number = i*block_count; + + operation(driver, block_number, block_count, + buffer_phys + i*request_size, + buffer_virt + i*request_size); + } + /* read results */ + size_t const time_after_ms = timer.elapsed_ms(); + ms = time_after_ms - time_before_ms; + + /* + * leave or adjust transfer amount according to measured time + * + * FIXME implement static inertia + */ + if (ms < 2000 || ms >= 2300) { + bytes = (((float) 2150 / ms) * bytes); + bytes &= 0xfffffe00; /* align to 512 byte blocks */ + printf("retry with %u B\n", bytes); + } else break; + } + /* convert and print results */ + float const mb = ((float)bytes / 1000) / 1000; + unsigned const mb_left = mb; + unsigned const mb_right = 1000 * ((float)mb - mb_left); + float const sec = (float)ms / 1000; + unsigned const sec_left = sec; + unsigned const sec_right = 1000 * ((float)sec - sec_left); + float const mb_per_sec = (float)mb / sec; + unsigned const mb_per_sec_left = mb_per_sec; + unsigned const mb_per_sec_right = 1000 * ((float)mb_per_sec + - mb_per_sec_left); + PLOG(" %10u %10u %10u.%03u %u.%03u %10u.%03u", request_size, bytes, + mb_left, mb_right, sec_left, sec_right, mb_per_sec_left, + mb_per_sec_right); +} + + +int main(int argc, char **argv) +{ + using namespace Genode; + + printf("AHCI bench\n"); + printf("==========\n"); + printf("\n"); + + static Ahci_driver driver; + + static Timer::Connection timer; + + long const request_sizes[] = { + 1048576, 262144, 16384, 8192, 4096, 2048, 1024, 512, 0 }; + + /* total size of communication buffer */ + size_t const buffer_size = 600*1024*1024; + + /* allocate read/write buffer */ + static Attached_ram_dataspace buffer(env()->ram_session(), buffer_size, + false); + char * const buffer_virt = buffer.local_addr(); + addr_t const buffer_phys = Dataspace_client(buffer.cap()).phys_addr(); + + /* + * Benchmark reading from SATA device + */ + + printf("read\n"); + printf("~~~~\n"); + printf("\n"); + printf("bytes/block bytes MB sec MB/sec\n"); + printf("--------------------------------------------------------------\n"); + + struct Read : Operation + { + void operator () (Block::Driver &driver, + addr_t number, size_t count, addr_t phys, char *virt) + { + if (driver.dma_enabled()) + driver.read_dma(number, count, phys); + else + driver.read(number, count, virt); + } + } read_operation; + + for (unsigned i = 0; request_sizes[i]; i++) + run_benchmark(driver, timer, buffer_virt, buffer_phys, buffer_size, + request_sizes[i], read_operation); + + /* + * Benchmark writing to SATA device + * + * We write back the content of the buffer, which we just filled during the + * read benchmark. If both read and write succeed, the SATA device + * will retain its original content. + */ + + printf("\n"); + printf("write\n"); + printf("~~~~~\n"); + printf("\n"); + printf("bytes/block bytes MB sec MB/sec\n"); + printf("--------------------------------------------------------------\n"); + + struct Write : Operation + { + void operator () (Block::Driver &driver, + addr_t number, size_t count, addr_t phys, char *virt) + { + if (driver.dma_enabled()) + driver.write_dma(number, count, phys); + else + driver.write(number, count, virt); + } + } write_operation; + + for (unsigned i = 0; request_sizes[i]; i++) + run_benchmark(driver, timer, buffer_virt, buffer_phys, buffer_size, + request_sizes[i], write_operation); + + printf("\n"); + printf("benchmark finished\n"); + sleep_forever(); + return 0; +} diff --git a/os/src/drivers/ahci/exynos5/bench/target.mk b/os/src/drivers/ahci/exynos5/bench/target.mk new file mode 100644 index 000000000..19745512c --- /dev/null +++ b/os/src/drivers/ahci/exynos5/bench/target.mk @@ -0,0 +1,6 @@ +TARGET = ahci_bench +REQUIRES = exynos5 +SRC_CC = main.cc ahci_driver.cc +LIBS = base +INC_DIR += $(PRG_DIR)/.. $(PRG_DIR)/../.. +vpath ahci_driver.cc $(PRG_DIR)/..