Является ли использование `@ code_lowered` эффективным способом устранения проблем с производительностью в Джулии? - PullRequest
4 голосов
/ 27 сентября 2019

Я хочу посмотреть, есть ли проблемы с производительностью в написанном мной коде Юлии.Я знаю, что @code_lowered дает хорошее представление о том, как компилятор интерпретирует код, но когда именно это @code_lowered будет наиболее полезным.Существуют ли определенные виды производительности или другие проблемы, которые хорошо подходят для выделения (если вы понимаете распечатки), тогда как в других случаях это менее полезно?

Я также знаю, что в Джулии есть и другие потрясающие инструменты профилированияЯ просто пытаюсь в целом понять варианты использования для каждого.

julia> @code_lowered Int(1.0)
CodeInfo(
1 ─ %1  = -9.223372036854776e18 <= x
└──       goto #3 if not %1
2 ─       @_3 = x < 9.223372036854776e18
└──       goto #4
3 ─       @_3 = false
4 ┄       goto #6 if not @_3
5 ─ %7  = Base.round(x, Base.RoundToZero)
│         @_4 = %7 == x
└──       goto #7
6 ─       @_4 = false
7 ┄       goto #9 if not @_4
8 ─ %12 = Base.unsafe_trunc(Int64, x)
└──       return %12
9 ─ %14 = Base.InexactError(:Int64, Int64, x)
│   %15 = Base.throw(%14)
└──       return %15
)

1 Ответ

5 голосов
/ 27 сентября 2019

@code_lowered не полезно для понимания производительности.@code_warntype лучше всего

В основном различные шаги:

Парсинг:

Исходный код -> Абстрактное синтаксическое дерево (как то, что манипулирует с макросами), блоки как циклы иусловными являются ветви в дереве.Вы можете увидеть это, цитируя исходный код.

quote
    if x>1
       x=x-1
    end
end

Понижение:

Абстрактное дерево Syntract -> Пониженное промежуточное представление (IR), которое, я думаю, лучше всего описать как список абстрактного синтаксиса.,

В основном с этим ничего не было сделано, без оптимизации и т. Д. Просто форма дерева превратилась в список, в котором ничто не имеет подвыражений, экземпляр каждого из которых находится в отдельной строке.Циклы и переходы становятся различными видами переходов (например, метки и условные переходы)

Некоторые вещи изменяются на пониженное представление, как end в xs[end-1] становится lastindex(xs)

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

. Вы можете получить к нему доступ через @code_lowered f(x) для некоторой функции f, принимающей аргумент x.или если у вас есть Method, то вы можете выполнить Base.uncompressed_ast(method).

Специализация

Информация о типе используется, и оптимизатор запускается.Вещи становятся встроенными, условия, которые всегда являются истинными или ложными, удаляются (например, проверки типов).Пониженный IR превращается в Typed IR.

  • @code_typed f(x) получает это вам.
  • @code_typed optimize=false f(x) получает это без шага оптимизации.
  • @code_warntype f(x) дает вам это с дополнительными полезными аннотациями производительности, подчеркивающими нестабильность типов

Это один из самых полезных уровней для рассмотрения.
Возможно, уступает только самому исходному коду.

Генерация кода (LLVM)

Именно здесь мы набрали IR, став LLVM.И LLVM внутренне проходит как связка промежуточных представлений.LLVM проводит массу собственных оптимизаций.Например, различные математические константы intrinstics распространяются на этом этапе.

Доступ к этому через @code_llvm f(x)

Это следующий наиболее полезный этап после Типизированный .(Связывание с собственным машинным кодом, в зависимости от того, читаете ли вы LLVM IR лучше или хуже, чем Assembly).

Генерация кода (Assembly)

LLVM становится в основном Assembly, машиночитаемым машинным кодом.Получите доступ к этому через @code_native f(x)

После этого к машинному коду добавляется только путаница.Хотя я подозреваю, что сборка обычно обходится, поскольку от LLVM идет прямо к машинному коду, поскольку они 1-1.

...