changeset 21766:d16d137eb485

[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 to the new directory. * scripts/general/module.mk: Remove moved m files. * scripts/profiler/module.mk: New file to hook in to build system. * scripts/module.mk: Add new directory.
author Daniel Kraft <dkraft@google.com>
date Thu, 05 May 2016 11:05:20 +0200
parents 23a610a3f001
children 7190a26977cb
files scripts/general/module.mk scripts/general/profexplore.m scripts/general/profile.m scripts/general/profshow.m scripts/module.mk scripts/profiler/module.mk scripts/profiler/profexplore.m scripts/profiler/profile.m scripts/profiler/profshow.m
diffstat 9 files changed, 426 insertions(+), 410 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/general/module.mk	Sat May 21 15:00:14 2016 +1000
+++ 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 \
--- a/scripts/general/profexplore.m	Sat May 21 15:00:14 2016 +1000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +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
-## <http://www.gnu.org/licenses/>.
-
-## -*- 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 <d@domob.eu>
-
-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
-
--- a/scripts/general/profile.m	Sat May 21 15:00:14 2016 +1000
+++ /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
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn  {} {} profile on
-## @deftypefnx {} {} profile off
-## @deftypefnx {} {} profile resume
-## @deftypefnx {} {} profile clear
-## @deftypefnx {} {@var{S} =} profile ("status")
-## @deftypefnx {} {@var{T} =} 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 <d@domob.eu>
-
-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")
-
--- a/scripts/general/profshow.m	Sat May 21 15:00:14 2016 +1000
+++ /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
-## <http://www.gnu.org/licenses/>.
-
-## -*- 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 <d@domob.eu>
-
-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 <N must be a positive integer> profshow (struct (), ones (2))
-%!error <N must be a positive integer> profshow (struct (), 1+i)
-%!error <N must be a positive integer> profshow (struct (), -1)
-
--- a/scripts/module.mk	Sat May 21 15:00:14 2016 +1000
+++ 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
--- /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,18 @@
+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)
+
+PKG_ADD_FILES += scripts/profiler/PKG_ADD
+
+DIRSTAMP_FILES += scripts/profiler/$(octave_dirstamp)
--- /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,139 @@
+## 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
+## <http://www.gnu.org/licenses/>.
+
+## -*- 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 <d@domob.eu>
+
+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
+
--- /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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} profile on
+## @deftypefnx {} {} profile off
+## @deftypefnx {} {} profile resume
+## @deftypefnx {} {} profile clear
+## @deftypefnx {} {@var{S} =} profile ("status")
+## @deftypefnx {} {@var{T} =} 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 <d@domob.eu>
+
+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")
+
--- /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
+## <http://www.gnu.org/licenses/>.
+
+## -*- 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 <d@domob.eu>
+
+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 <N must be a positive integer> profshow (struct (), ones (2))
+%!error <N must be a positive integer> profshow (struct (), 1+i)
+%!error <N must be a positive integer> profshow (struct (), -1)
+