6
$\begingroup$

There's a powerful tool call RuntimeTools`Profile, but it's hard to use.

I must turn on Debug mode, then use RuntimeTools`Profile, it'll open a new Notebook, then I need to copy the Cell and close the notebook, then turn off Debug mode if necessary.

That's too complicated!

Now I want a new funcion Profile to finish all the things above.

$\endgroup$
2
  • $\begingroup$ What do you call RuntimeTools`Profile on? $\endgroup$
    – b3m2a1
    Dec 5, 2017 at 16:18
  • $\begingroup$ Impossible I think.. $\endgroup$
    – yode
    Dec 5, 2017 at 19:18

1 Answer 1

15
$\begingroup$

Update

Here's a new version that doesn't require a stylesheet:

SetAttributes[profile, HoldAll]

profile[expr_] /; !TrueQ@$Once := Module[{eval=EvaluationNotebook[]},
    $Once = True;
    SetOptions[$FrontEndSession,"DebuggerSettings"->{"DebuggerEnabled"->True}];

    SelectionMove[EvaluationCell[], All, Cell];
    SelectionEvaluateCreateCell[eval]
]

profile[expr_] := Module[{nb},
    Block[{NotebookCreate = (nb = CreateDocument[{}, Visible->False])&},
        Internal`WithLocalSettings[
            $Once =.,

            RuntimeTools`Profile[expr],

            CellPrint @ NotebookImport[nb, "Text"->"Cell"];
            NotebookClose[nb];
            SetOptions[$FrontEndSession,"DebuggerSettings"->{"DebuggerEnabled"->False}]
        ]
    ]
]

And here it is in action:

profile[
    f[0] = 1;
    f[1] = 1;
    f[n_] := f[n-1] + f[n-2];
    f[5]
]

Calls Time Evaluation 7 0.000242 f[n_] 7 0.000212 f[n-1]+f[n-2] 7 0.000138 f[n-1] 1 0.000123 f[0]=1;f[1]=1;f[n_]:=f[Plus[<<2>>]]+f[Plus[<<2>>]];f[5] 1 0.0001 f[5] 7 0.00006 f[n-2] 1 0.000012 f[n_]:=f[n-1]+f[n-2]

8

Old version

You can programmatically change the debug status by using:

SetOptions[
    $FrontEnd,
    "DebuggerSettings"->{"DebuggerEnabled"->True}
]

However, RuntimeTools`Profile is expecting the debug status to be set at the beginning of the evaluation, so toggling the debug status needs to happen before evaluation starts. This makes it difficult to create a function that toggles the debug status, and then runs RuntimeTools`Profile.

My approach for solving this conundrum is to create a new style ("DebugInput") that toggles the debug status as part of the cell prolog. This occurs early enough that RuntimeTools`Profile will recognize that change in status. In order to make it easy to use this new style, I've added StyleKeyMapping so that typing Tab at the start of the cell will toggle between the "Input" and the "DebugInput" styles.

Here is some code to use a stylesheet with the new style:

SetOptions[
    EvaluationNotebook[],
    StyleDefinitions->Notebook[
        {
        Cell[StyleData[StyleDefinitions -> "Default.nb"]],
        Cell[StyleData["Input"],
            StyleKeyMapping->{"Tab"->"DebugInput"}
        ],
        Cell[StyleData["DebugInput", StyleDefinitions->StyleData["Input"]],
            StyleKeyMapping->{"Tab"->"Input"},
            CellProlog :> SetOptions[
                $FrontEnd,
					"DebuggerSettings"->{"DebuggerEnabled"->True}
				],
				CellEpilog :> SetOptions[
					$FrontEnd,
                "DebuggerSettings"->{"DebuggerEnabled"->False}
            ]
        ]
        },
        StyleDefinitions -> "PrivateStylesheetFormatting.nb"
    ]
]

The next problem is that RuntimeTools`Profile uses NotebookCreate instead of CreateDocument. This means that notebook options like Visible->False can't be used to hide the notebook. I work around this issue by blocking NotebookCreate to a CreateDocument call with the needed option. Here is the code for a function profile that runs RuntimeTools`Profile and puts the output in the notebook:

SetAttributes[profile,HoldFirst];

profile[expr_] := Module[{nb, style},
    style = MatchQ[
        "Style"/.Developer`CellInformation[EvaluationCell[]],
        "DebugInput"
    ];
    If[!style, Message[profile::style]];
    Internal`WithLocalSettings[
        Null,
        Block[{NotebookCreate = (nb = CreateDocument[{}, Visible->False])&},
            RuntimeTools`Profile[expr]
        ],
        CellPrint @ NotebookImport[nb, "Text"->"Cell"]
    ] /; style
]

profile::style = "Cell style must be \"DebugInput\". Use \[TabKey] at start of cell to change style";

Here is profile in action. The following code is in an ordinary "Input" cell:

profile[
    f[0] = 1;
    f[1] = 1;
    f[n_] := f[n - 1] + f[n - 2];
    f[6]
]

During evaluation of In[4]:= profile::style: Cell style must be "DebugInput". Use \[TabKey] at start of cell to change style

profile[f[0] = 1; f[1] = 1; f[n_] := f[n - 1] + f[n - 2]; f[6]]

Notice the instruction to use Tab at the start of the cell to change the cell style. After doing so, we get:

profile[
    f[0] = 1;
    f[1] = 1;
    f[n_] := f[n - 1] + f[n - 2];
    f[6]
]

Calls Time Evaluation 12 0.000689 f[n_] 12 0.000619 f[n-1]+f[n-2] 12 0.000407 f[n-1] 1 0.000258 f[0]=1;f[1]=1;f[n_]:=f[Plus[<<2>>]]+f[Plus[<<2>>]];f[6] 1 0.000222 f[6] 12 0.000187 f[n-2] 25 0.000019 f[0] 28 0.000015 f 1 0.000015 f[n_]:=f[n-1]+f[n-2]

13

$\endgroup$
9
  • $\begingroup$ Nice answer. I find it interesting that the rule for f[1] is never called. $\endgroup$
    – user21
    Dec 6, 2017 at 1:10
  • $\begingroup$ We arrive Rome from Berlin in New York transit. :) $\endgroup$
    – yode
    Dec 6, 2017 at 5:54
  • 1
    $\begingroup$ For some reason both versions return only number of evaluations on my system (Mathematica 11.2.0 on Win7 x64). The new version also returns empty table Calls|Time|Evaluation. $\endgroup$ Dec 6, 2017 at 8:05
  • $\begingroup$ @AlexeyPopkov Is it possible you didn’t set the attributes of profile to HoldFirst or HoldAll? $\endgroup$
    – Carl Woll
    Dec 6, 2017 at 17:54
  • 1
    $\begingroup$ As Alexey I only get an empty table. I'm also in Win7 and have tried Mathematica 10.4.1, 11.0.1, 11.1.1 and 11.2.0 ... Is there some setting that needs to be done before RuntimeTools`Profile will work? For me the manual use of RuntimeTools`Profile will also only return an empty table... $\endgroup$ Dec 7, 2017 at 9:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.