Skip to content

Base.MPFR: don't ccall for special value predicates #50674

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

Merged
merged 1 commit into from
Aug 14, 2023

Conversation

nsajko
Copy link
Contributor

@nsajko nsajko commented Jul 26, 2023

MPFR determines special values according to sentinel values of the exponent field. Although these constants are not documented (they're defined in MPFR's src/mpfr-impl.h), they're already used in Base.MPFR in the BigFloat inner constructor and for converting IEEE 754 FP types to BigFloat, so I guess it makes sense to avoid the ccall overhead for predicates like iszero and isnan, too.

The context here is that I'm working on generic IEEE 754-BigFloat conversion implementations that would work without using MPFR and improve correctness (#50642) and performance, so this PR seems like the obvious prerequisite for being able to use the Julian predicates like iszero without calling libmpfr unnecessarily.

@dkarrasch dkarrasch added the bignums BigInt and BigFloat label Jul 26, 2023
@nsajko
Copy link
Contributor Author

nsajko commented Jul 26, 2023

The test failures are not related to MPFR at all.

@nsajko nsajko force-pushed the mpfr_predicates branch from f40987c to 4770c81 Compare July 26, 2023 19:54
MPFR determines special values according to sentinel values of the
exponent field. Although these constants are not documented (they're
defined in MPFR's `src/mpfr-impl.h`), they're already used in
`Base.MPFR` in the `BigFloat` inner constructor and for converting IEEE
754 FP types to `BigFloat`, so I guess it makes sense to avoid the
`ccall` overhead for predicates like `iszero` and `isnan`, too.

The context here is that I'm working on generic IEEE 754-`BigFloat`
conversion implementations that would work without using MPFR and
improve correctness (JuliaLang#50642) and performance, so this PR seems like the
obvious prerequisite for being able to use the Julian predicates like
`iszero` without calling libmpfr unnecessarily.
@nsajko nsajko force-pushed the mpfr_predicates branch from 4770c81 to 175cab0 Compare July 26, 2023 19:58
nsajko added a commit to nsajko/julia that referenced this pull request Jul 27, 2023
There's lots of code, but most of it seems like it will be useful in
general. For example, I think I'll use the changes in float.jl and
rounding.jl to improve the JuliaLang#49749 PR. The changes in float.jl could
also be used to refactor float.jl to remove many magic constants.

Benchmarking script:
```julia
using BenchmarkTools
f(::Type{T} = BigFloat, n::Int = 2000) where {T} = rand(T, n)
g!(u, v) = map!(eltype(u), u, v)
@Btime g!(u, v) setup=(u = f(Float16); v = f();)
@Btime g!(u, v) setup=(u = f(Float32); v = f();)
@Btime g!(u, v) setup=(u = f(Float64); v = f();)
```

On master (dc06468):
```
  46.116 μs (0 allocations: 0 bytes)
  38.842 μs (0 allocations: 0 bytes)
  37.039 μs (0 allocations: 0 bytes)
```

With both this commit and JuliaLang#50674 applied:
```
  42.870 μs (0 allocations: 0 bytes)
  42.950 μs (0 allocations: 0 bytes)
  42.158 μs (0 allocations: 0 bytes)
```

So, with this benchmark at least, on an AMD Zen 2 laptop, conversion
to `Float16` is faster, but there's a slowdown for `Float32` and
`Float64`.

Fixes JuliaLang#50642 (exact conversion to `Float16`)
nsajko added a commit to nsajko/julia that referenced this pull request Jul 28, 2023
There's lots of code, but most of it seems like it will be useful in
general. For example, I think I'll use the changes in float.jl and
rounding.jl to improve the JuliaLang#49749 PR. The changes in float.jl could
also be used to refactor float.jl to remove many magic constants.

Benchmarking script:
```julia
using BenchmarkTools
f(::Type{T} = BigFloat, n::Int = 2000) where {T} = rand(T, n)
g!(u, v) = map!(eltype(u), u, v)
@Btime g!(u, v) setup=(u = f(Float16); v = f();)
@Btime g!(u, v) setup=(u = f(Float32); v = f();)
@Btime g!(u, v) setup=(u = f(Float64); v = f();)
```

On master (dc06468):
```
  46.116 μs (0 allocations: 0 bytes)
  38.842 μs (0 allocations: 0 bytes)
  37.039 μs (0 allocations: 0 bytes)
```

With both this commit and JuliaLang#50674 applied:
```
  42.310 μs (0 allocations: 0 bytes)
  42.661 μs (0 allocations: 0 bytes)
  41.608 μs (0 allocations: 0 bytes)
```

So, with this benchmark at least, on an AMD Zen 2 laptop, conversion
to `Float16` is faster, but there's a slowdown for `Float32` and
`Float64`.

Fixes JuliaLang#50642 (exact conversion to `Float16`)
nsajko added a commit to nsajko/julia that referenced this pull request Jul 28, 2023
There's lots of code, but most of it seems like it will be useful in
general. For example, I think I'll use the changes in float.jl and
rounding.jl to improve the JuliaLang#49749 PR. The changes in float.jl could
also be used to refactor float.jl to remove many magic constants.

Benchmarking script:
```julia
using BenchmarkTools
f(::Type{T} = BigFloat, n::Int = 2000) where {T} = rand(T, n)
g!(u, v) = map!(eltype(u), u, v)
@Btime g!(u, v) setup=(u = f(Float16); v = f();)
@Btime g!(u, v) setup=(u = f(Float32); v = f();)
@Btime g!(u, v) setup=(u = f(Float64); v = f();)
```

On master (dc06468):
```
  46.116 μs (0 allocations: 0 bytes)
  38.842 μs (0 allocations: 0 bytes)
  37.039 μs (0 allocations: 0 bytes)
```

With both this commit and JuliaLang#50674 applied:
```
  42.310 μs (0 allocations: 0 bytes)
  42.661 μs (0 allocations: 0 bytes)
  41.608 μs (0 allocations: 0 bytes)
```

So, with this benchmark at least, on an AMD Zen 2 laptop, conversion
to `Float16` is faster, but there's a slowdown for `Float32` and
`Float64`.

Fixes JuliaLang#50642 (exact conversion to `Float16`)
nsajko added a commit to nsajko/julia that referenced this pull request Jul 29, 2023
There's lots of code, but most of it seems like it will be useful in
general. For example, I think I'll use the changes in float.jl and
rounding.jl to improve the JuliaLang#49749 PR. The changes in float.jl could
also be used to refactor float.jl to remove many magic constants.

Benchmarking script:
```julia
using BenchmarkTools
f(::Type{T} = BigFloat, n::Int = 2000) where {T} = rand(T, n)
g!(u, v) = map!(eltype(u), u, v)
@Btime g!(u, v) setup=(u = f(Float16); v = f();)
@Btime g!(u, v) setup=(u = f(Float32); v = f();)
@Btime g!(u, v) setup=(u = f(Float64); v = f();)
```

On master (dc06468):
```
  46.116 μs (0 allocations: 0 bytes)
  38.842 μs (0 allocations: 0 bytes)
  37.039 μs (0 allocations: 0 bytes)
```

With both this commit and JuliaLang#50674 applied:
```
  42.310 μs (0 allocations: 0 bytes)
  42.661 μs (0 allocations: 0 bytes)
  41.608 μs (0 allocations: 0 bytes)
```

So, with this benchmark at least, on an AMD Zen 2 laptop, conversion
to `Float16` is faster, but there's a slowdown for `Float32` and
`Float64`.

Fixes JuliaLang#50642 (exact conversion to `Float16`)
nsajko added a commit to nsajko/julia that referenced this pull request Aug 11, 2023
There's lots of code, but most of it seems like it will be useful in
general. For example, I think I'll use the changes in float.jl and
rounding.jl to improve the JuliaLang#49749 PR. The changes in float.jl could
also be used to refactor float.jl to remove many magic constants.

Benchmarking script:
```julia
using BenchmarkTools
f(::Type{T} = BigFloat, n::Int = 2000) where {T} = rand(T, n)
g!(u, v) = map!(eltype(u), u, v)
@Btime g!(u, v) setup=(u = f(Float16); v = f();)
@Btime g!(u, v) setup=(u = f(Float32); v = f();)
@Btime g!(u, v) setup=(u = f(Float64); v = f();)
```

On master (dc06468):
```
  46.116 μs (0 allocations: 0 bytes)
  38.842 μs (0 allocations: 0 bytes)
  37.039 μs (0 allocations: 0 bytes)
```

With both this commit and JuliaLang#50674 applied:
```
  42.310 μs (0 allocations: 0 bytes)
  42.661 μs (0 allocations: 0 bytes)
  41.608 μs (0 allocations: 0 bytes)
```

So, with this benchmark at least, on an AMD Zen 2 laptop, conversion
to `Float16` is faster, but there's a slowdown for `Float32` and
`Float64`.

Fixes JuliaLang#50642 (exact conversion to `Float16`)
@KristofferC KristofferC merged commit b388d26 into JuliaLang:master Aug 14, 2023
@oscardssmith oscardssmith added the performance Must go faster label Aug 14, 2023
DilumAluthge pushed a commit that referenced this pull request Aug 21, 2023
There's lots of code, but most of it seems like it will be useful in
general. For example, I think I'll use the changes in float.jl and
rounding.jl to improve the #49749 PR. The changes in float.jl could also
be used to refactor float.jl to remove many magic constants.

Benchmarking script:
```julia
using BenchmarkTools
f(::Type{T} = BigFloat, n::Int = 2000) where {T} = rand(T, n)
g!(u, v) = map!(eltype(u), u, v)
@Btime g!(u, v) setup=(u = f(Float16); v = f();)
@Btime g!(u, v) setup=(u = f(Float32); v = f();)
@Btime g!(u, v) setup=(u = f(Float64); v = f();)
```

On master (dc06468):
```
  46.116 μs (0 allocations: 0 bytes)
  38.842 μs (0 allocations: 0 bytes)
  37.039 μs (0 allocations: 0 bytes)
```

With both this commit and #50674 applied:
```
  42.310 μs (0 allocations: 0 bytes)
  42.661 μs (0 allocations: 0 bytes)
  41.608 μs (0 allocations: 0 bytes)
```

So, with this benchmark at least, on an AMD Zen 2 laptop, conversion to
`Float16` is faster, but there's a slowdown for `Float32` and `Float64`.

Fixes #50642 (exact conversion to `Float16`)

Co-authored-by: Oscar Smith <oscardssmith@gmail.com>
@nsajko nsajko deleted the mpfr_predicates branch November 28, 2023 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bignums BigInt and BigFloat performance Must go faster
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants