【问题标题】:Line-by-line profiling of Julia code possible?可以逐行分析 Julia 代码吗?
【发布时间】:2021-01-08 08:18:54
【问题描述】:

我有一些数百行长的 Julia 函数,我想对其进行分析,以便我可以着手优化代码。

我知道 BenchmarkTools 包允许使用@btime@benchmark 测量函数的整体执行时间和内存消耗。但是这些函数并没有告诉我瓶颈在函数内部的什么位置。所以我的第一步必须是使用一些工具来识别代码的哪些部分是慢的。

例如,在 Matlab 中,有一个非常好的内置分析器,它运行一个脚本/函数,然后报告每一行代码所花费的时间。类似地,在 Python 中有一个名为 line_profiler 的模块,它可以生成逐行报告,显示函数的每一行花费了多少时间。

我正在寻找的只是一份逐行报告,显示每行代码花费的总时间以及特定代码段被调用的次数。

Julia 中有这样的功能吗?内置或通过某些第三方软件包。

【问题讨论】:

  • 是的,它有一个分析模块,此链接中还有内置分析的 IDE - docs.julialang.org/en/v1/manual/profile
  • @AWebb 但是可以将 Profile.print() 的输出格式化为显示每行代码所花费的时间吗?从我在他们的示例中可以看到,从 Profile 获得的打印输出没有显示每行花费的时间

标签: julia


【解决方案1】:

Julia 文档中有一个 Profiling 章节,其中包含所有必要的信息。

此外,您可以使用ProfileView.jl 或类似的包来可视化探索分析代码。

而且,不完全是分析,但在实践中非常有用的包是TimerOutputs.jl

UPD:由于 Julia 是一种编译语言,因此测量各个行的时间是没有意义的,因为执行的实际代码可能与用 Julia 编写的代码大不相同。

例如下面的朱莉娅代码

function f()
    x = 0
    for i in 0:100_000_000
        x += i
    end

    x
end

降低到

julia> @code_llvm f()
;  @ REPL[8]:1 within `f'
define i64 @julia_f_594() {
top:
;  @ REPL[8]:7 within `f'
  ret i64 5000000050000000
}

即根本没有循环。这就是为什么使用行在所有回溯集中出现的频率而不是执行时间代理指标的原因。当然,它与执行时间不一样,但它很好地近似了瓶颈所在的位置,因为执行时间长的行更频繁地出现在回溯中。

【讨论】:

  • 我查看了 Profiling 文档,并且之前尝试过他们列出的各种可视化工具。据我所知,他们大多会生成彩色的“火焰图”图形,文档中几乎没有解释应该如何解释它们。那不是我要找的。本质上,我想在我的代码的每一行上运行@time 函数,并有一个基于文本的输出,将我的代码的每一行与执行时间相关联。这可以使用分析工具吗?我在文档中看不到任何提及。
  • 使用统计(又称抽样)分析还有许多其他原因。在 Matlab 中,大部分“真正的工作”是用 C 代码完成的,它们的分析器无法访问;这意味着逐行分析的开销并不重要,因为您实际上并没有分析对性能敏感的代码。在 Julia 中,您正在分析对性能敏感的代码,因此更重要的是让分析器不碍事。就像在 Julia 中所做的那样,大多数高性能语言世界已经转向采样分析器。
  • > 文档中几乎没有解释如何解释 IMO,docs.julialang.org/en/v1/manual/profile 非常详细地说明了如何解释结果。但是如果具体的事情不清楚,请提出问题!
  • en.wikipedia.org/wiki/… 以防您没有点击该链接。
【解决方案2】:

OwnTime.jl。虽然不做调用计数,但应该很容易添加。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-01
    相关资源
    最近更新 更多