Improve general Block Device tests

Fixing all rand issues, aligning erase addresses, moving prints to debug mode.
pull/10110/head
Amir Cohen 2019-03-26 14:49:57 +02:00
parent f1e664be82
commit ba6748fe41
1 changed files with 67 additions and 104 deletions

View File

@ -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);