genode/repos/os/src/app/block_tester
Norman Feske 2208220c12 block session: remove Block::Session::Operations
This patch modernizes the 'Block::Session::info' interface. Instead of
using out parameters, the 'init' RPC function returns a compound 'Info'
object now. The rather complicated 'Operations' struct is replaced by
a 'writeable' attribute in the 'Info' object.

Fixes #3275
2019-05-03 13:53:12 +02:00
..
main.cc block session: remove Block::Session::Operations 2019-05-03 13:53:12 +02:00
README os: add Block session tester component 2018-04-10 13:56:04 +02:00
target.mk os: add Block session tester component 2018-04-10 13:56:04 +02:00
test_ping_pong.h block session: remove Block::Session::Operations 2019-05-03 13:53:12 +02:00
test_random.h block session: remove Block::Session::Operations 2019-05-03 13:53:12 +02:00
test_replay.h block session: remove Block::Session::Operations 2019-05-03 13:53:12 +02:00
test_sequential.h block session: remove Block::Session::Operations 2019-05-03 13:53:12 +02:00

Brief
=====

This component implements various Block session tests. All block number values
are specified in terms of the underlying Block session, i.e., the start block
1024 will be at byte offset 512KiB on a 512B sector session whereas it will be
at byte offset 4MiB on a 4K sector session. All size values must be given in
sector size granularity and the request size must be at least as larger as the
sector size. The tests can be executed consecutively and a new Block connection
will be used for every test. After each test has finished the result will be
printed to the LOG session and a report will be generated that contains the
duration, the number of operations and the amount of bytes processed if the
'log' and 'report' attribute are set to 'yes'. If the 'stop_on_error' attribute
is set, the execution stops whenever a tests failes. In addition, if the
'calculate' attribute is set, the component will calculate MiB/s and I/O
operations per second for each test (this data is only meaningful in conjunction
with the other information like block size and so on).

The following list contains all available tests:

* 'replay' executes a previously recorded Block session operation sequence.

    - If the 'bulk' attribute is specified, the test will try to fill up
      the packet stream with request until it is full.

    Each request is specified by a 'request' node which has the following
    attributes:

    - The 'lba' attribute specifies the logical block address where
      the request will start and is mandatory

    - The 'count' attribute specifies the number of blocks that are processed
      in the request and is mandatory.

    - The 'type' attribute specifies the kind of the request, valid values
      are 'read' and 'write' and is mandatory.

 * 'sequential' reads or writes a given amount of bytes sequentially.

   - The 'start' attribute specifies the logical block address where the test
     begins, if it is missing the first block is used.

   - The 'length' attribute specifies how many bytes are processed,
     if it is missing the whole underlying Block session starting on the given
     start block is used.

   - The 'size' attribute specifies the size of a request, if it is missing
     the block size of the underlying Block session is used.

   - The 'write' attribute specifies whether the tests writes or reads, if
     it is missing it defaults to reading.

   - The 'skip' attribute specifies how many bytes should be skipped between
     each request.

   - The 'synchronous' attribute specifies if each request is done in a
     synchronous fashion or if the component tries to fill up the transfer
     buffer as much as possible.

 * 'ping_pong' reads or writes Blocks from the beginning and the end of the
   specfied part of the Block session in an alternating fashion

   - The 'start' attribute specifies the logical block address where the test
     begins, if it is missing the first block is used.

   - The 'length' attribute specifies how many bytes are processed,
     if it is missing the whole underlying Block session starting on the given
     start block is used.

   - The 'write' attribute specifies whether the tests writes or reads, if
     it is missing it defaults to reading.

 * 'random' reads or writes random Blocks in a deterministic order that depends
   on the seed value of the PRNG (currently xoroshiro128+ is used).

   - The 'length' attribute specifies how much bytes are processed by the
     random test, if is missing the total length of the underlying block
     session are used.

   - The 'size' attribute specifies the size of a request, if it is missing
     the block size of the underlying Block session is used.

   - The 'write' or 'read' attribute denote how the access is done. If both
     attributes are specified the type of operation also depends on the PRNG.
     If the lowest bit is set it will be a 'write' and otherwise a 'read' access.

In addition to the test specific attributes, there are generic attributes,
which are supported by every test:

  - If the 'verbose' attribute is specified, the test will print each
    request to the LOG session before it will be executed.

Note: all tests use a fixed sized scratch buffer of 1 (replay 4) MiB, plan the
quota and request size accordingly.

The 'random' test might generate overlapping request, which might trigger
unstable operation with components that do not do sanity checking.


Configuration
=============

The following config snippet illustrates the use of the component:

! <config stop_on_error="yes" calculate="yes" log="yes" "report="no">
!   <tests>
!     <!-- read first 1GiB with request size = block size -->
!     <sequential length="1G"/>
!
!     <!-- read 512MiB starting at block 1024 with request size = 64KiB -->
!     <sequential start="1024" length="512M" size="64K"/>
!
!     <!-- read the last 16KiB in 512B chunks on a 512b sector session -->
!     <sequential start="-131072" size="512"/>
!
!     <!-- write 1200MiB in 8KiB requests -->
!     <sequential write="yes" length="1200M" size="8K"/>
!
!     <!-- read first 32GiB in 128K chunks skipping 1MiB inbetween -->
!     <sequential start="0" length="32G" size="128K" skip="1M"/>
!
!     <!-- replay the beginning Ext2 mount operations -->
!     <replay>
!       <request type="read"  block_number="2" count="1"/>
!       <request type="write" block_number="2" count="1"/>
!     </replay>
!
!     <!-- read the whole session in 64KiB chunks jumping back and forth -->
!     <ping_pong size="64K"/>
!
!     <!-- write 16GiB in 16KiB chunks starting at byte offset 4GiB on a 4K session -->
!     <ping_pong start="1048576" length="16G" size="16K"/>
!
!     <!-- read 32768 random 16KiB chunks -->
!     <random count="32768" size="16K" seed="0xdeadbeef"/>
!
!     <!-- write 6144 random chunks in underlying block size -->
!     <random write="yes" count="6144" seed="0xc0ffee"/>
!
!     <!-- read/write 123456 random 4KiB chunks -->
!     <random read="yes" write="yes" count="6144" size="4K" seed="42"/>
!   </tests>
! </config>


Result output
=============

There are two ways of presenting the test results, printing to a LOG
session and generating a Report.


LOG
---

The LOG output provides one line for every test that is composed of key and
value tuples:

  * bcount:<int>    total count of blocks
  * bsize:<int>     block size in bytes
  * bytes:<int>     total amount of bytes of all operations
  * duration:<int>  total duration time in milliseconds
  * iops:<float>    total number of I/O operatins
  * mibs:<float>    total throughput of the test in MiB/s
  * result:<number> result of the test, either 0 (ok) or 1 (failed)
  * rx:<int>        number of blocks read
  * size:<int>      size of one request in bytes
  * test:<string>   name of the test
  * tx:<int>        number of blocks written

Since the LOG output is mainly intended for automated testing and analyzing all
size values are given in bytes. The following examplary output illustrates the
structure:

! test:sequential rx:1048576 tx:0 bytes:536870912 size:65536 bsize:512 duration:302 mibs:1695.364 iops:27125.828 result:0


Report
------

The Report output contains a node for every test and is updated continuosly
during execution, i.e., new results are appended to the Report. The structure
of the report mirrors the LOG output and is as follows:

! <results>
!   <result test="sequential" rx="1048576" tx="0" bytes="536870912" size="65536" duration="302" mibs="1695.364" iops="27125.828" result="0"/>
!   <result test="random" rx="0" tx="3167616" bytes="1621819392" size="65536" bsize="512" duration="11921" mibs="129.744" iops="2075.916" result="1"/>
! <results>


TODO
====

- move boilerplate code to Test_base (_block etc.)
- check all range/overlap checks (_start, _end etc.)
- fix report=yes (add Report support)
- add req min/max/avg time
- make daemon like, i.e., react upon config changes and execute tests
  dynamically