mirror of https://github.com/ARMmbed/mbed-os.git
Improve general Block Device tests
Fixing all rand issues, aligning erase addresses, moving prints to debug mode.pull/10110/head
parent
f1e664be82
commit
ba6748fe41
|
@ -26,6 +26,7 @@
|
|||
#include <stdlib.h>
|
||||
#include "BufferedBlockDevice.h"
|
||||
#include "BlockDevice.h"
|
||||
#include <algorithm>
|
||||
|
||||
#if COMPONENT_SPIF
|
||||
#include "SPIFBlockDevice.h"
|
||||
|
@ -47,6 +48,17 @@
|
|||
#include "FlashIAPBlockDevice.h"
|
||||
#endif
|
||||
|
||||
// Debug available
|
||||
#ifndef MODE_DEBUG
|
||||
#define MODE_DEBUG 0
|
||||
#endif
|
||||
|
||||
#if MODE_DEBUG
|
||||
#define DEBUG_PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_PRINTF(...)
|
||||
#endif
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#define TEST_BLOCK_COUNT 10
|
||||
|
@ -54,6 +66,9 @@ using namespace utest::v1;
|
|||
#define TEST_NUM_OF_THREADS 5
|
||||
#define TEST_THREAD_STACK_SIZE 1024
|
||||
|
||||
uint8_t num_of_sectors = TEST_NUM_OF_THREADS * TEST_BLOCK_COUNT;
|
||||
uint32_t sectors_addr[TEST_NUM_OF_THREADS * TEST_BLOCK_COUNT] = {0};
|
||||
|
||||
const struct {
|
||||
const char *name;
|
||||
bd_size_t (BlockDevice::*method)() const;
|
||||
|
@ -194,13 +209,9 @@ void basic_erase_program_read_test(BlockDevice *block_device, bd_size_t block_si
|
|||
srand(block_seed++);
|
||||
|
||||
// Find a random block
|
||||
int threaded_rand_number = (rand() * TEST_NUM_OF_THREADS) + thread_num;
|
||||
bd_addr_t block = (threaded_rand_number * block_size) % block_device->size();
|
||||
|
||||
// Flashiap boards with inconsistent sector size will not align with random start addresses
|
||||
if (bd_arr[test_iteration] == flashiap) {
|
||||
block = 0;
|
||||
}
|
||||
bd_addr_t block = sectors_addr[thread_num];
|
||||
bd_size_t curr_block_size = block_device->get_erase_size(block);
|
||||
block_size = std::min(block_size, curr_block_size);
|
||||
|
||||
// Use next random number as temporary seed to keep
|
||||
// the address progressing in the pseudorandom sequence
|
||||
|
@ -212,14 +223,9 @@ void basic_erase_program_read_test(BlockDevice *block_device, bd_size_t block_si
|
|||
write_block[i_ind] = 0xff & rand();
|
||||
}
|
||||
// Write, sync, and read the block
|
||||
utest_printf("test %0*llx:%llu...\n", addrwidth, block, block_size);
|
||||
DEBUG_PRINTF("test %0*llx:%llu...\n", addrwidth, block, curr_block_size);
|
||||
|
||||
// Thread test for flashiap write to the same sector, so all write/read/erase actions should be locked
|
||||
if (bd_arr[test_iteration] != flashiap) {
|
||||
_mutex->unlock();
|
||||
}
|
||||
|
||||
err = block_device->erase(block, block_size);
|
||||
err = block_device->erase(block, curr_block_size);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
err = block_device->program(write_block, block, block_size);
|
||||
|
@ -228,10 +234,6 @@ void basic_erase_program_read_test(BlockDevice *block_device, bd_size_t block_si
|
|||
err = block_device->read(read_block, block, block_size);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
if (bd_arr[test_iteration] != flashiap) {
|
||||
_mutex->lock();
|
||||
}
|
||||
|
||||
// Check that the data was unmodified
|
||||
srand(seed);
|
||||
int val_rand;
|
||||
|
@ -253,11 +255,19 @@ void test_init_bd()
|
|||
utest_printf("\nTest Init block device.\n");
|
||||
|
||||
block_device = get_bd_instance(test_iteration);
|
||||
|
||||
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
|
||||
|
||||
int err = block_device->init();
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
bd_addr_t start_address = 0;
|
||||
uint8_t i = 0;
|
||||
for (; i < num_of_sectors && start_address < block_device->size(); i++) {
|
||||
sectors_addr[i] = start_address;
|
||||
DEBUG_PRINTF("start_address = 0x%llx, sector_size = %d\n", start_address, block_device->get_erase_size(start_address));
|
||||
start_address += block_device->get_erase_size(start_address);
|
||||
}
|
||||
num_of_sectors = i;
|
||||
}
|
||||
|
||||
void test_random_program_read_erase()
|
||||
|
@ -289,22 +299,23 @@ void test_random_program_read_erase()
|
|||
goto end;
|
||||
}
|
||||
|
||||
for (int b = 0; b < TEST_BLOCK_COUNT; b++) {
|
||||
basic_erase_program_read_test(block_device, block_size, write_block, read_block, addrwidth, 0);
|
||||
for (int b = 0; b < std::min((uint8_t)TEST_BLOCK_COUNT, num_of_sectors); b++) {
|
||||
basic_erase_program_read_test(block_device, block_size, write_block, read_block, addrwidth, b);
|
||||
}
|
||||
|
||||
end:
|
||||
delete[] write_block;
|
||||
delete[] read_block;
|
||||
delete[] write_block;
|
||||
}
|
||||
|
||||
static void test_thread_job(void *block_device_ptr)
|
||||
static void test_thread_job()
|
||||
{
|
||||
static int thread_num = 0;
|
||||
_mutex->lock();
|
||||
int block_num = thread_num++;
|
||||
int block_num = thread_num++ % TEST_NUM_OF_THREADS;
|
||||
_mutex->unlock();
|
||||
BlockDevice *block_device = (BlockDevice *)block_device_ptr;
|
||||
|
||||
uint8_t sector_per_thread = (num_of_sectors / TEST_NUM_OF_THREADS);
|
||||
|
||||
bd_size_t block_size = block_device->get_erase_size();
|
||||
unsigned addrwidth = ceil(log(float(block_device->size() - 1)) / log(float(16))) + 1;
|
||||
|
@ -317,13 +328,13 @@ static void test_thread_job(void *block_device_ptr)
|
|||
goto end;
|
||||
}
|
||||
|
||||
for (int b = 0; b < TEST_BLOCK_COUNT; b++) {
|
||||
basic_erase_program_read_test(block_device, block_size, write_block, read_block, addrwidth, block_num);
|
||||
for (int b = 0; b < sector_per_thread; b++) {
|
||||
basic_erase_program_read_test(block_device, block_size, write_block, read_block, addrwidth, block_num * sector_per_thread + b);
|
||||
}
|
||||
|
||||
end:
|
||||
delete[] write_block;
|
||||
delete[] read_block;
|
||||
delete[] write_block;
|
||||
}
|
||||
|
||||
void test_multi_threads()
|
||||
|
@ -363,7 +374,7 @@ void test_multi_threads()
|
|||
}
|
||||
delete[] dummy;
|
||||
|
||||
threadStatus = bd_thread[i_ind]->start(callback(test_thread_job, (void *)block_device));
|
||||
threadStatus = bd_thread[i_ind]->start(callback(test_thread_job));
|
||||
if (threadStatus != 0) {
|
||||
utest_printf("Thread %d Start Failed!\n", i_ind + 1);
|
||||
break;
|
||||
|
@ -398,7 +409,6 @@ void test_erase_functionality()
|
|||
|
||||
// Check erase value
|
||||
int erase_value_int = block_device->get_erase_value();
|
||||
utest_printf("block_device->get_erase_value()=%d\n", erase_value_int);
|
||||
TEST_SKIP_UNLESS_MESSAGE(erase_value_int >= 0, "Erase not supported in this block device. Test skipped.");
|
||||
|
||||
// Assuming that get_erase_value() returns byte value as documentation mentions
|
||||
|
@ -406,31 +416,22 @@ void test_erase_functionality()
|
|||
TEST_ASSERT(erase_value_int <= 255);
|
||||
uint8_t erase_value = (uint8_t)erase_value_int;
|
||||
|
||||
// Determine start_address
|
||||
bd_addr_t start_address = sectors_addr[rand() % num_of_sectors];
|
||||
utest_printf("start_address=0x%016" PRIx64 "\n", start_address);
|
||||
|
||||
// Determine data_buf_size
|
||||
bd_size_t erase_size = block_device->get_erase_size();
|
||||
bd_size_t erase_size = block_device->get_erase_size(start_address);
|
||||
TEST_ASSERT(erase_size > 0);
|
||||
bd_size_t data_buf_size = erase_size;
|
||||
|
||||
// Determine start_address
|
||||
bd_addr_t start_address = rand(); // low 32 bytes
|
||||
start_address += (uint64_t)rand() << 32; // high 32 bytes
|
||||
start_address %= block_device->size() - data_buf_size - erase_size; // fit all data + alignment reserve
|
||||
start_address += erase_size; // add alignment reserve
|
||||
start_address -= start_address % erase_size; // align with erase_block
|
||||
utest_printf("start_address=0x%016" PRIx64 "\n", start_address);
|
||||
|
||||
// Flashiap boards with inconsistent sector size will not align with random start addresses
|
||||
if (bd_arr[test_iteration] == flashiap) {
|
||||
start_address = 0;
|
||||
}
|
||||
|
||||
// Allocate buffer for write test data
|
||||
uint8_t *data_buf = (uint8_t *)malloc(data_buf_size);
|
||||
TEST_SKIP_UNLESS_MESSAGE(data_buf, "Not enough memory for test.\n");
|
||||
uint8_t *data_buf = new (std::nothrow) uint8_t[data_buf_size];
|
||||
TEST_SKIP_UNLESS_MESSAGE(data_buf != NULL, "Not enough memory for test");
|
||||
|
||||
// Allocate buffer for read test data
|
||||
uint8_t *out_data_buf = (uint8_t *)malloc(data_buf_size);
|
||||
TEST_SKIP_UNLESS_MESSAGE(out_data_buf, "Not enough memory for test.\n");
|
||||
uint8_t *out_data_buf = new (std::nothrow) uint8_t[data_buf_size];
|
||||
TEST_SKIP_UNLESS_MESSAGE(out_data_buf != NULL, "Not enough memory for test");
|
||||
|
||||
// First must Erase given memory region
|
||||
utest_printf("erasing given memory region\n");
|
||||
|
@ -476,8 +477,8 @@ void test_erase_functionality()
|
|||
TEST_ASSERT_EQUAL(erase_value, out_data_buf[i]);
|
||||
}
|
||||
|
||||
free(data_buf);
|
||||
free(out_data_buf);
|
||||
delete[] out_data_buf;
|
||||
delete[] data_buf;
|
||||
}
|
||||
|
||||
void test_contiguous_erase_write_read()
|
||||
|
@ -486,11 +487,6 @@ void test_contiguous_erase_write_read()
|
|||
|
||||
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
|
||||
|
||||
// Flashiap boards with inconsistent sector size will not align with random start addresses
|
||||
if (bd_arr[test_iteration] == flashiap) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Test flow:
|
||||
// 1. Erase whole test area
|
||||
// - Tests contiguous erase
|
||||
|
@ -499,57 +495,30 @@ void test_contiguous_erase_write_read()
|
|||
// 3. Return step 2 for whole erase region
|
||||
|
||||
// Test parameters
|
||||
bd_size_t erase_size = block_device->get_erase_size();
|
||||
TEST_ASSERT(erase_size > 0);
|
||||
bd_size_t program_size = block_device->get_program_size();
|
||||
TEST_ASSERT(program_size > 0);
|
||||
utest_printf("erase_size=%" PRId64 "\n", erase_size);
|
||||
utest_printf("program_size=%" PRId64 "\n", program_size);
|
||||
utest_printf("block_device->size()=%" PRId64 "\n", block_device->size());
|
||||
|
||||
// Determine write/read buffer size
|
||||
// start write_read_buf_size from 1% block_device->size()
|
||||
bd_size_t write_read_buf_size = block_device->size() / 100; // 1%, 10k=100, 100k=1k, 1MB=10k, 32MB=32k
|
||||
// try to limit write_read_buf_size to 10k. If program_size*2 is larger than 10k, that will be used instead.
|
||||
if (write_read_buf_size > 10000) {
|
||||
write_read_buf_size = 10000;
|
||||
}
|
||||
// 2 program_size blocks is minimum for contiguous write/read test
|
||||
if (write_read_buf_size < program_size * 2) {
|
||||
write_read_buf_size = program_size * 2; // going over 10k
|
||||
}
|
||||
bd_size_t contiguous_write_read_blocks_per_region = write_read_buf_size /
|
||||
program_size; // 2 is minimum to test contiguous write
|
||||
write_read_buf_size = contiguous_write_read_blocks_per_region * program_size;
|
||||
utest_printf("contiguous_write_read_blocks_per_region=%" PRIu64 "\n", contiguous_write_read_blocks_per_region);
|
||||
utest_printf("write_read_buf_size=%" PRIu64 "\n", write_read_buf_size);
|
||||
|
||||
// Determine test region count
|
||||
int contiguous_write_read_regions = TEST_BLOCK_COUNT;
|
||||
utest_printf("contiguous_write_read_regions=%d\n", contiguous_write_read_regions);
|
||||
|
||||
// Determine whole erase size
|
||||
bd_size_t contiguous_erase_size = write_read_buf_size * contiguous_write_read_regions;
|
||||
contiguous_erase_size -= contiguous_erase_size % erase_size; // aligned to erase_size
|
||||
contiguous_erase_size += erase_size; // but larger than write/read size * regions
|
||||
utest_printf("contiguous_erase_size=%" PRIu64 "\n", contiguous_erase_size);
|
||||
|
||||
// Determine starting address
|
||||
bd_addr_t start_address = rand(); // low 32 bytes
|
||||
start_address += (uint64_t)rand() << 32; // high 32 bytes
|
||||
start_address %= block_device->size() - contiguous_erase_size - erase_size; // fit all data + alignment reserve
|
||||
start_address += erase_size; // add alignment reserve
|
||||
start_address -= start_address % erase_size; // align with erase_block
|
||||
bd_addr_t stop_address = start_address + write_read_buf_size * contiguous_write_read_regions;
|
||||
// Determine start_address & stop_address
|
||||
uint8_t sector_num = rand() % (num_of_sectors - 2);
|
||||
bd_addr_t start_address = sectors_addr[sector_num];
|
||||
bd_addr_t stop_address = sectors_addr[sector_num + 2];
|
||||
utest_printf("start_address=0x%016" PRIx64 "\n", start_address);
|
||||
utest_printf("stop_address=0x%016" PRIx64 "\n", stop_address);
|
||||
|
||||
// Allocate write/read buffer
|
||||
uint8_t *write_read_buf = (uint8_t *)malloc(write_read_buf_size);
|
||||
if (write_read_buf == NULL) {
|
||||
TEST_SKIP_MESSAGE("not enough memory for test");
|
||||
bd_size_t contiguous_erase_size = stop_address - start_address;
|
||||
TEST_ASSERT(contiguous_erase_size > 0);
|
||||
utest_printf("contiguous_erase_size=%d\n", contiguous_erase_size);
|
||||
|
||||
bd_size_t write_read_buf_size = program_size;
|
||||
if (contiguous_erase_size / program_size > 8 && contiguous_erase_size % (program_size * 8) == 0) {
|
||||
write_read_buf_size = program_size * 8;
|
||||
}
|
||||
utest_printf("write_read_buf_size=%" PRIu64 "\n", (uint64_t)write_read_buf_size);
|
||||
|
||||
// Allocate write/read buffer
|
||||
uint8_t *write_read_buf = new (std::nothrow) uint8_t[write_read_buf_size];
|
||||
TEST_SKIP_UNLESS_MESSAGE(contiguous_erase_size, "Not enough memory for test.\n");
|
||||
|
||||
// Must Erase the whole region first
|
||||
utest_printf("erasing memory, from 0x%" PRIx64 " of size 0x%" PRIx64 "\n", start_address, contiguous_erase_size);
|
||||
|
@ -562,7 +531,7 @@ void test_contiguous_erase_write_read()
|
|||
for (size_t i = 0; i < write_read_buf_size; i++) {
|
||||
write_read_buf[i] = (uint8_t)rand();
|
||||
}
|
||||
utest_printf("pre-filling memory, from 0x%" PRIx64 " of size 0x%" PRIx64 "\n", start_address + offset,
|
||||
DEBUG_PRINTF("pre-filling memory, from 0x%" PRIx64 " of size 0x%" PRIx64 "", start_address + offset,
|
||||
write_read_buf_size);
|
||||
err = block_device->program((const void *)write_read_buf, start_address + offset, write_read_buf_size);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
@ -576,29 +545,24 @@ void test_contiguous_erase_write_read()
|
|||
// Loop through all write/read regions
|
||||
int region = 0;
|
||||
for (; start_address < stop_address; start_address += write_read_buf_size) {
|
||||
utest_printf("\nregion #%d start_address=0x%016" PRIx64 "\n", region++, start_address);
|
||||
|
||||
// Generate test data
|
||||
unsigned int seed = rand();
|
||||
utest_printf("generating test data, seed=%u\n", seed);
|
||||
srand(seed);
|
||||
for (size_t i = 0; i < write_read_buf_size; i++) {
|
||||
write_read_buf[i] = (uint8_t)rand();
|
||||
}
|
||||
|
||||
// Write test data
|
||||
utest_printf("writing test data\n");
|
||||
err = block_device->program((const void *)write_read_buf, start_address, write_read_buf_size);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
// Read test data
|
||||
memset(write_read_buf, 0, (size_t)write_read_buf_size);
|
||||
utest_printf("reading test data\n");
|
||||
err = block_device->read(write_read_buf, start_address, write_read_buf_size);
|
||||
TEST_ASSERT_EQUAL(0, err);
|
||||
|
||||
// Verify read data
|
||||
utest_printf("verifying test data\n");
|
||||
srand(seed);
|
||||
for (size_t i = 0; i < write_read_buf_size; i++) {
|
||||
uint8_t expected_value = (uint8_t)rand();
|
||||
|
@ -608,7 +572,6 @@ void test_contiguous_erase_write_read()
|
|||
}
|
||||
TEST_ASSERT_EQUAL(write_read_buf[i], expected_value);
|
||||
}
|
||||
utest_printf("verify OK\n");
|
||||
}
|
||||
|
||||
free(write_read_buf);
|
||||
|
|
Loading…
Reference in New Issue