I mostly just vacuum up a huge amount of material from as many sources as I can. My focus on game development might help here. A lot of it flows from understanding CPUs from a low level hardware perspective - you
might be able to reverse engineer this kind of knowledge from the wikipedia articles, although I haven't tried doing so myself.
E.g. the page for "CPU cache" references:
- CPUs read/write by cacheline
- Caches need to coordinate to avoid stale data through "cache coherence protocols" (which have a cost as mentioned on their own wiki page)
"False sharing" is just the interplay of those two mechanisms in worst case scenarios and such corner cases.
About the only time I've used this knowledge of false sharing has been when implementing a work-stealing task queue system. And I suppose the few times I've written a parallel for loop of some description.
Trying to think of similar performance issues to guide you towards, a few come to mind:
1) CPU caches are basically implemented as fixed sized hashmaps with a really poor hash - the address modulo some power of two, with a fixed limit of collisions supported.
http://www.lshift.net/blog/2013/10/08/cpu-cache-collisions-i...
I've never actually used this knowledge, although I could see it coming up if I were working on the design of a database's in-memory storage or something.
2) Reading "write combined" memory is really bad, including implicitly reading by failing to write entire cachelines (comes up with GPU resources such as textures)
https://fgiesen.wordpress.com/2013/01/29/write-combining-is-...
This one I'm mindful of whenever I'm porting programs to use new graphics APIs, or writing the low level systems that deal with them in the first place. I feel there's at least one more situation where write combined memory has come up for me in practice (since typical memory access is not write combined), but it escapes me at the moment. Fortunately most graphics API docs at least warn you not to read the memory they're pointing you towards, although they're not always as explicit as "memcpy entire cachelines from orbit, just to be sure."
3) Performance of atomics touching multiple cachelines is terrible, when it's even supported:
https://fgiesen.wordpress.com/2014/08/18/atomics-and-content...
Normally I find out that this has been happening when I port a program to ARM and suddenly it crashes doing some kind of atomic operation or lock, because someone reinterpreted a char buffer instead of allocating properly, because cross-cacheline atomics are too crazy for ARM to bother implementing. Things like SSE and AVX also tend to perform... not so great, unless stuff is properly aligned for them.
EDIT: I guess fgiesen is one resource, at least, as it cropped up twice trying to google for sources for the things I'm talking about ;)