2016-08-07 3 views
2

ジュリア(V0.5)は、パフォーマンスの低下につながる、次のように定数伝播しません:ディスパッチせずにif文を定数に伝播できますか?

julia> g(::Int) = true 
g (generic function with 1 method) 

julia> f(x) = g(x) ? 1 : 1.0 
f (generic function with 1 method) 

julia> @code_warntype f(1) 
Variables: 
    #self#::#f 
    x::Int64 

Body: 
    begin 
     unless $(QuoteNode(true)) goto 3 
     return 1 
     3: 
     return 1.0 
    end::Union{Float64,Int64} 

はその代わりに、私は次の操作を実行する必要があります。

julia> g(::Int) = Val{true} 
g (generic function with 1 method) 

julia> f_(::Type{Val{true}}) = 1 
f_ (generic function with 1 method) 

julia> f_(::Type{Val{false}}) = 1.0 
f_ (generic function with 2 methods) 

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

これは動作しますが、それは定義が必要です追加のコンパイル時オーバーヘッドを作成する追加の機能。このオーバーヘッドなしでv0.5で動作する既存のソリューションはありますか?

+2

これは、スタックオーバーフローの問題よりもパフォーマンス上の問題が多いようです。 – StefanKarpinski

+0

@StefanKarpinskiコンパイラはすでに定数伝播、インライン展開、推論を行っていますが、これらのステップは繰り返し実行でき、_ad nauseum_を組み合わせることができるので、コンパイル時間を不当にせずに最高のパフォーマンスを保証する方法はありません。だから私は、既存の行動と連携する方法が存在するかどうかに興味があります。 –

+0

@StefanKarpinskiそれにもかかわらず、私は問題https://github.com/JuliaLang/julia/issues/17880を提出しました。 –

答えて

1

投稿した問題に注意してください。実際にLLVMはこの定数伝搬を行いますので、実行時にブランチは存在しません。問題は、推論が定数伝搬とデッドコード除去を行うものではないので、メソッドがまだ型不安定であることです。

このようなタイプ推論の問題の回避策として、生成された関数があります。それは非常に重いですが、さらにコンパイル時のオーバーヘッドが発生する可能性があります。

実際に、最初の実行時間を見ると、生成された関数の割り当てがより少なくても、それでも約2〜3倍の時間がかかることがわかります。どちらもLLVM /ネイティブコードと全く同じであるため、ここでの唯一の考慮点はコンパイル時間と複雑さです。そしてその点で、生成された関数は簡単に失われます。私はあなたの現在の回避策が今のところ得られるほど良いと思います。

julia> g(::Int) = Val{true} 
     f_(::Type{Val{true}}) = 1 
     f_(::Type{Val{false}}) = 1.0 
     f(x) = f_(g(x)) 
f (generic function with 1 method) 

julia> @time f(1) 
    0.002720 seconds (521 allocations: 30.203 KB) 

julia> g′(::Type{Int}) = true 
     @generated f′(x) = g′(x) ? 1 : 1.0 
f′ (generic function with 1 method) 

julia> @time f′(1) 
    0.007655 seconds (351 allocations: 21.125 KB) 
関連する問題