Julia: sum|mapreduce versus entrollte for-Schleife. Leistungsunterschied

Erstellt am 8. Feb. 2017  ·  3Kommentare  ·  Quelle: JuliaLang/julia

mapreduce kann viel langsamer sein als die äquivalente for -Schleife. Ein kleines ( reales ) Beispiel:

function dsum(A::Matrix)
    z = zero(A[1,1])
    n = Base.LinAlg.checksquare(A)
    B = Vector{typeof(z)}(n)

    <strong i="9">@inbounds</strong> for j in 1:n
        B[j] = mapreduce(k -> A[j,k]*A[k,j], +, z, 1:j)
    end
    B
end
function dfor(A::Matrix)
    z = zero(A[1,1])
    n = Base.LinAlg.checksquare(A)
    B = Vector{typeof(z)}(n)

    <strong i="10">@inbounds</strong> for j in 1:n
        d = z
        for k in 1:j
            d += A[j,k]*A[k,j]
        end
        B[j] = d
    end
    B
end

A = randn(127,127)
time(median(<strong i="11">@benchmark</strong> dsum(A)))/time(median(<strong i="12">@benchmark</strong> dfor(A)))

gibt mir ein Leistungsverhältnis von etwa x50 auf Julia 0,5, juliabox.com. Ich denke, das könnte daran liegen, dass die for -Schleife automatisch simd sein kann und die MapReduce nicht? Wenn A = randn(N,N) und N gleich 16 sind, beträgt die Lücke etwa x75, und für N = 10000 beträgt die Lücke etwa x25. Das Ersetzen des Array-Zugriffs A[j,k] durch A[rand(1:size(A,1)),rand(1:size(A,2))] zerstört die Leistung auf beiden, aber das Verhältnis wird x1.

  1. Ist simd der Grund, warum man x50 schneller ist?
  2. Sollte dies in Leistungstipps beschrieben werden? mapreduce liegt sum zugrunde, daher könnte dies eine beliebte Falle sein, die derzeit nicht erwähnt wird
  3. Wäre das ein brauchbarer Maßstab? auf Nanosoldat?
  4. Könnte der Leistungsunterschied kleiner sein?

(Beim Benchmarking mapreduce versus for -Loops ohne Array-Zugriff sehe ich immer noch eine x2-Leistungslücke. ZB mapreduce(identity, +, 0, i for i in 1:n) gegenüber der äquivalenten ganzzahlsummierenden for -Schleife. Es sieht so aus, als wäre diese Lücke früher kleiner gewesen - einen weiteren Benchmark in CI wert?)

performance

Hilfreichster Kommentar

+1 für das Setzen eines Benchmarks davon in BaseBenchmarks; eine PR wäre toll.

Alle 3 Kommentare

Sieht aus wie ein Dup von https://github.com/JuliaLang/julia/issues/15276.

Tun:

function dsum(A::Matrix)
    z = zero(A[1,1])
    n = Base.LinAlg.checksquare(A)
    B = Vector{typeof(z)}(n)
    <strong i="8">@inbounds</strong> for j::Int in 1:n
        B[j] = _help(A, j, z)
    end
    B
end

_help(A, j, z) = mapreduce(k -> A[j,k]*A[k,j], +, z, 1:j)

gibt

julia> time(median(<strong i="12">@benchmark</strong> dsum(A)))/time(median(<strong i="13">@benchmark</strong> dfor(A)))
1.0013213312412255

Sie können das Problem sehen, indem Sie @code_warntype suchen und nach Core.Box suchen.

+1 für das Setzen eines Benchmarks davon in BaseBenchmarks; eine PR wäre toll.

Schließt als Dup von #15276.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen