Huge props to the team for finding this out. What a nasty issue. One question about the intro, which states that this is the first mass produced AMP architecture, but isn't the PlayStation 3's Cell CPU one?
A tale of an impossible bug: big.LITTLE and caching
21–30 of 116 posts
Re: A tale of an impossible bug: big.LITTLE and caching
#22I rather see the problem in the fact that there seems to be no possibility to say to the Linux scheduler: Only schedule this process/thread between cores that have the same cache line size. Or add an attribute when some thread is created on the cache line size of the cores it is allowed to run. Or an attribute when some thread is created for "allow arbitrary cache line size but don't let it run on cores with a different size". This way it would suffice to check for the cache size on program or thread start.
Re: A tale of an impossible bug: big.LITTLE and caching
#23It appears the that the caching code was added in this patch: https://gcc.gnu.org/ml/gcc-patches/2012-09/msg00076.html Prior to that, the call: asm volatile ("mrs\t%0, ctr_el0":"=r" (cache_info)); was always made.
But the task can be rescheduled on a little core part-way through the execution... The big cores should report the smaller cache line size always.
Re: A tale of an impossible bug: big.LITTLE and caching
#24I don't understand that level of coding, what i do understand is the great way of debugging. Its all about deduction mr Watson.
Re: A tale of an impossible bug: big.LITTLE and caching
#25Huge props to the team for finding this out. What a nasty issue. One question about the intro, which states that this is the first mass produced AMP architecture, but isn't the PlayStation 3's Cell CPU one?
PPE and SPE don't even share an ISA, SPE have a custom-built SIMD-oriented ISA.
Re: A tale of an impossible bug: big.LITTLE and caching
#26Properly configured big.LITTLE clusters should be set up so that all CPUs report the same cache line size (which might be smaller than the true cache line size for some of the CPUs), to avoid exactly this kind of problem. The libgcc code assumes the hardware is correctly put together. There is a Linux kernel patchset currently going through review which provides a workaround for this kind of erratum by trapping the C…
(Edit: rereading the blog post, they say they need to figure out the global minimum, but I can't see how their code actually does that, since there's nothing that guarantees that the icache flush code gets run on every cpu before it's needed in anger.)
Re: A tale of an impossible bug: big.LITTLE and caching
#27Still a bit hazy on why they manually flush the cache for a given block of memory (presumably for protecting disclosure?) but I'm also a bit curious how it works if you get the sequence big fetches a cache line, switches to little which fetches a line (half as long and changing half the bytes in the cache) and then you switch back to big and its thinking it has a full cache line? Presumably there is some mechanism that invalidates cache lines?
Re: A tale of an impossible bug: big.LITTLE and caching
#28Earlier quoted context omitted.
Performance. get_current_cpu_cache_line_size would need to run some code to determine the cache line size, and that code takes longer to run than using a cached value. Along similar lines, if you have an optimized routine using specific CPU instructions, you don't want to call CPUID (or equivalent) on every call to find out if you have those instructions; you want to call it once and cache the answer. If it can retur…
Stupid question but does that work in a virtualised environment where your program can be live-migrated to another physical machine with a different CPU?
Also, for this specific case, I doubt migration will keep around the contents of the cache lines and their 'dirty' bits (corollary: it will be possible to reliably detect a move, if one is willing to continuously run code that detects cache-line timing differences)
Re: A tale of an impossible bug: big.LITTLE and caching
#29wow, just wow. That is a really awesome bug (and like the authors I have issues with trying to sleep when that sort of puzzle is sitting there :-) Still a bit hazy on why they manually flush the cache for a given block of memory (presumably for protecting disclosure?) but I'm also a bit curious how it works if you get the sequence big fetches a cache line, switches to little which fetches a line (half as long and cha…
The reason for the manual cache operations is because they're generating JITted code -- on ARM to ensure that what you execute is the same thing you just wrote you have to (1) clean the data cache, so your changes get out to main memory[.] and then (2) invalidate the icache, so that execution will fetch the fresh data from memory rather than using stale info. This clean-and-invalidate operation is usually informally called a flush, though it isn't really one in ARM terminology.
[.] not actually main memory, usually: only has to go out to the "point of unification" where the iside and dside come together, which is probably the L2 cache.
Re: A tale of an impossible bug: big.LITTLE and caching
#30Properly configured big.LITTLE clusters should be set up so that all CPUs report the same cache line size (which might be smaller than the true cache line size for some of the CPUs), to avoid exactly this kind of problem. The libgcc code assumes the hardware is correctly put together. There is a Linux kernel patchset currently going through review which provides a workaround for this kind of erratum by trapping the C…
Also, if I'm reading the proposed fix in the mono pull request correctly, it doesn't deal with the problem entirely because there's a race condition where the code might start execution on the core with the larger cache line size, and then get context-switched to the core with the smaller cache line size midway through executing its cache-maintenance loop. The chances of things going wrong are much smaller, but they'…