News for hackers. Stuff that matters.
Re:No sane compiler would optimize atomics (2015) by dataflow on Sunday July 11, 2021 @06:32PM (#27804992)
It might be 0.000000000001% but it need not be, right? That's kind of the point. I'm pretty sure I could write you a program where the probability of observing that would be (say) 50% without the optimization, and with the optimization that would go to 0%, defeating the program. Should that be allowed?

This is basically a statistical/probabilistic version of another problem: should a compiler be allowed to change the time complexity of an algorithm? If I write linear search, and the compiler proves the list is sorted, should it be allowed to switch to binary search—or vice-versa? Traditionally the answer might be 'yes', but it's not exactly hard to argue an answer of 'no' might also be desirable in a number of situations. Now in this case, it's not the time complexity that's changing, but the statistical properties of the program... and while in some cases it might be negligible (1E-10 or what have you), that's not necessarily the case, at which point a difference in degree really can become a difference in kind.

Re:No sane compiler would optimize atomics (2015) by chrisseaton on Sunday July 11, 2021 @06:42PM (#27805068)
But no mechanism was ever guaranteeing the 50% in the first place. So their program could already stop working correctly without any changes and with the same compiler. What I'm saying is I don't know how they'd even tell the difference between my compiler being the problem, or them just being unlucky and not getting the interleavings they want even though they're statistically likely.
Re:No sane compiler would optimize atomics (2015) by dataflow on Sunday July 11, 2021 @06:58PM (#27805185)
I'm saying if you made a complier that made reduced that expected 50% to roughly 0%, it wouldn't matter to the user if it was 1E-10 or exactly 0%. Both could be undesirable for exactly the same reason. Again: you can complain that the 1E-10 compiler is still "correct" because there was never a 50% guarantee, but in doing that you're completely missing the point.

Here's an exaggerated example to get the point across. Imagine your Tesla autopilot's accuracy suddenly dropped from >99.9999% to <0.00001% overnight because of some stupid optimization (maybe this one) that was technically correct. Assume there was never a guarantee provided to the user that it would stay this accurate. Now if your 99.9999% became 99.9998% overnight, OK, I think a sane user would completely anticipate that and live with it. But when it drops orders of magnitude lower, do you really think you could shift the blame to the user because you were "technically" not guaranteeing anything? Is it really the user's fault that your optimization reduced that accuracy to 0.00001% and killed them? Can you walk away with your conscience clear at that point that you did everything 'right'? At what point do you feel like some kinds of changes just blatantly unfair and uncalled for, even if they're technically "by the book"?

Re:No sane compiler would optimize atomics (2015) by gizmo686 on Sunday July 11, 2021 @07:26PM (#27805369)
Tesla's autopilot has a guarantee for its accuracy. If that drops to 0.00001%, then that is a problem, because the autopilot functionality is failing to meet its requirements. If that drop in accuracy happens because of a technically correct change, then that just means the actual bug was somewhere else and just happened to work previously. It also means that there is a flaw in Testla's quality control process that allowed such a change to ship to customers.

If your program breaks because the compiler no longer interleaves atomics, then your program was always broken, and you have just been getting lucky until now. Normally when this type of situation comes up, the programmers perspective is at least understandable, since what they were doing was somewhat reasonable, even if not allowed by the standard. In this case, the point is that I (and, I presume chrisseaton) cannot come up with any reasonable program that would rely on an interleaving happening 50% of the time.

If the interleaving were originally observed 99.999999% of the time, I could imagine a program relying on it happening. However, if the writes are close enough that the compiler could optimize them together, chances are the pre-optmiztion chance of it happening was already much closer to 0% than to 100%; which, again, begs the question 'what was your program possibly doing that relied on the original behaviour?'

Re:No sane compiler would optimize atomics (2015) by dataflow on Sunday July 11, 2021 @07:46PM (#27805486)
> Tesla's autopilot has a guarantee for its accuracy.

Which (if true) is completely beside my the point. Just pick something that doesn't have a guarantee. The comment wasn't about Tesla. It was about empirical performance vs. written guarantees.

> Normally when this type of situation comes up, the programmers perspective is at least understandable, since what they were doing was somewhat reasonable, even if not allowed by the standard.

Okay great, we agree on that.

> In this case, the point is that I cannot come up with any reasonable program that would rely on an interleaving happening 50% of the time.

That's easily explained by our lack of imagination. No need to assume the person relying on it is being unreasonable.

Hypothetical example: suppose two threads are trying to alternate running some specific instructions with minimal latency. Maybe there are hardware requirements (e.g. they want to avoid overheating come specific components of a CPU core for too long?), so they try to alternate work via an atomically increasing counter? That's a starting point at least, feel free to improve the scenario.

Re:No sane compiler would optimize atomics (2015) by kllrnohj on Sunday July 11, 2021 @10:30PM (#27806314)
> so they try to alternate work via an atomically increasing counter?

Then why did they asked for an atomic that doesn't provide that instead of one that does? The docs on memory_order_relaxed are pretty clear it provides no thread synchronization of any kind: https://en.cppreference.com/w/cpp/atomic/memory_order#Relaxe...

This isn't some undefined behavior quirk being used to optimize, this is well-defined behavior being optimized in a well-defined fashion.

Re:No sane compiler would optimize atomics (2015) by dataflow on Sunday July 11, 2021 @10:49PM (#27806415)
> The docs on memory_order_relaxed are pretty clear it provides no thread synchronization of any kind

No, that's not what it's saying. "Synchronization" is an imprecise term, and you're misunderstanding what it means here. Atomics (as is literally in their name) perform each operation atomically; by definition they provide at least that thread synchronization guarantee, even if you believe they provide nothing else.

The documentation explains what "are not synchronization operations" refers to in the subsequent sentences; it's most certainly not saying it doesn't provide thread synchronization "of any kind" (again, I already listed one above). In fact, it lists 2 specific kinds of thread synchronization it does provide: "atomicity" (i.e. operations are all-or-nothing, as above) and "modification order consistency" (i.e. alterations of that same variable occur in a consistent order across different threads, even under std::memory_order_relaxed). What it does not provide is a consistent ordering across different variables ("an order among concurrent memory accesses"), which is fine as it's not not something we need in this example.

Collapsing multiple atomic operations into one has nothing to do with ordering, nor with multiple locations in memory. In fact, I don't think even std::memory_order_seq_cst can prevent this. The only way I can imagine preventing it is to mark atomics as volatile, and even then I'm not sure if it's guaranteed under the as-if rule.

Re:No sane compiler would optimize atomics (2015) by gpderetta on Monday July 12, 2021 @04:50AM (#27808357)
volatile should work. Each volatile access is a side effect from the point of view of the abstract machine and compilers are supposed to document this mapping to the concrete CPU (and usually is the obvious one).

In fact the fact that volatile atomic has additional guarantees is a strong reason for plain atomic not to have them, otherwise there wouldn't be a way to express the more relaxed requirement.

I think atomic not being volatile by default is a good default: the majority of code doesn't need to care about atomic in the first place, for the majority of the remaining code, these sort of optimizations are benign and desirable. For the remaining code that cares, volatile is the safety hatch.

Re:No sane compiler would optimize atomics (2015) by dataflow on Monday July 12, 2021 @05:06AM (#27808436)
I'm not so sure volatile is sufficient... I expect it would depend at least on how the variable is allocated/stored. Merely putting volatile shouldn't be sufficient to prevent access to it being optimized out. I forget if this was disallowed since C++20, but consider the program 'int main() { volatile int x = 0; ++x; }'. I'm fairly certain the compiler can optimize out the body despite the use of volatile, because of the as-if rule: it would be impossible to tell the difference from within the program.

Moreover, I'm not sure 'volatile' memory access without some sort of external linkage is even meaningful. The idea of volatile is that access to a volatile variable could have observable side effects outside the program, but that discussion seems rather moot for a variable that doesn't have connections to the outside world to begin with. Heck, by the same reasoning, even for a variable with external linkage, the rules might still permit it to be optimized out under link-time optimization, unless it has been declared to be externally reachable somehow (e.g. at a fixed/exported/otherwise 'known' address)... otherwise it's by definition externally unreachable and thus again unobservable under the as-if rule.

At least, I could see the reasoning going that way, and that's how it makes sense to me as far as the abstract machine goes. I can also see people disputing it though, and claiming (say) a debugger inspecting a program is sufficient accessibility for considering side effects, or something like that. I'm not sure I agree with every objection, but I see room for debate. It's just not clear what the implications are under the as-if rule.

Re:No sane compiler would optimize atomics (2015) by gpderetta on Monday July 12, 2021 @05:34AM (#27808576)
The ++x is a side effect from the abstract machine point of view. The issue is of course how the compiler maps the abstract machine to the real machine. Volatile is (purposefully) underspecified and I guess it is not completely unreasonable for a compiler to declare that a local volatile object whose address is never taken does not have a mapping at all.

There is little value on explicitly optimizing volatiles but of course that can happen as a side effect (ah!) of unrelated optimizations.

I rarely use volatile at all, but when I do, I do make sure not to apply it to local objects.

edit: I think the most reliable and portable way to make sure that the address of a variable escapes is something like this:

   volatile std::atomic<void*> sink; // global

   void escape(void*x) { 
     std::atomic_signal_fence(std::memory_oreder_release);
     sink.store(x, std::memory_order_relaxed);
   }
any signal handler executed after escape(&val) is guaranteed to be able to see the last value stored into val.
Re:No sane compiler would optimize atomics (2015) by dataflow on Monday July 12, 2021 @06:49AM (#27808984)
Yeah, I think this is probably sufficient without whole-program optimization, but I'm not sure it is with LTO. It might be sufficient today, but I can imagine Clang optimizing it away eventually. Really, the only realistic-yet-futureproof method I can imagine (and I'm not sure if it's even within the jurisdiction of the language spec) is either (a) exporting the variable, or (b) exposing its address through some other established I/O mechanism (like printf).
Re:No sane compiler would optimize atomics (2015) by chrisseaton on Sunday July 11, 2021 @07:08PM (#27805254)
I guess I don't know why the user would be betting on interleavings which I never said I could guarantee. If you build your car with a part that isn't rated for what you use it for that's your fault not the manufacturer of the part - even if it worked every time when they tested it and they never saw it fail before one time it kills someone.

I'm open to ideas on how to create understanding both ways on what the user wants and the compiler is able to provide?

Re:No sane compiler would optimize atomics (2015) by dataflow on Sunday July 11, 2021 @07:13PM (#27805289)
> I guess I don't know why the user would be betting on interleavings which I never said I could guarantee.

Same reason people walk outside without bodyguards and "bet" on coming back home alive despite the fact that nobody ever gave them such a guarantee. It's not insane to expect the future to bear some kind of resemblance to the past without some contract to guarantee it, is it?

Re:No sane compiler would optimize atomics (2015) by chrisseaton on Sunday July 11, 2021 @07:16PM (#27805309)
> It's not insane to expect the future to bear some kind of resemblance to the past without some contract to guarantee it, is it?

Well you used the example of a car and I think it would be insane to use a component in a car when the manufacturer tells you it's not designed to do that and I can't possibly guarantee that's going to work just because you think you tested it and it seemed fine.

Re:No sane compiler would optimize atomics (2015) by dataflow on Sunday July 11, 2021 @07:20PM (#27805344)
Sigh. What about my subsequent example? About walking outside with a bodyguard despite the lack of a guarantee you'd stay safe?
Re:No sane compiler would optimize atomics (2015) by chrisseaton on Sunday July 11, 2021 @07:22PM (#27805349)
I don't get why you're sighing at me when I'm answering your questions politely. If you don't like my replies feel free to stop asking me questions.

Your example about going outside isn't covered by a technical specification with a long list of guarantees formally agreed between two parties so I don't really see how it's comparable.

Re:No sane compiler would optimize atomics (2015) by dataflow on Sunday July 11, 2021 @07:33PM (#27805410)
The question was about whether the original designer deserves any blame for making a sudden change like that. Not about whether the manufacturer is at fault vs. the user vs. a bunch of other middlemen that weren't in the story. That twist just derailed the discussion, and it's frustrating to discuss something when the other person is so keen to avoid the crux of the question. So much so that you didn't even try to address everything else I wrote.
Re:No sane compiler would optimize atomics (2015) by chrisseaton on Sunday July 11, 2021 @07:46PM (#27805485)
> The question was about whether the original designer deserves any blame for making a sudden change like that.

I don't believe so - as long as there is a version change and it's documented in the change log, which I aim to do with optimisations I write.

If you're using undocumented apparent behaviour, please check the change log when upgrading, or ask us to document the behaviour. But as already described, we may not be able to guarantee what you want while keeping other things you depend on like performance!

Re:No sane compiler would optimize atomics (2015) by chc on Sunday July 11, 2021 @07:49PM (#27805502)
If you only had a 50% chance of surviving before, I would say it was already a bad idea.