Explore the PIE capabilities on the ESP32-P4 · Espressif Developer Portal #353
Replies: 7 comments 21 replies
|
Has the *.QUP variant for all the *.VMULAS.* instructions been removed in ESP32-P4 that was present in ESP32-S3? It was really useful... |
|
In the inline assembly example, the employed 'manual' way to allocate registers and save them on the stack should not be done. The way it is now, it's somewhat inefficient, and, more importantly, may result in corruption/incorrect operation, e.g. if the compiler decides to (inline the add_pie() function and) provide "y" in register x31 to the assembly fragment (i.e. %1 = x31). The better approach is to let the compiler handle the allocation of the (non-Q) registers, like |
|
How can I make use of the optimized memcpy on the p4, is that already part of newlib, or do I have to manually add this? |
ESP32-P4 PIE-Optimized memcpy BenchmarkTest ResultsJust ran some tests on my board with 128KB L2 cache config. Got pretty similar results: AnalysisThe SRAM→SRAM is significantly faster, around 4-5x speedup compared to PSRAM access. My PSRAM numbers are slightly higher than the earlier benchmarks, probably because I'm running at 200MHz PSRAM speed. The PSRAM→SRAM hitting ~185 MB/s makes sense - pretty close to the theoretical 200 MB/s limit. The bottleneck is definitely the PSRAM interface, not the CPU or cache. Test Code#include <stdio.h>
#include <stdint.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "esp_timer.h"
#include "rom/cache.h"
extern "C" {
void dl_esp32p4_memcpy(void *dst, const void *src, const size_t n);
}
#define BUFFER_SIZE (128 * 1024)
#define EVICT_SIZE (256 * 1024)
#define ALIGNMENT 128
#define NUM_ITERATIONS 10
static volatile uint64_t g_prevent_optimization = 0;
static void force_cache_eviction(volatile uint8_t *evict_buf)
{
volatile uint64_t sum = 0;
for (size_t i = 0; i < EVICT_SIZE; i += 64) {
sum += evict_buf[i];
}
g_prevent_optimization += sum;
asm volatile("fence" ::: "memory");
}
static void test_optimized_memcpy()
{
printf("\n========================================\n");
printf("ESP32-P4 Optimized memcpy Test\n");
printf("========================================\n");
printf("Buffer size: 128 KB\n");
printf("Iterations: %d\n\n", NUM_ITERATIONS);
volatile uint8_t *psram_src = (volatile uint8_t *)heap_caps_aligned_alloc(
ALIGNMENT, BUFFER_SIZE, MALLOC_CAP_SPIRAM);
uint8_t *sram_dst = (uint8_t *)heap_caps_aligned_alloc(
ALIGNMENT, BUFFER_SIZE, MALLOC_CAP_INTERNAL);
uint8_t *sram_src = (uint8_t *)heap_caps_aligned_alloc(
ALIGNMENT, BUFFER_SIZE, MALLOC_CAP_INTERNAL);
volatile uint8_t *evict_buf = (volatile uint8_t *)heap_caps_aligned_alloc(
ALIGNMENT, EVICT_SIZE, MALLOC_CAP_SPIRAM);
if (!psram_src || !sram_dst || !sram_src || !evict_buf) {
printf("ERROR: Allocation failed\n");
return;
}
for (size_t i = 0; i < BUFFER_SIZE; i++) {
psram_src[i] = (uint8_t)(i & 0xFF);
sram_src[i] = (uint8_t)((i + 128) & 0xFF);
}
for (size_t i = 0; i < EVICT_SIZE; i++) {
evict_buf[i] = (uint8_t)(i & 0xFF);
}
printf("TEST 1: PSRAM → SRAM\n");
printf("====================\n");
uint64_t total_psram_us = 0;
for (int i = 0; i < NUM_ITERATIONS; i++) {
force_cache_eviction(evict_buf);
Cache_Invalidate_Addr(CACHE_MAP_L2_CACHE, (uint32_t)psram_src, BUFFER_SIZE);
vTaskDelay(pdMS_TO_TICKS(10));
asm volatile("fence" ::: "memory");
int64_t start = esp_timer_get_time();
dl_esp32p4_memcpy(sram_dst, (const void *)psram_src, BUFFER_SIZE);
asm volatile("fence" ::: "memory");
int64_t end = esp_timer_get_time();
volatile uint64_t check = 0;
for (size_t j = 0; j < BUFFER_SIZE; j += 64) {
check += sram_dst[j];
}
g_prevent_optimization += check;
total_psram_us += (end - start);
}
float avg_psram_us = (float)total_psram_us / NUM_ITERATIONS;
float psram_bw = (BUFFER_SIZE / (1024.0f * 1024.0f)) / (avg_psram_us / 1e6f);
printf("Average time: %.1f us\n", avg_psram_us);
printf("Bandwidth: %.1f MB/s\n\n", psram_bw);
printf("TEST 2: SRAM → SRAM\n");
printf("====================\n");
uint64_t total_sram_us = 0;
for (int i = 0; i < NUM_ITERATIONS; i++) {
asm volatile("fence" ::: "memory");
int64_t start = esp_timer_get_time();
dl_esp32p4_memcpy(sram_dst, sram_src, BUFFER_SIZE);
asm volatile("fence" ::: "memory");
int64_t end = esp_timer_get_time();
volatile uint64_t check = 0;
for (size_t j = 0; j < BUFFER_SIZE; j += 64) {
check += sram_dst[j];
}
g_prevent_optimization += check;
total_sram_us += (end - start);
}
float avg_sram_us = (float)total_sram_us / NUM_ITERATIONS;
float sram_bw = (BUFFER_SIZE / (1024.0f * 1024.0f)) / (avg_sram_us / 1e6f);
printf("Average time: %.1f us\n", avg_sram_us);
printf("Bandwidth: %.1f MB/s\n\n", sram_bw);
printf("SUMMARY\n");
printf("=======\n");
printf("PSRAM → SRAM: %.1f MB/s\n", psram_bw);
printf("SRAM → SRAM: %.1f MB/s\n", sram_bw);
printf("Speedup: %.2fx\n", sram_bw / psram_bw);
printf("\nPSRAM theoretical max: ~200 MB/s\n");
printf("Prevent optimization: %llu\n", g_prevent_optimization);
printf("========================================\n\n");
heap_caps_free((void *)psram_src);
heap_caps_free(sram_dst);
heap_caps_free(sram_src);
heap_caps_free((void *)evict_buf);
}
extern "C" void app_main(void)
{
vTaskDelay(pdMS_TO_TICKS(100));
test_optimized_memcpy();
}Configuration# sdkconfig.defaults.esp32p4
CONFIG_IDF_TARGET="esp32p4"
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_SPIRAM=y
CONFIG_SPIRAM_SPEED_200M=y
CONFIG_CACHE_L2_CACHE_128KB=y
CONFIG_CACHE_L2_CACHE_LINE_128B=y
CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=n
CONFIG_ESP_INT_WDT=n
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_IDF_EXPERIMENTAL_FEATURES=yKey Configuration Parameters
DependenciesThis test requires the PIE-optimized memcpy from esp-dl: Source: https://github.com/espressif/esp-dl/blob/master/esp-dl/dl/tool/isa/esp32p4/dl_esp32p4_memcpy.S Build Instructions |
|
I wrote a blog post to help you transition from writing ESP32-S3 SIMD code to the ESP32-P4: |
|
With the help of AI (claude) i wrote a SIMD test app (P4 on the Tanmatsu device) and document the SIMD instruction we could find: https://github.com/nullislandspace/tanmatsu-simd-tests/blob/main/PIE_REFERENCE.md Not sure how helpful this is to anyone, but at least its a start. |
|
Some more information (brief description of (many of?) the instructions) here: |
Uh oh!
There was an error while loading. Please reload this page.
Explore the PIE capabilities on the ESP32-P4 · Espressif Developer Portal
The developer resources in just one place!
https://developer.espressif.com/blog/2024/12/pie-introduction/
All reactions