mfc >> volatile and optimizations

by Joseph M. Newcomer » Sat, 22 Nov 2003 08:06:09 GMT

At the Microsoft Driver Conference I went to a talk by Adrian Oney, the Guru Of All Device
Driver Writers. He was talking about memory addressing, caches, optimization fences, and
the importance of using volatile to defeat compiler optimizations when there is thread
concurrency. At one point, the discussion went like this:

me: "I've actually had people assert forcefully to me that volatile is not necessary to
defeat compiler optimizations"
AO: "BLAH-HA-HA-HA-HA-HA!!!"

He then went on to give examples where compiler optimizations will move accesses so that
there are serious errors with concurrent access.

I rest my case.
joe

Joseph M. Newcomer [MVP]
email: XXXX@XXXXX.COM
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm


mfc >> volatile and optimizations

by Doug Harrison [MVP] » Sun, 23 Nov 2003 03:27:00 GMT


oseph M. Newcomer wrote:


Sigh. It sounds like you asked the wrong question, Joe.

The word "synchronization" does not appear above, and what I've said is that
volatile is not necessary when proper synchronization techniques are used.
I've said this in response to your repeated assertion that you need to use
volatile on every variable that can be touched by multiple threads,
including those variables accessed under the protection of a mutex. I've
explained in detail why it's not necessary to use volatile when proper
synchronization techniques are used. That's what you've been stubbornly
disagreeing with. If you're right, that would mean two threads can't use the
same non-volatile CString object under the protection of a mutex. Do you
really believe that? I've explained in detail to you why that belief is
nonsense.

It's easy to show volatile can be necessary when a simple variable is
accessed _concurrently_ (and I hope atomically) by multiple threads in the
_absence_ of synchronization. I never said otherwise, and in fact, I gave an
example of this myself in the first message linked to below.

To refresh your memory, here are some relevant messages from me, all from
the same thread in Jul-2003, the last two being replies to you:

http://groups.google.com/groups?selm=ahkaivkbeq8pn3ei715rcm7a6rikr68hop%404ax.com
http://groups.google.com/groups?selm=doadivk1vul95bpkdpnlb2se9b4grmhour%404ax.com
http://groups.google.com/groups?selm=o7meiv4alic4cndi2qq8krmlnvfc875tsn%404ax.com

Prove me wrong.

If for some reason you require an independent source for what I've been
saying, here's some additional reading material for you, culled from
comp.programming.threads. Do note that Butenhof is generally talking about
the POSIX thread model and weakly ordered memory systems, and thus his
comments about volatile tend to be even stronger than the ones I've made,
though I have hinted from time to time at his memory barrier concerns, which
may well affect Win64 systems. Unfortunately, Win32 (at least) doesn't
really define a memory model for MT programming, but I explained in
excruciating detail in my earlier messages why I believe the Windows
compilers and synchronization objects, particularly the mutex (and critical
section), must behave in a certain way, which happens to be consistent with
the POSIX model. I just don't see any reasonable alternative, and I have no
reason to believe they behave any differently than I've said. In the
messages linked to above, I gave an example and explained why the compiler
can't reorder things around mutex lock/unlock operations, and I explained
why it must be considered a bug if it does. Like I said, "If you can
demonstrate a legitimate problem, it's something MS will need to fix." I
stand by that, and as ever, I await your example. Good luck! :)

http://groups.google.com/groups?selm=%25yc48.20%24am1.537%40news.cpqcorp.net
http://groups.google.com/groups?selm=QJZo9.17%24X93.717939%40news.cpqcorp.net
http://www.lambdacs.com/cpt/FAQ.html#Q56
http://www.lambdacs.com/cpt/FAQ.html#Q246
http://www.lambdacs.com/cpt/FAQ.html#Q308

--
Doug Harrison
Microsoft MVP - Visual C++



mfc >> volatile and optimizations

by Joseph M. Newcomer » Sun, 23 Nov 2003 17:51:09 GMT

ctually, Adrian had just explained that proper synchronization does NOT guarantee
correctness in the absence of volatile. He then presented several counterexamples for that
case as well. In fact, in the kernel, you have to introduce "memory fences" to force the
hardware to keep the data consistent, which was the real bulk of his presentation. And
that is WITH synchronization.

He had a really great example where the absence of volatile allows the compiler to do a
code motion that causes an evaluation to be deferred until AFTER the mutex is released,
with fatal consequences. He claims to have discovered this in a driver.
joe


On Sat, 22 Nov 2003 13:27:00 -0600, "Doug Harrison [MVP]" < XXXX@XXXXX.COM > wrote:


Joseph M. Newcomer [MVP]
email: XXXX@XXXXX.COM
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm


volatile and optimizations

by Joseph M. Newcomer » Mon, 24 Nov 2003 06:49:47 GMT

t is also worth examing some of the Microsoft data structures, such as LIST_ENTRY. This
is a simple header for a 2-way linked list. The pointers are both declared 'volatile' Now
the interesting thing about this structure is that it is either used by a single thread,
in which case neither volatile nor synchronization are relevant, or it is used
multithread, multiprocessor, in which case synchronization is manadatory. In spite of the
fact that synchronization is mandatory, volatile is used. Adrian's example, if I recall
correctly, demonstrated an error caused by a code motion that took place when volatile had
been omitted on a structure that was locked, so that the moved code was executed after the
lock was released. He was emphasizing the importance of volatile.
joe

On Sun, 23 Nov 2003 04:51:09 -0500, Joseph M. Newcomer < XXXX@XXXXX.COM > wrote:


Joseph M. Newcomer [MVP]
email: XXXX@XXXXX.COM
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm


volatile and optimizations

by Doug Harrison [MVP] » Mon, 24 Nov 2003 09:34:06 GMT

oseph M. Newcomer wrote:


For the umpteenth time, can you present an example of this or not? Or are
you just spreading FUD once again, like with your imaginary "bool" bug?
Remember that one? For three years, you told a story about it every chance
you got and called MS guys "slovenly" and "sloppy thinking" and "fools" and
whatnot. When I saw you doing this, I politely told you I had never heard of
such a bug, asked you for an example of it, and suggested what I thought
probably was the real problem to you. It would have been your mistake, so I
guess that must have made it seem very unlikely to you, especially since the
inconvenient truth would have interfered with one of your favorite rants. I
did this multiple times over a three year period, and finally, I don't know
what happened, but you sort of (but not entirely) saw the light on this one,
and as it turned out, what I had suggested to you years earlier was right
all along. Unfortunately, by this time, people had come to the newsgroups
parroting the unsubstantiated nonsense you had been spreading for three
years. If you don't remember it, I can give you the Google Groups references
to prove this.

And this is not an isolated incident. Many times you have made outlandish
claims, provided questionable proof for them, or like this time, no proof
whatsoever, and rejected counter-examples to what you said. I can also go to
your "essays" and find places where you present a problem which exists for
you only because of your lack of understanding of C++ and MFC, and after you
present your misleading, sub-optimal "solution", you smugly conclude, "Much
better. This is how C++ is supposed to be used." The sad thing is, it's
mostly nonsense, and where you aren't plainly wrong, you fail to include the
truly relevant and important information. I can give you a link to a message
on Google in which I explained this in great detail to one of your essay
victims. That I think I will link to:

http://groups.google.com/groups?selm=v49g3vo3ddrrpsmmltnhk5v5du4i6hn8do%404ax.com

Scroll down about halfway through it and read the part beginning with:


I could go on with this. For example, you're fond of saying that secondary
threads keep C and C++ programs alive forever. I tried to disabuse you of
this incorrect notion in a 10/10/1999 email concerning one of your essays,
and again more recently:

http://groups.google.com/groups?selm=kf7n6vkc418e80i036rfvms636gf9cbjjs%404ax.com
http://groups.google.com/groups?selm=p7f7vug2npd1j35fmqq37ng95dp42qofgi%404ax.com

I've also had to repeatedly point out the race conditions inherent to the
naive application shutdown protocols you recommend, which the messages above
actually touch on in an incidental way. I did that once again just a few
days ago, and it took several messages to even partly get the point across
to you; see the thread starting here:

http://groups.google.com/groups?selm=tf2mqv8q70g8h82kbbr20gr420602gjaav%404ax.com

This is just scratching the surface. I'm sick and tired of this.

This message is more personal than I ever like to get, especially in a
newsgroup post. So why didn't I send you an email? For starters, I'm the
only one I know who has disputed your statements in this group on this
issue, and instead of writing to me directly to continue my attempts to have
a sincere discussion with you, you started this new thread to crow about
your non-existent "case" and (I think) try to indirectly

volatile and optimizations

by Alexander Grigoriev » Mon, 24 Nov 2003 09:43:29 GMT

In my copy of Win2003 DDK and SDK, LIST_ENTRY pointers are NOT volatile:

typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;



LIST_ENTRY. This
'volatile' Now
single thread,
used
In spite of the
example, if I recall
when volatile had
executed after the




volatile and optimizations

by Doug Harrison [MVP] » Mon, 24 Nov 2003 09:44:49 GMT





What in the world are you talking about? I've never even heard of
LIST_ENTRY, but when I grep the Platform SDK headers, I find the following
in <winnt.h>:

typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;

Now even if the struct was declared as you say, for your point to have any
validity, you would need to show that the gazillions of other structs and
classes written by MS and others which don't declare their members volatile
are incorrect when accessed under the protection of a mutex in MT programs.
Don't you see that?

--
Doug Harrison
Microsoft MVP - Visual C++


volatile and optimizations

by Joseph M. Newcomer » Tue, 25 Nov 2003 11:26:59 GMT

y 'bool' bug was not imaginary; it took me hours to find it, and it was clearly bad code
being generated. I found it in real code. I did this at a client site, and I do not have
access to that code any longer. I no longer even remember which version of VS I was using
(4.2, 5 or 6). I did not imagine this; I really, truly saw the code which was generated.
It was on the screen in front of me. I don't make these things up.

You may also note that my rant about bool stopped after your very detailed rebuttal. I was
unable to reproduce it in VS6 at all.

As for accusing MS of slovenly coding, the original Win32 spec said that successful APIs
would return TRUE. The Win9x people found this concept inconvenient, and just returned
some random non-zero value, because they would have to add a couple instructions to meet
the spec, which they found "inconvenient" (this was told to me by one of the MS
developers). Nothing changes the fact that sloppy programming is sloppy programming, and
violating the spec based on laziness is not a good excuse.

I do not have proof of the volatile problem because it takes time to generate these
examples; I just delivered a product last week, and I'm two weeks late on another product
deliverable. I just spent too many years being done in by compiler bugs of this nature to
be naively trusting of an optimizer. I spent about fifteen years fighting other peoples'
optimizers, as a tool developer (1969-1974) an OS developer (1975-1978), compiler
developer (1977-1984), compiler tool implementor(1981-1984), and QA tester (1983-1984).
I'm sorry you weren't there for Adrian's rant, and if anyone is entitled to rant about
optimizers and memory fences, he is clearly among the world's experts. The fact that his
rant corresponds to my rant doesn't discount either his or mine. He was giving examples
from real drivers he has debugged (unless he is simply imagining the bugs), and those of
us who worked with optimizing compilers just sat there and said "yeah, yeah, and there's
another" for each bug he described.

I could not generate a failure in the simple case; the real cases come about with
pointers and aliasing. Optimizers are scary pieces of code. I know at least three people
who are considered world-class experts in optimizing compiler code generation, and they
crucially depend on declarations like 'volatile' to direct the compiler to avoid key
optimizations.

I quote from Harbison & Steele, 4th edition, p.83, "The volatile type qualifier informs
ISO C implementations that certain objects can have their values altered in ways not under
control of the implementation. That is, any object (strictly speaking, any lvalue
expression) of a volatile-qualified type should not participate in optimizations that
would increase, decrease, or delay any references to, or modifications of, the object" It
goes on to explain at length the notion of sequence points and how volatile references and
modifications are not permitted to cross sequence points. Nonvolatile references and
modifications clearly are. A function call is a sequence point (in fact, the completion of
argument evaluation is a sequence point). Now a particular compiler may choose, in some
release, and with some configuration of optimization options, to artificially limit
certain optimizations across sequence points, but in other configurations it is free to do
so. volatile forbids code motions in all cases, even when the user has en

volatile and optimizations

by Joseph M. Newcomer » Tue, 25 Nov 2003 14:18:50 GMT





Actually, I am a bit curious about which of my books contains the material plagiarized
from your 10/10/99 email. The book I wrote in 1995-1996 (Win32 Programming; First Printing
December, 1996), or the book I wrote in 1997-1998 (Developing Windows NT Device Drivers;
First Printing, March 1999)? Or was it the one I wrote in 1986-1989 (IDL: The Language and
Its Implementation; 990)?

Since I no longer have the 10/10/99 email (having lost most of my historical email in a
system crash in early 2000 and never having bothered to restore it), I would appreciate a
specific reference as to which book stole which material from this email.

Also, I remain a bit confused. When I took an email and gave you credit (including
pointing out several places where your logic superseded my view, proving me wrong), I get
flamed, and if I apparently don't credit you, I get flamed. I feel a bit like I can't win.
joe

Joseph M. Newcomer [MVP]
email: XXXX@XXXXX.COM
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm


volatile and optimizations

by Alexander Grigoriev » Wed, 26 Nov 2003 01:58:14 GMT




clearly bad code
I do not have
VS I was using
was generated.

There is one good rule (mentioned in "Writing Solid Code" book): NEVER
compare a BOOL against TRUE. BOOL is supposed to have two values: zero
(FALSE) and non-zero.

kernel; this is
that it is
And I'm always
one remaining
kill a thread
case some very,

Properly written drivers use UserMode for waiting in an user context (or
Irp->RequestorMode which can be UserMode or KernelMode). UserMode wait
operations are awaken when a thread is being killed. A thread is also not
killed until all of its pending I/O requests are cleaned up, which is again
a matter of correctly written driver.




volatile and optimizations

by Ian Semmel » Wed, 26 Nov 2003 03:44:38 GMT

I am not commenting on this case as I have no idea what it is about, but the
concept of 'plagiarization' in computer programming is a moot point.

If plagiarization is looking at someone's code and modifying/improving it to
suit ones own needs, then who isn't guilty of it ? That's what this newsgroup
and sites like CodeGuru are all about aren't they ?

The art of computer programming at any point of time is the sum of all
endeavours up to that point. The body of knowledge has been built up, and built
upon for the past 50 years.


For example, who was the first person to write an ascii to binary conversion
routine ? The answer, of course, is no one and everyone. Hundreds of people
independently arrived at their own solutions. Probably, there exists today the
ultimate routine, incorporating all the others.

This applies to almost all code.

On the question of 'volatile'. What about the case when a variable can be
changed externally to the program, eg by a hardware device or the OS ? In those
cases a mutex is irrelevant, isn't it ?






volatile and optimizations

by WTH » Wed, 26 Nov 2003 04:17:58 GMT

> >4. A couple of years later, I found you incorporated an idea from the
other
years
had
plagiarized
Programming; First Printing
Device Drivers;
The Language and

I read Doug's statement as "you having not known about the solution when
writing your essay and a book, and later claiming that during this same
period you were already aware of the method he informed you about."

Of course, I could be wrong as well. :)

WTH




volatile and optimizations

by Doug Harrison [MVP] » Wed, 26 Nov 2003 05:20:35 GMT





Yes. Something internal to the program, such as another thread, could also
render a mutex irrelevant. There's no point in protecting a variable with a
mutex, when some entity which doesn't observe the locking protocol can
modify it.

--
Doug Harrison
Microsoft MVP - Visual C++


volatile and optimizations

by Doug Harrison [MVP] » Wed, 26 Nov 2003 07:47:26 GMT

oseph M. Newcomer wrote:


I never doubted you had a problem of some sort. I just doubted your analysis
of it, and here's why:

1. I never heard any other reports of the problem.
2. You never tried to demonstrate it.
3. I couldn't demonstrate the problem myself.
4. Your description was always accompanied by a rant.
5. At times you mischaracterized the problem as due to the expected behavior
of the built-in bool, resulting from sizeof(bool) < sizeof(BOOL), which was
dead wrong.

Based on all this, I believed you were mistaken to blame the problem on the
compiler and consequently advise people not to use bool, and I explained all
this to you several times. I suggested a far more likely cause for your
problem. You never acknowledged any of it until very late in the game. And
now, you appear to be back where you started, blaming it on the compiler's
handling of the standard C++ bool type.


Joe, that's not the way things happened. In your own words, someone sent you
"private mail" suggesting what I had suggested to you years earlier, namely
a screw up in which someone #defined or typedef'd char as bool:

2002-03-06
http://groups.google.com/groups?selm=avic8uk1brvlm22d2getpu5rn73s93dkg5%404ax.com

This is when you stopped your rant. On second reading, it's clear you
continued to present a compiler bug as equally likely. Moreover, in this
message, you continued to present the use of bool as "a massive trap",
roughly five years after VC implemented the type. I don't think that advice
was ever supportable. For example, people who use the Standard C++ Library
can't easily avoid bool.

Here are some of my replies to you on this issue:

2000/03/05 (Here, I hinted at the probable problem, and did all but
challenge you to prove it.)
http://groups.google.com/groups?selm=%23lxKZbwh%24GA.2044%40cppssbbsa06

Relevant quote:


2001-03-11 (Here, I suggested the probable problem outright, and did all but
challenge you to prove it.)
http://groups.google.com/groups?selm=696oat44il50ccpui8185kbvokshers47g%404ax.com

Relevant quote:


You didn't reply to that message either.

2001-12-06 (In this message, I didn't respond to your standard rant
elsewhere in the thread, because I had given up. However, I did describe the
way bool actually behaves, which I hoped would be sufficient.)
http://groups.google.com/groups?selm=99gv0ugjoqek7fdu0ifj9u6qo128pcf8kv%404ax.com

2001-12-06 (Here's your rant from that thread.)
http://groups.google.com/groups?selm=co7v0ucrp0e3plbuk417e37uhqf6mb2qcg%404ax.com

In that message, you attributed the problem to what you mistakenly thought
was the normal behavior of bool and talked once again about the irrelevant

Similar Threads

1. Volatile variable as initializer for non-volatile variable?

2. VC linker optimizations and whole program optimization

Hi all.

( Visual Studio 2005 )

We do not use any compiler optimizations (/O...) in our release builds
due to the subtle bugs they may reveal and due to the fact that
debugging C++ code in optimized build is a real pain (and, yes, we need
to debug release builds rather too often).

My real question now is with regard to the linker optimizations and
whole program optimization: We have seen that enabling the following
switches:
compiler: (... /Od ) ... /GL
linker: (... /DEBUG) ... /OPT:REF /OPT:ICF /ltcg

where

GL = [Enable link-time code generation]
REF = [Eliminate Unreferenced Data]
ICF = [Remove Redundant COMDATs]
ltcg = [Use Link Time Code Generation]

significantly reduces the size of the resulting binaries.
(The Size difference btw. /OPT + /GL + /LCTG vs. only /OPT is about 15%)

My question is now: Will the LTCG mess around and optimize something in
the compiler-sense (reordering, removing code, ... etc.) or is it safe,
i.e. the only optimizations performed in our case would be removal of
unreferenced functions/data and some merging of template instantiations
... ??

Any insights welcome!

cheers,
Martin

3. Value of compiler/habitual optimization (was: optimization of static data initialization)

4. Access to volatile objects applies to non-volatile objects?

5. volatile bool - CSharp/C#

6. volatile member variable with Interlocked

I have an member variable (int) that is accessed by multiple threads using 
Interlocked.Increment(), Interlocked.Decrement(), and read directly.

Using volatile gives me "CS0420: a reference to a volatile field will not be 
treated as volatile" warnings when using the Interlocked functions, which I 
can easily disable with "#pragma warning disable 420".

Should this variable be marked volatile?  Is volatile necessary in this 
case?

Thanks!
Mark

-- 
Mark Salsbery
Microsoft MVP - Visual C++
 

7. C# volatile field - CSharp/C#

8. Volatile & Interlocked

Using the "volatile" keyword, creates a problem  if I intend to use any of 
the interlocked APIs. The compiler generates an error if I use the following 
line, for example:

Interlocked.Increment(ref count);

The error says that a volatile field cannot be used as ref or out, but if I 
don't use the volatile field, the value may be cached away in some method 
that is just reading the field.

Consider, for example, an integer field being used by three threads. Two 
threads intend to increment the value of the field while the third one just 
wishes to check the value. Consider, for example, the initial value of the 
field is 5.

If both the writer threads increment the value using the interlocked API, 
the final value of the field is guaranteed to be  7. Without the use of the 
interlocked API, the final value could be 6. Therefore, using the 
interlocked API is a must in this case.

Without the field being marked as volatile, the reader thread may always see 
the value as 5.

As can be seen, we need both the mechanisms under some cases.

What might be the solution for such situations?