我想看看我写的 Julia 代码是否有任何性能问题。我知道 @code_lowered
可以很好地了解编译器是如何解释代码的,但是这 @code_lowered
究竟是什么时候?是最有用的。是否有某些性能或其他问题可以很好地突出显示(如果您能理解打印输出),而在其他情况下它不太有用?
我也知道 Julia 中还有其他很棒的分析工具,我只是想大致了解每个工具的用例。
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
)
最佳答案
@code_lowered
对理解性能没有用处。@code_warntype
是最好的。
基本上不同的步骤:
解析:
源代码 -> 抽象语法树(就像用宏操作的那样),循环和条件等 block 是树中的分支。
您可以通过引用源代码来查看它。
quote
if x>1
x=x-1
end
end
降低:
抽象语法树->降低中间表示(IR),我认为最好将其描述为抽象语法列表,
基本上没有做任何事情,没有优化等。
只是树形已经变成了一个列表,其中没有任何子表达式,每个临时都在自己的行上。循环和 ifs 变成了各种跳转(如标签和条件 goto)
一些事情会改变为降低的表示形式,例如
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)
这就是我们 Typed IR 变成 LLVM 的地方。
LLVM 在内部就像一堆中间表示一样。
LLVM 自己进行了大量优化。
例如各种数学内在常数在这个阶段传播。
通过
@code_llvm f(x)
访问它这是 Typed 之后的下一个最有用的阶段。
(与 native 机器代码绑定(bind),取决于您对 LLVM IR 的阅读是否比汇编更好或更差)。
代码生成(程序集)
LLVM 变成了汇编,
基本上是人类可读的机器代码。
通过
@code_native f(x)
访问它之后只有假设,机器码。
虽然我怀疑程序集通常会被绕过,因为它们是 1-1,因为它们从 LLVM 直接转到机器代码。
另见:https://stackoverflow.com/a/43456211/179081
关于julia - 使用 `@code_lowered` 是解决 Julia 中的性能问题的有效方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58137665/