Оптимизация кода Джулии на примере - PullRequest
0 голосов
/ 10 мая 2018

Я сейчас пишу числовой решатель в Джулии. Я не думаю, что математика стоит за этим слишком много. Все сводится к тому, что определенная операция выполняется несколько раз и использует большой процент (~ 80%) времени выполнения.

Я попытался максимально уменьшить его и представить вам этот фрагмент кода, который можно сохранить как dummy.jl, а затем выполнить с помощью include("dummy.jl"), затем dummy(10) (для компиляции) и затем dummy(1000).

function dummy(N::Int64)
    A = rand(N,N)
    @time timethis(A)
end

function timethis(A::Array{Float64,2})
    dummyvariable = 0.0
    for k=1:100 # just repeat a few times
        for i=2:size(A)[1]-1
            for j=2:size(A)[2]-1
                    dummyvariable += slopefit(A[i-1,j],A[i,j],A[i+1,j],2.0)
                    dummyvariable += slopefit(A[i,j-1],A[i,j],A[i,j+1],2.0)
            end
        end
    end
    println(dummyvariable) 
end

@inline function minmod(x::Float64, y::Float64)
    return sign(x) * max(0.0, min(abs(x),y*sign(x) ) );
end

@inline function slopefit(left::Float64,center::Float64,right::Float64,theta::Float64)
    # arg=ccall((:minmod,"libminmod"),Float64,(Float64,Float64),0.5*(right-left),theta*(center-left));
    # result=ccall((:minmod,"libminmod"),Float64,(Float64,Float64),theta*(right-center),arg);
    # return result

    tmp = minmod(0.5*(right-left),theta*(center-left));
    return minmod(theta*(right-center),tmp);
    #return 1.0
end

Здесь timethis будет имитировать ту часть кода, где я провожу много времени. Я замечаю, что slopefit чрезвычайно дорого выполнять.

Например, dummy(1000) занимает примерно 4 секунды на моей машине. Если вместо этого slopefit будет всегда возвращать 1 и ничего не вычислять, время сокращается до одной десятой от общего времени.

Теперь, очевидно, нет бесплатного обеда.

Мне известно, что это просто дорогостоящая операция. Но я все равно попытался бы оптимизировать его как можно больше, учитывая, что много времени тратится на то, что выглядит так, как если бы это можно было легко оптимизировать, поскольку это всего лишь несколько строк кода.

До сих пор я пытался реализовать minmod и slopefit как C-функции и вызывать их, однако это только увеличивало время вычислений (возможно, я сделал это неправильно).

Итак, мой вопрос: какие у меня есть возможности оптимизировать вызов slopefit?

Обратите внимание, что в фактическом коде аргументы slopefit не являются упомянутыми здесь, а зависят от условных операторов, которые усложняют векторизацию (если это приведет к какому-либо приросту производительности, я не уверен).

1 Ответ

0 голосов
/ 11 мая 2018

Есть два уровня оптимизации, о которых я могу подумать.

Первый: следующая реализация minmod будет быстрее, так как избегает разветвлений (я понимаю, это та функция, которую вы хотите):

@inline minmod(x::Float64, y::Float64) = ifelse(x<0, clamp(y, x, 0.0), clamp(y, 0.0, x))

Второе: вы можете использовать @inbounds, чтобы немного ускорить цикл:

 @inbounds for i=2:size(A)[1]-1
...