在 Go 中使用 Neon
由于大模型的爆火,SIMD 正在受到越来越多的关注
什么是 Neon
Arm Neon 技术是面向 A/R 型处理器的先进单指令多数据(SIMD)架构扩展。
A 系列处理器面向高性能计算设备,支持 32 位和 64 位软件;而 R 系列处理器则专注于实时和深度嵌入式系统,注重确定性和低延迟响应时间。这两个配置都属于 ARM 架构,并为不同的应用领域提供支持。
Neon 技术是一种打包的 SIMD 架构。Neon 寄存器被视为具有相同数据类型的元素的向量,Neon 指令可以同时对多个元素进行操作。该技术支持多种数据类型,包括浮点和整数运算。Neon 技术在 ARM 处理器中广泛应用于加速多媒体和信号处理等计算密集型任务,提高了移动设备和嵌入式系统的性能和效率。
如何在 Go 中使用 Neon
cgo
Github 已经有一些库已经封装好了对 arm 的调用
C 语言的函数调用是通过寄存器,而 Go 的函数调用主要是通过栈调用。如果你对如果使用 c 语言和 arm 汇编感兴趣,可以看下
使用汇编调用
在 Golang 中,调用机器指令并不是一个简单的事情:
Go Asm 缺少官方规范
处理器架构差异,寄存器的名称数量,使用方式上都有较大的差异
本文默认读者已经掌握一定的Go Asm
和 Arm Asm
的相关知识。下面知识是可以用于简单回顾下 Go Asm 汇编的知识。
这里不会展开过多,只是提供一个简单的例子,【2 个字节数组的相加】。
当前我们有 2 个字节数组,每个数组的长度为 8a1 := []byte{0, 1, 2, 3, 4, 5, 6, 7}a2 := []byte{1, 1, 1, 1, 1, 1, 1, 1}我们需要将相同序号的数字进行相加,获得一个他们的和的数组,不需要考虑溢出。
通常情况下我们会使用 for 对数据进行处理,但如果是使用 Neon,只需要执行一次相加处理即可(不考虑内存拷贝等操作)。
汇编文件
新建一个 asm.s 文件
Arm 中有 32 个向量寄存器,每个寄存器为 128-bit。在 Arm 汇编中,我们使用 V1 代表一个 128-bit 的寄存器,D0 代表 V1 低 64 位寄存器,D1 代表高 64 位寄存器。
如果你想要相加的数据为 uint16(2 个 byte),即
a1 := []byte{0, 1, 2, 3}a2 := []byte{1, 1, 1, 1}
Go 函数
在 asm.s 的目录下,新建一个 asm.go
然后在 main.go 中调用_SIMD_ADD_Byte8
这里我们把一个 8 个元素的字节当作一个 uint64 数字,是为了让例子更简单
注意点
不能直接从栈拷贝到向量寄存器/从向量寄存器拷贝到栈,暂时还没找到原因。我猜测跟 FP 是 Go Asm 的虚拟寄存器有关系,希望有大佬解答下。
Go Asm 使用 MOV 指令来做数据加载操作,跟 arm 汇编有较大的差距,需要留意他们的映射规则
版权声明: 本文为 InfoQ 作者【geange】的原创文章。
原文链接:【http://xie.infoq.cn/article/147a06f2ee4f1d3b0ccc8ad3f】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论