2016-10-11 3 views
3

Недавно я проверил проверку стабильности типа в моем коде. Когда я называю @code_warntype на нем, я получаю следующий результат:Julia @code_warntype показывает скрытую временную переменную # temp #

Variables: 
    #unused#::IHT.#kw##L0_reg 
    #temp#@_2::Array{Any,1} 
    ::IHT.#L0_reg 
    x::Array{Float64,2} 
    y::Array{Float64,1} 
    k::Int64 
    #temp#@_7::Bool 
    #temp#@_8::Bool 
    max_iter::Int64 
    max_step::Int64 
    quiet::Bool 
    v::IHT.IHTVariables{Float64,Array{Float64,1}} 
    tol::Float64 
    #temp#@_14::Int64 
    #temp#@_15::Int64 
    #temp#@_16::Int64 
    #temp#@_17::Any 
    ###...### 
    #temp#@_17::Any = (Core.arrayref(#temp#@_2::Array{Any,1},#temp#@_16::Int64)::Any 
    ###...### 
    v::IHT.IHTVariables{Float64,Array{Float64,1}} = (Core.typeassert)((Core.arrayref)(#temp#@_2::Array{Any,1},(Base.box)(Int64,(Base.add_int)(#temp#@_16::Int64,1)))::Any,IHT.IHTVariables{Float64,Array{Float64,1}})::IHT.IHTVariables{Float64,Array{Float64,1}} 

Минимальный рабочий пример, используя мой IHT.jl пакет:

Pkg.clone("https://github.com/klkeys/IHT.jl") 
n = 100; p = 250; k = 2; 
x = randn(n,p) 
b = zeros(p); b[1:k] = randn(k); shuffle!(b) 
y = x*b + randn(n) 
@code_warntype L0_reg(x, y, k, quiet=true) 

Казалось бы, как компилятор использует #temp# читать аргументы функция L0_reg. Аргументы функции полностью определены. Откуда возникает эта злая маленькая переменная #temp#@_2? Могу ли я сообщить компилятору, каков его тип? (Надеюсь, не Array{Any,1} ...)

ответ

6

Вы можете использовать @code_lowered для просмотра, где #temp# переменные поступают из:

julia> @code_lowered L0_reg(x, y, k, quiet=true) 
LambdaInfo template for (::IHT.#kw##L0_reg){T<:Union{Float32,Float64}}(::Array{Any,1}, ::IHT.#L0_reg, x::DenseArray{T,2}, y::DenseArray{T,1}, k::Int64) 
:(begin 
     NewvarNode(:(temp)) 
     NewvarNode(:(tol)) 
     #temp#@_7 = true 
     #temp#@_8 = true 
     max_iter = 100 
     max_step = 50 
     quiet = true 
     SSAValue(0) = (IHT.colon)(1,(Base.length)(#temp#@_2) >> 1) 
     #temp#@_14 = (Base.start)(SSAValue(0)) 
     10: 
     unless !((Base.done)(SSAValue(0),#temp#@_14)) goto 42 
     SSAValue(1) = (Base.next)(SSAValue(0),#temp#@_14) 
     #temp#@_15 = (Core.getfield)(SSAValue(1),1) 
     #temp#@_14 = (Core.getfield)(SSAValue(1),2) 
     #temp#@_16 = #temp#@_15 * 2 - 1 
     #temp#@_17 = (Core.arrayref)(#temp#@_2,#temp#@_16) 
     unless #temp#@_17 === :quiet goto 20 
     quiet = (Core.typeassert)((Core.arrayref)(#temp#@_2,#temp#@_16 + 1),IHT.Bool) 
     goto 40 
     20: 
     unless #temp#@_17 === :max_step goto 24 
     max_step = (Core.typeassert)((Core.arrayref)(#temp#@_2,#temp#@_16 + 1),IHT.Int) 
     goto 40 
     24: 
     unless #temp#@_17 === :max_iter goto 28 
     max_iter = (Core.typeassert)((Core.arrayref)(#temp#@_2,#temp#@_16 + 1),IHT.Int) 
     goto 40 
     28: 
     unless #temp#@_17 === :tol goto 33 
     tol = (Core.typeassert)((Core.arrayref)(#temp#@_2,#temp#@_16 + 1),IHT.Float) 
     #temp#@_8 = false 
     goto 40 
     33: 
     unless #temp#@_17 === :temp goto 38 
     temp = (Core.typeassert)((Core.arrayref)(#temp#@_2,#temp#@_16 + 1),(Core.apply_type)(IHT.IHTVariables,$(Expr(:static_parameter, 1)))) 
     #temp#@_7 = false 
     goto 40 
     38: 
     (Base.kwerr)(#temp#@_2,,x,y,k) 
     40: 
     goto 10 
     42: 
     unless #temp#@_7 goto 45 
     temp = (IHT.IHTVariables)(x,y,k) 
     45: 
     unless #temp#@_8 goto 48 
     tol = (IHT.convert)($(Expr(:static_parameter, 1)),0.0001) 
     48: 
     return (IHT.#L0_reg#75)(temp,tol,max_iter,max_step,quiet,,x,y,k) 
    end) 

В этом случае временные секретари (в частности #temp#@_2) поступают из ключевых аргументов , Это вполне нормально для аргументов ключевого слова.

julia> f(; x=1) = x 
f (generic function with 1 method) 

julia> @code_warntype f(x=1) 
Variables: 
    #unused#::#kw##f 
    #temp#@_2::Array{Any,1} 
    ::#f 
    x::Any 
    #temp#@_5::Int64 
    #temp#@_6::Int64 
    #temp#@_7::Int64 
    #temp#@_8::Any 

Body: 
    begin 
     x::Any = 1 
     SSAValue(2) = (Base.arraylen)(#temp#@_2::Array{Any,1})::Int64 
     SSAValue(3) = (Base.select_value)((Base.sle_int)(0,1)::Bool,(Base.box)(Int64,(Base.ashr_int)(SSAValue(2),(Base.box)(UInt64,1))),(Base.box)(Int64,(Base.shl_int)(SSAValue(2),(Base.box)(UInt64,(Base.box)(Int64,(Base.neg_int)(1))))))::Int64 
     SSAValue(4) = (Base.select_value)((Base.sle_int)(1,SSAValue(3))::Bool,SSAValue(3),(Base.box)(Int64,(Base.sub_int)(1,1)))::Int64 
     #temp#@_5::Int64 = 1 
     6: 
     unless (Base.box)(Base.Bool,(Base.not_int)((#temp#@_5::Int64 === (Base.box)(Int64,(Base.add_int)(SSAValue(4),1)))::Bool)) goto 21 
     SSAValue(5) = #temp#@_5::Int64 
     SSAValue(6) = (Base.box)(Int64,(Base.add_int)(#temp#@_5::Int64,1)) 
     #temp#@_6::Int64 = SSAValue(5) 
     #temp#@_5::Int64 = SSAValue(6) 
     #temp#@_7::Int64 = (Base.box)(Int64,(Base.sub_int)((Base.box)(Int64,(Base.mul_int)(#temp#@_6::Int64,2)),1)) 
     #temp#@_8::Any = (Core.arrayref)(#temp#@_2::Array{Any,1},#temp#@_7::Int64)::Any 
     unless (#temp#@_8::Any === :x)::Bool goto 17 
     x::Any = (Core.arrayref)(#temp#@_2::Array{Any,1},(Base.box)(Int64,(Base.add_int)(#temp#@_7::Int64,1)))::Any 
     goto 19 
     17: 
     (Base.throw)($(Expr(:new, :(Base.MethodError), :((Core.getfield)((Core.getfield)((Core.getfield)(#f,:name)::TypeName,:mt),:kwsorter)), :((Core.tuple)(#temp#@_2,)::Tuple{Array{Any,1},#f}))))::Union{} 
     19: 
     goto 6 
     21: 
     return x::Any 
    end::Any 

Аргументы с ключевыми словами известны как callsite overhead that can be somewhat worked around by declaring types. Обратите внимание, что, если ваша функция не очень мала, вряд ли сортировка аргументов ключевого слова на самом деле является огромным узким местом (несмотря на неприятный вывод @code_warntype).

Когда вы делаете @code_warntype на вызове аргумента ключевого слова, вы фактически просматриваете нестабильности типа ключевого слова сортировщика аргументов, автогенерированную оболочку вокруг реальной функции. Как вы можете видеть, код заканчивается вызовом (IHT.#L0_reg#75)(temp,tol,max_iter,max_step,quiet,,x,y,k), который является простой функцией, которая принимает позиционные аргументы. Таким образом, выход @code_warntype практически бесполезен в этом случае.

+0

so _that_ - это то, что означают переменные «kw» и «kwargs» ... Я хочу, чтобы я знал это 2 года назад X- ( –

+0

спасибо за очень тщательный ответ! –

Смежные вопросы