-
Notifications
You must be signed in to change notification settings - Fork 18k
x/sys/cpu: add type CacheLinePad #25203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I think it'd be fine to export |
If these are exported i suggest to add a warning in the documentation that these are best effort guesses based on GOARCH and might not be the cpus actual cache line size. They shouldn't be used anywhere where their correctness matters for the programs correctness to avoid issues like: |
C++17 introduced http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html |
Like @martisch, I think it's problematic to export I would be OK with exporting it as a variable if we can arrange to set the variable correctly. |
@ianlancetaylor How about instead of a |
An array type doesn't sound very flexible, as it doesn't permit adjusting the padding to be only what is required to avoid cache contention. A constant like |
Regarding the |
Change https://golang.org/cl/111775 mentions this issue: |
I'm uncomfortable with the name Since the only use case identified so far is to avoid false sharing I think we should use a name like |
Calling it CacheLineSize or MaxCacheLineSize does seem to promise more than we need and maybe more than we can deliver. Would it be enough to introduce:
appropriately sized for each system, and leave it at that? At least then it's clear what it's for, and people would be discouraged from using it for other things. Still doesn't seem particularly clean but maybe this is just not something we can do cleanly. |
In #25203 (comment) @ianlancetaylor mentioned that an array type might be a bit too inflexible. I also see @mundaym's and @rsc's point about the name being ambiguous and/or promising something we can't deliver. I think renaming the const to either |
Since I made the proposal thought I'd give my opinions. I don't really care what you guys call it, but I do see the benefit of a
I'm not too sure what's the use case of a |
A const is fine with me as long as it's clear that it represents the maximum cache line size of a particular architecture. And, of course, it may change over time. I was thinking of a var because within a single architecture different processors have different cache line sizes. But since the main use seems to be for struct padding, a var is not helpful. An array type is more awkward than a const in some cases but is perhaps more clear for the intended use. The array type can still be used in the same way as the const by calling |
I feel like there could be some benefit with naming the const similar to C++17 (less confusion over what it represents), tho that being said As far as I can tell, So would everyone be ok with just Unless there is a situation where |
To avoid destructive interference we want to make sure that the data is in two separate cache lines. To ensure constructive interference we want data to be in the same cache line. That means that for That said I'm not sure how you could safely/portably use |
Ahh, now that makes more sense. In the sample code from the site you linked, So I was thinking maybe just put this check into a test? |
Check ConstructiveInterferenceSize and DestructiveInterferenceSize.
To prevent confusion. There is very little chance that this will prevent confusion outside of a specific set of users who are already familiar with this hideous name. It doesnt even make too much sense in an engineering context unless you hunt down the specific proposal in the c++ realm and extrapolate its meaning from that document. I have never heard this word in the context given here, unlike cachelinesize. Its also confusing because of the semantics of constructive and destructive -> min, max. Sorry for leaving the bike without hair, but I think the name is bad. |
@as since you down voted every comment with a proposed name, even |
Sorry just noticed you up voted |
The c++ proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
A quote from the author of the proposal who introduced the proposed terms that C++ uses. The author wrote (this was from a stackoverflow question):
It appears that the two values should be the same, and were only included for completeness. I don't know what completeness means in this context exactly. A few articles suggest that false sharing on L2 is not possible where as at least one family of benchmarks suggests performance gains occur when data are padded to a multiple of the L1 cache line size (it implies that some prefetching is done to L2 in pairs, so that multiple is 2 and the value used is 128 instead of 64). The question I have is: should Go be clever like C++, and create effect-based variables/values like Regarding |
@as the statement:
Would appear to be contradicted by the authors answer :
So in situations where an ISA has shipped with different cache line sizes (like the arm64 case linked in @martisch's reply) the values may be different. Since gc doesn't expose a way to specify the target arch the constructive and destructive interference sizes will therefore always be different on arm64. The same is presumably true for the new wasm backend. I am also starting to think that the |
Seems using the cache line size as padding to avoid false sharing is not sufficient on newer Intel architectures and on the amd64 arch we should consider 2x cache line size for struct padding since the spatial prefetcher pulls in the adjacent cache line too:
This was discussed and benchmarked in https://groups.google.com/forum/#!topic/mechanical-sympathy/i3-M2uCYTJE. Also seems a case were Destructive and Constructive inference size can diverge. Using CacheLInePad[N]byte or another name sounds like the better option to account for the original use case that should be solved. This also avoids pinning the meaning to another programming language/standard when using e.g. ConstructiveInterferenceSize. |
For the points given above, I too would agree So should we talk about a |
How so? The prefetch itself should cause the two cache lines to interfere constructively, but the need to re-mark the cache lines as dirty on write (and the extra bus traffic for the cache invalidations) should cause them to interfere destructively: it seems like the destructive and constructive interference sizes are both two cache lines. |
I was thinking about it in the context of the amd64 platform as a whole as i assumed we likely wont do runtime detection of these sizes for use in padding structs if we use the current const approach. In amd64 we have some cpu doing spatial prefetching and some not. So Constructive seems to be ok at 64bytes (does somebody know a am64 compatible cpu thats used widely with less than 64byte cache lines?) but for some newer amd64 compatible cpus there is some Destructive interference within 128byte (might not be as bad as within the same cache line). |
Soo I wrote a false/true sharing benchmark using amd64 numbers (64 and 128). Instead of guessing, if anyone has access to those cpus, just run the benchmark and let the numbers speak for themselves. I have an old intel so constructive and destructive sizes are the same. |
I don't see much difference here between 64 and 128 bytes. |
If the cache line were 64 bytes then I can understand why middle 128 would be better than 64. 64 - 12 = 52 bytes Weird that on my i7 middle performs the same on 64 vs 128. (cpuid reports cache line of 64 bytes)
|
OK, does anyone object to |
@rsc nope, I think pretty much everyone who commented here think that makes the most sense for the padding. |
Revising my earlier comment, instead of:
We should make this an opaque struct so that the only interesting property of the type is that it has the given size:
Then code cannot depend on it being an array somehow. But otherwise, proposal accepted. |
Now that I think about it, using unsafe.Sizeof() is prob better/clearer than len() and other advance usage of the padding size prob would result in using unsafe anyway. So I 100% agree the struct type is the best so far. |
Change https://golang.org/cl/116276 mentions this issue: |
Made above CL to see how CacheLinePad could be used when added to internal/cpu (the package x/sys/cpu was forked from) and applied to the runtime package which already imports internal/cpu. Most uses of runtime/internal/sys.CacheLineSize (except two) are for padding. This would also remove the redundant definition of CacheLineSize per Arch in runtime/internal/sys and internal/cpu. |
https://golang.org/cl/111775 (the CL for |
Change https://golang.org/cl/126601 mentions this issue: |
Add a CacheLinePad struct type to internal/cpu that has a size of CacheLineSize. This can be used for padding structs in order to avoid false sharing. Updates #25203 Change-Id: Icb95ae68d3c711f5f8217140811cad1a1d5be79a Reviewed-on: https://go-review.googlesource.com/116276 Run-TryBot: Martin Möhrmann <moehrmann@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
…t and vars sys here is runtime/internal/sys. Replace uses of sys.CacheLineSize for padding by cpu.CacheLinePad or cpu.CacheLinePadSize. Replace other uses of sys.CacheLineSize by cpu.CacheLineSize. Remove now unused sys.CacheLineSize. Updates #25203 Change-Id: I1daf410fe8f6c0493471c2ceccb9ca0a5a75ed8f Reviewed-on: https://go-review.googlesource.com/126601 Run-TryBot: Martin Möhrmann <moehrmann@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
#24843 added a new package for CPU feature detection, when looking through the package I noticed
const cacheLineSize
and thought that could be useful if it were exported.My use case is the same as the package, adding padding to structs to prevent false sharing.
The text was updated successfully, but these errors were encountered: