CPU cache-friendly data structures in Go
21–30 of 88 posts
Re: CPU cache-friendly data structures in Go
#22Most of this should be handled by the compiler already. But it is only 2025, I guess we're just not ready for it.
Because if a compiler starts automatically padding all my structures to put all of the members on their own cache line I'm going to be quite peeved. It would be easy for it to do, yes, but it would be wrong 99%+ of the time.
A far more trenchant complaint is that Go won't automatically sort struct members if necessary to shrink them and you have to apply a linter to get that at linting time if you want it.
Re: CPU cache-friendly data structures in Go
#23Most of this should be handled by the compiler already. But it is only 2025, I guess we're just not ready for it.
or at least Linter should catch this https://golangci-lint.run/docs/linters/
Re: CPU cache-friendly data structures in Go
#24If you are worrying about cache structure latencies in Go, maybe you should just be using Rust or Zig instead that implicitly handle this better.
Re: CPU cache-friendly data structures in Go
#25Source code of the benchmarks? At least, the False Sharing and AddVectors trick don't work on my computer. (I only benchmarked the two. The "Data-Oriented Design" trick is a joke to me, so I stopped benchmarking more.) And I never heard of this following trick. Can anyone explain it? // Force 64-byte alignment for cache lines type AlignedBuffer struct { _ [0]byte // Magic trick for alignment data [1024]float64 } Mayb…
If you embed an AlignedBuffer in another struct type, with smaller fields in front of it, it doesn't get 64-byte alignment.
If you directly allocate an AlignedBuffer (as a stack var or with new), it seems to end up page-aligned (the allocator probably has size classes) regardless of the presence of the [0]byte field.
https://go.dev/play/p/Ok7fFk3uhDn
Example output (w is a wrapper, w.b is the field in the wrapper, x is an allocated int32 to try to push the heap base forward, b is an allocated AlignedStruct):
&w = 0xc000126000
&w.b = 0xc000126008
&x = 0xc00010e020
&b = 0xc000138000
Take out the [0]byte field and the results look similar.Re: CPU cache-friendly data structures in Go
#26Re: CPU cache-friendly data structures in Go
#27Re: CPU cache-friendly data structures in Go
#28Most of this should be handled by the compiler already. But it is only 2025, I guess we're just not ready for it.
Likewise, one of the examples is moving from an array of structs to a struct of arrays; that's a lot more complex of a code reorganization than you'd want a compiler doing.
It would be good to have a static analyzer that could suggest these changes, but, at least in many cases, you don't want them done automatically.
Re: CPU cache-friendly data structures in Go
#29Most of this should be handled by the compiler already. But it is only 2025, I guess we're just not ready for it.
Re: CPU cache-friendly data structures in Go
#30Most of this should be handled by the compiler already. But it is only 2025, I guess we're just not ready for it.
Not really, virtually all these patterns involve tradeoffs that require understanding the data access patterns. I don't want my compiler adding more padding than bare minimum to every struct. I don't want it transforming an AoS to SoA when I choose AoS to match data access patterns. And so on... At best Go could add some local directives for compiling these optimizations, but these code changes are really minimal any…
I guess this is largely provided by std::hardware_destructive_interference_size in C++17, but I'm not sure if there are other language equivalents.
https://en.cppreference.com/w/cpp/thread/hardware_destructiv...