genode/repos/os/src/drivers/sd_card/benchmark.h

167 lines
4.9 KiB
C++

/*
* \brief SD-card benchmark
* \author Norman Feske
* \author Martin Stein
* \date 2012-07-19
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <timer_session/connection.h>
#include <base/attached_ram_dataspace.h>
#include <base/attached_rom_dataspace.h>
/* local includes */
#include <driver.h>
using namespace Genode;
struct Benchmark
{
using Packet_descriptor = Block::Packet_descriptor;
struct Block_operation_failed : Exception { };
enum Operation { READ, WRITE };
struct Driver_session : Block::Driver_session_base
{
Signal_transmitter sig;
unsigned long nr_of_acks { 0 };
Driver_session(Signal_context_capability sig) : sig(sig) { }
void ack_packet(Packet_descriptor &, bool success) override
{
if (!success) {
throw Block_operation_failed(); }
nr_of_acks++;
sig.submit();
}
};
Env &env;
Attached_rom_dataspace config { env, "config" };
Packet_descriptor pkt { };
uint64_t time_before_ms { };
Timer::Connection timer { env };
Operation operation { READ };
Signal_handler<Benchmark> ack_handler { env.ep(), *this, &Benchmark::update_state };
Driver_session drv_session { ack_handler };
Sd_card::Driver drv { env };
size_t const buf_size_kib { config.xml().attribute_value("buffer_size_kib",
(size_t)0) };
size_t const buf_size { buf_size_kib * 1024 };
Attached_ram_dataspace buf { env.ram(), env.rm(), buf_size, UNCACHED };
char *buf_virt { buf.local_addr<char>() };
addr_t buf_phys { Dataspace_client(buf.cap())
.phys_addr() };
size_t buf_off_done { 0 };
size_t buf_off_pend { 0 };
unsigned req_size_id { 0 };
size_t req_sizes[9] { 512, 1024, 1024 * 2, 1024 * 4,
1024 * 8, 1024 * 16, 1024 * 32,
1024 * 64, 1024 * 128 };
size_t req_size() const { return req_sizes[req_size_id]; }
void update_state()
{
/* raise done counter and check if the buffer is full */
buf_off_done += drv_session.nr_of_acks * req_size();
drv_session.nr_of_acks = 0;
if (buf_off_done == buf_size) {
/* print stats for the current request size */
uint64_t const time_after_ms = timer.elapsed_ms();
uint64_t const duration_ms = time_after_ms - time_before_ms;
size_t const kib_per_sec = (1000 * buf_size_kib) /
duration_ms;
log(" duration: ", duration_ms, " ms");
log(" amount: ", buf_size_kib, " KiB");
log(" throughput: ", kib_per_sec, " KiB/sec");
/* go to next request size */
buf_off_pend = 0;
buf_off_done = 0;
req_size_id++;
/* check if we have done all request sizes for an operation */
if (req_size_id == sizeof(req_sizes)/sizeof(req_sizes[0])) {
/* go to next operation or end the test */
log("");
req_size_id = 0;
switch (operation) {
case READ:
operation = WRITE;
log("-- writing to SD card --");
break;
case WRITE:
log("--- SD card benchmark finished ---");
return;
}
}
log(" request size ", req_size(), " bytes");
time_before_ms = timer.elapsed_ms();
}
/* issue as many requests for the current request size as possible */
try {
size_t const block_size = drv.info().block_size;
size_t const cnt = req_size() / block_size;
for (; buf_off_pend < buf_size; buf_off_pend += req_size()) {
/* calculate block offset */
addr_t const nr = buf_off_pend / block_size;
if (drv.dma_enabled()) {
/* request with DMA */
addr_t const phys = buf_phys + buf_off_pend;
switch (operation) {
case READ: drv.read_dma(nr, cnt, phys, pkt); break;
case WRITE: drv.write_dma(nr, cnt, phys, pkt); break; }
} else {
/* request without DMA */
char *const virt = buf_virt + buf_off_pend;
switch (operation) {
case READ: drv.read(nr, cnt, virt, pkt); break;
case WRITE: drv.write(nr, cnt, virt, pkt); break; }
}
}
} catch (Block::Driver::Request_congestion) { }
}
Benchmark(Env &env) : env(env)
{
log("");
log("--- SD card benchmark (", drv.dma_enabled() ? "with" : "no", " DMA) ---");
drv.session(&drv_session);
/* start issuing requests */
log("");
log("-- reading from SD card --");
log(" request size ", req_size(), " bytes");
time_before_ms = timer.elapsed_ms();
update_state();
}
private:
/*
* Noncopyable
*/
Benchmark(Benchmark const &);
Benchmark &operator = (Benchmark const &);
};