Skip to content

Optimizing Normed -> Normed conversions #140

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

Closed
kimikage opened this issue Nov 19, 2019 · 2 comments
Closed

Optimizing Normed -> Normed conversions #140

kimikage opened this issue Nov 19, 2019 · 2 comments

Comments

@kimikage
Copy link
Collaborator

kimikage commented Nov 19, 2019

As I suggested here, the current Normed -> Normed conversions are inefficient in some cases.

function Normed{T,f}(x::Normed{T2}) where {T <: Unsigned,T2 <: Unsigned,f}
U = Normed{T,f}
y = round((rawone(U)/rawone(x))*reinterpret(x))
(0 <= y) & (y <= typemax(T)) || throw_converterror(U, x)
reinterpret(U, _unsafe_trunc(T, y))
end

The current conversion method has two problems:

  1. It always checks the input range even if there is no need, and may throw the exception.
  2. It always uses floating-point operations even if there is no need.

The former means that the method is not SIMD-suitable.
Regarding the latter, the conversion between types with the same f is already specialized.

Normed{T1,f}(x::Normed{T2,f}) where {T1 <: Unsigned,T2 <: Unsigned,f} = Normed{T1,f}(convert(T1, x.i), 0)

There is also the N0f8->N0f16 specialization. (I wonder why.)
N0f16(x::N0f8) = reinterpret(N0f16, convert(UInt16, 0x0101*reinterpret(x)))

I do not think these are urgent problems. However, the optimization may be useful in the future to speed up the accumulation (reduce). And I just found a (ugly) workaround for the constant division problem, so I am writing this issue as a memorandum or reminder.

The figures below visualize the cases where the optimization is available.

  • The positive (greenish) area means that the conversion is overflow-safe (i.e. there is no need for the range checking).
  • The negative (reddish) area means that the conversion is unsafe (i.e. it may throw the exception).
  • The deep-colored cells means that the conversion does not need floating-point operations.
    • As mentioned above, the f1 == f2 lines are already supported.

n8_n16
n8_n32
n16_n32

You can get the result of other cases with the following script:

using Gadfly, Colors

set_default_plot_size(15cm, 8cm)

function mat(dest, src)
    b1, b2 = 8*sizeof(dest), 8*sizeof(src)
    if b1 > b2 # widening
        safe = [b1-f1 > b2-f2 || b2 == f2 ? 1 : -1 for f2=1:b2, f1=1:b1]
    else
        safe = [b1-f1 >= b2-f2 ? 1 : -1 for f2=1:b2, f1=1:b1]
    end
    safe .* [isinteger(f1/f2) ? f2/f1 : 1/36 for f2=1:b2, f1=1:b1]
end;

function plot_mat(dest, src)
    s = Scale.color_continuous(
        colormap=Scale.lab_gradient(LCHab(0, 100, 20), "white", LCHab(30, 100, 200)),
        minvalue=-1, maxvalue=1)
    m = mat(dest, src)
    spy(m, 
        Guide.title("Normed{$src,f2} -> Normed{$dest,f1}"),
        Guide.xlabel("f1"), Guide.xticks(ticks=axes(m, 2)),
        Guide.ylabel("f2"), Guide.yticks(ticks=axes(m, 1)),
        Guide.colorkey(title="scale"), s,
        Theme(plot_padding=[0mm,2mm,5mm,0mm]))
end;

plot_mat(UInt16, UInt8)
plot_mat(UInt32, UInt8)
plot_mat(UInt32, UInt16)

Edit: The safe areas are wrong. I forgot to take account of the "carry" or "overlapping". I will soon fix the figures and the script above. Updated.

@timholy
Copy link
Member

timholy commented Nov 19, 2019

There is also the N0f8->N0f16 specialization. (I wonder why.)

I can't remember for sure, it seemed important at the time 😄. (Probably, performance.) But it's certainly more specific than needed. Julia's compiler was not what it is now, so the implementations in #138 probably would have resulted in a big branch.

And I agree, Normed->Normed conversions may be a good way to improve reduce. Kudos as always for looking into this!

@kimikage
Copy link
Collaborator Author

See also: #97 (It seems to mainly focus on Fixed.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants