分析 F# 函数——分析器看不到函数体的任何调用。为啥?
Posted
技术标签:
【中文标题】分析 F# 函数——分析器看不到函数体的任何调用。为啥?【英文标题】:Profiling F# function -- profiler doesn't see any of the calls of the function's body. Why?分析 F# 函数——分析器看不到函数体的任何调用。为什么? 【发布时间】:2013-06-16 18:30:02 【问题描述】:我写了以下函数
let getTriangles maxPerimeter =
let mutable count = 0
for c in 1..maxPerimeter do
let cc = (int64 (c*c))
for b in 1..Math.Min(c-1, maxPerimeter-c-1) do
let bb = (int64 (b*b))
for a in 1..Math.Min(maxPerimeter-c-b, (int (Math.Ceiling(Math.Sqrt(float (cc+1L-bb)))))) do
let aa = (int64 (a*a))
if cc + 1L = aa + bb then
count <- count + 1
count
现在是时候调整它了。
为此,我安装了dot Trace Performance
并在我的应用程序上运行了一个非常大的maxPerimeter
,以确保程序需要一段时间才能运行。
这是我得到的:
正如你想象的那样,我真正想知道的是使用时间是如何分布的内部 getTriangles'
函数体,所以这似乎没有特别的帮助。我尝试在Build
窗格中关闭代码优化,但它似乎对我没有一点帮助。
-
我做错了吗?
我应该如何分析这个函数?
这是 F# 或 CLR 特定的行为吗?
我所拥有的所有性能分析经验都与 Java 相关,因此我在 CLR 世界中可能有点偏离。我也尝试过 ANTS Performance,但结果是一样的。
【问题讨论】:
显然,基本上所有时间都花在了内部循环的最后三行上,如果它没有行级分辨率,分析器不会告诉你。一小部分时间用于各种Math.
例程。如果没有为他们启用分析,它可能不会向您显示这些内容。
【参考方案1】:
我不了解 dotTrace,我使用 ANTS Performance Profiler,因为我发现它与 F# 配合得很好;我最近一直在使用新版本 (v8) 来分析我的 fsharp-tools 项目。
在 ANTS Performance Profiler 中完成分析运行并显示结果后,默认视图仅显示您拥有源的方法(即,您正在分析的 .exe/.dll 旁边有一个 .pdb它指向您机器上的某个有效源位置)。您可以使用下拉菜单(参见屏幕截图)显示所有方法,这对于 F# 代码非常有用;因为您正在传递函数,执行堆栈往往会进出您可能正在使用的库,因此查看“所有方法”可以更好地了解您的代码实际在做什么,以及来自外部库的代码如何可能会影响代码的性能。
也就是说——F# 有两种不同的for
循环;它们看起来很相似,但实际上在引擎盖下却大不相同。您使用的那个 (for x in y do
) 大致相当于 C# 中的 foreach
循环——也就是说,循环编译为一个迭代器,该迭代器从某个值序列中提取每个值。第二种更快的循环(for i = x to y do
或 for i = x downto y do
)编译为非常简单的 IL,就像在 C#、Java、C 等语言中使用 for
循环一样。
这是您的函数的修改版本,它使用第二种for
循环。在这种情况下,它只是稍微快一点(13.749s
与 13.520s
,N = 5000
在我的笔记本电脑上),但毫无疑问,如果您在数值范围内执行任何紧密循环,您想要编写代码的方式.
let getTriangles' maxPerimeter =
let mutable count = 0
for c = 1 to maxPerimeter do
let cc = int64 (c * c)
for b = 1 to min (c-1) (maxPerimeter-c-1) do
let bb = int64 (b * b)
for a = 1 to min (maxPerimeter-c-b) (int <| ceil (sqrt <| float (cc+1L-bb))) do
let aa = int64 (a * a)
if cc + 1L = aa + bb then
count <- count + 1
count
就函数内的行为而言,ANTS Performance Profiler 还可以为您提供行级计时(但仅适用于您有源代码的方法)。我编译并分析了你的函数和我的修改版本(maxPerimeter = 2000
):
【讨论】:
i.stack.imgur.com/jORA0.png 。看?那里什么都没有。我敢说,这两个分析器都会发生这种情况,这只能意味着它与 .NET 框架有关。 @devouredelysium 我不认为这是一个分析器问题——当我分析你的代码以获得第二个屏幕截图时,几乎所有的执行时间都被getTriangles
和 getTriangles'
函数占用; IIRC,我的版本只调用了一个外部函数,即Math.Sqrt
——其他所有内容都内联到函数中。但是,如果您真的想查看所有内容,请进入 ANTS Performance Profiler 中的选项菜单并取消选中隐藏无关方法的复选框;分析器运行得更慢,但它绝对会记录所有内容。
@devouredelysium 另外,如果您不介意,请花点时间将您的屏幕截图发布到ANTS Performance Profiler Support Forum。我怀疑右边的 NaN
值应该在那里。以上是关于分析 F# 函数——分析器看不到函数体的任何调用。为啥?的主要内容,如果未能解决你的问题,请参考以下文章