[ET Trac] [Einstein Toolkit] #928: openmp parallelization within Exact broken
Einstein Toolkit
trac-noreply at einsteintoolkit.org
Sat Oct 6 13:12:12 CDT 2012
#928: openmp parallelization within Exact broken
------------------------------------+---------------------------------------
Reporter: knarf | Owner:
Type: defect | Status: confirmed
Priority: minor | Milestone: ET_2012_11
Component: EinsteinToolkit thorn | Version: development version
Resolution: | Keywords:
------------------------------------+---------------------------------------
Comment (by rhaas):
The attached patch replaces the SAVE variable with THREADPRIVATE variables
(ie. the per-thread equivalent). I also did this substitution in boost.F77
where currently a CRITICAL section is used. I believe that the way the the
critical section was used does not properly address the race condition
(and I think I sprinkled a couple such constructs through the Cactus
code). The code and reasoning go like this:
{{{
logical,save :: firstcall = .true.
integer,save :: somevalue
if (firstcall) then
$omp critical
if (firstcall) then
somevalue = 42
firstcall = .false.
end if
$end critical
end if
}}}
with the aim in skipping the whole critical section once somevalue has
been initialized and firstcall set to true on the first go. The two if
statements on the same condition are seens as a first speculative one the
allows a quick skip and only if we think we might have to do something (ie
if firstcall.eqv..true.) do we enter the expensive section of code. The
critical section is intended to ensure we really only do so once.
The mistake now is that as far as I know, an optimizing compiler is free
to actually execute the following code:
{{{
logical,save :: firstcall = .true.
integer,save :: somevalue
if (firstcall) then
$omp critical
if (firstcall) then
! order of statements reversed
firstcall = .false.
somevalue = 42
end if
$end critical
end if
}}}
since there is no (visible to the compiler) ordering required. This can go
wrong in the following way
1. thread 0 sets firstcall=.false. and flushes this value to memory.
1. before thread 0 sets somevalue, thread 1 comes along, encounters the
outer if statement, finds that firstcall=.false.
1. thread 1 proceeds with the wrong value of somevalue.
There seems to be no way to force a compiler (C or Fortran) to *not*
change a value temporarily (or to explicitly enforce an ordering on the
statements). C's volatile attribute (think of using it to access a
hardware register) seems the closest (and C also defines synchronization
points where the compiler must ensure that all variable data is in memory,
eg. before function calls, though optimization might do funny things as
well if the compiler thinks it can be sure that a variable is not visible
to anyone else). None of this helps with Fortran code of course.
--
Ticket URL: <https://trac.einsteintoolkit.org/ticket/928#comment:7>
Einstein Toolkit <http://einsteintoolkit.org>
The Einstein Toolkit
More information about the Trac
mailing list