Julia: sum|mapreduce versus loop for desenrolado. disparidade de desempenho

Criado em 8 fev. 2017  ·  3Comentários  ·  Fonte: JuliaLang/julia

mapreduce pode ser muito mais lento que o for -loop equivalente. Um pequeno exemplo ( da 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 dá uma taxa de desempenho de cerca de x50 em Julia 0.5, juliabox.com. Eu acho que isso pode ser porque o for -loop pode ser automaticamente simd , e o mapreduce não é? Quando A = randn(N,N) e N são 16 , a diferença é em torno de x75 e para N = 10000 , a diferença é em torno de x25. Substituir o acesso ao array A[j,k] por A[rand(1:size(A,1)),rand(1:size(A,2))] destrói o desempenho em ambos, mas a proporção se torna x1.

  1. simd é a razão pela qual um é x50 mais rápido?
  2. Isso deve ser descrito em Dicas de desempenho ? mapreduce está subjacente sum , então esta pode ser uma armadilha popular que não é mencionada no momento
  3. Seria este um benchmark útil? em nanosoldado?
  4. A diferença de desempenho poderia ser menor?

(Avaliando mapreduce versus for -loops sem acesso ao array, ainda vejo uma diferença de desempenho x2. Por exemplo mapreduce(identity, +, 0, i for i in 1:n) versus o loop for equivalente de soma inteira. Parece que essa lacuna costumava ser menor ? Vale outro benchmark em CI?)

performance

Comentários muito úteis

+1 por colocar um benchmark disso no BaseBenchmarks; um PR lá seria ótimo.

Todos 3 comentários

Parece duplicação de https://github.com/JuliaLang/julia/issues/15276.

Fazendo:

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)

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

Você pode ver o problema por @code_warntype e procurando por Core.Box .

+1 por colocar um benchmark disso no BaseBenchmarks; um PR lá seria ótimo.

Fechando como duplicação de #15276.

Esta página foi útil?
0 / 5 - 0 avaliações