genode/repos/os/src/test/blk/bench/main.cc

161 lines
3.4 KiB
C++

#include <base/allocator_avl.h>
#include <block_session/connection.h>
#include <os/server.h>
#include <timer_session/connection.h>
#include <libc/component.h>
#include <stdio.h>
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:
typedef Genode::size_t size_t;
Allocator_avl _alloc{env()->heap() };
Block::Connection _session { &_alloc, TX_BUFFER };
Timer::Connection _timer;
Signal_rpc_member<Throughput> _disp_ack;
Signal_rpc_member<Throughput> _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;
if (_read_done && (_write_done || !TEST_WRITE))
return;
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())
error("packet error: block: ", p.block_number(), " "
"count: ", 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 %lu 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);
warning("block count ", _blk_count, " size ", _blk_size);
log("read/write ", TEST_SIZE / 1024, " KB ...");
_start = _timer.elapsed_ms();
_submit();
}
};
struct Test::Main
{
Main(Server::Entrypoint &ep)
{
new (env()->heap()) Throughput(ep);
}
};
void Libc::Component::construct(Genode::Env &env)
{
static Test::Main server(env.ep());
}