151 lines
3.7 KiB
C++
151 lines
3.7 KiB
C++
/*
|
|
* \brief Benchmark for block connection
|
|
* \author Sebastian Sumpf
|
|
* \author Stefan Kalkowski
|
|
* \date 2015-03-24
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2015-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.
|
|
*/
|
|
|
|
#include <base/allocator_avl.h>
|
|
#include <base/component.h>
|
|
#include <base/heap.h>
|
|
#include <base/log.h>
|
|
#include <block_session/connection.h>
|
|
#include <timer_session/connection.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
|
|
};
|
|
|
|
|
|
class Throughput
|
|
{
|
|
private:
|
|
|
|
typedef Genode::size_t size_t;
|
|
|
|
Env & _env;
|
|
Heap _heap { _env.ram(), _env.rm() };
|
|
Allocator_avl _alloc { &_heap };
|
|
Block::Connection<> _session { _env, &_alloc, TX_BUFFER };
|
|
Timer::Connection _timer { _env };
|
|
|
|
Signal_handler<Throughput> _disp_ack { _env.ep(), *this,
|
|
&Throughput::_ack };
|
|
Signal_handler<Throughput> _disp_submit { _env.ep(), *this,
|
|
&Throughput::_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;
|
|
|
|
Block::Session::Info const _info { _session.info() };
|
|
size_t const _blk_size { _info.block_size };
|
|
Block::sector_t const _blk_count { _info.block_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.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 _ack()
|
|
{
|
|
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();
|
|
log(!_read_done ? "Read" : "Wrote", " ", _bytes / 1024, " KiB in ",
|
|
_stop - _start, " ms (",
|
|
((double)_bytes / (1024 * 1024)) / ((double)(_stop - _start) / 1000),
|
|
" MiB/s)");
|
|
|
|
/* start write */
|
|
if (!_read_done ) {
|
|
_read_done = true;
|
|
_start = _timer.elapsed_ms();
|
|
_bytes = 0;
|
|
_current = 0;
|
|
if (TEST_WRITE)
|
|
_submit();
|
|
else
|
|
log("Done");
|
|
} else if (!_write_done && TEST_WRITE) {
|
|
_write_done = true;
|
|
log("Done");
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
Throughput(Env & env)
|
|
: _env(env)
|
|
{
|
|
_session.tx_channel()->sigh_ack_avail(_disp_ack);
|
|
_session.tx_channel()->sigh_ready_to_submit(_disp_submit);
|
|
|
|
warning("block count ", _blk_count, " size ", _blk_size);
|
|
log("read/write ", TEST_SIZE / 1024, " KiB ...");
|
|
_start = _timer.elapsed_ms();
|
|
_submit();
|
|
}
|
|
};
|
|
|
|
|
|
void Component::construct(Env &env) { static Throughput test(env); }
|