Skip to content

Improve genenral BlockDevice tests #10110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 27, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 67 additions & 104 deletions features/storage/TESTS/blockdevice/general_block_device/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <stdlib.h>
#include "BufferedBlockDevice.h"
#include "BlockDevice.h"
#include <algorithm>

#if COMPONENT_SPIF
#include "SPIFBlockDevice.h"
Expand All @@ -47,13 +48,27 @@
#include "FlashIAPBlockDevice.h"
#endif

// Debug available
#ifndef MODE_DEBUG
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we had other debug macros.
Or is this the pattern used within the storage tests?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@theamirocohen @davidsaada Would appreciate an answer here (I realise I only asked four hrs ago), but won't hold up the merge on it.

If it need to be fixed, it can be brought in later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unrelated to other debug macros. Original test code poured a lot of unnecessary prints during the test. Current change removed them (among the rest), by simply using the DEBUG_PRINT define, which is turned off by default depending on MODE_DEBUG. Guess these prints could have been removed altogether, but @theamirocohen took precautions by keeping them in for the case someone should want to see them while debugging.

#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
#define TEST_ERROR_MASK 16
#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;
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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()
Expand Down Expand Up @@ -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;
Expand All @@ -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()
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -398,39 +409,29 @@ 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
// "If get_erase_value() returns a non-negative byte value" for unknown case.
TEST_ASSERT(erase_value_int <= 255);
uint8_t erase_value = (uint8_t)erase_value_int;

// Determine data_buf_size
bd_size_t erase_size = block_device->get_erase_size();
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
bd_addr_t start_address = sectors_addr[rand() % num_of_sectors];
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;
}
// Determine data_buf_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;

// 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");
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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();
Expand All @@ -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);
Expand Down