esp32s3 simd 指令集简单介绍与使用

news/2024/12/19 19:03:43/文章来源:https://www.cnblogs.com/shumei52/p/18617794

什么是SIMD

SIMD(Single Instruction, Multiple Data,单指令多数据)是一种并行计算的架构和技术,用于在计算机处理器中同时对多个数据点执行相同的操作

  • 单指令多数据
    • 在SIMD架构中,一条指令可以处理多个数据
  • 并行处理
    • SIMD通过并行处理多个数据元素来提高计算效率。这种并行性特别适合于需要对大量数据进行相同操作的任务,如图像处理、音频处理和矩阵运算
  • 硬件实现
    • ESP32S3中,乐鑫为了提升此芯片的神经网络运算能力,加入了SIMD相关指令集,程序员可以使用这些指令集来优化性能

如何查看这些指令集

在esp32-s3_technical_reference_manual中的第一章处理器指令扩展中,乐鑫详细的介绍了S3芯片中SIMD指令以及使用方法

esp32s3都出来几年了,但是乐鑫在今年的文档中才开始描述这部分

  • 处理器指令拓展 (PIE, Processor Instruction Extensions) 具有如下特性
    • 增加 128-bit 位宽通用寄存器
    • 支持 128-bit 位宽的向量数据操作,包括:乘法、加法、减法、累加、移位、比较等
    • 合并数据搬运指令与运算指令
    • 支持非对齐 128-bit 带宽的向量数据
    • 支持取饱和操作

更详细的指令说明在参考手册文档的表1-4中

如何使用

我是一个汇编小白,间断性的学习过几次,但是工作中根本用不到,都忘记了

目前已经有很多开源项目中使用了ESP32S3的SIMD指令,例如:

  • JPEGDEC开源库,作者针对ESP32S3进行了SIMD优化,大大降低jpeg的解码了时间 https://github.com/bitbank2/JPEGDEC/issues/56
  • 陈亮在此对其进行了测试 https://www.bilibili.com/video/BV1t94y1a7k6/
  • 乐鑫官方在esp_lvgl_port中,在对lvgl9的适配中 增加了simd的渲染适配,但是比较局限,只支持数据填充,不支持颜色混合等 https://github.com/espressif/esp-bsp/tree/master/components/esp_lvgl_port/src/lvgl9/simd
  • 乐鑫在esp_new_jpg库中,也使用simd对jpeg解码进行了加速

编码测试

我写了一个测试demo,用来测试使用pie编程和c语言编程,simd指令能提速多少

测试内容为将两个8K的int16数据进行相加,使用定时器记录其时间,并进行对比

首先建立一个空白工程,然后新建一个asm_test.s,并且在cmakelists.txt中将其导入编译

在asm_test.s中增加以下内容(我参考了很多代码后,并且边问gpt边猜测边学,写下了以下代码)

# 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 nmovi a9, 0 # control number of data
process_channel:ee.vld.128.ip q0, a2, 16ee.vld.128.ip q1, a3,16ee.vadds.s16 q2, q0, q1ee.vst.128.ip q2, a4, 16addi a9, a9, 8bge a9, a5, pie_loop_endj process_channelpie_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();input_2[i] = rand();}// test asmprintf("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 ansicprintf("\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]);
}

额外的,我增加了sdkconfig.defaults, 为了将芯片的性能拉到最高

CONFIG_IDF_TARGET="esp32s3"
CONFIG_IDF_TARGET_ESP32S3=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B=y
CONFIG_ESP32S3_DATA_CACHE_64KB=y
CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y

测试

编译烧录后,开发板上打印出了以下信息:

start asm
output[2]:32767
output[4]:32767
output[8]:14096
output[16]:32767
output[32]:-14332
output[64]:-21112
output[128]:12022
output[256]:20041
output[512]:30343
output[1024]:-4054
output[2048]:-3496start c
output[2]:-18248
output[4]:-24817
output[8]:14096
output[16]:-19842
output[32]:-14332
output[64]:-21112
output[128]:12022
output[256]:20041
output[512]:30343
output[1024]:-4054
output[2048]:-3496pie: 55 us, ansic 379 us, pie faster: 85%

可以看到pie指令集所消耗的时间远小于C语言,pie速度几乎是c语言的7倍

但是输出好像有些问题,pie计算时,一些本来应该溢出的计算值,变成了32767,通过查阅手册,发现这种问题是正常的,在1.5.4章节,详细说明了数据溢出相关的问题

将input_1和input_2的值进行限制,输出结果就没有问题了

    input_1[i] = rand() % 5000;input_2[i] = rand() % 5000;

输出结果

start asm
output[2]:5208
output[4]:5375
output[8]:5696
output[16]:3814
output[32]:1188
output[64]:1696
output[128]:4990
output[256]:3433
output[512]:4159
output[1024]:3106
output[2048]:2464start c
output[2]:5208
output[4]:5375
output[8]:5696
output[16]:3814
output[32]:1188
output[64]:1696
output[128]:4990
output[256]:3433
output[512]:4159
output[1024]:3106
output[2048]:2464
pie: 57 us, ansic 381 us, pie faster: 85%

其他

ESP32S3的SIMD指令集,应用场合较为局限,对程序员的能力要求较高,并且没有将这些指令广泛的封装成库

自己写的话,受限于汇编能力,只能完成一些较为简单的功能,并且数据在不对齐的情况下,加速效果会稍慢

JPEGDEC的作者在这里也有两篇博客,可以额外了解esp32s3 simd的更多信息:

  • https://bitbanksoftware.blogspot.com/2024/01/esp32-s3-simd-minimal-example.html?m=1
  • https://bitbanksoftware.blogspot.com/2024/01/surprise-esp32-s3-has-few-simd.html?m=1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/855528.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCL 编程步骤 2. 获取设备

clGetDeviceIDs 查询支持OpenCL设备列表: cl_int clGetDeviceIDs(cl_platform_id platform ,cl_device_type device_type ,cl_uint num_entries ,cl_device_id *devices ,cl_uint *num_devices )与clGetPlatformIDs函数类似,第一次调用时,devic…

记录一下:小华半导体HC32F448建立MDK工程

1.先到官网上下载文件 a>下载驱动库:HC32F448_DDL_Rev1.1.0.zip 驱动库中是包括了例程的。 b>下载样例:HC32F448_Template_Rev1.0.1.zip 可以直接复制官方的样例,就不用自己创建工程了。 c>下载芯片支持包:HC32F448_IDE_Rev1.0.1.zip 下载后双击安装即可。否则KEI…

4大应用场景揭秘:AI视频监控在养老院中的智能化管理与安全保障

随着人口老龄化的加剧,养老院的管理面临着越来越多的挑战。传统的人工巡查方式不仅难以做到全天候监控,而且存在响应迟缓、效率低下等问题。为了解决这些问题,思通数科推出的AI视频监控系统,利用人工智能技术提供了一种高效、智能化的解决方案。尤其在养老院的老人体征监控…

考勤管理系统

实现对用户信息的添加,查看,删除 实现对部门信息的添加,查看 实现用户登录功能,修改密码功能。 页面与之前的大相径庭。 还是一样的框架总体感觉换汤不换药,目前就是熟练度问题

浏览器怎么渲染数据的

突然发现自己对于css的样式规则一直都没有完全明白,今天写文好好整明白 浏览器渲染原理 1. 浏览器向服务器请求html文件 2. html文件返回浏览器 3. 浏览器解读html文件<!DOCTYPE html>//告诉浏览器,这是html5文件// html树<html lang="en">//语言<h…

在宝塔里添加反向代理

安装OnlyOffice时,需要配置反向代理; 完成以上操作之后,访问时有可能出现504报错,也可能就可以正常访问了。如果报错可以修改上图反向代理中的目标URL的内容将域名改成127.0.0.1。我当时改成http://127.0.0.1:9633就可以了本文来自博客园,作者:飞龙在生,转载请注明原文链…

2024 Clion安装使用教程(附激活以及常见问题处理)

第一步:下载Clion安装包 访问Clion官网,下载Clion第二步: 安装 Clion下载完成后,进行安装,next,安装完成点击xx 关掉程序! 第三步: 下载补丁 Clion补丁文件 点击获取补丁下载成功后,打开标注的文件文件夹 , 进入到文件夹 /jetbra 注意: 这个文件夹单独copy一份,所属文…

语言沟通中的设计实现

系统设计的目的是更好的支持需求 我们常说,只要业务能将你的需求描述清楚,能自圆其说,我们就有办法实现。 这其实是系统设计的最理想的状态, 如果业务没想清楚,那么在系统实现中,一定会把问题暴露出来。很多时候,问题的暴露源于没有考虑周全亦或都没有考虑这种场景! 比…

Python 解密 Navicat导出的数据库连接,Navicat数据库连接导入DBeaver。

最近公司收到Navicat律师告知书,让停止使用Navicat,用了那么久的数据库连接工具,不得不换其他的。 最终选择了开源的DBeaver。 安装完DBeaver后,把Navicat导出的connections.ncx文件直接导入DBeaver。直接访问提示连接失败,因为connections.ncx文件里的密码都是加密的。 如…

营销系统缺失投放概念

营销系统现阶段分为营销权益工具、玩法、招商提报三大块。其中权益工具主要负责创建券、促销、换购类优惠权益。玩法负责用户与平台之间的连接,通过任务式交互获得权益。招商提报主要是面向商家参与活动的连接。比如要做一个活动,需要从招商发布活动信息,提报统一创建营销权…

一款使用NET+MQTT+Arduino开发的智能浇花工具

最近闲来无事,对硬件控制产生了兴趣。看到家里的盆栽,我突然萌生了制作一个自动浇水工具的想法。通过在淘宝搜索并查找相关资料,我了解了需要的硬件和通信协议。接下来,我们先看看需要做哪些准备工作(如安装 Arduino、.NET、EMQX 工具等,请自行搜索并完成安装)。 准备工…