Julia: sum|mapreduce по сравнению с развернутым циклом for. несоответствие производительности

Созданный на 8 февр. 2017  ·  3Комментарии  ·  Источник: JuliaLang/julia

mapreduce может быть намного медленнее, чем эквивалентный цикл for . Небольшой ( реальный ) пример:

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

дает мне коэффициент производительности около x50 на Julia 0.5, juliabox.com. Я думаю, это может быть потому, что for -loop может быть автоматически simd , а mapreduce - нет? Когда A = randn(N,N) и N равно 16 , разрыв составляет около x75, а для N = 10000 разрыв составляет около x25. Замена доступа к массиву A[j,k] на A[rand(1:size(A,1)),rand(1:size(A,2))] снижает производительность на обоих, но соотношение становится x1.

  1. Является ли simd причиной того, что один из них в 50 раз быстрее?
  2. Должно ли это быть описано в Советах по производительности ? mapreduce лежит в основе sum , так что это может быть популярная ловушка, которая в настоящее время не упоминается.
  3. Будет ли это полезным эталоном? на наносолдат?
  4. Может ли разрыв в производительности быть меньше?

(Сравнивая циклы mapreduce и циклы for без доступа к массиву, я все еще вижу разрыв в производительности x2. Например, mapreduce(identity, +, 0, i for i in 1:n) по сравнению с эквивалентным циклом целочисленного суммирования for . Похоже, раньше этот разрыв был меньше ? Стоит ли еще один бенчмарк в CI?)

performance

Самый полезный комментарий

+1 за то, что поместил этот тест в BaseBenchmarks; PR там было бы здорово.

Все 3 Комментарий

Похоже на дубликат https://github.com/JuliaLang/julia/issues/15276.

Делает:

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

Вы можете увидеть проблему по @code_warntype и искать Core.Box .

+1 за то, что поместил этот тест в BaseBenchmarks; PR там было бы здорово.

Закрытие как дубликат № 15276.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги