Julia: sum|mapreduce versus bucle for desenrollado. disparidad de rendimiento

Creado en 8 feb. 2017  ·  3Comentarios  ·  Fuente: JuliaLang/julia

mapreduce puede ser mucho más lento que el ciclo equivalente for . Un pequeño ejemplo ( de la vida real ):

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)))

me da una relación de rendimiento de aproximadamente x50 en Julia 0.5, juliabox.com. Creo que esto podría deberse a que el bucle for puede ser automáticamente simd , y el mapreduce no lo es. Cuando A = randn(N,N) y N es 16 , la brecha es de alrededor de x75, y para N = 10000 , la brecha es de alrededor de x25. Reemplazar el acceso a la matriz A[j,k] con A[rand(1:size(A,1)),rand(1:size(A,2))] destruye el rendimiento en ambos, pero la proporción se vuelve x1.

  1. ¿Es simd la razón por la que uno es x50 más rápido?
  2. ¿Debería describirse esto en Consejos de rendimiento ? mapreduce subyace sum , por lo que podría ser una trampa popular que no se menciona actualmente
  3. ¿Sería este un punto de referencia útil? en nanosoldado?
  4. ¿Podría la brecha de rendimiento ser menor?

(Comparando mapreduce versus for -bucles sin acceso a la matriz, todavía veo una brecha de rendimiento x2. Por ejemplo mapreduce(identity, +, 0, i for i in 1:n) versus el bucle equivalente de suma de enteros for . Parece que esta brecha solía ser más pequeña (¿Vale la pena otro punto de referencia en CI?)

performance

Comentario más útil

+1 por poner un punto de referencia de esto en BaseBenchmarks; un PR allí sería genial.

Todos 3 comentarios

Parece una copia de https://github.com/JuliaLang/julia/issues/15276.

Haciendo:

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)

da

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

Puede ver el problema por @code_warntype y buscando Core.Box .

+1 por poner un punto de referencia de esto en BaseBenchmarks; un PR allí sería genial.

Cerrando como duplicado de #15276.

¿Fue útil esta página
0 / 5 - 0 calificaciones