esp32s3 新增了扩展指令集 有一些寄存器可以实现并行运算,达到simd的效果
主要的指令集详细说明在技术手册中的第一章节,但是感觉上来说,应用场景比较局限,我简单学习了一下后,写了个测试代码
先建立一个空白工程,main下面新增一个.s文件,粘贴拷贝,然后将这个汇编文件编译进去:
# use to esp32s3 simd test
.global esp32s3_simd_test_asm
esp32s3_simd_test_asm:
entry a1, 48
#a2 in_1
#a3 in_2
#a4 out
#a5 n
movi a9, 0 # control number of data
process_channel:
ee.vld.128.ip q0, a2, 16
ee.vld.128.ip q1, a3,16
ee.vadds.s16 q2, q0, q1
ee.vst.128.ip q2, a4, 16
addi a9, a9, 8
bge a9, a5, pie_loop_end
j process_channel
pie_loop_end:
retw
在main.c中 增加以下测试代码:
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_heap_caps.h"
#include <stdint.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "esp_timer.h"
int16_t __attribute__((aligned (16))) input_1[8192];
int16_t __attribute__((aligned (16))) input_2[8192];
int16_t __attribute__((aligned (16))) out[8192];
//使用此函数完成input1 和 input2 中的元素逐个相加,并且将数据保存在output中。传入的数组长度为8192=8*1024
void esp32s3_simd_test_asm(int16_t *input1, int16_t *input2, int16_t *output,int size);
void esp32s3_simd_test_c(int16_t *input1, int16_t *input2, int16_t *output ,int size);
void output_debug(int16_t *output);
void app_main(void)
{
long long start_time, end_time, time_instance_ansi_c, time_instance_pie;
//赋予初始值
for(int i = 0 ; i < 8192 ; i++)
{
input_1[i] = rand() % 5000;
input_2[i] = rand() % 5000;
}
// test asm
printf("start asm\n");
start_time = esp_timer_get_time();
esp32s3_simd_test_asm(input_1,input_2,out,8192);
end_time = esp_timer_get_time();
time_instance_pie = end_time - start_time;
output_debug(out);
// test ansic
printf("\nstart c\n");
start_time = esp_timer_get_time();
esp32s3_simd_test_c(input_1,input_2,out,8192);
end_time = esp_timer_get_time();
time_instance_ansi_c = end_time - start_time;
output_debug(out);
printf("pie: %llu us, ansic %llu us, pie faster: %lld%%\n",
time_instance_pie,
time_instance_ansi_c,
(time_instance_ansi_c - time_instance_pie) * 100 / time_instance_ansi_c);
}
void esp32s3_simd_test_c(int16_t *input1, int16_t *input2, int16_t *output ,int size)
{
for(int i = 0 ; i < size ; i++)
{
output[i] = input1[i] + input2[i];
}
}
void output_debug(int16_t *output)
{
printf("output[%d]:%d\n",2,output[2]);
printf("output[%d]:%d\n",4,output[4]);
printf("output[%d]:%d\n",8,output[8]);
printf("output[%d]:%d\n",16,output[16]);
printf("output[%d]:%d\n",32,output[32]);
printf("output[%d]:%d\n",64,output[64]);
printf("output[%d]:%d\n",128,output[128]);
printf("output[%d]:%d\n",256,output[256]);
printf("output[%d]:%d\n",512,output[512]);
printf("output[%d]:%d\n",1024,output[1024]);
printf("output[%d]:%d\n",2048,output[2048]);
}
代码主要实现的是两个8K长度的int16数组相加,然后将部分计算结果验证对错,并且计算使用时长
在主频240Mhz的情况下,消耗时间如下:
pie: 57 us, ansic 381 us, pie faster: 85%
汇编比C语言快7倍左右
还有一个地方需要注意的是,128bit的寄存器在相加时,超过最大值后会封顶,但不会溢出,比如:
计算 20000 + 20000 ,simd计算结果为32767 正常C语言计算为 40000−65536=−25536
离线
更详细的说明:
如何简单使用esp32s3的simd
离线