您尚未登录。

楼主 # 2024-12-19 14:32:59

树莓学LINUX
会员
注册时间: 2021-10-28
已发帖子: 103
积分: 113
个人网站

esp32s3 SIMD的简单使用

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

离线

楼主 #1 2024-12-20 11:02:23

树莓学LINUX
会员
注册时间: 2021-10-28
已发帖子: 103
积分: 113
个人网站

Re: esp32s3 SIMD的简单使用

更详细的说明:
如何简单使用esp32s3的simd

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn