forked from thesofproject/sof
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add/enchance existing virtual memory heap testing. Change boot test trigger. Signed-off-by: Jakub Dabek <[email protected]>
- Loading branch information
1 parent
f6baccc
commit f6aa027
Showing
3 changed files
with
251 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,13 @@ | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
/* | ||
* Copyright(c) 2023 Intel Corporation. All rights reserved. | ||
* | ||
* Author: Guennadi Liakhovetski <[email protected]> | ||
*/ | ||
* Copyright(c) 2023 Intel Corporation. All rights reserved. | ||
* | ||
* Author: Guennadi Liakhovetski <[email protected]> | ||
*/ | ||
|
||
#include <errno.h> | ||
#include <stdbool.h> | ||
#include <stdlib.h> | ||
|
||
#include <adsp_memory_regions.h> | ||
#include <sof/boot_test.h> | ||
|
@@ -17,81 +18,264 @@ | |
|
||
LOG_MODULE_DECLARE(sof_boot_test, CONFIG_SOF_LOG_LEVEL); | ||
|
||
#define ALLOC_SIZE1 1616 | ||
#define ALLOC_SIZE2 26 | ||
/* Test function creating and freeing a vmh from given parameters */ | ||
static void test_vmh_init_and_free_heap(int memory_region_attribute, | ||
struct vmh_heap_config *config, | ||
int core_id, | ||
bool allocating_continuously, | ||
bool expect_success) | ||
{ | ||
struct vmh_heap *heap = vmh_init_heap(config, memory_region_attribute, | ||
core_id, allocating_continuously); | ||
if (expect_success) { | ||
zassert_not_null(heap, | ||
"Heap initialization expected to succeed but failed"); | ||
} | ||
else | ||
zassert_is_null(heap, "Heap initialization expected to fail but succeeded"); | ||
|
||
if (heap) { | ||
int ret = vmh_free_heap(heap); | ||
|
||
zassert_equal(ret, 0, "Failed to free heap"); | ||
} | ||
} | ||
|
||
static int vmh_test_single(bool span) | ||
/* Parametrized test function for vmh_alloc and vmh_free */ | ||
static void test_vmh_alloc_free_no_check(struct vmh_heap *heap, | ||
uint32_t alloc_size, | ||
bool expect_success) | ||
{ | ||
struct vmh_heap *h = vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, span); | ||
|
||
if (!h) | ||
return -EINVAL; | ||
|
||
char *buf = vmh_alloc(h, ALLOC_SIZE1); | ||
int ret1; | ||
|
||
if (buf) { | ||
buf[0] = 0; | ||
buf[ALLOC_SIZE1 - 1] = 15; | ||
|
||
ret1 = vmh_free(h, buf); | ||
if (ret1 < 0) | ||
goto out; | ||
} else if (span) { | ||
ret1 = -ENOMEM; | ||
LOG_ERR("Failed to allocate %u in contiguous mode", ALLOC_SIZE1); | ||
goto out; | ||
} else { | ||
LOG_WRN("Ignoring failure to allocate %u in non-contiguous mode", | ||
ALLOC_SIZE1); | ||
void *ptr = vmh_alloc(heap, alloc_size); | ||
|
||
if (expect_success) | ||
zassert_not_null(ptr, "Allocation expected to succeed but failed"); | ||
else | ||
zassert_is_null(ptr, "Allocation expected to fail but succeeded"); | ||
|
||
if (ptr) { | ||
int ret = vmh_free(heap, ptr); | ||
|
||
zassert_equal(ret, 0, "Failed to free allocated memory"); | ||
} | ||
} | ||
|
||
buf = vmh_alloc(h, ALLOC_SIZE2); | ||
/* Parametrized test function for vmh_alloc and vmh_free with memory read/write */ | ||
static void test_vmh_alloc_free_check(struct vmh_heap *heap, | ||
uint32_t alloc_size, | ||
bool expect_success) | ||
{ | ||
void *ptr = vmh_alloc(heap, alloc_size); | ||
|
||
if (!buf) { | ||
ret1 = -ENOMEM; | ||
LOG_ERR("Failed to allocate %u", ALLOC_SIZE2); | ||
goto out; | ||
if (expect_success) | ||
zassert_not_null(ptr, "Allocation expected to succeed but failed"); | ||
else { | ||
zassert_is_null(ptr, "Allocation expected to fail but succeeded"); | ||
return; // No need to proceed if allocation was expected to fail | ||
} | ||
|
||
buf[0] = 0; | ||
buf[ALLOC_SIZE2 - 1] = 15; | ||
if (ptr) { | ||
// Write test pattern to the allocated memory | ||
memset(ptr, 0xAA, alloc_size); | ||
|
||
// Verify the written test pattern at the start of the memory | ||
uint8_t start_val = *((uint8_t *)ptr); | ||
|
||
zassert_equal(start_val, 0xAA, | ||
"Memory content verification failed at the start"); | ||
|
||
ret1 = vmh_free(h, buf); | ||
if (ret1 < 0) | ||
LOG_ERR("Free error %d", ret1); | ||
// Verify the written test pattern at the end of the memory | ||
uint8_t end_val = *((uint8_t *)ptr + alloc_size - 1); | ||
|
||
out: | ||
int ret2 = vmh_free_heap(h); | ||
zassert_equal(end_val, 0xAA, | ||
"Memory content verification failed at the end"); | ||
|
||
if (ret2 < 0) | ||
LOG_ERR("Free heap error %d", ret2); | ||
// Verify the written test pattern at a random position within the memory | ||
if (alloc_size > 2) { | ||
uint32_t middle_pos = alloc_size / 2; // Example position in the middle | ||
uint8_t middle_val = *((uint8_t *)ptr + middle_pos); | ||
|
||
if (!ret1) | ||
ret1 = ret2; | ||
zassert_equal(middle_val, 0xAA, | ||
"Memory content verification failed in the middle"); | ||
} | ||
|
||
// Free the allocated memory | ||
int ret = vmh_free(heap, ptr); | ||
|
||
return ret1; | ||
zassert_equal(ret, 0, "Failed to free allocated memory"); | ||
} | ||
} | ||
|
||
static int vmh_test(void) | ||
/* Parametrized test function for multiple allocations on the same heap */ | ||
static void test_vmh_multiple_allocs(struct vmh_heap *heap, int num_allocs, | ||
uint32_t min_alloc_size, | ||
uint32_t max_alloc_size) | ||
{ | ||
int ret = vmh_test_single(false); | ||
void *ptrs[num_allocs]; | ||
uint32_t alloc_size; | ||
bool success; | ||
int ret; | ||
|
||
/* Perform multiple allocations */ | ||
for (int i = 0; i < num_allocs; i++) { | ||
/* Generate a random allocation size between min_alloc_size and max_alloc_size */ | ||
alloc_size = min_alloc_size + | ||
k_cycle_get_32() % (max_alloc_size - min_alloc_size + 1); | ||
|
||
if (ret < 0) { | ||
LOG_ERR("Non-contiguous test error %d", ret); | ||
return ret; | ||
/* Attempt to allocate memory */ | ||
ptrs[i] = vmh_alloc(heap, alloc_size); | ||
|
||
/* Check if allocation was expected to succeed */ | ||
zassert_true(ptrs[i] != NULL, | ||
"Allocation of size %u expected to succeed but failed", | ||
alloc_size); | ||
|
||
if (ptrs[i] != NULL) { | ||
LOG_INF("Test allocation size: %d", alloc_size); | ||
/* Example test pattern */ | ||
memset(ptrs[i], 0xAA, alloc_size); | ||
|
||
/* Verify the written test pattern */ | ||
uint8_t *byte_ptr = (uint8_t *)ptrs[i]; | ||
|
||
for (uint32_t j = 0; j < alloc_size; j++) { | ||
zassert_equal(byte_ptr[j], 0xAA, | ||
"Memory content verification failed at position %u", j); | ||
} | ||
} | ||
} | ||
|
||
/* Free the allocated memory */ | ||
for (int i = 0; i < num_allocs; i++) { | ||
if (ptrs[i]) { | ||
ret = vmh_free(heap, ptrs[i]); | ||
zassert_equal(ret, 0, "Failed to free allocated memory"); | ||
} | ||
} | ||
} | ||
|
||
ret = vmh_test_single(true); | ||
if (ret < 0) | ||
LOG_ERR("Contiguous test error %d", ret); | ||
/* Test case that uses the parametrized function for multiple allocations */ | ||
static void test_vmh_alloc_multiple_times(bool allocating_continuously) | ||
{ | ||
struct vmh_heap *heap = | ||
vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); | ||
|
||
zassert_not_null(heap, "Heap initialization failed"); | ||
|
||
/* Test multiple allocations with small sizes */ | ||
test_vmh_multiple_allocs(heap, 64, 4, 8); | ||
test_vmh_multiple_allocs(heap, 64, 4, 8); | ||
test_vmh_multiple_allocs(heap, 64, 4, 8); | ||
test_vmh_multiple_allocs(heap, 16, 4, 1024); | ||
test_vmh_multiple_allocs(heap, 16, 4, 1024); | ||
test_vmh_multiple_allocs(heap, 64, 1024, 4096); | ||
test_vmh_multiple_allocs(heap, 64, 4096, 8192); | ||
test_vmh_multiple_allocs(heap, 16, 1024, 4096); | ||
test_vmh_multiple_allocs(heap, 16, 4096, 8192); | ||
|
||
/* Clean up the heap after testing */ | ||
int ret = vmh_free_heap(heap); | ||
|
||
zassert_equal(ret, 0, "Failed to free heap after multiple allocations"); | ||
} | ||
|
||
/* Test function that calls parametrized tests for vmh_alloc and vmh_free */ | ||
static void test_vmh_alloc_free(bool allocating_continuously) | ||
{ | ||
struct vmh_heap *heap = | ||
vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); | ||
|
||
return ret; | ||
zassert_not_null(heap, "Heap initialization failed"); | ||
|
||
test_vmh_alloc_free_no_check(heap, 512, true); | ||
test_vmh_alloc_free_no_check(heap, 2048, true); | ||
test_vmh_alloc_free_no_check(heap, sizeof(int), false); | ||
test_vmh_alloc_free_no_check(heap, 0, false); | ||
|
||
test_vmh_alloc_free_check(heap, 512, true); | ||
test_vmh_alloc_free_check(heap, 2048, true); | ||
test_vmh_alloc_free_check(heap, sizeof(int), false); | ||
test_vmh_alloc_free_check(heap, 0, false); | ||
|
||
int ret = vmh_free_heap(heap); | ||
|
||
zassert_equal(ret, 0, "Failed to free heap"); | ||
|
||
/* Could add tests with configs for heaps*/ | ||
} | ||
|
||
/* Test function that calls parametrized tests for vmh_alloc and vmh_free */ | ||
static void test_heap_creation(void) | ||
{ | ||
test_vmh_init_and_free_heap(MEM_REG_ATTR_CORE_HEAP, NULL, 0, false, true); | ||
|
||
/* Try to setup with pre defined heap config */ | ||
struct vmh_heap_config config; | ||
|
||
config.block_bundles_table[0].block_size = 4; | ||
|
||
config.block_bundles_table[0].number_of_blocks = 80; | ||
|
||
config.block_bundles_table[1].block_size = 4; | ||
|
||
config.block_bundles_table[1].number_of_blocks = 80; | ||
|
||
test_vmh_init_and_free_heap(MEM_REG_ATTR_CORE_HEAP, &config, 0, false, true); | ||
} | ||
|
||
static void test_alloc_on_configured_heap(bool allocating_continuously) | ||
{ | ||
|
||
/* Try to setup with pre defined heap config */ | ||
struct vmh_heap_config config; | ||
|
||
config.block_bundles_table[0].block_size = 20; | ||
|
||
config.block_bundles_table[0].number_of_blocks = 80; | ||
|
||
/* Create continuous allocation heap for success test */ | ||
struct vmh_heap *heap = | ||
vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); | ||
|
||
/* Will succeed on continuous and fail with single block alloc */ | ||
test_vmh_alloc_free_check(heap, 512, allocating_continuously); | ||
|
||
int ret = vmh_free_heap(heap); | ||
|
||
zassert_equal(ret, 0, "Failed to free heap"); | ||
} | ||
|
||
/* Test cases for initializing heaps on all available regions */ | ||
static void test_vmh_init_all_heaps(void) | ||
{ | ||
int num_regions = CONFIG_MP_MAX_NUM_CPUS + VIRTUAL_REGION_COUNT; | ||
int i; | ||
const struct sys_mm_drv_region *virtual_memory_region = | ||
sys_mm_drv_query_memory_regions(); | ||
|
||
/* Test initializing all types of heaps */ | ||
for (i = 0; i < num_regions; i++) { | ||
|
||
/* Test without continuous allocation */ | ||
test_vmh_init_and_free_heap(virtual_memory_region[i].attr, NULL, 0, false, | ||
true); | ||
|
||
/* Test if it fails when heap already exists */ | ||
test_vmh_init_and_free_heap(virtual_memory_region[i].attr, NULL, 0, true, | ||
false); | ||
} | ||
} | ||
|
||
ZTEST(sof_boot, virtual_memory_heap) | ||
{ | ||
int ret = vmh_test(); | ||
test_heap_creation(); | ||
test_vmh_init_all_heaps(); | ||
test_alloc_on_configured_heap(true); | ||
test_alloc_on_configured_heap(false); | ||
test_vmh_alloc_free(true); | ||
test_vmh_alloc_free(false); | ||
test_vmh_alloc_multiple_times(true); | ||
test_vmh_alloc_multiple_times(false); | ||
|
||
TEST_CHECK_RET(ret, "virtual_memory_heap"); | ||
TEST_CHECK_RET(true, "virtual_memory_heap"); | ||
} |