Re: Is WRITE_ONCE() enough to prevent invention of stores?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2017/09/16 18:07:30 -0700, Paul E. McKenney wrote:
> On Sat, Sep 16, 2017 at 08:01:45PM +0900, Akira Yokosawa wrote:
>> Hi Paul,
>>
>> I'm a bit disturbed by the description in Section 14.3.1 "Memory-Reference
>> Restrictions" quoted below:
>>
>>> Oddly enough, the compiler is within its rights to use a variable
>>> as temporary storage just before a store to that variable, thus
>>> inventing stores to that variable.
>>> Fortunately, most compilers avoid this sort of thing, at least outside
>>> of stack variables.
>>> Nevertheless, using WRITE_ONCE() (or declaring the variable
>>> volatile) should prevent this sort of thing.
>>> But take care: If you have a translation unit that uses that variable,
>>> and never makes a volatile access to it, the compiler has no way of
>>> knowing that it needs to be careful.
>>
>> I'm wondering if using WRITE_ONCE() in a translation unit is really
>> enough to prevent invention of stores.
>>
>> Accessing via a volatile-cast pointer guarantees the access is not
>> optimized out (and hopefully the referenced value is respected).
>>
>> But I suspect that it has any effect in preventing invention of extra
>> loads/stores.
>>
>> Isn't declaring the variable volatile necessary for the guarantee?
>>
>> In practice, as is described in the above quote: "Fortunately, most
>> compilers avoid this sort of thing, at least outside of stack variables",
>> we can assume non-volatile shared variables are not spilled out to
>> the variables themselves as far as GCC/LLVM is concerned.
>> But this is compiler dependent, I suppose.
> 
> I suspect that it will turn out to be impossible for the compiler to
> actually invent these stores in the general case.  For example, it might
> be that there is some lock held or other synchronization mechanism unknown
> to the compiler that prevents this behavior.  But I haven't fully worked
> this out yet.

You mean the invented stores wouldn't be visible from other threads anyway?
In a meaningful parallel code, that can be the case.

> 
> But I do know that if you just do plain stores, the compiler is fully
> within its rights to invent stores preceding any given plain store.

So, the rules to use WRITE_ONCE() is something like the following?

---
1) Declare the variable without volatile.
2) READ_ONCE() and plain loads can be mixed. A plain load will see
   a value at least newer than or equal to the one obtained at the
   program-order most recent READ_ONCE().
3) WRITE_ONCE() should not be mixed with plain stores when invention
   of stores is to be avoided.

Invention of stores is the opposite of fusing stores.
Suppose you don't want to update progress in the while loop:

	while (!am_done()) {
	  do_something(p);
	  tmp++;
	}
	progress = tmp;

The compiler might transform this to

	while (!am_done()) {
	  do_something(p);
	  progress++;
	}

if it wants to avoid allocation of a register/stack to tmp for whatever
reason. WRITE_ONCE() prevents the unintended accesses of progress:

	while (!am_done()) {
	  do_something(p);
	  tmp++;
	}
	WRITE_ONCE(progress, tmp);

---
Adding this example in the text might be too verbose.
Would a Quick Quiz be reasonable?

        Thanks, Akira

> 
> 							Thanx, Paul
> 
> 

--
To unsubscribe from this list: send the line "unsubscribe perfbook" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux