segmentio/asm
GitHub: segmentio/asm
一个利用现代 CPU 高级指令集(如 SIMD)为 Go 程序提供高性能算法的底层库,涵盖编码、排序和内存操作等热点路径优化。
Stars: 924 | Forks: 38
# asm  [](https://godoc.org/github.com/segmentio/asm)
提供算法的 Go 库,这些算法利用现代 CPU 的全部能力来获得
最佳性能。
## 动机
云计算使得获取大规模计算能力变得比以往任何时候都更容易,
运行部署在数十个甚至数百个 CPU 上的分布式系统已变得司空见惯。
由于现在的项目运行在如此多的核心上,程序的性能和效率在今天显得比以往任何时候都更加重要。
现代 CPU 是复杂的机器,其性能特征可能会因使用方式的不同而有数量级的差异。
分支预测、指令重排、流水线或缓存等功能都是决定 CPU 可实现计算吞吐量的
输入变量。尽管编译器不断改进,并且经常采用对人类开发者而言可能适得其反的微优化,
但它们的能力仍然存在局限性,而汇编语言在优化大规模应用程序的热点代码路径(hot code paths)中的算法方面,
依然发挥着重要作用。
SIMD 指令集为软件工程师提供了有趣的机遇。
利用这些指令通常需要重新思考程序如何表示和操作数据,
这超出了编译器所能实现的优化范围。当向云提供商租用 CPU 时间时,
未能利用所有可用指令集的程序实际上是在为他们未使用的功能买单。
本包旨在提供此类算法,经过优化以利用现代 CPU 的高级指令集,
从而最大化吞吐量并充分利用可用的计算能力。该包的用户将发现,
这些函数通常被设计用于处理**值数组**,而这正是 SIMD 和无分支(branchless)算法大放异彩之处。
该库中的函数已在 Segment 的高吞吐量生产环境中使用,
我们希望它们能对其他在性能敏感型软件中使用 Go 的开发者有所帮助。
## 用法
该库由多个 Go 包组成,旨在作为共享相似属性的函数的逻辑分组:
| 包 | 用途 |
| ------- | ------- |
| [ascii](ascii) | 专为处理 ASCII 输入而设计的函数库 |
| [base64](base64) | 与标准库兼容的 base64 编码 |
| [bswap](bswap) | 对固定大小项数组进行字节交换的算法 |
| [cpu](cpu) | 用于检测 CPU 特性的 ABI 定义 |
| [mem](mem) | 对字节数组进行操作的函数 |
| [qsort](qsort) | 针对固定大小项数组的快速排序实现 |
| [slices](slices) | 对成对 slice 执行计算的函数 |
| [sortedset](sortedset) | 处理固定大小项有序数组的函数 |
当目标平台没有某个函数的汇编版本时,该包会提供一个由编译器自动选取的 Go 通用实现。
## 展示
由于该库的目的是提高 Go 程序的运行时效率,我们整理了一些基准测试运行的快照,
以展示这些代码路径在利用 SIMD 和无分支优化后所能获得的改进效果:
```
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
```
```
pkg: github.com/segmentio/asm/ascii
name old time/op new time/op delta
EqualFoldString/0512 276ns ± 1% 21ns ± 2% -92.50% (p=0.008 n=5+5)
name old speed new speed delta
EqualFoldString/0512 3.71GB/s ± 1% 49.44GB/s ± 2% +1232.79% (p=0.008 n=5+5)
```
```
pkg: github.com/segmentio/asm/bswap
name old time/op new time/op delta
Swap64 11.2µs ± 1% 0.9µs ± 9% -92.06% (p=0.008 n=5+5)
name old speed new speed delta
Swap64 5.83GB/s ± 1% 73.67GB/s ± 9% +1162.98% (p=0.008 n=5+5)
```
```
pkg: github.com/segmentio/asm/qsort
name old time/op new time/op delta
Sort16/1000000 269ms ± 2% 46ms ± 3% -83.08% (p=0.008 n=5+5)
name old speed new speed delta
Sort16/1000000 59.4MB/s ± 2% 351.2MB/s ± 3% +491.24% (p=0.008 n=5+5)
```
## 维护
汇编代码由 [AVO](https://github.com/mmcloughlin/avo) 生成,
并由 Makefile 进行编排,以帮助维护者在 AVO 文件被修改时重新构建汇编源代码。
该仓库包含两个 Go 模块;主模块在仓库根目录下声明为
`github.com/segmentio/asm`,第二个模块位于 `build` 子目录中。
`build` 模块用于将构建依赖与导入主模块的程序隔离开来。
通过这种机制,AVO 不会成为使用 `github.com/segmentio/asm` 程序的依赖,
从而将用户的依赖管理开销降至最低,并允许维护者对 `build` 包进行修改。
这两个模块的版本管理是独立的;虽然我们致力于在主包上提供稳定的 API,
但 `build` 包可能会更频繁地引入破坏性更新,因为它旨在作为项目中更多实验性结构的基础。
### 要求
某些库针对 amd64 和 arm64 都有专门定制的代码。
其他库(如 qsort)则仅支持 amd64。
请查找与您的架构匹配的 `.s` 文件,以确保您使用的是经过汇编器优化的库指令。
此 Go 代码需要 Go 1.17 或更高版本。这些版本包含了相较于以往 Go 版本的显著性能改进。
`asm` v1.1.5 及更早版本保持与 Go 1.16 的兼容性。
### purego
`build` 模块中的程序应添加以下声明:
```
func init() {
ConstraintExpr("!purego")
}
```
它指示 AVO 在生成的文件中注入 `!purego` 标签,
从而允许通过如下构建命令在没有任何汇编优化的情况下编译这些库:
```
go build -tags purego ...
```
这主要用于对比使用经过汇编优化的版本与更简单的纯 Go 实现所带来的影响。
标签:EVTX分析, Go库, SIMD, 底层开发, 性能优化, 日志审计, 检测绕过, 汇编, 算法, 自动回退