From 39ee704e757268de833ffb956dda28f6aa2fa3a1 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 31 May 2012 10:27:29 +0200 Subject: libblock: Add read-ahead task Read-ahead requests were previously executed in the context of the reading task. This blocks the reading task until the complete read with read-ahead transfer is finished. A read-ahead task is introduced to off-load the read-ahead transfer. This allows the reading task to work with the requested block more quickly. The read-ahead is triggered after two misses of ascending consecutive blocks or a read hit of a block read by the most-recent read-ahead transfer. The read-ahead feature is configurable and can be disabled. --- cpukit/libblock/include/rtems/bdbuf.h | 26 ++- cpukit/libblock/include/rtems/diskdevs.h | 37 ++++ cpukit/libblock/src/bdbuf.c | 347 ++++++++++++++++++++----------- cpukit/libblock/src/diskdevs-init.c | 2 + cpukit/sapi/include/confdefs.h | 11 +- testsuites/libtests/Makefile.am | 1 + testsuites/libtests/block13/Makefile.am | 19 ++ testsuites/libtests/block13/block13.doc | 11 + testsuites/libtests/block13/block13.scn | 11 + testsuites/libtests/block13/init.c | 232 +++++++++++++++++++++ testsuites/libtests/configure.ac | 1 + 11 files changed, 568 insertions(+), 130 deletions(-) create mode 100644 testsuites/libtests/block13/Makefile.am create mode 100644 testsuites/libtests/block13/block13.doc create mode 100644 testsuites/libtests/block13/block13.scn create mode 100644 testsuites/libtests/block13/init.c diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h index 43a95dfe99..5275c13beb 100644 --- a/cpukit/libblock/include/rtems/bdbuf.h +++ b/cpukit/libblock/include/rtems/bdbuf.h @@ -46,7 +46,7 @@ extern "C" { * @ingroup rtems_libblock * * The Block Device Buffer Management implements a cache between the disk - * devices and file systems. The code provides read ahead and write queuing to + * devices and file systems. The code provides read-ahead and write queuing to * the drivers and fast cache look-up using an AVL tree. * * The block size used by a file system can be set at runtime and must be a @@ -152,10 +152,13 @@ extern "C" { * written. This would be a performance problem. * * The code performs multiple block reads and writes. Multiple block reads or - * read ahead increases performance with hardware that supports it. It also + * read-ahead increases performance with hardware that supports it. It also * helps with a large cache as the disk head movement is reduced. It however * is a speculative operation so excessive use can remove valuable and needed - * blocks from the cache. + * blocks from the cache. The read-ahead is triggered after two misses of + * ascending consecutive blocks or a read hit of a block read by the + * most-resent read-ahead transfer. The read-ahead works per disk, but all + * transfers are issued by the read-ahead task. * * The cache has the following lists of buffers: * - LRU: Accessed or transfered buffers released in least recently used @@ -379,6 +382,8 @@ typedef struct rtems_bdbuf_config { uint32_t buffer_max; /**< Maximum buffer size * supported. It is also the * allocation size. */ + rtems_task_priority read_ahead_priority; /**< Priority of the read-ahead + * task. */ } rtems_bdbuf_config; /** @@ -389,8 +394,8 @@ typedef struct rtems_bdbuf_config { extern const rtems_bdbuf_config rtems_bdbuf_configuration; /** - * The max_read_ahead_blocks value is altered if there are fewer buffers - * than this defined max. This stops thrashing in the cache. + * The default value for the maximum read-ahead blocks disables the read-ahead + * feature. */ #define RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT 0 @@ -425,6 +430,12 @@ extern const rtems_bdbuf_config rtems_bdbuf_configuration; #define RTEMS_BDBUF_SWAPOUT_WORKER_TASK_PRIORITY_DEFAULT \ RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT +/** + * Default read-ahead task priority. The same as the swap-out task. + */ +#define RTEMS_BDBUF_READ_AHEAD_TASK_PRIORITY_DEFAULT \ + RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT + /** * Default task stack size for swap-out and worker tasks. */ @@ -621,7 +632,7 @@ rtems_bdbuf_syncdev (rtems_disk_device *dd); /** * @brief Purges all buffers corresponding to the disk device @a dd. * - * This may result in loss of data. + * This may result in loss of data. The read-ahead state of this device is reset. * * Before you can use this function, the rtems_bdbuf_init() routine must be * called at least once to initialize the cache, otherwise a fatal error will @@ -635,7 +646,8 @@ rtems_bdbuf_purge_dev (rtems_disk_device *dd); /** * @brief Sets the block size of a disk device. * - * This will set the block size derived fields of the disk device. + * This will set the block size derived fields of the disk device. The + * read-ahead state of this device is reset. * * Before you can use this function, the rtems_bdbuf_init() routine must be * called at least once to initialize the cache, otherwise a fatal error will diff --git a/cpukit/libblock/include/rtems/diskdevs.h b/cpukit/libblock/include/rtems/diskdevs.h index fe931f8a94..0b194096a5 100644 --- a/cpukit/libblock/include/rtems/diskdevs.h +++ b/cpukit/libblock/include/rtems/diskdevs.h @@ -16,6 +16,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -54,6 +55,37 @@ typedef int (*rtems_block_device_ioctl)( void *argp ); +/** + * @brief Trigger value to disable further read-ahead requests. + */ +#define RTEMS_DISK_READ_AHEAD_NO_TRIGGER ((rtems_blkdev_bnum) -1) + +/** + * @brief Read-ahead control. + */ +typedef struct { + /** + * @brief Chain node for the read-ahead request queue of the read-ahead task. + */ + rtems_chain_node node; + + /** + * @brief Block value to trigger the read-ahead request. + * + * A value of @ref RTEMS_DISK_READ_AHEAD_NO_TRIGGER will disable further + * read-ahead requests since no valid block can have this value. + */ + rtems_blkdev_bnum trigger; + + /** + * @brief Start block for the next read-ahead request. + * + * In case the trigger value is out of range of valid blocks, this value my + * be arbitrary. + */ + rtems_blkdev_bnum next; +} rtems_disk_read_ahread; + /** * @brief Description of a disk device (logical and physical disks). * @@ -168,6 +200,11 @@ struct rtems_disk_device { * releases this disk. */ bool deleted; + + /** + * @brief Read-ahead control for this disk. + */ + rtems_disk_read_ahread read_ahead; }; /** diff --git a/cpukit/libblock/src/bdbuf.c b/cpukit/libblock/src/bdbuf.c index 4c53ff38c1..424b9a3481 100644 --- a/cpukit/libblock/src/bdbuf.c +++ b/cpukit/libblock/src/bdbuf.c @@ -134,6 +134,9 @@ typedef struct rtems_bdbuf_cache size_t group_count; /**< The number of groups. */ rtems_bdbuf_group* groups; /**< The groups. */ + rtems_id read_ahead_task; /**< Read-ahead task */ + rtems_chain_control read_ahead_chain; /**< Read-ahead request chain */ + bool read_ahead_enabled; /**< Read-ahead enabled */ bool initialised; /**< Initialised state. */ } rtems_bdbuf_cache; @@ -180,6 +183,7 @@ typedef struct rtems_bdbuf_cache #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_0 RTEMS_BLKDEV_FATAL_ERROR(28) #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_1 RTEMS_BLKDEV_FATAL_ERROR(29) #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_2 RTEMS_BLKDEV_FATAL_ERROR(30) +#define RTEMS_BLKDEV_FATAL_BDBUF_RA_WAKE_UP RTEMS_BLKDEV_FATAL_ERROR(31) /** * The events used in this code. These should be system events rather than @@ -187,6 +191,7 @@ typedef struct rtems_bdbuf_cache */ #define RTEMS_BDBUF_TRANSFER_SYNC RTEMS_EVENT_1 #define RTEMS_BDBUF_SWAPOUT_SYNC RTEMS_EVENT_2 +#define RTEMS_BDBUF_READ_AHEAD_WAKE_UP RTEMS_EVENT_1 /** * Lock semaphore attributes. This is used for locking type mutexes. @@ -219,11 +224,10 @@ typedef struct rtems_bdbuf_cache (TOD_MICROSECONDS_TO_TICKS (20000000)) #endif -/* - * The swap out task. - */ static rtems_task rtems_bdbuf_swapout_task(rtems_task_argument arg); +static rtems_task rtems_bdbuf_read_ahead_task(rtems_task_argument arg); + /** * The Buffer Descriptor cache. */ @@ -1365,6 +1369,7 @@ rtems_bdbuf_init (void) rtems_chain_initialize_empty (&bdbuf_cache.lru); rtems_chain_initialize_empty (&bdbuf_cache.modified); rtems_chain_initialize_empty (&bdbuf_cache.sync); + rtems_chain_initialize_empty (&bdbuf_cache.read_ahead_chain); /* * Create the locks for the cache. @@ -1486,12 +1491,28 @@ rtems_bdbuf_init (void) if (sc != RTEMS_SUCCESSFUL) goto error; + if (bdbuf_config.max_read_ahead_blocks > 0) + { + bdbuf_cache.read_ahead_enabled = true; + sc = rtems_bdbuf_create_task (rtems_build_name('B', 'R', 'D', 'A'), + bdbuf_config.read_ahead_priority, + RTEMS_BDBUF_READ_AHEAD_TASK_PRIORITY_DEFAULT, + rtems_bdbuf_read_ahead_task, + 0, + &bdbuf_cache.read_ahead_task); + if (sc != RTEMS_SUCCESSFUL) + goto error; + } + rtems_bdbuf_unlock_cache (); return RTEMS_SUCCESSFUL; error: + if (bdbuf_cache.read_ahead_task != 0) + rtems_task_delete (bdbuf_cache.read_ahead_task); + if (bdbuf_cache.swapout != 0) rtems_task_delete (bdbuf_cache.swapout); @@ -1852,81 +1873,6 @@ rtems_bdbuf_transfer_done (void* arg, rtems_status_code status) rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC); } -static void -rtems_bdbuf_create_read_request (const rtems_disk_device *dd, - rtems_blkdev_bnum media_block, - rtems_blkdev_request *req, - rtems_bdbuf_buffer **bd_ptr) -{ - rtems_bdbuf_buffer *bd = NULL; - rtems_blkdev_bnum media_block_end = dd->start + dd->size; - rtems_blkdev_bnum media_block_count = dd->block_to_media_block_shift >= 0 ? - 1U << dd->block_to_media_block_shift - : dd->block_size / dd->media_block_size; - uint32_t block_size = dd->block_size; - uint32_t transfer_index = 1; - uint32_t transfer_count = bdbuf_config.max_read_ahead_blocks + 1; - - if (media_block_end - media_block < transfer_count) - transfer_count = media_block_end - media_block; - - req->req = RTEMS_BLKDEV_REQ_READ; - req->req_done = rtems_bdbuf_transfer_done; - req->done_arg = req; - req->io_task = rtems_task_self (); - req->status = RTEMS_RESOURCE_IN_USE; - req->bufnum = 0; - - bd = rtems_bdbuf_get_buffer_for_access (dd, media_block); - - *bd_ptr = bd; - - req->bufs [0].user = bd; - req->bufs [0].block = media_block; - req->bufs [0].length = block_size; - req->bufs [0].buffer = bd->buffer; - - if (rtems_bdbuf_tracer) - rtems_bdbuf_show_users ("read", bd); - - switch (bd->state) - { - case RTEMS_BDBUF_STATE_CACHED: - case RTEMS_BDBUF_STATE_MODIFIED: - return; - case RTEMS_BDBUF_STATE_EMPTY: - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_TRANSFER); - break; - default: - rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_1); - break; - } - - while (transfer_index < transfer_count) - { - media_block += media_block_count; - - bd = rtems_bdbuf_get_buffer_for_read_ahead (dd, media_block); - - if (bd == NULL) - break; - - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_TRANSFER); - - req->bufs [transfer_index].user = bd; - req->bufs [transfer_index].block = media_block; - req->bufs [transfer_index].length = block_size; - req->bufs [transfer_index].buffer = bd->buffer; - - if (rtems_bdbuf_tracer) - rtems_bdbuf_show_users ("read-ahead", bd); - - ++transfer_index; - } - - req->bufnum = transfer_index; -} - static rtems_status_code rtems_bdbuf_execute_transfer_request (const rtems_disk_device *dd, rtems_blkdev_request *req, @@ -1989,15 +1935,16 @@ rtems_bdbuf_execute_transfer_request (const rtems_disk_device *dd, return RTEMS_IO_ERROR; } -rtems_status_code -rtems_bdbuf_read (rtems_disk_device *dd, - rtems_blkdev_bnum block, - rtems_bdbuf_buffer **bd_ptr) +static rtems_status_code +rtems_bdbuf_execute_read_request (const rtems_disk_device *dd, + rtems_bdbuf_buffer *bd, + uint32_t transfer_count) { - rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_blkdev_request *req = NULL; - rtems_bdbuf_buffer *bd = NULL; - rtems_blkdev_bnum media_block; + rtems_blkdev_bnum media_block = bd->block; + uint32_t media_blocks_per_block = dd->media_blocks_per_block; + uint32_t block_size = dd->block_size; + uint32_t transfer_index = 1; /* * TODO: This type of request structure is wrong and should be removed. @@ -2005,8 +1952,113 @@ rtems_bdbuf_read (rtems_disk_device *dd, #define bdbuf_alloc(size) __builtin_alloca (size) req = bdbuf_alloc (sizeof (rtems_blkdev_request) + - sizeof (rtems_blkdev_sg_buffer) * - (bdbuf_config.max_read_ahead_blocks + 1)); + sizeof (rtems_blkdev_sg_buffer) * transfer_count); + + req->req = RTEMS_BLKDEV_REQ_READ; + req->req_done = rtems_bdbuf_transfer_done; + req->done_arg = req; + req->io_task = rtems_task_self (); + req->status = RTEMS_RESOURCE_IN_USE; + req->bufnum = 0; + + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_TRANSFER); + + req->bufs [0].user = bd; + req->bufs [0].block = media_block; + req->bufs [0].length = block_size; + req->bufs [0].buffer = bd->buffer; + + if (rtems_bdbuf_tracer) + rtems_bdbuf_show_users ("read", bd); + + while (transfer_index < transfer_count) + { + media_block += media_blocks_per_block; + + bd = rtems_bdbuf_get_buffer_for_read_ahead (dd, media_block); + + if (bd == NULL) + break; + + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_TRANSFER); + + req->bufs [transfer_index].user = bd; + req->bufs [transfer_index].block = media_block; + req->bufs [transfer_index].length = block_size; + req->bufs [transfer_index].buffer = bd->buffer; + + if (rtems_bdbuf_tracer) + rtems_bdbuf_show_users ("read", bd); + + ++transfer_index; + } + + req->bufnum = transfer_index; + + return rtems_bdbuf_execute_transfer_request (dd, req, true); +} + +static bool +rtems_bdbuf_is_read_ahead_active (const rtems_disk_device *dd) +{ + return !rtems_chain_is_node_off_chain (&dd->read_ahead.node); +} + +static void +rtems_bdbuf_read_ahead_cancel (rtems_disk_device *dd) +{ + if (rtems_bdbuf_is_read_ahead_active (dd)) + { + rtems_chain_extract_unprotected (&dd->read_ahead.node); + rtems_chain_set_off_chain (&dd->read_ahead.node); + } +} + +static void +rtems_bdbuf_read_ahead_reset (rtems_disk_device *dd) +{ + rtems_bdbuf_read_ahead_cancel (dd); + dd->read_ahead.trigger = RTEMS_DISK_READ_AHEAD_NO_TRIGGER; +} + +static void +rtems_bdbuf_check_read_ahead_trigger (rtems_disk_device *dd, + rtems_blkdev_bnum block) +{ + if (dd->read_ahead.trigger == block + && !rtems_bdbuf_is_read_ahead_active (dd)) + { + rtems_status_code sc; + rtems_chain_control *chain = &bdbuf_cache.read_ahead_chain; + + rtems_chain_append_unprotected (chain, &dd->read_ahead.node); + sc = rtems_event_send (bdbuf_cache.read_ahead_task, + RTEMS_BDBUF_READ_AHEAD_WAKE_UP); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_RA_WAKE_UP); + } +} + +static void +rtems_bdbuf_set_read_ahead_trigger (rtems_disk_device *dd, + rtems_blkdev_bnum block) +{ + if (dd->read_ahead.trigger != block) + { + rtems_bdbuf_read_ahead_cancel (dd); + dd->read_ahead.trigger = block + 1; + dd->read_ahead.next = block + 2; + } +} + +rtems_status_code +rtems_bdbuf_read (rtems_disk_device *dd, + rtems_blkdev_bnum block, + rtems_bdbuf_buffer **bd_ptr) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_bdbuf_buffer *bd = NULL; + rtems_blkdev_bnum media_block; rtems_bdbuf_lock_cache (); @@ -2017,42 +2069,33 @@ rtems_bdbuf_read (rtems_disk_device *dd, printf ("bdbuf:read: %" PRIu32 " (%" PRIu32 ") (dev = %08x)\n", media_block + dd->start, block, (unsigned) dd->dev); - rtems_bdbuf_create_read_request (dd, media_block, req, &bd); - - if (req->bufnum > 0) - { - sc = rtems_bdbuf_execute_transfer_request (dd, req, true); - if (sc == RTEMS_SUCCESSFUL) - { - rtems_chain_extract_unprotected (&bd->link); - rtems_bdbuf_group_obtain (bd); - } - } - - if (sc == RTEMS_SUCCESSFUL) + rtems_bdbuf_check_read_ahead_trigger (dd, block); + bd = rtems_bdbuf_get_buffer_for_access (dd, media_block); + switch (bd->state) { - switch (bd->state) - { - case RTEMS_BDBUF_STATE_CACHED: + case RTEMS_BDBUF_STATE_CACHED: + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_CACHED); + break; + case RTEMS_BDBUF_STATE_MODIFIED: + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_MODIFIED); + break; + case RTEMS_BDBUF_STATE_EMPTY: + rtems_bdbuf_set_read_ahead_trigger (dd, block); + sc = rtems_bdbuf_execute_read_request (dd, bd, 1); + if (sc == RTEMS_SUCCESSFUL) + { rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_CACHED); - break; - case RTEMS_BDBUF_STATE_MODIFIED: - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_MODIFIED); - break; - default: - rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_4); - break; - } - - if (rtems_bdbuf_tracer) - { - rtems_bdbuf_show_users ("read", bd); - rtems_bdbuf_show_usage (); - } - } - else - { - bd = NULL; + rtems_chain_extract_unprotected (&bd->link); + rtems_bdbuf_group_obtain (bd); + } + else + { + bd = NULL; + } + break; + default: + rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_4); + break; } } @@ -2884,6 +2927,7 @@ rtems_bdbuf_purge_dev (rtems_disk_device *dd) rtems_chain_initialize_empty (&purge_list); rtems_bdbuf_lock_cache (); + rtems_bdbuf_read_ahead_reset (dd); rtems_bdbuf_gather_for_purge (&purge_list, dd); rtems_bdbuf_purge_list (&purge_list); rtems_bdbuf_unlock_cache (); @@ -2919,6 +2963,8 @@ rtems_bdbuf_set_block_size (rtems_disk_device *dd, uint32_t block_size) dd->media_blocks_per_block = media_blocks_per_block; dd->block_to_media_block_shift = block_to_media_block_shift; dd->bds_per_group = bds_per_group; + + rtems_bdbuf_read_ahead_reset (dd); } else { @@ -2934,3 +2980,62 @@ rtems_bdbuf_set_block_size (rtems_disk_device *dd, uint32_t block_size) return sc; } + +static rtems_task +rtems_bdbuf_read_ahead_task (rtems_task_argument arg) +{ + rtems_chain_control *chain = &bdbuf_cache.read_ahead_chain; + + while (bdbuf_cache.read_ahead_enabled) + { + rtems_chain_node *node; + + rtems_bdbuf_wait_for_event (RTEMS_BDBUF_READ_AHEAD_WAKE_UP); + rtems_bdbuf_lock_cache (); + + while ((node = rtems_chain_get_unprotected (chain)) != NULL) + { + rtems_disk_device *dd = (rtems_disk_device *) + ((char *) node - offsetof (rtems_disk_device, read_ahead.node)); + rtems_blkdev_bnum block = dd->read_ahead.next; + rtems_blkdev_bnum media_block = 0; + rtems_status_code sc = + rtems_bdbuf_get_media_block (dd, block, &media_block); + + rtems_chain_set_off_chain (&dd->read_ahead.node); + + if (sc == RTEMS_SUCCESSFUL) + { + rtems_bdbuf_buffer *bd = + rtems_bdbuf_get_buffer_for_read_ahead (dd, media_block); + + if (bd != NULL) + { + uint32_t transfer_count = dd->block_count - block; + uint32_t max_transfer_count = bdbuf_config.max_read_ahead_blocks; + + if (transfer_count >= max_transfer_count) + { + transfer_count = max_transfer_count; + dd->read_ahead.trigger += max_transfer_count / 2 + 1; + dd->read_ahead.next += max_transfer_count; + } + else + { + dd->read_ahead.trigger = RTEMS_DISK_READ_AHEAD_NO_TRIGGER; + } + + rtems_bdbuf_execute_read_request (dd, bd, transfer_count); + } + } + else + { + dd->read_ahead.trigger = RTEMS_DISK_READ_AHEAD_NO_TRIGGER; + } + } + + rtems_bdbuf_unlock_cache (); + } + + rtems_task_delete (RTEMS_SELF); +} diff --git a/cpukit/libblock/src/diskdevs-init.c b/cpukit/libblock/src/diskdevs-init.c index ccf954a49a..5ec96b250c 100644 --- a/cpukit/libblock/src/diskdevs-init.c +++ b/cpukit/libblock/src/diskdevs-init.c @@ -36,6 +36,7 @@ rtems_status_code rtems_disk_init_phys( dd->media_block_size = block_size; dd->ioctl = handler; dd->driver_data = driver_data; + dd->read_ahead.trigger = RTEMS_DISK_READ_AHEAD_NO_TRIGGER; if (block_count > 0) { if ((*handler)(dd, RTEMS_BLKIO_CAPABILITIES, &dd->capabilities) != 0) { @@ -67,6 +68,7 @@ rtems_status_code rtems_disk_init_log( dd->media_block_size = phys_dd->media_block_size; dd->ioctl = phys_dd->ioctl; dd->driver_data = phys_dd->driver_data; + dd->read_ahead.trigger = RTEMS_DISK_READ_AHEAD_NO_TRIGGER; if (phys_dd->phys_dev == phys_dd) { rtems_blkdev_bnum phys_block_count = phys_dd->size; diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h index 4e43a27f45..0f804ee7cc 100644 --- a/cpukit/sapi/include/confdefs.h +++ b/cpukit/sapi/include/confdefs.h @@ -1241,6 +1241,10 @@ rtems_fs_init_functions_t rtems_fs_init_helper = #define CONFIGURE_BDBUF_BUFFER_MAX_SIZE \ RTEMS_BDBUF_BUFFER_MAX_SIZE_DEFAULT #endif + #ifndef CONFIGURE_BDBUF_READ_AHEAD_TASK_PRIORITY + #define CONFIGURE_BDBUF_READ_AHEAD_TASK_PRIORITY \ + RTEMS_BDBUF_READ_AHEAD_TASK_PRIORITY_DEFAULT + #endif #ifdef CONFIGURE_INIT const rtems_bdbuf_config rtems_bdbuf_configuration = { CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS, @@ -1253,11 +1257,14 @@ rtems_fs_init_functions_t rtems_fs_init_helper = CONFIGURE_BDBUF_TASK_STACK_SIZE, CONFIGURE_BDBUF_CACHE_MEMORY_SIZE, CONFIGURE_BDBUF_BUFFER_MIN_SIZE, - CONFIGURE_BDBUF_BUFFER_MAX_SIZE + CONFIGURE_BDBUF_BUFFER_MAX_SIZE, + CONFIGURE_BDBUF_READ_AHEAD_TASK_PRIORITY }; #endif - #define CONFIGURE_LIBBLOCK_TASKS (1 + CONFIGURE_SWAPOUT_WORKER_TASKS) + #define CONFIGURE_LIBBLOCK_TASKS \ + (1 + CONFIGURE_SWAPOUT_WORKER_TASKS + \ + (CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS != 0)) #define CONFIGURE_LIBBLOCK_TASK_EXTRA_STACKS \ (CONFIGURE_LIBBLOCK_TASKS * \ diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am index 1274f2637b..9747ad19c6 100644 --- a/testsuites/libtests/Makefile.am +++ b/testsuites/libtests/Makefile.am @@ -1,6 +1,7 @@ ACLOCAL_AMFLAGS = -I ../aclocal SUBDIRS = POSIX +SUBDIRS += block13 SUBDIRS += rbheap01 SUBDIRS += flashdisk01 diff --git a/testsuites/libtests/block13/Makefile.am b/testsuites/libtests/block13/Makefile.am new file mode 100644 index 0000000000..9b4a76d0eb --- /dev/null +++ b/testsuites/libtests/block13/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = block13 +block13_SOURCES = init.c + +dist_rtems_tests_DATA = block13.scn block13.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include + +LINK_OBJS = $(block13_OBJECTS) +LINK_LIBS = $(block13_LDLIBS) + +block13$(EXEEXT): $(block13_OBJECTS) $(block13_DEPENDENCIES) + @rm -f block13$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/libtests/block13/block13.doc b/testsuites/libtests/block13/block13.doc new file mode 100644 index 0000000000..04fc066ada --- /dev/null +++ b/testsuites/libtests/block13/block13.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: block13 + +directives: + + TBD + +concepts: + + Tests the read-ahead feature of bdbuf. diff --git a/testsuites/libtests/block13/block13.scn b/testsuites/libtests/block13/block13.scn new file mode 100644 index 0000000000..8cce71806d --- /dev/null +++ b/testsuites/libtests/block13/block13.scn @@ -0,0 +1,11 @@ +*** TEST BLOCK 13 *** +0 2 3 4 5 6 7 8 +reset +8 +reset +7 +reset +6 7 +reset +5 6 8 +*** END OF TEST BLOCK 13 *** diff --git a/testsuites/libtests/block13/init.c b/testsuites/libtests/block13/init.c new file mode 100644 index 0000000000..43ce38860e --- /dev/null +++ b/testsuites/libtests/block13/init.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include "tmacros.h" + +#include +#include + +#include +#include + +#define BLOCK_COUNT 9 +#define READ_COUNT 19 + +static int block_access_counts [BLOCK_COUNT]; + +#define RESET_CACHE (-1) + +static const int action_sequence [READ_COUNT] = { + 0, 2, 3, 4, 5, 6, 7, 8, + RESET_CACHE, + 8, + RESET_CACHE, + 7, + RESET_CACHE, + 6, 7, + RESET_CACHE, + 5, 6, 8 +}; + +#define UNUSED_LINE { 0, 0, 0, 0, 0, 0, 0, 0, 0 } + +static int expected_block_access_counts [READ_COUNT] [BLOCK_COUNT] = { + { 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 1, 1, 1, 1, 0, 0, 0 }, + { 1, 0, 1, 1, 1, 1, 0, 0, 0 }, + { 1, 0, 1, 1, 1, 1, 1, 1, 0 }, + { 1, 0, 1, 1, 1, 1, 1, 1, 0 }, + { 1, 0, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 0, 1, 1, 1, 1, 1, 1, 1 }, + UNUSED_LINE, + { 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + UNUSED_LINE, + { 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + UNUSED_LINE, + { 0, 0, 0, 0, 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, 1, 1 }, + UNUSED_LINE, + { 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 1 } +}; + +#define NO_TRIGGER RTEMS_DISK_READ_AHEAD_NO_TRIGGER + +#define TRIGGER_AFTER_RESET RTEMS_DISK_READ_AHEAD_NO_TRIGGER + +static const rtems_blkdev_bnum trigger [READ_COUNT] = { + 1, 3, 5, 5, 7, 7, NO_TRIGGER, NO_TRIGGER, + TRIGGER_AFTER_RESET, + 9, + TRIGGER_AFTER_RESET, + 8, + TRIGGER_AFTER_RESET, + 7, NO_TRIGGER, + TRIGGER_AFTER_RESET, + 6, 8, NO_TRIGGER +}; + +#define NOT_CHANGED_BY_RESET(i) (i) + +static const rtems_blkdev_bnum next [READ_COUNT] = { + 2, 4, 6, 6, 8, 8, 8, 8, + NOT_CHANGED_BY_RESET(8), + 10, + NOT_CHANGED_BY_RESET(10), + 9, + NOT_CHANGED_BY_RESET(9), + 8, 8, + NOT_CHANGED_BY_RESET(8), + 7, 9, 9 +}; + +static int test_disk_ioctl(rtems_disk_device *dd, uint32_t req, void *arg) +{ + int rv = 0; + + if (req == RTEMS_BLKIO_REQUEST) { + rtems_blkdev_request *breq = arg; + rtems_blkdev_sg_buffer *sg = breq->bufs; + uint32_t i; + + rtems_test_assert(breq->req == RTEMS_BLKDEV_REQ_READ); + + for (i = 0; i < breq->bufnum; ++i) { + rtems_blkdev_bnum block = sg [i].block; + + rtems_test_assert(block < BLOCK_COUNT); + + ++block_access_counts [block]; + } + + (*breq->req_done)(breq->done_arg, RTEMS_SUCCESSFUL); + } else { + errno = EINVAL; + rv = -1; + } + + return rv; +} + +static void test_read_ahead(rtems_disk_device *dd) +{ + int i; + + for (i = 0; i < READ_COUNT; ++i) { + int action = action_sequence [i]; + + if (action != RESET_CACHE) { + rtems_blkdev_bnum block = (rtems_blkdev_bnum) action; + rtems_status_code sc; + rtems_bdbuf_buffer *bd; + + printf("%i ", action); + + sc = rtems_bdbuf_read(dd, block, &bd); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_bdbuf_release(bd); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + rtems_test_assert( + memcmp( + block_access_counts, + expected_block_access_counts [i], + sizeof(block_access_counts) + ) == 0 + ); + } else { + printf("\nreset\n"); + + rtems_bdbuf_purge_dev(dd); + memset(&block_access_counts, 0, sizeof(block_access_counts)); + } + + rtems_test_assert(trigger [i] == dd->read_ahead.trigger); + rtems_test_assert(next [i] == dd->read_ahead.next); + } + + printf("\n"); +} + +static void test(void) +{ + rtems_status_code sc; + dev_t dev = 0; + rtems_disk_device *dd; + + sc = rtems_disk_io_initialize(); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_disk_create_phys( + dev, + 1, + BLOCK_COUNT, + test_disk_ioctl, + NULL, + NULL + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + dd = rtems_disk_obtain(dev); + rtems_test_assert(dd != NULL); + + test_read_ahead(dd); + + sc = rtems_disk_release(dd); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_disk_delete(dev); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void Init(rtems_task_argument arg) +{ + puts("\n\n*** TEST BLOCK 13 ***"); + + test(); + + puts("*** END OF TEST BLOCK 13 ***"); + + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK + +#define CONFIGURE_BDBUF_BUFFER_MIN_SIZE 1 +#define CONFIGURE_BDBUF_BUFFER_MAX_SIZE 1 +#define CONFIGURE_BDBUF_CACHE_MEMORY_SIZE BLOCK_COUNT +#define CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS 2 +#define CONFIGURE_BDBUF_READ_AHEAD_TASK_PRIORITY 1 + +#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_TASKS 1 + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES +#define CONFIGURE_INIT_TASK_PRIORITY 2 + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/configure.ac index f6af3b11cd..7df0520f87 100644 --- a/testsuites/libtests/configure.ac +++ b/testsuites/libtests/configure.ac @@ -41,6 +41,7 @@ AM_CONDITIONAL(NETTESTS,test "$rtems_cv_RTEMS_NETWORKING" = "yes") # Explicitly list all Makefiles here AC_CONFIG_FILES([Makefile +block13/Makefile rbheap01/Makefile syscall01/Makefile flashdisk01/Makefile -- cgit v1.2.3