# HG changeset patch # User Daniel Kraft # Date 1462439120 -7200 # Thu May 05 11:05:20 2016 +0200 # Node ID ff4c0d97dd91613f7efa0d30ced855e4a4e469d5 # Parent 5e083d07ba35f423983e191bbe37ebecca4d8043 [maint] Move profiler scripts to own directory. * scripts/profiler: New directory for profiler-related m files. * scripts/general/profile.m, profexplore.m, profshow.m: Move away to the new directory. * scripts/general/module.mk: Remove moved m files. * scripts/module.mk: Add new directory. diff -r 5e083d07ba35 -r ff4c0d97dd91 scripts/general/module.mk --- a/scripts/general/module.mk Tue May 03 15:19:47 2016 -0700 +++ b/scripts/general/module.mk Thu May 05 11:05:20 2016 +0200 @@ -60,9 +60,6 @@ scripts/general/polyarea.m \ scripts/general/postpad.m \ scripts/general/prepad.m \ - scripts/general/profexplore.m \ - scripts/general/profile.m \ - scripts/general/profshow.m \ scripts/general/quadgk.m \ scripts/general/quadl.m \ scripts/general/quadv.m \ diff -r 5e083d07ba35 -r ff4c0d97dd91 scripts/general/profexplore.m --- a/scripts/general/profexplore.m Tue May 03 15:19:47 2016 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,138 +0,0 @@ -## Copyright (C) 2012-2015 Daniel Kraft -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {} {} profexplore () -## @deftypefnx {} {} profexplore (@var{data}) -## Interactively explore hierarchical profiler output. -## -## Assuming @var{data} is the structure with profile data returned by -## @code{profile (@qcode{"info"})}, this command opens an interactive prompt -## that can be used to explore the call-tree. Type @kbd{help} to get a list -## of possible commands. If @var{data} is omitted, @code{profile ("info")} -## is called and used in its place. -## @seealso{profile, profshow} -## @end deftypefn - -## Built-in profiler. -## Author: Daniel Kraft - -function profexplore (data) - - if (nargin == 0) - data = profile ("info"); - elseif (nargin != 1) - print_usage (); - endif - - ## The actual work is done by a recursive worker function, since that - ## is an easy way to traverse the tree datastructure. Here, we just check - ## the arguments (already done) and give over to it. - - __profexplore_worker (data.FunctionTable, data.Hierarchical, "Top\n", " "); - -endfunction - -## This is the worker function. tree is the current subtree we want to -## display / explore. parents is a string containing the already "rendered" -## data for the parents which is displayed on top of the list of current -## children. prefix is the prefix to add to each line rendered; this -## is just a string of spaces to get indentation right. -## -## Returning 0 indicates that the user requested to totally exit the -## explorer, thus also all higher levels should exit immediately. An integer -## greater zero indicates to exit that many levels since the user wants to go -## up (but not necessarily quit). - -function rv = __profexplore_worker (fcn_table, tree, parents, prefix) - - ## Sort children by total time. - times = -[ tree.TotalTime ]; - [~, p] = sort (times); - tree = tree(p); - - while (true) - - printf ("\n%s", parents); - strings = cell (length (tree), 1); - for i = 1 : length (tree) - strings{i} = sprintf ("%s: %d calls, %.3f total, %.3f self", ... - fcn_table(tree(i).Index).FunctionName, ... - tree(i).NumCalls, ... - tree(i).TotalTime, tree(i).SelfTime); - printf ("%s%d) %s\n", prefix, i, strings{i}); - endfor - printf ("\n"); - - cmd = input ("profexplore> ", "s"); - option = fix (str2double (cmd)); - - if (strcmp (cmd, "exit") || strcmp (cmd, "quit")) - rv = 0; - return; - elseif (strcmp (cmd, "help")) - printf ("\nCommands for profile explorer:\n\n"); - printf ("exit Return to Octave prompt.\n"); - printf ("quit Return to Octave prompt.\n"); - printf ("help Display this help message.\n"); - printf ("up [N] Go up N levels, where N is an integer. Default is 1.\n"); - printf ("N Go down a level into option N.\n"); - elseif (! isnan (option)) - if (option < 1 || option > length (tree)) - printf ("The chosen option is out of range!\n"); - else - newParents = sprintf ("%s%s%s\n", parents, prefix, strings{option}); - newPrefix = sprintf ("%s ", prefix); - - rv = __profexplore_worker (fcn_table, tree(option).Children, ... - newParents, newPrefix); - - if (rv == 0) - return; - elseif (rv > 1) - rv -= 1; - return; - else - assert (rv == 1); - ## It was requested to return to this level, so just stay. - endif - endif - elseif (length (cmd) >= 2 && strcmp (substr (cmd, 1, 2), "up")) - if (length (cmd) == 2) - rv = 1; - return; - endif - - if (length (cmd) > 3 && cmd(3) == ' ') - opt = fix (str2double (substr (cmd, 3))); - if (! isnan (opt) && opt > 0) - rv = opt; - return; - endif - endif - - printf ("Invalid 'up' command. Type 'help' for further"); - printf (" information.\n"); - else - printf ("Unrecognized input. Type 'help' to get a list of possible"); - printf (" commands.\n"); - endif - - endwhile -endfunction - diff -r 5e083d07ba35 -r ff4c0d97dd91 scripts/general/profile.m --- a/scripts/general/profile.m Tue May 03 15:19:47 2016 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -## Copyright (C) 2012-2015 Daniel Kraft -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {} {} profile on -## @deftypefnx {} {} profile off -## @deftypefnx {} {} profile resume -## @deftypefnx {} {} profile clear -## @deftypefnx {} address@hidden =} profile ("status") -## @deftypefnx {} address@hidden =} profile ("info") -## Control the built-in profiler. -## -## @table @code -## @item profile on -## Start the profiler, clearing all previously collected data if there is any. -## -## @item profile off -## Stop profiling. The collected data can later be retrieved and examined -## with @code{T = profile ("info")}. -## -## @item profile clear -## Clear all collected profiler data. -## -## @item profile resume -## Restart profiling without clearing the old data. All newly collected -## statistics are added to the existing ones. -## -## @item @var{S} = profile ("status") -## Return a structure with information about the current status of the -## profiler. At the moment, the only field is @code{ProfilerStatus} which is -## either @qcode{"on"} or @qcode{"off"}. -## -## @item @var{T} = profile ("info") -## Return the collected profiling statistics in the structure @var{T}. The -## flat profile is returned in the field @code{FunctionTable} which is an -## array of structures, each entry corresponding to a function which was called -## and for which profiling statistics are present. In addition, the field -## @code{Hierarchical} contains the hierarchical call tree. Each node has an -## index into the @code{FunctionTable} identifying the function it corresponds -## to as well as data fields for number of calls and time spent at this level -## in the call tree. -## @seealso{profshow, profexplore} -## @end table -## @end deftypefn - -## Built-in profiler. -## Author: Daniel Kraft - -function retval = profile (option) - - if (nargin != 1) - print_usage (); - endif - - switch (option) - case "on" - __profiler_reset__ (); - __profiler_enable__ (true); - - case "off" - __profiler_enable__ (false); - - case "clear" - __profiler_reset__ (); - - case "resume" - __profiler_enable__ (true); - - case "status" - enabled = __profiler_enable__ (); - if (enabled) - enabled = "on"; - else - enabled = "off"; - endif - retval = struct ("ProfilerStatus", enabled); - - case "info" - [flat, tree] = __profiler_data__ (); - retval = struct ("FunctionTable", flat, "Hierarchical", tree); - - otherwise - warning ("profile: Unrecognized option '%s'", option); - print_usage (); - - endswitch - -endfunction - - -%!demo -%! profile on; -%! A = rand (100); -%! B = expm (A); -%! profile off; -%! profile resume; -%! C = sqrtm (A); -%! profile off; -%! T = profile ("info"); -%! profshow (T); - -%!test -%! on_struct.ProfilerStatus = "on"; -%! off_struct.ProfilerStatus = "off"; -%! profile ("on"); -%! result = logm (rand (200) + 10 * eye (200)); -%! assert (profile ("status"), on_struct); -%! profile ("off"); -%! assert (profile ("status"), off_struct); -%! profile ("resume"); -%! result = logm (rand (200) + 10 * eye (200)); -%! profile ("off"); -%! assert (profile ("status"), off_struct); -%! info = profile ("info"); -%! assert (isstruct (info)); -%! assert (size (info), [1, 1]); -%! assert (fieldnames (info), {"FunctionTable"; "Hierarchical"}); -%! ftbl = info.FunctionTable; -%! assert (fieldnames (ftbl), {"FunctionName"; "TotalTime"; "NumCalls"; "IsRecursive"; "Parents"; "Children"}); -%! hier = info.Hierarchical; -%! assert (fieldnames (hier), {"Index"; "SelfTime"; "TotalTime"; "NumCalls"; "Children"}); -%! profile ("clear"); -%! info = profile ("info"); -%! assert (isstruct (info)); -%! assert (size (info), [1, 1]); -%! assert (fieldnames (info), {"FunctionTable"; "Hierarchical"}); -%! ftbl = info.FunctionTable; -%! assert (size (ftbl), [0, 1]); -%! assert (fieldnames (ftbl), {"FunctionName"; "TotalTime"; "NumCalls"; "IsRecursive"; "Parents"; "Children"}); -%! hier = info.Hierarchical; -%! assert (size (hier), [0, 1]); -%! assert (fieldnames (hier), {"Index"; "SelfTime"; "NumCalls"; "Children"}); - -## Test input validation -%!error profile () -%!error profile ("on", 2) -%!error profile ("INVALID_OPTION") - diff -r 5e083d07ba35 -r ff4c0d97dd91 scripts/general/profshow.m --- a/scripts/general/profshow.m Tue May 03 15:19:47 2016 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -## Copyright (C) 2012-2014 Daniel Kraft -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {} {} profshow (@var{data}) -## @deftypefnx {} {} profshow (@var{data}, @var{n}) -## @deftypefnx {} {} profshow () -## @deftypefnx {} {} profshow (@var{n}) -## Display flat per-function profiler results. -## -## Print out profiler data (execution time, number of calls) for the most -## critical @var{n} functions. The results are sorted in descending order by -## the total time spent in each function. If @var{n} is unspecified it -## defaults to 20. -## -## The input @var{data} is the structure returned by @code{profile ("info")}. -## If unspecified, @code{profshow} will use the current profile dataset. -## -## The attribute column displays @samp{R} for recursive functions, and is blank -## for all other function types. -## @seealso{profexplore, profile} -## @end deftypefn - -## Built-in profiler. -## Author: Daniel Kraft - -function profshow (data, n = 20) - - if (nargin > 2) - print_usage (); - endif - - if (nargin == 0) - data = profile ("info"); - elseif (nargin == 1 && ! isstruct (data)) - n = data; - data = profile ("info"); - endif - - n = fix (n); - if (! isscalar (n) || ! isreal (n) || ! (n > 0)) - error ("profile: N must be a positive integer"); - endif - - m = length (data.FunctionTable); - n = min (n, m); - - ## We want to sort by times in descending order. For this, extract the - ## times to an array, then sort this, and use the resulting index permutation - ## to print out our table. - times = [ data.FunctionTable.TotalTime ]; - totalTime = sum (times); - - [~, p] = sort (times, "descend"); - - ## For printing the table, find out the maximum length of a function name - ## so that we can proportion the table accordingly. Based on this, - ## we can build the format used for printing table rows. - nameLen = max (length ("Function"), - columns (char (data.FunctionTable(p(1:n)).FunctionName))); - headerFormat = sprintf ("%%4s %%%ds %%4s %%12s %%10s %%12s\n", nameLen); - rowFormat = sprintf ("%%4d %%%ds %%4s %%12.3f %%10.2f %%12d\n", nameLen); - - printf (headerFormat, ... - "#", "Function", "Attr", "Time (s)", "Time (%)", "Calls"); - printf ("%s\n", repmat ("-", 1, nameLen + 2 * 5 + 11 + 2 * 13)); - - for i = 1 : n - row = data.FunctionTable(p(i)); - timePercent = 100 * row.TotalTime / totalTime; - attr = ""; - if (row.IsRecursive) - attr = "R"; - endif - printf (rowFormat, p(i), row.FunctionName, attr, - row.TotalTime, timePercent, row.NumCalls); - endfor - -endfunction - - -%!demo -%! profile on; -%! A = rand (100); -%! B = expm (A); -%! profile off; -%! T = profile ("info"); -%! profshow (T, 10); - -%!demo -%! profile on; -%! expm (rand (500) + eye (500)); -%! profile off; -%! profshow (profile ("info"), 5); - -%!error profshow (1, 2, 3) -%!error profshow (struct (), ones (2)) -%!error profshow (struct (), 1+i) -%!error profshow (struct (), -1) - diff -r 5e083d07ba35 -r ff4c0d97dd91 scripts/module.mk --- a/scripts/module.mk Tue May 03 15:19:47 2016 -0700 +++ b/scripts/module.mk Thu May 05 11:05:20 2016 +0200 @@ -25,6 +25,7 @@ include scripts/plot/util/module.mk include scripts/polynomial/module.mk include scripts/prefs/module.mk +include scripts/profiler/module.mk include scripts/set/module.mk include scripts/signal/module.mk include scripts/sparse/module.mk diff -r 5e083d07ba35 -r ff4c0d97dd91 scripts/profiler/module.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/profiler/module.mk Thu May 05 11:05:20 2016 +0200 @@ -0,0 +1,16 @@ +FCN_FILE_DIRS += \ + scripts/profiler + +scripts_profiler_FCN_FILES = \ + scripts/profiler/profexplore.m \ + scripts/profiler/profile.m \ + scripts/profiler/profshow.m + +scripts_profilerdir = $(fcnfiledir)/profiler + +scripts_profiler_DATA = $(scripts_profiler_FCN_FILES) + +FCN_FILES += \ + $(scripts_profiler_FCN_FILES) + +DIRSTAMP_FILES += scripts/profiler/$(octave_dirstamp) diff -r 5e083d07ba35 -r ff4c0d97dd91 scripts/profiler/profexplore.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/profiler/profexplore.m Thu May 05 11:05:20 2016 +0200 @@ -0,0 +1,138 @@ +## Copyright (C) 2012-2015 Daniel Kraft +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {} {} profexplore () +## @deftypefnx {} {} profexplore (@var{data}) +## Interactively explore hierarchical profiler output. +## +## Assuming @var{data} is the structure with profile data returned by +## @code{profile (@qcode{"info"})}, this command opens an interactive prompt +## that can be used to explore the call-tree. Type @kbd{help} to get a list +## of possible commands. If @var{data} is omitted, @code{profile ("info")} +## is called and used in its place. +## @seealso{profile, profshow} +## @end deftypefn + +## Built-in profiler. +## Author: Daniel Kraft + +function profexplore (data) + + if (nargin == 0) + data = profile ("info"); + elseif (nargin != 1) + print_usage (); + endif + + ## The actual work is done by a recursive worker function, since that + ## is an easy way to traverse the tree datastructure. Here, we just check + ## the arguments (already done) and give over to it. + + __profexplore_worker (data.FunctionTable, data.Hierarchical, "Top\n", " "); + +endfunction + +## This is the worker function. tree is the current subtree we want to +## display / explore. parents is a string containing the already "rendered" +## data for the parents which is displayed on top of the list of current +## children. prefix is the prefix to add to each line rendered; this +## is just a string of spaces to get indentation right. +## +## Returning 0 indicates that the user requested to totally exit the +## explorer, thus also all higher levels should exit immediately. An integer +## greater zero indicates to exit that many levels since the user wants to go +## up (but not necessarily quit). + +function rv = __profexplore_worker (fcn_table, tree, parents, prefix) + + ## Sort children by total time. + times = -[ tree.TotalTime ]; + [~, p] = sort (times); + tree = tree(p); + + while (true) + + printf ("\n%s", parents); + strings = cell (length (tree), 1); + for i = 1 : length (tree) + strings{i} = sprintf ("%s: %d calls, %.3f total, %.3f self", ... + fcn_table(tree(i).Index).FunctionName, ... + tree(i).NumCalls, ... + tree(i).TotalTime, tree(i).SelfTime); + printf ("%s%d) %s\n", prefix, i, strings{i}); + endfor + printf ("\n"); + + cmd = input ("profexplore> ", "s"); + option = fix (str2double (cmd)); + + if (strcmp (cmd, "exit") || strcmp (cmd, "quit")) + rv = 0; + return; + elseif (strcmp (cmd, "help")) + printf ("\nCommands for profile explorer:\n\n"); + printf ("exit Return to Octave prompt.\n"); + printf ("quit Return to Octave prompt.\n"); + printf ("help Display this help message.\n"); + printf ("up [N] Go up N levels, where N is an integer. Default is 1.\n"); + printf ("N Go down a level into option N.\n"); + elseif (! isnan (option)) + if (option < 1 || option > length (tree)) + printf ("The chosen option is out of range!\n"); + else + newParents = sprintf ("%s%s%s\n", parents, prefix, strings{option}); + newPrefix = sprintf ("%s ", prefix); + + rv = __profexplore_worker (fcn_table, tree(option).Children, ... + newParents, newPrefix); + + if (rv == 0) + return; + elseif (rv > 1) + rv -= 1; + return; + else + assert (rv == 1); + ## It was requested to return to this level, so just stay. + endif + endif + elseif (length (cmd) >= 2 && strcmp (substr (cmd, 1, 2), "up")) + if (length (cmd) == 2) + rv = 1; + return; + endif + + if (length (cmd) > 3 && cmd(3) == ' ') + opt = fix (str2double (substr (cmd, 3))); + if (! isnan (opt) && opt > 0) + rv = opt; + return; + endif + endif + + printf ("Invalid 'up' command. Type 'help' for further"); + printf (" information.\n"); + else + printf ("Unrecognized input. Type 'help' to get a list of possible"); + printf (" commands.\n"); + endif + + endwhile +endfunction + diff -r 5e083d07ba35 -r ff4c0d97dd91 scripts/profiler/profile.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/profiler/profile.m Thu May 05 11:05:20 2016 +0200 @@ -0,0 +1,153 @@ +## Copyright (C) 2012-2015 Daniel Kraft +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {} {} profile on +## @deftypefnx {} {} profile off +## @deftypefnx {} {} profile resume +## @deftypefnx {} {} profile clear +## @deftypefnx {} address@hidden =} profile ("status") +## @deftypefnx {} address@hidden =} profile ("info") +## Control the built-in profiler. +## +## @table @code +## @item profile on +## Start the profiler, clearing all previously collected data if there is any. +## +## @item profile off +## Stop profiling. The collected data can later be retrieved and examined +## with @code{T = profile ("info")}. +## +## @item profile clear +## Clear all collected profiler data. +## +## @item profile resume +## Restart profiling without clearing the old data. All newly collected +## statistics are added to the existing ones. +## +## @item @var{S} = profile ("status") +## Return a structure with information about the current status of the +## profiler. At the moment, the only field is @code{ProfilerStatus} which is +## either @qcode{"on"} or @qcode{"off"}. +## +## @item @var{T} = profile ("info") +## Return the collected profiling statistics in the structure @var{T}. The +## flat profile is returned in the field @code{FunctionTable} which is an +## array of structures, each entry corresponding to a function which was called +## and for which profiling statistics are present. In addition, the field +## @code{Hierarchical} contains the hierarchical call tree. Each node has an +## index into the @code{FunctionTable} identifying the function it corresponds +## to as well as data fields for number of calls and time spent at this level +## in the call tree. +## @seealso{profshow, profexplore} +## @end table +## @end deftypefn + +## Built-in profiler. +## Author: Daniel Kraft + +function retval = profile (option) + + if (nargin != 1) + print_usage (); + endif + + switch (option) + case "on" + __profiler_reset__ (); + __profiler_enable__ (true); + + case "off" + __profiler_enable__ (false); + + case "clear" + __profiler_reset__ (); + + case "resume" + __profiler_enable__ (true); + + case "status" + enabled = __profiler_enable__ (); + if (enabled) + enabled = "on"; + else + enabled = "off"; + endif + retval = struct ("ProfilerStatus", enabled); + + case "info" + [flat, tree] = __profiler_data__ (); + retval = struct ("FunctionTable", flat, "Hierarchical", tree); + + otherwise + warning ("profile: Unrecognized option '%s'", option); + print_usage (); + + endswitch + +endfunction + + +%!demo +%! profile on; +%! A = rand (100); +%! B = expm (A); +%! profile off; +%! profile resume; +%! C = sqrtm (A); +%! profile off; +%! T = profile ("info"); +%! profshow (T); + +%!test +%! on_struct.ProfilerStatus = "on"; +%! off_struct.ProfilerStatus = "off"; +%! profile ("on"); +%! result = logm (rand (200) + 10 * eye (200)); +%! assert (profile ("status"), on_struct); +%! profile ("off"); +%! assert (profile ("status"), off_struct); +%! profile ("resume"); +%! result = logm (rand (200) + 10 * eye (200)); +%! profile ("off"); +%! assert (profile ("status"), off_struct); +%! info = profile ("info"); +%! assert (isstruct (info)); +%! assert (size (info), [1, 1]); +%! assert (fieldnames (info), {"FunctionTable"; "Hierarchical"}); +%! ftbl = info.FunctionTable; +%! assert (fieldnames (ftbl), {"FunctionName"; "TotalTime"; "NumCalls"; "IsRecursive"; "Parents"; "Children"}); +%! hier = info.Hierarchical; +%! assert (fieldnames (hier), {"Index"; "SelfTime"; "TotalTime"; "NumCalls"; "Children"}); +%! profile ("clear"); +%! info = profile ("info"); +%! assert (isstruct (info)); +%! assert (size (info), [1, 1]); +%! assert (fieldnames (info), {"FunctionTable"; "Hierarchical"}); +%! ftbl = info.FunctionTable; +%! assert (size (ftbl), [0, 1]); +%! assert (fieldnames (ftbl), {"FunctionName"; "TotalTime"; "NumCalls"; "IsRecursive"; "Parents"; "Children"}); +%! hier = info.Hierarchical; +%! assert (size (hier), [0, 1]); +%! assert (fieldnames (hier), {"Index"; "SelfTime"; "NumCalls"; "Children"}); + +## Test input validation +%!error profile () +%!error profile ("on", 2) +%!error profile ("INVALID_OPTION") + diff -r 5e083d07ba35 -r ff4c0d97dd91 scripts/profiler/profshow.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/profiler/profshow.m Thu May 05 11:05:20 2016 +0200 @@ -0,0 +1,115 @@ +## Copyright (C) 2012-2014 Daniel Kraft +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {} {} profshow (@var{data}) +## @deftypefnx {} {} profshow (@var{data}, @var{n}) +## @deftypefnx {} {} profshow () +## @deftypefnx {} {} profshow (@var{n}) +## Display flat per-function profiler results. +## +## Print out profiler data (execution time, number of calls) for the most +## critical @var{n} functions. The results are sorted in descending order by +## the total time spent in each function. If @var{n} is unspecified it +## defaults to 20. +## +## The input @var{data} is the structure returned by @code{profile ("info")}. +## If unspecified, @code{profshow} will use the current profile dataset. +## +## The attribute column displays @samp{R} for recursive functions, and is blank +## for all other function types. +## @seealso{profexplore, profile} +## @end deftypefn + +## Built-in profiler. +## Author: Daniel Kraft + +function profshow (data, n = 20) + + if (nargin > 2) + print_usage (); + endif + + if (nargin == 0) + data = profile ("info"); + elseif (nargin == 1 && ! isstruct (data)) + n = data; + data = profile ("info"); + endif + + n = fix (n); + if (! isscalar (n) || ! isreal (n) || ! (n > 0)) + error ("profile: N must be a positive integer"); + endif + + m = length (data.FunctionTable); + n = min (n, m); + + ## We want to sort by times in descending order. For this, extract the + ## times to an array, then sort this, and use the resulting index permutation + ## to print out our table. + times = [ data.FunctionTable.TotalTime ]; + totalTime = sum (times); + + [~, p] = sort (times, "descend"); + + ## For printing the table, find out the maximum length of a function name + ## so that we can proportion the table accordingly. Based on this, + ## we can build the format used for printing table rows. + nameLen = max (length ("Function"), + columns (char (data.FunctionTable(p(1:n)).FunctionName))); + headerFormat = sprintf ("%%4s %%%ds %%4s %%12s %%10s %%12s\n", nameLen); + rowFormat = sprintf ("%%4d %%%ds %%4s %%12.3f %%10.2f %%12d\n", nameLen); + + printf (headerFormat, ... + "#", "Function", "Attr", "Time (s)", "Time (%)", "Calls"); + printf ("%s\n", repmat ("-", 1, nameLen + 2 * 5 + 11 + 2 * 13)); + + for i = 1 : n + row = data.FunctionTable(p(i)); + timePercent = 100 * row.TotalTime / totalTime; + attr = ""; + if (row.IsRecursive) + attr = "R"; + endif + printf (rowFormat, p(i), row.FunctionName, attr, + row.TotalTime, timePercent, row.NumCalls); + endfor + +endfunction + + +%!demo +%! profile on; +%! A = rand (100); +%! B = expm (A); +%! profile off; +%! T = profile ("info"); +%! profshow (T, 10); + +%!demo +%! profile on; +%! expm (rand (500) + eye (500)); +%! profile off; +%! profshow (profile ("info"), 5); + +%!error profshow (1, 2, 3) +%!error profshow (struct (), ones (2)) +%!error profshow (struct (), 1+i) +%!error profshow (struct (), -1) +