【问题标题】:Profiling Mathematica Code分析 Mathematica 代码
【发布时间】:2011-11-11 01:37:08
【问题描述】:

有没有在 Mathematica 中分析代码的好方法?我希望能够递归(即,如果我说f[a_] := b[a],那么Profile[f[1]] 应该给出与Profile[b[1]] 几乎相同的输出),但我会满足于能够做一些事情,比如应用Timing到每个相关的子表达式。如果我不必像 Module 这样的特殊情况会很好,但我想,例如,Profile[Module[{x=1+2},x!]] 给我一个输出像

Time    Expression         Result
0       1                  1
0       2                  2
0       1 + 2              3
0       x$1234             3   
0       x$1234 !           6
0       Module[{x=1+2},x!] 6

6

【问题讨论】:

标签: wolfram-mathematica profiling


【解决方案1】:

是的,Wolfram Workbench 确实有一个分析器,尽管 according to the documentation 的输出不是您想要的形式。

我要注意的是,Mr.Wizard 在 cmets 中提出的问题——缓存的结果会导致不同的计时结果——也可以应用在配置文件中。

如果您只想在 Mathematica 中做某事,您可以尝试以下方法:

myProfile[fun_Symbol,inputs_List]:=  
    TableForm[#[[{1,3,2}]]&/@ (Join @@@ ({Timing[f[#]],#} & /@ inputs))]

如果您很高兴将输出设为 {timing,output, input},而不是问题中指定的 {timing, input, output},则可以去掉 #[[{1,3,2}]] 位。

编辑

因为我有 Workbench,所以这里有一个例子。我有一个包AdvancedPlots,其中包含一个函数CobwebPlot(是的,函数本身可以改进)。

CobwebPlot[x_?MatrixQ, opts___Rule] /; 
  And @@ (NumericQ /@ Flatten[x]) :=   
 Module[{n, \[Theta]s, numgrids, grids, struts, gridstyle, min, max, 
   data, labels, epilabels, pad},
  n = Length[First[x]];
  \[Theta]s = (2 \[Pi])/n Range[0, n] + If[OddQ[n], \[Pi]/2, 0];
  numgrids = 
   If[IntegerQ[#] && Positive[#], #, 
      NumberofGrids /. 
       Options[CobwebPlot] ] & @ (NumberofGrids /. {opts});
  {min, max} = {Min[#], Max[#]} &@ Flatten[x];
  gridstyle = GridStyle /. {opts} /. Options[CobwebPlot];
  pad = CobwebPadding /. {opts} /. Options[CobwebPlot];
  grids = 
   Outer[List, \[Theta]s, FindDivisions[{0, max + 1}, numgrids]];
  struts = Transpose[grids];
  labels = CobwebLabels /. {opts} /. Options[CobwebPlot];
  epilabels = 
   If[Length[labels] == n, 
    Thread[Text[
      labels, (1.2 max) Transpose[{Cos[Most[\[Theta]s]], 
         Sin[Most[\[Theta]s]]}]]], None];
  data = Map[Reverse, 
    Inner[List, Join[#, {First[#]}] & /@ x, \[Theta]s, List], {2}];
  Show[ListPolarPlot[grids, gridstyle, Joined -> True, Axes -> False, 
    PlotRangePadding -> pad], 
   ListPolarPlot[struts, gridstyle, Joined -> True, Axes -> False], 
   ListPolarPlot[data, 
    Sequence @@ FilterRules[{opts}, Options[ListPolarPlot]], 
    Sequence @@ 
     FilterRules[Options[CobwebPlot], Options[ListPolarPlot]], 
    Joined -> True, Axes -> None] , 
   If[Length[labels] == n, Graphics /@ epilabels, 
    Sequence @@ FilterRules[{opts}, Options[Graphics]] ]]
  ]

在调试模式下运行包

然后运行这个笔记本

给出以下输出。

【讨论】:

  • 如果你觉得这个功能可以改进,为什么不把它贴在 Code Review 上呢?
  • 这几乎是我要找的,但 Profile 似乎错过了我的大部分代码。我现在尝试分析的代码需要 63 秒才能执行(根据时序),但对分析的最大贡献是 90 次调用 MakeBoxes[Peak:PeakObject[List],FormatType]时间为 0.718(每个?总计?),723344 次调用 7,时间为 0.655(每个?总计?)。此外,像 Profile[Do[100000!, {100}]] 这样的东西根本不会在配置文件中提供任何条目。
【解决方案2】:

这是尝试使用TraceScan 来计时各个评估步骤。它使用原始的AbsoluteTime[] deltas,这可能是好是坏,具体取决于您实际期望的时间。

确保在新内核上运行此示例,否则Prime 将缓存其结果,所有时间都将是 ~= 0。

t = AbsoluteTime[]; step = "start";

TraceScan[
  (Print[AbsoluteTime[] - t, " for ", step]; t = AbsoluteTime[]; step = #) &,
  Module[{x = 7 + 7}, Sqrt@Prime[x!]]
]
0.0010001 开始

0.*10^-8 为 Module[{x=7+7},Sqrt[Prime[x!]]]

0.*10^-8 用于模块

0.*10^-8 为 7+7

0.*10^-8 加号

0.*10^-8 为 7

0.*10^-8 为 7

0.*10^-8 为 14

0.*10^-8 for x$149=未评估[14]

0.*10^-8 用于设置

0.*10^-8 对于 x$149=14

0.*10^-8 为 14

0.*10^-8 对于 Sqrt[Prime[x$149!]]

0.*10^-8 为 Sqrt

0.*10^-8 为 Prime[x$149!]

0.*10^-8 为素数

0.*10^-8 x 149 美元!

0.*10^-8 为阶乘

0.*10^-8 x $149

0.*10^-8 为 14

0.*10^-8 为 14!

0.*10^-8 为 87178291200

2.6691526 为 Prime[87178291200]

0.*10^-8 为 2394322471421

0.*10^-8 为 Sqrt[2394322471421]

0.*10^-8 为 Sqrt[2394322471421]

0.*10^-8 功率

0.*10^-8 为 2394322471421

0.*10^-8 为 1/2

【讨论】:

    【解决方案3】:

    正如贝利撒留在回答我上面链接的问题时所显示的那样,Wolfram Workbench includes a profiler 似乎是。但是我不使用 Workbench,所以我不能详细说明它的使用。

    【讨论】:

      猜你喜欢
      • 2012-10-27
      • 1970-01-01
      • 2011-08-14
      • 2011-05-04
      • 2015-02-15
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多