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

Non-idempotent compilation #29952

Closed
maleadt opened this issue Nov 7, 2018 · 4 comments
Closed

Non-idempotent compilation #29952

maleadt opened this issue Nov 7, 2018 · 4 comments
Labels
bug Indicates an unexpected problem or unintended behavior gpu Affects running Julia on a GPU

Comments

@maleadt
Copy link
Member

maleadt commented Nov 7, 2018

Reduced from JuliaGPU/CUDAnative.jl#278, where a simple CUDAnative kernel that calls print_to_string doesn't work anymore since #28876 due to unsupported recursion. Although the recursion itself is problematic, which #25984 is supposed to fix, there seems to be a greater issue here, where multiple invocations of the compiler yield different results. Maybe that falls under the known problem of order-dependent inference, but I'm not sure so putting it out here anyway.

MWE without CUDAnative:

function codegen()
    f = Base.checked_sub
    tt = Tuple{Int,Int}

    # get the method instance
    world = typemax(UInt)
    meth = which(f, tt)
    sig = Base.signature_type(f, tt)::Type
    (ti, env) = ccall(:jl_type_intersection_with_env, Any,
                      (Any, Any), sig, meth.sig)::Core.SimpleVector
    meth = Base.func_for_method_checked(meth, ti)
    linfo = ccall(:jl_specializations_get_linfo, Ref{Core.MethodInstance},
                  (Any, Any, Any, UInt), meth, ti, env, world)

    # set-up hooks
    method_stack = Vector{Core.MethodInstance}()
    function hook_emit_function(method_instance, code, world)
        println("  "^length(method_stack), "emit_function($method_instance)")
        push!(method_stack, method_instance)

        # check for recursion
        if method_instance in method_stack[1:end-1]
            throw("recursion is currently not supported")
        end
    end
    function hook_emitted_function(method_instance, code, world)
        @assert last(method_stack) == method_instance ctx
        pop!(method_stack)
    end

    # set-up params
    params = Base.CodegenParams(cached             = false,
                                track_allocations  = false,
                                code_coverage      = false,
                                static_alloc       = false,
                                prefer_specsig     = true,
                                emit_function      = hook_emit_function,
                                emitted_function   = hook_emitted_function)

    ccall(:jl_get_llvmf_defn, Ptr{Cvoid},
          (Any, UInt, Bool, Bool, Base.CodegenParams),
          linfo, world, #=wrapper=#false, #=optimize=#false, params)

    return
end

Calling codegen() twice yields different results, where the second one results in recursive codegen for print_to_string:

julia> codegen()
emit_function(MethodInstance for checked_sub(::Int64, ::Int64))
  emit_function(MethodInstance for throw_overflowerr_binaryop(::Symbol, ::Int64, ::Int64))

julia> codegen()
emit_function(MethodInstance for checked_sub(::Int64, ::Int64))
  emit_function(MethodInstance for throw_overflowerr_binaryop(::Symbol, ::Int64, ::Int64))
    emit_function(MethodInstance for print_to_string(::Int64, ::Vararg{Any,N} where N))
      emit_function(MethodInstance for getindex(::Tuple{}, ::Int64))
      emit_function(MethodInstance for #IOBuffer#300(::Bool, ::Bool, ::Nothing, ::Bool, ::Int64, ::Int64, ::Type))
        emit_function(MethodInstance for getindex(::Tuple{}, ::Int64))
        emit_function(MethodInstance for throw_inexacterror(::Symbol, ::Any, ::Int64))
          emit_function(MethodInstance for InexactError(::Symbol, ::Any, ::Any))
        emit_function(MethodInstance for getindex(::Tuple{}, ::Int64))
        emit_function(MethodInstance for #IOBuffer#299(::Bool, ::Bool, ::Bool, ::Bool, ::Int64, ::Nothing, ::Type, ::Array{UInt8,1}))
          emit_function(MethodInstance for print_to_string(::String, ::Vararg{Any,N} where N))
            emit_function(MethodInstance for (::getfield(Core, Symbol("#kw#Type")))(::NamedTuple{(:sizehint,),Tuple{Int64}}, ::Type{Base.GenericIOBuffer{Array{UInt8,1}}}))
              emit_function(MethodInstance for getindex(::Tuple{}, ::Int64))
              emit_function(MethodInstance for #IOBuffer#300(::Bool, ::Bool, ::Nothing, ::Bool, ::Int64, ::Int64, ::Type))
ERROR: "recursion is currently not supported"

The part of #28876 that has resulted in this behavior, is the removal of a keyword argument. Adding an unused one back fixes the recursion:

julia> @eval Base begin
          function print_to_string(xs...; whatever=nothing)
              if isempty(xs)
                  return ""
              end
              siz = 0
              for x in xs
                  siz += tostr_sizehint(x)
              end
              # specialized for performance reasons
              s = IOBuffer(sizehint=siz)
              for x in xs
                  print(s, x)
              end
              String(resize!(s.data, s.size))
          end
        end
print_to_string (generic function with 1 method)

julia> codegen()
emit_function(MethodInstance for checked_sub(::Int64, ::Int64))
  emit_function(MethodInstance for throw_overflowerr_binaryop(::Symbol, ::Int64, ::Int64))

julia> codegen()
emit_function(MethodInstance for checked_sub(::Int64, ::Int64))
  emit_function(MethodInstance for throw_overflowerr_binaryop(::Symbol, ::Int64, ::Int64))

This is on latest 1.0.2 (b196720).

Another possible clue:

julia> @eval Base begin
          function print_to_string(xs...; whatever=nothing)
              if isempty(xs)
                  return ""
              end
              siz = 0
              for x in xs
                  siz += tostr_sizehint(x)
              end
              # specialized for performance reasons
              s = IOBuffer(sizehint=siz)
              for x in xs
                  print(s, x)
              end
              String(resize!(s.data, s.size))
          end
        end
print_to_string (generic function with 1 method)

julia> using CUDAnative
julia: /home/tim/Julia/julia-1.0/src/gf.c:157: jl_method_instance_t *jl_specializations_get_linfo(jl_method_t *, jl_value_t *, jl_svec_t *, size_t): Assertion `linfo->min_world <= sf->min_world && linfo->max_world >= sf->max_world' failed.

signal (6): Aborted
in expression starting at no file:0
gsignal at /usr/lib/libc.so.6 (unknown line)
abort at /usr/lib/libc.so.6 (unknown line)
__assert_fail_base.cold.0 at /usr/lib/libc.so.6 (unknown line)
__assert_fail at /usr/lib/libc.so.6 (unknown line)
jl_specializations_get_linfo at /home/tim/Julia/julia-1.0/src/gf.c:157
jl_recache_method_instance at /home/tim/Julia/julia-1.0/src/dump.c:2996 [inlined]
jl_recache_other at /home/tim/Julia/julia-1.0/src/dump.c:3016 [inlined]
_jl_restore_incremental at /home/tim/Julia/julia-1.0/src/dump.c:3104
jl_restore_incremental at /home/tim/Julia/julia-1.0/src/dump.c:3146
_include_from_serialized at ./loading.jl:617
macro expansion at ./logging.jl:310 [inlined]
_require_search_from_serialized at ./loading.jl:704
_tryrequire_from_serialized at ./loading.jl:648
_require_search_from_serialized at ./loading.jl:702
_require at ./loading.jl:937
require at ./loading.jl:858
macro expansion at ./logging.jl:309 [inlined]
require at ./loading.jl:840
jl_fptr_trampoline at /home/tim/Julia/julia-1.0/src/gf.c:1831
jl_apply_generic at /home/tim/Julia/julia-1.0/src/gf.c:2184
jl_apply at /home/tim/Julia/julia-1.0/src/julia.h:1537 [inlined]
call_require at /home/tim/Julia/julia-1.0/src/toplevel.c:441 [inlined]
eval_import_path at /home/tim/Julia/julia-1.0/src/toplevel.c:476
jl_toplevel_eval_flex at /home/tim/Julia/julia-1.0/src/toplevel.c:671
jl_toplevel_eval_in at /home/tim/Julia/julia-1.0/src/builtins.c:622
eval at ./boot.jl:319
jl_apply_generic at /home/tim/Julia/julia-1.0/src/gf.c:2184
eval_user_input at /home/tim/Julia/julia-1.0/build/release/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:85
macro expansion at /home/tim/Julia/julia-1.0/build/release/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:117 [inlined]
#28 at ./task.jl:259
jl_apply_generic at /home/tim/Julia/julia-1.0/src/gf.c:2184
jl_apply at /home/tim/Julia/julia-1.0/src/julia.h:1537 [inlined]
start_task at /home/tim/Julia/julia-1.0/src/task.c:268
unknown function (ip: 0xffffffffffffffff)
Allocations: 16752583 (Pool: 16747964; Big: 4619); GC: 35
zsh: abort      julia --depwarn=no --color=yes
@maleadt maleadt added bug Indicates an unexpected problem or unintended behavior compiler:inference Type inference labels Nov 7, 2018
maleadt added a commit that referenced this issue Nov 7, 2018
@maleadt maleadt changed the title Non-idempotent inference breaks CUDAnative due to recursion Non-idempotent compilation breaks CUDAnative due to recursion Nov 7, 2018
@maleadt
Copy link
Member Author

maleadt commented Nov 8, 2018

Note that with #29957 merged, one needs to revert that change in order to have recursion with the checked_add function as tested in this MWE.

@maleadt maleadt added gpu Affects running Julia on a GPU and removed compiler:inference Type inference labels Nov 8, 2018
@KristofferC
Copy link
Member

KristofferC commented Nov 8, 2018

Fixed by #29957

Edit: Or well, maybe the non-idempotence is still an issue

@maleadt
Copy link
Member Author

maleadt commented Nov 9, 2018

Annoyingly, this seems precompilation/sysimg related. Can't reproduce with similar functions that are defined in the file itself, only by calling eg. Base.checked_sub. Also doesn't reproduce on master, only on release-1.0, and I bisected it to 17a5754...

@maleadt maleadt changed the title Non-idempotent compilation breaks CUDAnative due to recursion Non-idempotent compilation Nov 9, 2018
@maleadt
Copy link
Member Author

maleadt commented May 5, 2020

Probably not relevant anymore after the codegen refactor.

@maleadt maleadt closed this as completed May 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior gpu Affects running Julia on a GPU
Projects
None yet
Development

No branches or pull requests

2 participants