mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
spiflash: added esp_flash API concurrency pressure test
This commit is contained in:
parent
0e6d3aa9cd
commit
267ab08a29
@ -0,0 +1,8 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
project(test_esp_flash_stress)
|
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
|
@ -0,0 +1,7 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_esp_flash_stress.c")
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(SRCS ${srcs}
|
||||
WHOLE_ARCHIVE)
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// load partition table in tests will use memory
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (600)
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
esp_reent_cleanup(); //clean up some of the newlib's lazy allocations
|
||||
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf(" ______ _____ _____ ______ _ _ _____ _ \n");
|
||||
printf("| ____|/ ____| __ \\ | ____| | | | / ____| | \n");
|
||||
printf("| |__ | (___ | |__) | | |__ | | __ _ ___| |__ | (___ | |_ _ __ ___ ___ ___ \n");
|
||||
printf("| __| \\___ \\| ___/ | __| | |/ _` / __| '_ \\ \\___ \\| __| '__/ _ \\/ __/ __|\n");
|
||||
printf("| |____ ____) | | | | | | (_| \\__ \\ | | | ____) | |_| | | __/\\__ \\__ \\\n");
|
||||
printf("|______|_____/|_| |_| |_|\\__,_|___/_| |_| |_____/ \\__|_| \\___||___/___/\n");
|
||||
|
||||
unity_run_menu();
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_partition.h"
|
||||
|
||||
portMUX_TYPE s_test_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ESP Flash API Concurrency Pressure Test
|
||||
---------------------------------------------------------------*/
|
||||
#define TEST_FLASH_CONCURRENCY_TASK_NUM 12
|
||||
|
||||
static int s_test_concurrency_id;
|
||||
//only used for finite loop for CI test
|
||||
SemaphoreHandle_t s_test_concurrency_smphr;
|
||||
|
||||
typedef struct {
|
||||
bool is_pressure_test;
|
||||
const esp_partition_t *part;
|
||||
} test_concurrency_ctx_t;
|
||||
|
||||
|
||||
static const esp_partition_t *get_test_flash_partition(void)
|
||||
{
|
||||
/* This finds "flash_test" partition defined in partition_table_unit_test_app.csv */
|
||||
const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
|
||||
ESP_PARTITION_SUBTYPE_ANY, "flash_test");
|
||||
assert(result != NULL); /* means partition table set wrong */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void s_test_flash_ops_task(void *arg)
|
||||
{
|
||||
test_concurrency_ctx_t *test_ctx = (test_concurrency_ctx_t *)arg;
|
||||
bool is_pressure_test = test_ctx->is_pressure_test;;
|
||||
esp_flash_t *chip = test_ctx->part->flash_chip;
|
||||
uint32_t offs = test_ctx->part->address;
|
||||
|
||||
portENTER_CRITICAL(&s_test_spinlock);
|
||||
int id = s_test_concurrency_id;
|
||||
s_test_concurrency_id++;
|
||||
portEXIT_CRITICAL(&s_test_spinlock);
|
||||
|
||||
int flash_block_sz = 4096;
|
||||
char *buffer = calloc(1, flash_block_sz);
|
||||
TEST_ASSERT(buffer);
|
||||
srand(id + 299);
|
||||
int delay_us = rand() % 1000;
|
||||
printf("delay_us: %d\n", delay_us);
|
||||
|
||||
if (is_pressure_test) {
|
||||
printf("INFINITE_LOOP\n");
|
||||
while (1) {
|
||||
printf("%s %d is running\n", __func__, id);
|
||||
TEST_ESP_OK(esp_flash_erase_region(chip, id * flash_block_sz + offs, flash_block_sz));
|
||||
TEST_ESP_OK(esp_flash_write(chip, buffer, id * flash_block_sz + offs, flash_block_sz));
|
||||
TEST_ESP_OK(esp_flash_read(chip, buffer, id * flash_block_sz + offs, flash_block_sz));
|
||||
vTaskDelay(pdMS_TO_TICKS(delay_us));
|
||||
}
|
||||
} else {
|
||||
printf("FINITE_LOOP\n");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
TEST_ESP_OK(esp_flash_erase_region(chip, id * flash_block_sz + offs, 4096));
|
||||
TEST_ESP_OK(esp_flash_write(chip, buffer, id * flash_block_sz + offs, flash_block_sz));
|
||||
TEST_ESP_OK(esp_flash_read(chip, buffer, id * flash_block_sz + offs, flash_block_sz));
|
||||
vTaskDelay(pdMS_TO_TICKS(delay_us));
|
||||
}
|
||||
printf("%s %d finishes\n", __func__, id);
|
||||
free(buffer);
|
||||
xSemaphoreGive(s_test_concurrency_smphr);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------
|
||||
Uni Core
|
||||
-------------------------------------------*/
|
||||
TEST_CASE("Flash UniCore: Test ESP Flash API Concurrency", "[esp_flash]")
|
||||
{
|
||||
const esp_partition_t* part = get_test_flash_partition();
|
||||
|
||||
s_test_concurrency_id = 0;
|
||||
s_test_concurrency_smphr = xSemaphoreCreateCounting(TEST_FLASH_CONCURRENCY_TASK_NUM, 0);
|
||||
TEST_ASSERT(s_test_concurrency_smphr);
|
||||
|
||||
char flash_task_name[32];
|
||||
test_concurrency_ctx_t ctx = {
|
||||
.is_pressure_test = false,
|
||||
.part = part,
|
||||
};
|
||||
|
||||
for (int i = 0; i < TEST_FLASH_CONCURRENCY_TASK_NUM; i++) {
|
||||
int l = snprintf(flash_task_name, 32, "flash_ops_task%d", i);
|
||||
flash_task_name[l] = '\0';
|
||||
xTaskCreatePinnedToCore(&s_test_flash_ops_task, flash_task_name, 4096, (void *)(&ctx), 5, NULL, 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TEST_FLASH_CONCURRENCY_TASK_NUM; i++) {
|
||||
TEST_ASSERT(xSemaphoreTake(s_test_concurrency_smphr, portMAX_DELAY) == pdTRUE);
|
||||
}
|
||||
vTaskDelay(1);
|
||||
vSemaphoreDelete(s_test_concurrency_smphr);
|
||||
}
|
||||
|
||||
/**
|
||||
* esp_flash APIs concurrency pressure test
|
||||
* This test is for manually test
|
||||
*/
|
||||
TEST_CASE("Flash UniCore: Test ESP Flash API Concurrency [Stress]", "[esp_flash][stress][manual][ignore]")
|
||||
{
|
||||
const esp_partition_t* part = get_test_flash_partition();
|
||||
|
||||
s_test_concurrency_id = 0;
|
||||
char flash_task_name[32];
|
||||
test_concurrency_ctx_t ctx = {
|
||||
.is_pressure_test = true,
|
||||
.part = part,
|
||||
};
|
||||
|
||||
for (int i = 0; i < TEST_FLASH_CONCURRENCY_TASK_NUM; i++) {
|
||||
int l = snprintf(flash_task_name, 32, "flash_ops_task%d", i);
|
||||
flash_task_name[l] = '\0';
|
||||
xTaskCreatePinnedToCore(&s_test_flash_ops_task, flash_task_name, 4096, (void *)(&ctx), 5, NULL, 0);
|
||||
}
|
||||
|
||||
while(1);
|
||||
}
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
/*-------------------------------------------
|
||||
Dual Core
|
||||
-------------------------------------------*/
|
||||
TEST_CASE("Flash DualCore: Test ESP Flash API Concurrency", "[esp_flash]")
|
||||
{
|
||||
const esp_partition_t* part = get_test_flash_partition();
|
||||
|
||||
s_test_concurrency_id = 0;
|
||||
s_test_concurrency_smphr = xSemaphoreCreateCounting(TEST_FLASH_CONCURRENCY_TASK_NUM, 0);
|
||||
TEST_ASSERT(s_test_concurrency_smphr);
|
||||
|
||||
char flash_task_name[32];
|
||||
test_concurrency_ctx_t ctx = {
|
||||
.is_pressure_test = false,
|
||||
.part = part,
|
||||
};
|
||||
|
||||
for (int i = 0; i < TEST_FLASH_CONCURRENCY_TASK_NUM / 2; i++) {
|
||||
int l = snprintf(flash_task_name, 32, "core0_flash_ops_task%d", i);
|
||||
flash_task_name[l] = '\0';
|
||||
xTaskCreatePinnedToCore(&s_test_flash_ops_task, flash_task_name, 4096, (void *)(&ctx), 5, NULL, 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TEST_FLASH_CONCURRENCY_TASK_NUM / 2; i++) {
|
||||
int l = snprintf(flash_task_name, 32, "core1_flash_ops_task%d", i);
|
||||
flash_task_name[l] = '\0';
|
||||
xTaskCreatePinnedToCore(&s_test_flash_ops_task, flash_task_name, 4096, (void *)(&ctx), 5, NULL, 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TEST_FLASH_CONCURRENCY_TASK_NUM; i++) {
|
||||
TEST_ASSERT(xSemaphoreTake(s_test_concurrency_smphr, portMAX_DELAY) == pdTRUE);
|
||||
}
|
||||
vTaskDelay(1);
|
||||
vSemaphoreDelete(s_test_concurrency_smphr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* esp_flash APIs concurrency pressure test
|
||||
* This test is for manually test
|
||||
*/
|
||||
TEST_CASE("Flash DualCore: Test ESP Flash API Concurrency [Stress]", "[esp_flash][stress][manual][ignore]")
|
||||
{
|
||||
const esp_partition_t* part = get_test_flash_partition();
|
||||
|
||||
s_test_concurrency_id = 0;
|
||||
char flash_task_name[32];
|
||||
test_concurrency_ctx_t ctx = {
|
||||
.is_pressure_test = true,
|
||||
.part = part,
|
||||
};
|
||||
|
||||
for (int i = 0; i < TEST_FLASH_CONCURRENCY_TASK_NUM / 2; i++) {
|
||||
int l = snprintf(flash_task_name, 32, "core0_flash_ops_task%d", i);
|
||||
flash_task_name[l] = '\0';
|
||||
xTaskCreatePinnedToCore(&s_test_flash_ops_task, flash_task_name, 4096, (void *)(&ctx), 5, NULL, 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TEST_FLASH_CONCURRENCY_TASK_NUM / 2; i++) {
|
||||
int l = snprintf(flash_task_name, 32, "core1_flash_ops_task%d", i);
|
||||
flash_task_name[l] = '\0';
|
||||
xTaskCreatePinnedToCore(&s_test_flash_ops_task, flash_task_name, 4096, (void *)(&ctx), 5, NULL, 1);
|
||||
}
|
||||
|
||||
while(1);
|
||||
}
|
||||
#endif //#if !CONFIG_FREERTOS_UNICORE
|
@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
flash_test, data, fat, , 512K,
|
|
@ -0,0 +1,57 @@
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.supported_targets
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'release',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_esp_flash_stress(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases(group='esp_flash')
|
||||
|
||||
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.MSPI_F8R8
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'esp32s3_f8r8',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_esp_flash_stress_f8r8(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'esp32s3_rom_xip_psram',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_esp_flash_stress_rom_xip_psram(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.flash_suspend
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'esp32c3_suspend',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_flash_auto_suspend(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
@ -0,0 +1,4 @@
|
||||
# ESP32S3, F8R8, Flash 80M DDR, PSRAM 80M DDR, XIP_PSRAM
|
||||
|
||||
CONFIG_IDF_TARGET="esp32c3"
|
||||
CONFIG_SPI_FLASH_AUTO_SUSPEND=y
|
@ -0,0 +1,12 @@
|
||||
# ESP32S3, F8R8, Flash 80M DDR, PSRAM 80M DDR, XIP_PSRAM
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
CONFIG_ESPTOOLPY_OCT_FLASH=y
|
||||
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
|
||||
CONFIG_SPIRAM_RODATA=y
|
@ -0,0 +1,8 @@
|
||||
# ESP32S3, F8R8, ESP Flash ROM Version, XIP_PSRAM
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
|
||||
CONFIG_SPIRAM_RODATA=y
|
||||
CONFIG_SPI_FLASH_ROM_IMPL=y
|
@ -0,0 +1,3 @@
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
@ -0,0 +1,4 @@
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
Loading…
Reference in New Issue
Block a user