NEON快速入门
NEON
- 1.簡介
- 2.簡單實例
- 3.總結
1.簡介
沒有長篇大論,只用于NEON快速入門!
SIMD:
- 單指令處理多個數據的并行技術
- 例如在C語言中對一個int[8]的數組里每一個數都執行加1操作,SIMD技術可以通過一條add指令并行處理;而通常我們自己寫for循環需要執行8次add才能完成,耗時更多
NEON:
- 一種基于SIMD并適用于ARM的技術,從ARM-V7開始被采用,目前可以在ARM Cortex-A和Cortex-R系列處理器中使用
- 寄存器,用于存放需要操作的數據;16個128bit的寄存器(128bit代表最大長度,對于int類型數據,能存放4個,對于char類型數據能存放16個,也就是說我能直接把int[4]或者char[16]直接放到128bit的寄存器中)、32個64bit寄存器
- 支持的數據類型,上官網查詢
- 常用操作:加減乘除,數據之間的讀寫等
2.簡單實例
實例內容:兩個長度為5000的int型數組相加,把每個結果存入另一個長度為5000的數組當中,對比純C語言實現和NEON實現的性能。
純C實現函數:平平無奇,誰都能寫
NEON實現函數:
int32x4_t in1, in2, out:用于存放4個int型數據的變量,int32x4_t是一個數據類型聲明(和int效果一致),類似的還有int16x8_t(用于存放8個short類型數據)、int8x16_t(用于存放16個char類型數據),更詳細的去官網查詢
in1 = vld1q_s32(src1):將指針src1的4個數據加載到in1當中,vld1q_s32用于加載int型的數據,并且只會是4個數據,其余類型的加載函數自行查詢,但都是相對應的
src1 += 4:數據加載完成后,指針向后移動4位,用于后續數據加載
out = vaddq_s32(in1, in2):執行in1和in2兩個向量相加操作,并存入out中
vst1q_s32(dst, out):將out里的數據存入dst指針指向的內存中
完畢!
整體代碼
#include<time.h> #include<stdio.h> #include<stdlib.h> #include<arm_neon.h>void add_int_c(int* dst, int* src1, int* src2, int count) {int i;for (i = 0; i < count; i++)dst[i] = src1[i] + src2[i]; }void add_int_neon(int* dst, int* src1, int* src2, int count) {int i;for (i = 0; i < count; i += 4){int32x4_t in1, in2, out;in1 = vld1q_s32(src1);src1 += 4;in2 = vld1q_s32(src2);src2 += 4;out = vaddq_s32(in1, in2);vst1q_s32(dst, out);dst += 4;} }int main() {/* 數據內存分配,初始化 */int size = 5000;int *dst = (int*)malloc(size * sizeof(int));int *src1 = (int*)malloc(size * sizeof(int));int *src2 = (int*)malloc(size * sizeof(int));for(int i = 0; i < size; i++){src1[i] = i;src2[i] = i;}/* 時間初始化 */struct timespec time1_img = {0, 0};struct timespec time2_img = {0, 0};clock_gettime(CLOCK_REALTIME, &time1_img);for(int i = 0; i < size; i++){add_int_c(dst, src1, src2, size);}clock_gettime(CLOCK_REALTIME, &time2_img);printf("C time:%d ms\n", (time2_img.tv_sec - time1_img.tv_sec)*1000 + (time2_img.tv_nsec - time1_img.tv_nsec)/1000000);printf("dst[0]:%d\n", dst[0]);memset(dst, 0, size);clock_gettime(CLOCK_REALTIME, &time1_img);for(int i = 0; i < size; i++){add_int_neon(dst, src1, src2, size);}clock_gettime(CLOCK_REALTIME, &time2_img);printf("Neon time:%d ms\n", (time2_img.tv_sec - time1_img.tv_sec)*1000 + (time2_img.tv_nsec - time1_img.tv_nsec)/1000000);printf("dst[0]:%d\n", dst[0]);free(dst);free(src1);free(src2);return 0; }Makefile
CC = @echo " GCC $@"; $(CROSS)gccCROSS = arm-xmv2-linux- CFLAGS += -mcpu=cortex-a9 -mfloat-abi=softfp -mfpu=neon -mno-unaligned-access -fno-aggressive-loop-optimizations -flax-vector-conversions -fsigned-char -fopenmp CFLAGS += -std=gnu99 -Wall -O2TESTSOURCE = $(wildcard ./main.c) TESTTARGET = main.outTARGET = $(TESTTARGET) all:$(TARGET)$(TESTTARGET):$(CC) $(CFLAGS) -save-temps -o $(TESTTARGET) $(TESTSOURCE) -lstdc++ -lmclean:rm -f $(TESTTARGET)效果對比
3.總結
- demo中可以明顯看到程序執行耗時減少一半,效果非常明顯
- neon只適用于重復運算,我們只需要找到那些具有重復運算的地方,然后使用neon進行加速
- 第一次看到這些函數非常陌生,多去官網查幾次就熟悉了
總結
- 上一篇: Neon 指令
- 下一篇: rtx3060ti参数配置