起源是这个 PR:
https://github.com/Yiling-J/theine-go/pull/42
我想优化 Theine 的 Read 性能所以做了一些改进。在我自己的 bnechmark 环境下
goos: darwin
goarch: amd64
pkg: github.com/maypok86/benchmarks/throughput
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
以及阿里云 ECS(同样 Intel 架构)上性能是超过 Ristretto 的,但是在 maypok86 的环境下(M1 Max)却还是比 Ristretto 慢挺多。因此想收集一下更多的测试结果。希望有 M 系列芯片的 v 友能帮忙测试一下。 步骤:
replace github.com/Yiling-J/theine-go => github.com/Yiling-J/theine-go perf
go mod tidy
go test -run='^$' -cpu=8 -bench . -timeout=0
如果确实比 Ristretto 慢的话希望能做个 cpuprofile 然后把结果文件发给我, 注意 profile 前修改throughput/bench_test.go
文件,只保留client.Theine
以及reads=100%,writes=0%
cpuprofile 方法
go test -run='^$' -cpu=8 -bench . -timeout=0 -cpuprofile cpu.out
1
Satelli 141 天前 1
我是 M3 基础款 4 大核 4 小核。
go test -run='^$' -cpu=4 -bench . -timeout=0 goos: darwin goarch: arm64 pkg: github.com/maypok86/benchmarks/throughput BenchmarkCache/zipf_theine_reads=100%,writes=0%-4 32749303 35.09 ns/op 28500255 ops/s BenchmarkCache/zipf_ristretto_reads=100%,writes=0%-4 42503578 29.13 ns/op 34334351 ops/s go test -run='^$' -cpu=8 -bench . -timeout=0 goos: darwin goarch: arm64 pkg: github.com/maypok86/benchmarks/throughput BenchmarkCache/zipf_theine_reads=100%,writes=0%-8 21759266 53.32 ns/op 18756136 ops/s BenchmarkCache/zipf_ristretto_reads=100%,writes=0%-8 47587416 26.35 ns/op 37944749 ops/s |
2
Satelli 141 天前 1
profile 文件,分别是 -cpu=4 和 -cpu=8 。
https://send.cm/a/QEN |
3
matrix1010 OP @Satelli 感谢!
|
4
mengzhuo 141 天前
大致看了下,我觉得是不是要设定好大小核亲和性?大小核核测试经常会跟预期不一样的。
而且你这样用 runtime 的 fastrand ,回头可能会被 Russ 挂出来(笑 https://github.com/golang/go/issues/67401 目前 fastrand 背后是 wyrand ( wyhash )改进版,你可以自己实现一个,或者用库。 |
6
matrix1010 OP @mengzhuo 我看了看 profile 又简单查了查资料,猜测是指令集问题。因为根据 profile 很多时间都花在 atomic add 操作上,intel 没这个问题因为有专门的指令集,而 go 在 arm64 默认 v8.0, 没有专门的指令集,8.1 才有 LDADD( https://github.com/golang/go/issues/60905)。没这方面知识纯猜测,还在继续研究
|
8
hxzhouh1 141 天前 1
|
9
Kauruus 133 天前 1
看到里面实现了一个 Counter ,然后加了 cache line pad ,cacheLineSize 写死了 64 。
但是 Apple Silicon 的 cache line 是 128 ,所以还是有 false sharing 。 然后 Intel 虽然 cache line 是 64 ,但是 prefetcher 一次可能会读两个 cache line ,而 AMD 又没类似的优化。 还有些大小核 cache line 不一样的。 所以现在常见的做法是 ARM64, AMD64 都假设是 128 。 参考: - crossbeam::utils::CachePadded 的 PR: https://github.com/crossbeam-rs/crossbeam/pull/636, 顺藤摸瓜可以找到很多讨论 - https://github.com/embedded-momo/fastcounter-go 一个类似的 Go 实现,固定 128 cache line 。 |
10
matrix1010 OP @Kauruus 你说的很有道理,x/sys/cpu 里有个 CacheLinePad 可以直接用
|
11
Kauruus 133 天前
|
12
Kauruus 133 天前
@matrix1010 想起来为什么没有用 x/sys/cpu ,因为它的 cacheLineSize 是私有的,只能用 CacheLinePad ,浪费了一点点内存 :|
|