User: Password:
|
|
Subscribe / Log in / New account

ACCESS_ONCE()

ACCESS_ONCE()

Posted Aug 10, 2012 7:40 UTC (Fri) by jezuch (subscriber, #52988)
In reply to: ACCESS_ONCE() by daglwn
Parent article: ACCESS_ONCE()

> Take a very simple but common issue: undefined data.

Undefined data, hah. In Java it is a compilation error to use a variable that is not provably assigned in all possible code paths between declaration and use. I like this feature *a lot* and I'm always surprised that C compilers have such a great difficulty with detecting it. (The JVM verifier does this analysis as well during class loading, so it has to be *fast* as well as correct.)


(Log in to post comments)

ACCESS_ONCE()

Posted Aug 10, 2012 14:58 UTC (Fri) by quanstro (guest, #77996) [Link]

the claim above is that the choice is to
(a) follow the standard, or
(b) do something arbitrary.

that is not the choice in this case. the choice is to
either
(a) rearrange the code in optimization, or
(b) leave it as the developer wrote it.

personally, i find this sort of code reorg by compilers
to be problematic as it generally makes code quite hard
to reason about. experienced developers would lift the
assignment out of the loop if it mattered, and it were
legal.

ACCESS_ONCE()

Posted Aug 10, 2012 15:40 UTC (Fri) by daglwn (guest, #65432) [Link]

> the claim above is that the choice is to
> (a) follow the standard, or
> (b) do something arbitrary.

This is a false choice. (a) and (b) are the same thing in the presence of undefined/unspecified/implementation-defined behavior. And it's not arbitrary. It's the decision of the compiler engineers.

> personally, i find this sort of code reorg by compilers
> to be problematic as it generally makes code quite hard
> to reason about. experienced developers would lift the
> assignment out of the loop if it mattered, and it were
> legal.

I hear this a lot. Then people get surprised when I show them what the compiler did to their code. Believe me, there is no reason anyone should waste time hand-optimizing code without proof of need. Either they're going to miss a lot of opportunity or they are going to screw things up and make the compiler's job harder.

If a developer were to hand-optimize code to achieve the same performance result, the source code would be unmaintainable.

We want optimizing compilers. I can't believe anyone would suggest otherwise.

ACCESS_ONCE()

Posted Aug 12, 2012 16:16 UTC (Sun) by quanstro (guest, #77996) [Link]

in the example given in the op, there was no reason for the read to be in the
loop, except if it might change. the compiler made the assumption that the
coder was wrong. that might not be a useful assumption.

as i see it, the trade-off here is non-standard constructions, and the
principle of least surprise for performance.

i'm not convinced of the claim that this is always a win.

the compiler i use on a daily basis does not do strength reduction or optimize
away indirection. it assumes you know what you're doing. i don't notice that
it is slower. i also don't have to worry that the compiler will break my
drivers by "optimizing" them.

(never mind that with modern intel cpus, strength reduction can be a loss due
to microop caching.)

i think this is a good trade off for my case because it avoids obtuse, and
non-portable constructions that can be hard to remember to apply. that is,
for most code, developer time is more expensive than run time.

just my two cents, and i realize that there are cases in the linux kernel
where complex macros need this sort of optimization. but perhaps that's
complexity begetting itself.

ACCESS_ONCE()

Posted Aug 13, 2012 12:05 UTC (Mon) by nye (guest, #51576) [Link]

>in the example given in the op, there was no reason for the read to be in the
> loop, except if it might change. the compiler made the assumption that the
> coder was wrong. that might not be a useful assumption.

No, the coder *was* wrong, and the assumption is *always correct in standard C*. That's the point. The programmer might have assumed semantics which are not C, but the compiler merely assumed that the programmer was writing in C, not writing in some unspecified language that looks a lot *like* C and exists only in the programmer's head.

It is axiomatic that a valid optimisation (ie. one which precisely follows C semantics, and any which don't are buggy and tend to be quickly fixed) cannot break correct valid C; if code breaks then it is because the programmer has made incorrect assumptions about the exact meaning *in C* of what they're writing.

If your variable might change between accesses, then you need to tell the compiler that, because it is not the case in the standard C model, which is why there's a keyword existing specifically for that purpose.

ACCESS_ONCE()

Posted Aug 16, 2012 14:52 UTC (Thu) by quanstro (guest, #77996) [Link]

i agree with what you say, but that's not the point i'm trying to make.
(and btw, i don't think that ACCESS_ONCE is standard c. nor can the
kernel be compiled with an arbitrary compiler; it depends on gcc.)

for me, making code safe from all possible according-to-hoyle legal
transformations of the code is not really interesting or useful.
i'd much rather focus on having a tractable, easy-to-use programming
environment.

if restricting the compiler from making some theoretically legal
code transformations reduces bugs and generally makes life easier,
then why not do it?

as it is i believe there are some gcc optimizations that can break the
kernel.

ACCESS_ONCE()

Posted Aug 19, 2012 19:38 UTC (Sun) by PaulMcKenney (subscriber, #9624) [Link]

ACCESS_ONCE() is simply the macro called out in the article, which simply uses the volatile keyword in a cast, which is part of standard C.

ACCESS_ONCE()

Posted Aug 10, 2012 17:33 UTC (Fri) by nix (subscriber, #2304) [Link]

personally, i find this sort of code reorg by compilers to be problematic as it generally makes code quite hard to reason about.
I'm curious. Why don't you say the same about register allocation? Combined with stack spilling, that can often have the same effect as code motion. How do you plan to get rid of that?

(I've seen this from various safety-critical embedded people too: they want the compiler to 'not optimize'. I've tried pointing out that this is a meaningless request, that translation necessarily implies many of the same transformations that optimization does, but they never seem to get it. What they generally *mean* is that they want the smallest possible number of transformations -- or perhaps that they want the transformations to be guaranteed bug-free.)

ACCESS_ONCE()

Posted Aug 10, 2012 15:35 UTC (Fri) by daglwn (guest, #65432) [Link]

C compilers detect it all the time. It is a trivial analysis. Users tend to ignore the warnings, however.

ACCESS_ONCE()

Posted Aug 12, 2012 18:52 UTC (Sun) by Wol (guest, #4433) [Link]

Which is why, when I gave a bunch of novice programmers instruction about how to maintain code, I said "the standard is (a) always turn warnings to max and (b) always fix or otherwise understand *every* warning".

We had a bunch of warnings we couldn't get rid of, hence it didn't say "fix all warnings", but "explain it away" is just as effective, if less satisfying.

Cheers,
Wol

ACCESS_ONCE()

Posted Aug 13, 2012 8:02 UTC (Mon) by jezuch (subscriber, #52988) [Link]

> C compilers detect it all the time. It is a trivial analysis. Users tend to ignore the warnings, however.

It is. And they do. And every time I see someone fixing a "use of undefined variable" warning by initializing it to zero at declaration point, I cringe. I've seen it in stable updates to the kernel a lot...

ACCESS_ONCE()

Posted Aug 13, 2012 16:31 UTC (Mon) by daglwn (guest, #65432) [Link]

Absolutely. One needs to first understand _why_ the warning is there before fixing it. Warnings don't replace understanding.

ACCESS_ONCE()

Posted Aug 13, 2012 9:38 UTC (Mon) by etienne (guest, #25256) [Link]

It is not trivial, or even possible, to detect if a variable is only initialised and used when another variable is set to a special value.
Something like (very simplified):
extern unsigned loglevel;

void fct (void) {
int avar;
if (loglevel = 4) avar = 10;
increase_loglevel();
do_some_unrelated_stuff();
if (loglevel == 5) printf ("%d\n", avar);
}

ACCESS_ONCE()

Posted Aug 13, 2012 16:34 UTC (Mon) by daglwn (guest, #65432) [Link]

It is not trivial to get an exact and accurate answer in the general case, true, but I was assuming we were talking about the common case of locally-declared variables.

Still, even in this case the compiler could warn about it even if it doesn't know for sure. The code certainly looks suspicious and a warning would be appropriate. False positives are just fine if they are limited in number. The compiler can provide directives to suppress them if the programmer knows it's not a problem.

Note that gcc does just this. It warns that variables *might* be uninitialized.

ACCESS_ONCE()

Posted Aug 13, 2012 16:50 UTC (Mon) by nybble41 (subscriber, #55106) [Link]

Fortunately, in your example avar is always initialized to 10. :)

Assuming "loglevel = 4" was replaced with "loglevel == 4", I would expect the compiler to generate a warning in this case, since it can't _prove_ that avar was initialized before the printf() call. I would also hope that the compiler would take advantage of the fact that avar is either 10 or undefined to simply set it to 10 regardless of loglevel, for code size and performance reasons if nothing else.

In cases like this, IMHO, it would be better to use a common flag rather than testing loglevel multiple times:

void fct (void) {
int avar;
bool use_avar;
use_avar = (loglevel == 4);
if (use_avar) avar = 10;
increase_loglevel();
do_some_unrelated_stuff();
if (use_avar) printf ("%d\n", avar);
}

I'm not sure whether the compiler can follow this any better than before, so there may still be a warning, but at least the coupling is visible to anyone reading the code, and doesn't depend on the implementation of external functions.


Copyright © 2017, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds