161 lines
3.4 KiB
C++
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());
|
|
}
|