Re: Strange Windows problem, lock_timeout test request - Mailing list pgsql-hackers
From | Robert Haas |
---|---|
Subject | Re: Strange Windows problem, lock_timeout test request |
Date | |
Msg-id | CA+TgmobkMbQVCtKNYgXzA=g+OEteAkYDacCnM9XpeX332-yV9g@mail.gmail.com Whole thread Raw |
In response to | Re: Strange Windows problem, lock_timeout test request (Tom Lane <tgl@sss.pgh.pa.us>) |
Responses |
Re: Strange Windows problem, lock_timeout test request
(Greg Stark <stark@mit.edu>)
|
List | pgsql-hackers |
On Thu, Mar 21, 2013 at 8:16 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote: > Robert Haas <robertmhaas@gmail.com> writes: >> On Mon, Mar 18, 2013 at 10:09 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote: >>> Because it's wrong. Removing "volatile" means that the compiler is >>> permitted to optimize away stores (and fetches!) on the basis of their >>> being unnecessary according to straight-line analysis of the code. >>> Write barriers don't fix that, they only say that stores that the >>> compiler chooses to issue at all have to be ordered a certain way. > >> I don't think this is correct. The read and write barriers as >> implemented are designed to function as compiler barriers also, just >> as they do in the Linux kernel and every other piece of software I've >> found that implements anything remotely like this, with the lone >> exception of PostgreSQL. In PostgreSQL, spinlock acquisition and >> release are defined as CPU barriers but not a compiler barrier, and >> this necessitates extensive use of volatile all over the code base >> which would be unnecessary if we did this the way it's done in Linux >> and elsewhere. > > I think you're just as mistaken as Zoltan. Barriers enforce ordering > of operations, not whether an operation occurs at all. Surely not. Suppose the user does this: some_global_var = 1; some_function(); some_global_var = 2; I hope we can both agree that any compiler which thinks it doesn't need to store 1 in some_global_var is completely nuts, because some_function() might perform any arbitrary computation, including one that depends on some_global_var being 1 rather than whatever value it had before that. Of course, if a global optimizer can prove that some_function() can't do anything that can possibly care about some_global_var, then the store could be omitted, but not otherwise. Should the compiler omit the store and should there then be a bug in the program, we wouldn't say "oh, some_global_var ought to be declared volatile". We would say "that compiler is buggy". Now, conversely, in this situation, it seems to me (and I think you'll agree) that the compiler could be forgiven for omitting one of the stores: some_global_var = 1; local_var = 42; some_global_var = 2; If we declare some_global_var as volatile, it will force the compiler to perform both stores regardless of what the optimizer thinks, and moreover, the second store is required to happen after the first one, because the definition of volatile is that volatile references are globally sequenced with respect TO EACH OTHER. However, the store to local_var could be moved around with respect to the other two or omitted altogether unless local_var is also declared volatile. Now, consider this: some_global_var = 1; pg_compiler_barrier(); /* or in Linux, barrier() */ some_global_var = 2; The compiler barrier is exactly equivalent to the unknown function in the first example, except that no function is actually called. The semantics are precisely that the compiler must assume that, at the point the barrier intervenes, an unknown operation will occur which may depend on the contents of any word in memory and which may modify any word in memory. Thus, the compiler may not postpone stores requested before the barrier until after the barrier on the grounds that the values will be overwritten after the barrier; and if any global variables have been loaded into registers before the barrier it must be assumed that, after the barrier, the registers may no longer match those global variables. It is true that any barrier, including a compiler barrier, serves only to separate instructions. But I don't believe it follows in any way that the barrier therefore prohibits reordering operations but not omitting them altogether. Such a definition would have no practical utility. The compiler is not free to willy-nilly leave out things that the user asks it to do any more than it is free to willy-nilly reorder them. If it were, programming would be chaos, and everything would have to be volatile. What the compiler is free to do is to reorder and omit instructions where the programmer won't, in a single-thread execution context, be able to notice the difference. And a compiler barrier is an explicit notification that, in essence, the programmer will notice if things are not just the way he wrote them when that point in the code is reached. To see the difference between this and volatile, consider the following: a = 1; b = 1; c = 1; a = 2; b = 2; c = 2; Absent any special precautions, the compiler may well optimize the first set of stores away completely and perform the second set in any order it likes. If we make all the variables volatile, it will do all 6 stores in precisely the order specified, omitting nothing and reordering nothing. If we instead stick a compiler barrier just after the assignment "c = 1", then the compiler must store 1 in all three variables (in any order that it likes), and then store 2 in all three variables (in any order that it likes). The "barrier" essentially divides up the code into chunks and requires that those chunks be optimized independently by the compiler without knowledge of what earlier or later chunks are doing. -- Robert Haas EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company
pgsql-hackers by date: