Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use ScopedValues for MPFR precision and rounding #51362

Merged
merged 1 commit into from
Feb 26, 2024
Merged

Conversation

simonbyrne
Copy link
Contributor

@simonbyrne simonbyrne commented Sep 17, 2023

Should fix thread safety issues.

Actually fixes #27139

@brenhinkeller brenhinkeller added bugfix This change fixes an existing bug bignums BigInt and BigFloat labels Sep 17, 2023
@longemen3000
Copy link
Contributor

Could this fix #51058?

const DEFAULT_PRECISION = Ref{Clong}(256)

const CURRENT_PRECISION = ScopedValue{Clong}()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could set it to default precision? Or is it important that the default precision could be changed globally?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We support it at the moment, so dropping it would be breaking, but I'm not sure how necessary it is?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you need to be able to change it, don't you need this to be

const CURRENT_PRECISION = ScopedValue{RefValue{Clong}}(Ref{Clong}())

since ScopedValue is immutable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but the default field is marked const:

mutable struct ScopedValue{T}
const has_default::Bool
const default::T
ScopedValue{T}() where T = new(false)
ScopedValue{T}(val) where T = new{T}(true, val)
ScopedValue(val::T) where T = new{T}(true, val)
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't mean that it's an immutable struct, I just mean that you can't actually change the value other than by introducing a new dynamic scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's correct.

@vchuravy
Copy link
Member

Nice! I would be curious to see what's the performance impact.

@@ -158,11 +159,17 @@ end
# The rounding mode here shouldn't matter.
significand_limb_count(x::BigFloat) = div(sizeof(x._d), sizeof(Limb), RoundToZero)

rounding_raw(::Type{BigFloat}) = ROUNDING_MODE[]
rounding_raw(::Type{BigFloat}) = something(Base.ScopedValues.get(CURRENT_ROUNDING_MODE), ROUNDING_MODE[])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vchuravy should this overload Base.get?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has different API so I decided not to.

get(dict, key, value) vs get(ScopedValue). But that was me being conservative, also it returns Some/Nothing.

I could see an argument for get(SValue, value)

@simonbyrne
Copy link
Contributor Author

I see a minor impact:

function f(N)
    x = big(0.0)
    for i = 1:N
        x += BigFloat("0.1")
    end
    return x
end

function g(N)
    setrounding(BigFloat, RoundDown) do
        f(N)
    end
end

On master:

julia> @btime f(1_000_000)
  197.769 ms (5000002 allocations: 202.18 MiB)
100000.0000000000000000000000000000000000000000000000000000000000000000001391156

julia> @btime g(1_000_000)
  202.435 ms (5000002 allocations: 202.18 MiB)
99999.99999999999999999999999999999999999999999999999999999999999999999955990192

On this branch:

julia> @btime f(1_000_000)
  208.775 ms (5000002 allocations: 202.18 MiB)
100000.0000000000000000000000000000000000000000000000000000000000000000001391156

julia> @btime g(1_000_000)
  251.740 ms (5000007 allocations: 202.18 MiB)
99999.99999999999999999999999999999999999999999999999999999999999999999955990192

So a bit of overhead, but not too bad.

@simonbyrne
Copy link
Contributor Author

simonbyrne commented Sep 20, 2023

To clarify, this would access the scoped values around 4 million times (in each iteration, access both rounding mode and precision for thee decimal to binary conversion, then the addition), so 40 milliseconds of overhead would be about 10ns per call.

@simonbyrne simonbyrne marked this pull request as ready for review September 21, 2023 05:03
@simonbyrne
Copy link
Contributor Author

Could this fix #51058?

No.

@vchuravy
Copy link
Member

Changing the precision has a bit more overhead, but we would assume that's a rare operation to begin with?

@simonbyrne
Copy link
Contributor Author

Changing the precision has a bit more overhead, but we would assume that's a rare operation to begin with?

Actually, that's probably more common. However I see roughly the same overhead when using the following:

function h(N)
    setprecision(BigFloat, 256) do
        f(N)
    end
end

@KristofferC
Copy link
Sponsor Member

KristofferC commented Feb 13, 2024

What's the status here @simonbyrne? Rebase and merge?

@simonbyrne
Copy link
Contributor Author

I think this is ready to go now.

@KristofferC KristofferC merged commit 3ebba8f into master Feb 26, 2024
7 checks passed
@KristofferC KristofferC deleted the sb/mpfr-scope branch February 26, 2024 14:06
tecosaur pushed a commit to tecosaur/julia that referenced this pull request Mar 4, 2024
mkitti pushed a commit to mkitti/julia that referenced this pull request Mar 7, 2024
@nsajko
Copy link
Contributor

nsajko commented Oct 1, 2024

PR #55911 fixes a regression introduced by this PR, could anyone help review it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bignums BigInt and BigFloat bugfix This change fixes an existing bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BigFloat precision and rounding mode are not thread-safe
7 participants