2015-03-24 15:48:46 +01:00
|
|
|
#include <base/allocator_avl.h>
|
|
|
|
#include <block_session/connection.h>
|
|
|
|
#include <os/server.h>
|
|
|
|
#include <timer_session/connection.h>
|
2016-12-22 15:01:19 +01:00
|
|
|
#include <libc/component.h>
|
2015-03-24 15:48:46 +01:00
|
|
|
|
|
|
|
#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:
|
|
|
|
|
2016-09-15 14:40:37 +02:00
|
|
|
typedef Genode::size_t size_t;
|
|
|
|
|
2015-03-24 15:48:46 +01:00
|
|
|
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;
|
|
|
|
|
2015-12-16 14:49:27 +01:00
|
|
|
if (_read_done && (_write_done || !TEST_WRITE))
|
|
|
|
return;
|
|
|
|
|
2015-03-24 15:48:46 +01:00
|
|
|
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())
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
error("packet error: block: ", p.block_number(), " "
|
|
|
|
"count: ", p.block_count());
|
2015-03-24 15:48:46 +01:00
|
|
|
|
|
|
|
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();
|
2016-09-15 14:40:37 +02:00
|
|
|
::printf("%s %lu KB in %lu ms (%.02f MB/s)\n",
|
2015-03-24 15:48:46 +01:00
|
|
|
!_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);
|
|
|
|
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
warning("block count ", _blk_count, " size ", _blk_size);
|
|
|
|
log("read/write ", TEST_SIZE / 1024, " KB ...");
|
2015-03-24 15:48:46 +01:00
|
|
|
_start = _timer.elapsed_ms();
|
|
|
|
_submit();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Test::Main
|
|
|
|
{
|
|
|
|
Main(Server::Entrypoint &ep)
|
|
|
|
{
|
|
|
|
new (env()->heap()) Throughput(ep);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-12-22 15:01:19 +01:00
|
|
|
void Libc::Component::construct(Genode::Env &env)
|
|
|
|
{
|
|
|
|
static Test::Main server(env.ep());
|
2015-03-24 15:48:46 +01:00
|
|
|
}
|