mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-23 21:08:00 +00:00
0cbd1d1b7c
Fix #3956
168 lines
5.0 KiB
C++
168 lines
5.0 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;
|
|
Platform::Connection platform { 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, platform };
|
|
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 &);
|
|
};
|