Thread safety with BigFloats (and elsewhere in Base)

214 views
Skip to first unread message

Scott Jones

unread,
Jun 21, 2016, 10:50:42 AM6/21/16
to julia-dev
@yuyichao brought up an interesting point in the discussion on @rfourquet's nice #17015 (https://github.com/JuliaLang/julia/pull/17015), about thead safety.

I have been making an MPFR wrapper to test a strategy to replace BigFloat (similar to #17015 for BigInt), and realized that DEFAULT_PRECISION and ROUNDING_MODE would also not be thread-safe.

There are so many cases in just Base where some global setting is kept like that, which means that very little of Julia will actually work correctly with threads, IIUC.

Making things like that thread-safe can incur a very heavy performance penalty also.

What is the best practice for dealing with these sorts of global state in Base (and packages)?

Thanks,
Scott




Páll Haraldsson

unread,
Jul 13, 2016, 9:03:00 AM7/13/16
to julia-dev
On Tuesday, June 21, 2016 at 2:50:42 PM UTC, Scott Jones wrote:
Making things like that thread-safe can incur a very heavy performance penalty also.

Are you sure?
 
I'm no expert on threading/locks/lock-free in general (or for Julia in particular), but would you likely not change these settings ever in your code? Or probably at most only once?

My understanding lock[-free] can be fast when there isn't any contention.

--
Palli.

Páll Haraldsson

unread,
Jul 13, 2016, 9:11:35 AM7/13/16
to julia-dev
On Tuesday, June 21, 2016 at 2:50:42 PM UTC, Scott Jones wrote:
@yuyichao brought up an interesting point in the discussion on @rfourquet's nice #17015 (https://github.com/JuliaLang/julia/pull/17015), about thead safety.

I have been making an MPFR wrapper to test a strategy to replace BigFloat (similar to #17015 for BigInt), and realized that DEFAULT_PRECISION and ROUNDING_MODE would also not be thread-safe.

There are so many cases in just Base where some global setting is kept like that, which means that very little of Julia will actually work correctly with threads, IIUC.

Can at least this just thread_local, rather than global? As I said, do people change these things back and forth much? Or only set once?

[Here for BigFloat, this is a pure software thing, not sure it matters, but couldn't this apply even more (or less?) for setting for the FPU in CPUs?]

--
Palli.

Scott Jones

unread,
Jul 13, 2016, 5:47:33 PM7/13/16
to julia-dev


On Wednesday, July 13, 2016 at 9:03:00 AM UTC-4, Páll Haraldsson wrote:
On Tuesday, June 21, 2016 at 2:50:42 PM UTC, Scott Jones wrote:
Making things like that thread-safe can incur a very heavy performance penalty also.

Are you sure?

Yes.   The problem is that global state like the rounding mode, or default precision, can be set by any thread.
That means that each thread needs it's own copy of those value.
Currently, any use of the rounding mode or default precision is not safe if you have multiple threads, because you can never be sure another thread doesn't modify it.
Julia currently has no easy way of saying that particular values in global scope need to be thread local (i.e. have the variable in thread-local-storage, and when it is set or fetched, have it gotten from there).
There would also need to be a way of initializing those values for every thread.

The workaround that Yichao Yu proposed means 1) making a Julia vector for each value that needs to be thread safe, resizing it based on the max # of threads in __init__, and then initializing all of them, 2) changing all gets and sets to index by the thread id.

Having to call a C function to get the thread id and then use it to index the vectors every time you do an operation on a BigFloat incurs a pretty big performance penalty.

I'm no expert on threading/locks/lock-free in general (or for Julia in particular), but would you likely not change these settings ever in your code? Or probably at most only once?

My understanding lock[-free] can be fast when there isn't any contention.


The problem has nothing to do with that, it has to do with each thread needs its own state, and there is no mechanism to handle that AFAIK in Julia (and I think Yichao Yu would have proposed a different scheme if there were).

Scott

Scott Jones

unread,
Jul 13, 2016, 5:50:39 PM7/13/16
to julia-dev


On Wednesday, July 13, 2016 at 9:11:35 AM UTC-4, Páll Haraldsson wrote:
On Tuesday, June 21, 2016 at 2:50:42 PM UTC, Scott Jones wrote:
@yuyichao brought up an interesting point in the discussion on @rfourquet's nice #17015 (https://github.com/JuliaLang/julia/pull/17015), about thead safety.

I have been making an MPFR wrapper to test a strategy to replace BigFloat (similar to #17015 for BigInt), and realized that DEFAULT_PRECISION and ROUNDING_MODE would also not be thread-safe.

There are so many cases in just Base where some global setting is kept like that, which means that very little of Julia will actually work correctly with threads, IIUC.

Can at least this just thread_local, rather than global? As I said, do people change these things back and forth much? Or only set once?

Yes, these need to be thread local - but just how would you do that in Julia?
 
[Here for BigFloat, this is a pure software thing, not sure it matters, but couldn't this apply even more (or less?) for setting for the FPU in CPUs?]

Saving/restoring the FPU's rounding mode on thread switches is something that is already taken care of, AFAIK, otherwise nobody could use threads for floating point software.

Scott
Reply all
Reply to author
Forward
0 new messages