gomp - cost of threadprivate data access

Matevz Tadel matevz.tadel@cern.ch
Tue Jun 9 18:47:00 GMT 2009


Hello,

Andrew Pinski wrote:
> On Mon, Mar 16, 2009 at 12:07 PM, Matevz Tadel <matevz.tadel@cern.ch> wrote:
>> The "fortran object-files" are linked into a shared library.
>>
>> I put the output of
>>  gfortran -O2 -g -fno-second-underscore -m64 -fno-f2c -fPIC -DCERNLIB_LXIA64
>>    -DCERNLIB_BLDLIB -DCERNLIB_CZ -DCERNLIB_GFORTRAN -I. -Iminicern -fPIC
>>    -fopenmp -pthread -ffixed-line-length-none -c gtrak/gtelec.F -S -o
>> gtelec.s
>> here:
>>  <http://mtadel.home.cern.ch/mtadel/gtelec.s>
>>
>> There are 142 lines with:
>>        call    __tls_get_addr@PLT
>>
>> Can these calls be transformed during linking phase?
> 
> There is nothing can be done if this is in a shared library as TLS
> (private data) has to be allocated via ld.so at runtime and then
> figured out the offsets also.  This is part of the ABI, there is not
> much can be done really.  Thread local data will always be slower in
> shared libraries than the use in executables.

I've come up with a simple example that reproduces the reported issue:
http://mtadel.home.cern.ch/mtadel/gomp/

In short it is just a loop doing basic operations on a common (3 variables), 
running in 4 threads. It provides dynamically and statically linked executables.

Now, running the test with various optimization levels (and with callgrind) 
seems to bring up even more questions. Here's a report.

In static executable case __tls_get_addr() is never called.
Normal timing tests were run with 2*10^9 loop iterations.
Callgrind timing - 10^6 loop iterations.

-O0
===
Running-time ratio dynamic/static = 2 (with callgrind 17.3)
Callgrind reports 32M calls to __tls_get_addr() (73% time spent there).
Every access to a common variable goes via __tls_get_addr().

The 73% in __tls_get_addr() seems utterly wrong - is this some internal 
callgrind problem?

-O1
===
Running-time ratio dynamic/static = 1.03 (with callgrind 3.7)
Callgrind reports 4M calls to __tls_get_addr() (53% time spent there).
One call to __tls_get_addr() per loop iteration.

The 4M calls to __tls_get_addr() seem to contradict the very small speed 
difference (3%). Again, 53% time reported by valgrind seems completely bogus.

-O2
===
Running-time ratio dynamic/static = 1 (also 1 with callgrind)
Callgrind reports 8 calls to __tls_get_addr().
Looking at assembler code one sees that thread-specific common variable 
addresses were stored in registers.

In full geant3 example the common addresses can not be stored in registers as 
the code is much more complex - there are intermittent function calls and the 
variable / common count is much higher.

However - it also seems that the time usage reports of callgrind are completely 
off - so I'm beginning to doubt (almost) everything.

Any comment appreciated!

Best,
Matevz



More information about the Fortran mailing list