没有长篇大论,只用于NEON快速入门!
SIMD:
NEON:
实例内容:两个长度为5000的int型数组相加,把每个结果存入另一个长度为5000的数组当中,对比纯C语言实现和NEON实现的性能。
纯C实现函数:平平无奇,谁都能写
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];
}
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指针指向的内存中
完毕!
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;
}
}
整体代码
#include
#include
#include
#include
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)gcc
CROSS = 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 -O2
TESTSOURCE = $(wildcard ./main.c)
TESTTARGET = main.out
TARGET = $(TESTTARGET)
all:$(TARGET)
$(TESTTARGET):
$(CC) $(CFLAGS) -save-temps -o $(TESTTARGET) $(TESTSOURCE) -lstdc++ -lm
clean:
rm -f $(TESTTARGET)
效果对比