Mercurial > octave
changeset 23753:c3828bd031cd
move profiler inside evaluator and inside octave namespace
* interpreter.h, interpreter.cc (interpreter::get_profiler):
New function.
* pt-eval.h, pt-eval.cc (tree_evaluator::m_profiler): New data member.
(tree_evaluator::get_profiler): New function.
* profiler.h, profiler.cc (profiler): Delete global variable.
(class profiler): Rename from profile_data_accumulator. Move inside
octave namespace. Change all uses.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sat, 08 Jul 2017 10:33:07 -0400 |
parents | 6be1bf9455e3 |
children | afe45e9ff6b0 |
files | libinterp/corefcn/interpreter.cc libinterp/corefcn/interpreter.h libinterp/octave-value/ov-builtin.cc libinterp/octave-value/ov-mex-fcn.cc libinterp/octave-value/ov-usr-fcn.cc libinterp/parse-tree/profiler.cc libinterp/parse-tree/profiler.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h |
diffstat | 9 files changed, 511 insertions(+), 487 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/interpreter.cc Sat Jul 08 10:14:32 2017 -0400 +++ b/libinterp/corefcn/interpreter.cc Sat Jul 08 10:33:07 2017 -0400 @@ -1202,6 +1202,11 @@ return m_evaluator.get_call_stack (); } + profiler& interpreter::get_profiler (void) + { + return m_evaluator.get_profiler (); + } + void interpreter::mlock (void) { call_stack& cs = get_call_stack ();
--- a/libinterp/corefcn/interpreter.h Sat Jul 08 10:14:32 2017 -0400 +++ b/libinterp/corefcn/interpreter.h Sat Jul 08 10:33:07 2017 -0400 @@ -51,6 +51,7 @@ namespace octave { + class profiler; class call_stack; class tree_evaluator; @@ -171,6 +172,8 @@ call_stack& get_call_stack (void); + profiler& get_profiler (void); + tree_evaluator& get_evaluator (void); stream_list& get_stream_list (void);
--- a/libinterp/octave-value/ov-builtin.cc Sat Jul 08 10:14:32 2017 -0400 +++ b/libinterp/octave-value/ov-builtin.cc Sat Jul 08 10:33:07 2017 -0400 @@ -41,7 +41,7 @@ "built-in function"); octave_value_list -octave_builtin::call (octave::tree_evaluator&, int nargout, +octave_builtin::call (octave::tree_evaluator& tw, int nargout, const octave_value_list& args) { octave_value_list retval; @@ -57,7 +57,9 @@ frame.add_method (cs, &octave::call_stack::pop); - profile_data_accumulator::enter<octave_builtin> block (profiler, *this); + octave::profiler& profiler = tw.get_profiler (); + + octave::profiler::enter<octave_builtin> block (profiler, *this); if (f) retval = (*f) (args, nargout);
--- a/libinterp/octave-value/ov-mex-fcn.cc Sat Jul 08 10:14:32 2017 -0400 +++ b/libinterp/octave-value/ov-mex-fcn.cc Sat Jul 08 10:33:07 2017 -0400 @@ -88,7 +88,7 @@ int nargout); octave_value_list -octave_mex_function::call (octave::tree_evaluator&, int nargout, +octave_mex_function::call (octave::tree_evaluator& tw, int nargout, const octave_value_list& args) { octave_value_list retval; @@ -105,7 +105,9 @@ frame.add_method (cs, &octave::call_stack::pop); - profile_data_accumulator::enter<octave_mex_function> block (profiler, *this); + octave::profiler& profiler = tw.get_profiler (); + + octave::profiler::enter<octave_mex_function> block (profiler, *this); retval = call_mex (*this, args, nargout);
--- a/libinterp/octave-value/ov-usr-fcn.cc Sat Jul 08 10:14:32 2017 -0400 +++ b/libinterp/octave-value/ov-usr-fcn.cc Sat Jul 08 10:33:07 2017 -0400 @@ -200,8 +200,9 @@ frame.protect_var (octave::tree_evaluator::statement_context); octave::tree_evaluator::statement_context = octave::tree_evaluator::script; - profile_data_accumulator::enter<octave_user_script> - block (profiler, *this); + octave::profiler& profiler = tw.get_profiler (); + + octave::profiler::enter<octave_user_script> block (profiler, *this); if (tw.echo ()) tw.push_echo_state (frame, octave::tree_evaluator::ECHO_SCRIPTS, @@ -616,8 +617,9 @@ octave::tree_evaluator::statement_context = octave::tree_evaluator::function; { - profile_data_accumulator::enter<octave_user_function> - block (profiler, *this); + octave::profiler& profiler = tw.get_profiler (); + + octave::profiler::enter<octave_user_function> block (profiler, *this); if (tw.echo ()) tw.push_echo_state (frame, octave::tree_evaluator::ECHO_FUNCTIONS,
--- a/libinterp/parse-tree/profiler.cc Sat Jul 08 10:14:32 2017 -0400 +++ b/libinterp/parse-tree/profiler.cc Sat Jul 08 10:33:07 2017 -0400 @@ -28,361 +28,363 @@ #include <iostream> #include "defun.h" +#include "interpreter.h" #include "oct-time.h" #include "ov-struct.h" #include "pager.h" #include "profiler.h" -profile_data_accumulator::stats::stats () - : time (0.0), calls (0), recursive (false), - parents (), children () -{ } - -octave_value -profile_data_accumulator::stats::function_set_value (const function_set& list) +namespace octave { - const octave_idx_type n = list.size (); + profiler::stats::stats () + : time (0.0), calls (0), recursive (false), + parents (), children () + { } + + octave_value + profiler::stats::function_set_value (const function_set& list) + { + const octave_idx_type n = list.size (); + + RowVector retval (n); + octave_idx_type i = 0; + for (const auto& nm : list) + retval(i++) = nm; + + assert (i == n); - RowVector retval (n); - octave_idx_type i = 0; - for (const auto& nm : list) - retval(i++) = nm; + return retval; + } + + profiler::tree_node::tree_node (tree_node *p, octave_idx_type f) + : parent (p), fcn_id (f), children (), time (0.0), calls (0) + { } - assert (i == n); + profiler::tree_node::~tree_node () + { + for (auto& idx_tnode : children) + delete idx_tnode.second; + } + + profiler::tree_node* + profiler::tree_node::enter (octave_idx_type fcn) + { + tree_node *retval; - return retval; -} + child_map::iterator pos = children.find (fcn); + if (pos == children.end ()) + { + retval = new tree_node (this, fcn); + children[fcn] = retval; + } + else + retval = pos->second; -profile_data_accumulator::tree_node::tree_node (tree_node *p, octave_idx_type f) - : parent (p), fcn_id (f), children (), time (0.0), calls (0) -{ } + ++retval->calls; + return retval; + } + + profiler::tree_node* + profiler::tree_node::exit (octave_idx_type /* fcn */) + { + // FIXME: These assert statements don't make sense if profile() is called + // from within a function hierarchy to begin with. See bug #39587. + // assert (parent); + // assert (fcn_id == fcn); -profile_data_accumulator::tree_node::~tree_node () -{ - for (auto& idx_tnode : children) - delete idx_tnode.second; -} + return parent; + } -profile_data_accumulator::tree_node* -profile_data_accumulator::tree_node::enter (octave_idx_type fcn) -{ - tree_node *retval; + void + profiler::tree_node::build_flat (flat_profile& data) const + { + // If this is not the top-level node, update profile entry for this function. + if (fcn_id != 0) + { + stats& entry = data[fcn_id - 1]; + + entry.time += time; + entry.calls += calls; + + assert (parent); + if (parent->fcn_id != 0) + { + entry.parents.insert (parent->fcn_id); + data[parent->fcn_id - 1].children.insert (fcn_id); + } - child_map::iterator pos = children.find (fcn); - if (pos == children.end ()) - { - retval = new tree_node (this, fcn); - children[fcn] = retval; - } - else - retval = pos->second; + if (! entry.recursive) + for (const tree_node *i = parent; i; i = i->parent) + if (i->fcn_id == fcn_id) + { + entry.recursive = true; + break; + } + } + + // Recurse on children. + for (const auto& idx_tnode : children) + idx_tnode.second->build_flat (data); + } - ++retval->calls; - return retval; -} + octave_value + profiler::tree_node::get_hierarchical (double *total) const + { + // Note that we don't generate the entry just for this node, but + // rather a struct-array with entries for all children. This way, the + // top-node (for which we don't want a real entry) generates already + // the final hierarchical profile data. + + const octave_idx_type n = children.size (); + + Cell rv_indices (n, 1); + Cell rv_times (n, 1); + Cell rv_totals (n, 1); + Cell rv_calls (n, 1); + Cell rv_children (n, 1); + + octave_idx_type i = 0; + for (const auto& idx_tnode : children) + { + const tree_node& entry = *idx_tnode.second; + double child_total = entry.time; + + rv_indices(i) = octave_value (idx_tnode.first); + rv_times(i) = octave_value (entry.time); + rv_calls(i) = octave_value (entry.calls); + rv_children(i) = entry.get_hierarchical (&child_total); + rv_totals(i) = octave_value (child_total); -profile_data_accumulator::tree_node* -profile_data_accumulator::tree_node::exit (octave_idx_type /* fcn */) -{ - // FIXME: These assert statements don't make sense if profile() is called - // from within a function hierarchy to begin with. See bug #39587. - // assert (parent); - // assert (fcn_id == fcn); + if (total) + *total += child_total; + + ++i; + } + assert (i == n); + + octave_map retval; - return parent; -} + retval.assign ("Index", rv_indices); + retval.assign ("SelfTime", rv_times); + retval.assign ("TotalTime", rv_totals); + retval.assign ("NumCalls", rv_calls); + retval.assign ("Children", rv_children); + + return retval; + } -void -profile_data_accumulator::tree_node::build_flat (flat_profile& data) const -{ - // If this is not the top-level node, update profile entry for this function. - if (fcn_id != 0) - { - stats& entry = data[fcn_id - 1]; + profiler::profiler (void) + : known_functions (), fcn_index (), + enabled (false), call_tree (new tree_node (0, 0)), + active_fcn (0), last_time (-1.0) + { } + + profiler::~profiler (void) + { + delete call_tree; + } - entry.time += time; - entry.calls += calls; + void + profiler::set_active (bool value) + { + enabled = value; + } + + void + profiler::enter_function (const std::string& fcn) + { + // The enter class will check and only call us if the profiler is active. + assert (is_active ()); + assert (call_tree); + + // If there is already an active function, add to its time before + // pushing the new one. + if (active_fcn && active_fcn != call_tree) + add_current_time (); - assert (parent); - if (parent->fcn_id != 0) - { - entry.parents.insert (parent->fcn_id); - data[parent->fcn_id - 1].children.insert (fcn_id); - } + // Map the function's name to its index. + octave_idx_type fcn_idx; + fcn_index_map::iterator pos = fcn_index.find (fcn); + if (pos == fcn_index.end ()) + { + known_functions.push_back (fcn); + fcn_idx = known_functions.size (); + fcn_index[fcn] = fcn_idx; + } + else + fcn_idx = pos->second; + + if (! active_fcn) + active_fcn = call_tree; + + active_fcn = active_fcn->enter (fcn_idx); + + last_time = query_time (); + + } - if (! entry.recursive) - for (const tree_node *i = parent; i; i = i->parent) - if (i->fcn_id == fcn_id) - { - entry.recursive = true; - break; - } - } + void + profiler::exit_function (const std::string& fcn) + { + if (active_fcn) + { + assert (call_tree); + // FIXME: This assert statements doesn't make sense if profile() is called + // from within a function hierarchy to begin with. See bug #39587. + //assert (active_fcn != call_tree); + + // Usually, if we are disabled this function is not even called. But the + // call disabling the profiler is an exception. So also check here + // and only record the time if enabled. + if (is_active ()) + add_current_time (); + + fcn_index_map::iterator pos = fcn_index.find (fcn); + // FIXME: This assert statements doesn't make sense if profile() is called + // from within a function hierarchy to begin with. See bug #39587. + //assert (pos != fcn_index.end ()); + active_fcn = active_fcn->exit (pos->second); - // Recurse on children. - for (const auto& idx_tnode : children) - idx_tnode.second->build_flat (data); -} + // If this was an "inner call", we resume executing the parent function + // up the stack. So note the start-time for this! + last_time = query_time (); + } + } + + void + profiler::reset (void) + { + if (is_active ()) + error ("Can't reset active profiler."); + + known_functions.clear (); + fcn_index.clear (); + + if (call_tree) + { + delete call_tree; + call_tree = new tree_node (0, 0); + active_fcn = 0; + } -octave_value -profile_data_accumulator::tree_node::get_hierarchical (double *total) const -{ - // Note that we don't generate the entry just for this node, but - // rather a struct-array with entries for all children. This way, the - // top-node (for which we don't want a real entry) generates already - // the final hierarchical profile data. + last_time = -1.0; + } + + octave_value + profiler::get_flat (void) const + { + octave_value retval; + + const octave_idx_type n = known_functions.size (); - const octave_idx_type n = children.size (); + flat_profile flat (n); + + if (call_tree) + { + call_tree->build_flat (flat); - Cell rv_indices (n, 1); - Cell rv_times (n, 1); - Cell rv_totals (n, 1); - Cell rv_calls (n, 1); - Cell rv_children (n, 1); + Cell rv_names (n, 1); + Cell rv_times (n, 1); + Cell rv_calls (n, 1); + Cell rv_recursive (n, 1); + Cell rv_parents (n, 1); + Cell rv_children (n, 1); - octave_idx_type i = 0; - for (const auto& idx_tnode : children) - { - const tree_node& entry = *idx_tnode.second; - double child_total = entry.time; + for (octave_idx_type i = 0; i != n; ++i) + { + rv_names(i) = octave_value (known_functions[i]); + rv_times(i) = octave_value (flat[i].time); + rv_calls(i) = octave_value (flat[i].calls); + rv_recursive(i) = octave_value (flat[i].recursive); + rv_parents(i) = stats::function_set_value (flat[i].parents); + rv_children(i) = stats::function_set_value (flat[i].children); + } + + octave_map m; + + m.assign ("FunctionName", rv_names); + m.assign ("TotalTime", rv_times); + m.assign ("NumCalls", rv_calls); + m.assign ("IsRecursive", rv_recursive); + m.assign ("Parents", rv_parents); + m.assign ("Children", rv_children); - rv_indices(i) = octave_value (idx_tnode.first); - rv_times(i) = octave_value (entry.time); - rv_calls(i) = octave_value (entry.calls); - rv_children(i) = entry.get_hierarchical (&child_total); - rv_totals(i) = octave_value (child_total); + retval = m; + } + else + { + static const char *fn[] = + { + "FunctionName", + "TotalTime", + "NumCalls", + "IsRecursive", + "Parents", + "Children", + 0 + }; - if (total) - *total += child_total; + static octave_map m (dim_vector (0, 1), string_vector (fn)); - ++i; - } - assert (i == n); + retval = m; + } - octave_map retval; + return retval; + } - retval.assign ("Index", rv_indices); - retval.assign ("SelfTime", rv_times); - retval.assign ("TotalTime", rv_totals); - retval.assign ("NumCalls", rv_calls); - retval.assign ("Children", rv_children); + octave_value + profiler::get_hierarchical (void) const + { + octave_value retval; - return retval; -} + if (call_tree) + retval = call_tree->get_hierarchical (); + else + { + static const char *fn[] = + { + "Index", + "SelfTime", + "NumCalls", + "Children", + 0 + }; + + static octave_map m (dim_vector (0, 1), string_vector (fn)); + + retval = m; + } -profile_data_accumulator::profile_data_accumulator () - : known_functions (), fcn_index (), - enabled (false), call_tree (new tree_node (0, 0)), - active_fcn (0), last_time (-1.0) -{ } + return retval; + } + + double + profiler::query_time (void) const + { + sys::time now; + + // FIXME: is this volatile declaration really needed? + // See bug #34210 for additional details. + volatile double dnow = now.double_value (); -profile_data_accumulator::~profile_data_accumulator () -{ - delete call_tree; -} + return dnow; + } -void -profile_data_accumulator::set_active (bool value) -{ - enabled = value; + void + profiler::add_current_time (void) + { + if (active_fcn) + { + const double t = query_time (); + + active_fcn->add_time (t - last_time); + } + } } -void -profile_data_accumulator::enter_function (const std::string& fcn) -{ - // The enter class will check and only call us if the profiler is active. - assert (is_active ()); - assert (call_tree); - - // If there is already an active function, add to its time before - // pushing the new one. - if (active_fcn && active_fcn != call_tree) - add_current_time (); - - // Map the function's name to its index. - octave_idx_type fcn_idx; - fcn_index_map::iterator pos = fcn_index.find (fcn); - if (pos == fcn_index.end ()) - { - known_functions.push_back (fcn); - fcn_idx = known_functions.size (); - fcn_index[fcn] = fcn_idx; - } - else - fcn_idx = pos->second; - - if (! active_fcn) - active_fcn = call_tree; - - active_fcn = active_fcn->enter (fcn_idx); - - last_time = query_time (); - -} - -void -profile_data_accumulator::exit_function (const std::string& fcn) -{ - if (active_fcn) - { - assert (call_tree); - // FIXME: This assert statements doesn't make sense if profile() is called - // from within a function hierarchy to begin with. See bug #39587. - //assert (active_fcn != call_tree); - - // Usually, if we are disabled this function is not even called. But the - // call disabling the profiler is an exception. So also check here - // and only record the time if enabled. - if (is_active ()) - add_current_time (); - - fcn_index_map::iterator pos = fcn_index.find (fcn); - // FIXME: This assert statements doesn't make sense if profile() is called - // from within a function hierarchy to begin with. See bug #39587. - //assert (pos != fcn_index.end ()); - active_fcn = active_fcn->exit (pos->second); - - // If this was an "inner call", we resume executing the parent function - // up the stack. So note the start-time for this! - last_time = query_time (); - } -} - -void -profile_data_accumulator::reset (void) -{ - if (is_active ()) - error ("Can't reset active profiler."); - - known_functions.clear (); - fcn_index.clear (); - - if (call_tree) - { - delete call_tree; - call_tree = new tree_node (0, 0); - active_fcn = 0; - } - - last_time = -1.0; -} - -octave_value -profile_data_accumulator::get_flat (void) const -{ - octave_value retval; - - const octave_idx_type n = known_functions.size (); - - flat_profile flat (n); - - if (call_tree) - { - call_tree->build_flat (flat); - - Cell rv_names (n, 1); - Cell rv_times (n, 1); - Cell rv_calls (n, 1); - Cell rv_recursive (n, 1); - Cell rv_parents (n, 1); - Cell rv_children (n, 1); - - for (octave_idx_type i = 0; i != n; ++i) - { - rv_names(i) = octave_value (known_functions[i]); - rv_times(i) = octave_value (flat[i].time); - rv_calls(i) = octave_value (flat[i].calls); - rv_recursive(i) = octave_value (flat[i].recursive); - rv_parents(i) = stats::function_set_value (flat[i].parents); - rv_children(i) = stats::function_set_value (flat[i].children); - } - - octave_map m; - - m.assign ("FunctionName", rv_names); - m.assign ("TotalTime", rv_times); - m.assign ("NumCalls", rv_calls); - m.assign ("IsRecursive", rv_recursive); - m.assign ("Parents", rv_parents); - m.assign ("Children", rv_children); - - retval = m; - } - else - { - static const char *fn[] = - { - "FunctionName", - "TotalTime", - "NumCalls", - "IsRecursive", - "Parents", - "Children", - 0 - }; - - static octave_map m (dim_vector (0, 1), string_vector (fn)); - - retval = m; - } - - return retval; -} - -octave_value -profile_data_accumulator::get_hierarchical (void) const -{ - octave_value retval; - - if (call_tree) - retval = call_tree->get_hierarchical (); - else - { - static const char *fn[] = - { - "Index", - "SelfTime", - "NumCalls", - "Children", - 0 - }; - - static octave_map m (dim_vector (0, 1), string_vector (fn)); - - retval = m; - } - - return retval; -} - -double -profile_data_accumulator::query_time (void) const -{ - octave::sys::time now; - - // FIXME: is this volatile declaration really needed? - // See bug #34210 for additional details. - volatile double dnow = now.double_value (); - - return dnow; -} - -void -profile_data_accumulator::add_current_time (void) -{ - if (active_fcn) - { - const double t = query_time (); - - active_fcn->add_time (t - last_time); - } -} - -profile_data_accumulator profiler; - // Enable or disable the profiler data collection. -DEFUN (__profiler_enable__, args, , - doc: /* -*- texinfo -*- +DEFMETHOD (__profiler_enable__, interp, args, , + doc: /* -*- texinfo -*- @deftypefn {} {} __profiler_enable__ () Undocumented internal function. @end deftypefn */) @@ -392,6 +394,8 @@ if (nargin > 1) print_usage (); + octave::profiler& profiler = interp.get_profiler (); + if (nargin == 1) profiler.set_active (args(0).bool_value ()); @@ -399,8 +403,8 @@ } // Clear all collected profiling data. -DEFUN (__profiler_reset__, args, , - doc: /* -*- texinfo -*- +DEFMETHOD (__profiler_reset__, interp, args, , + doc: /* -*- texinfo -*- @deftypefn {} {} __profiler_reset__ () Undocumented internal function. @end deftypefn */) @@ -408,14 +412,16 @@ if (args.length () != 0) print_usage (); + octave::profiler& profiler = interp.get_profiler (); + profiler.reset (); return ovl (); } // Query the timings collected by the profiler. -DEFUN (__profiler_data__, args, nargout, - doc: /* -*- texinfo -*- +DEFMETHOD (__profiler_data__, interp, args, nargout, + doc: /* -*- texinfo -*- @deftypefn {} {} __profiler_data__ () Undocumented internal function. @end deftypefn */) @@ -423,6 +429,8 @@ if (args.length () != 0) print_usage (); + octave::profiler& profiler = interp.get_profiler (); + if (nargout > 1) return ovl (profiler.get_flat (), profiler.get_hierarchical ()); else
--- a/libinterp/parse-tree/profiler.h Sat Jul 08 10:14:32 2017 -0400 +++ b/libinterp/parse-tree/profiler.h Sat Jul 08 10:33:07 2017 -0400 @@ -34,182 +34,181 @@ class octave_value; -class -OCTINTERP_API -profile_data_accumulator +namespace octave { -public: - - // This is a utility class that can be used to call the enter/exit - // functions in a manner protected from stack unwinding. - template <typename T> class enter + class + OCTINTERP_API + profiler { - private: - - profile_data_accumulator& acc; - std::string fcn; - bool is_active; - public: - enter (profile_data_accumulator& a, const T& t) : acc (a) + // This is a utility class that can be used to call the enter/exit + // functions in a manner protected from stack unwinding. + template <typename T> class enter { - // A profiling block cannot be active if the profiler is not - is_active = acc.is_active (); + private: + + profiler& m_profiler; + std::string fcn; + bool is_active; + + public: - if (is_active) - { - fcn = t.profiler_name (); + enter (profiler& p, const T& t) : m_profiler (p) + { + // A profiling block cannot be active if the profiler is not + is_active = m_profiler.is_active (); + + if (is_active) + { + fcn = t.profiler_name (); - // NOTE: The test f != "" must be kept to prevent a blank line showing - // up in profiler statistics. See bug #39524. The root cause is that - // the function name is not set for the recurring readline hook function. - if (fcn == "") - is_active = false; // Inactive profiling block - else - acc.enter_function (fcn); - } - } + // NOTE: The test f != "" must be kept to prevent a blank line showing + // up in profiler statistics. See bug #39524. The root cause is that + // the function name is not set for the recurring readline hook function. + if (fcn == "") + is_active = false; // Inactive profiling block + else + m_profiler.enter_function (fcn); + } + } + + // No copying! + + enter (const enter&) = delete; + + enter& operator = (const enter&) = delete; + + ~enter (void) + { + if (is_active) + m_profiler.exit_function (fcn); + } + }; + + profiler (void); // No copying! - enter (const enter&) = delete; - - enter& operator = (const enter&) = delete; - - ~enter () - { - if (is_active) - acc.exit_function (fcn); - } - }; - - profile_data_accumulator (void); - - // No copying! - - profile_data_accumulator (const profile_data_accumulator&) = delete; - - profile_data_accumulator& - operator = (const profile_data_accumulator&) = delete; + profiler (const profiler&) = delete; - virtual ~profile_data_accumulator (); - - bool is_active (void) const { return enabled; } - void set_active (bool); - - void reset (void); - - octave_value get_flat (void) const; - octave_value get_hierarchical (void) const; + profiler& operator = (const profiler&) = delete; -private: - - // One entry in the flat profile (i.e., a collection of data for a single - // function). This is filled in when building the flat profile from the - // hierarchical call tree. - struct stats - { - stats (); - - double time; - unsigned calls; + virtual ~profiler (void); - bool recursive; - - typedef std::set<octave_idx_type> function_set; - function_set parents; - function_set children; - - // Convert a function_set list to an Octave array of indices. - static octave_value function_set_value (const function_set&); - }; - - typedef std::vector<stats> flat_profile; - - // Store data for one node in the call-tree of the hierarchical profiler - // data we collect. - class tree_node - { - public: - - tree_node (tree_node*, octave_idx_type); - virtual ~tree_node (); + bool is_active (void) const { return enabled; } + void set_active (bool); - // No copying! - - tree_node (const tree_node&) = delete; - - tree_node& operator = (const tree_node&) = delete; - - void add_time (double dt) { time += dt; } - - // Enter a child function. It is created in the list of children if it - // wasn't already there. The now-active child node is returned. - tree_node *enter (octave_idx_type); + void reset (void); - // Exit function. As a sanity-check, it is verified that the currently - // active function actually is the one handed in here. Returned is the - // then-active node, which is our parent. - tree_node *exit (octave_idx_type); - - void build_flat (flat_profile&) const; - - // Get the hierarchical profile for this node and its children. If total - // is set, accumulate total time of the subtree in that variable as - // additional return value. - octave_value get_hierarchical (double *total = nullptr) const; + octave_value get_flat (void) const; + octave_value get_hierarchical (void) const; private: - tree_node *parent; - octave_idx_type fcn_id; + // One entry in the flat profile (i.e., a collection of data for a single + // function). This is filled in when building the flat profile from the + // hierarchical call tree. + struct stats + { + stats (void); - typedef std::map<octave_idx_type, tree_node*> child_map; - child_map children; + double time; + unsigned calls; - // This is only time spent *directly* on this level, excluding children! - double time; + bool recursive; + + typedef std::set<octave_idx_type> function_set; + function_set parents; + function_set children; - unsigned calls; - }; + // Convert a function_set list to an Octave array of indices. + static octave_value function_set_value (const function_set&); + }; + + typedef std::vector<stats> flat_profile; - // Each function we see in the profiler is given a unique index (which - // simply counts starting from 1). We thus have to map profiler-names to - // those indices. For all other stuff, we identify functions by their index. + // Store data for one node in the call-tree of the hierarchical profiler + // data we collect. + class tree_node + { + public: + + tree_node (tree_node*, octave_idx_type); + virtual ~tree_node (void); + + // No copying! + + tree_node (const tree_node&) = delete; - typedef std::vector<std::string> function_set; - typedef std::map<std::string, octave_idx_type> fcn_index_map; + tree_node& operator = (const tree_node&) = delete; + + void add_time (double dt) { time += dt; } - function_set known_functions; - fcn_index_map fcn_index; + // Enter a child function. It is created in the list of children if it + // wasn't already there. The now-active child node is returned. + tree_node *enter (octave_idx_type); - bool enabled; + // Exit function. As a sanity-check, it is verified that the currently + // active function actually is the one handed in here. Returned is the + // then-active node, which is our parent. + tree_node *exit (octave_idx_type); + + void build_flat (flat_profile&) const; - tree_node *call_tree; - tree_node *active_fcn; + // Get the hierarchical profile for this node and its children. If total + // is set, accumulate total time of the subtree in that variable as + // additional return value. + octave_value get_hierarchical (double *total = nullptr) const; + + private: + + tree_node *parent; + octave_idx_type fcn_id; + + typedef std::map<octave_idx_type, tree_node*> child_map; + child_map children; - // Store last timestamp we had, when the currently active function was called. - double last_time; + // This is only time spent *directly* on this level, excluding children! + double time; + + unsigned calls; + }; - // These are private as only the unwind-protecting inner class enter - // should be allowed to call them. - void enter_function (const std::string&); - void exit_function (const std::string&); + // Each function we see in the profiler is given a unique index (which + // simply counts starting from 1). We thus have to map profiler-names to + // those indices. For all other stuff, we identify functions by their index. + + typedef std::vector<std::string> function_set; + typedef std::map<std::string, octave_idx_type> fcn_index_map; - // Query a timestamp, used for timing calls (obviously). - // This is not static because in the future, maybe we want a flag - // in the profiler or something to choose between cputime, wall-time, - // user-time, system-time, ... - double query_time () const; + function_set known_functions; + fcn_index_map fcn_index; + + bool enabled; + + tree_node *call_tree; + tree_node *active_fcn; + + // Store last timestamp we had, when the currently active function was called. + double last_time; - // Add the time elapsed since last_time to the function we're currently in. - // This is called from two different positions, thus it is useful to have - // it as a seperate function. - void add_current_time (void); -}; + // These are private as only the unwind-protecting inner class enter + // should be allowed to call them. + void enter_function (const std::string&); + void exit_function (const std::string&); -// The instance used. -extern OCTINTERP_API profile_data_accumulator profiler; + // Query a timestamp, used for timing calls (obviously). + // This is not static because in the future, maybe we want a flag + // in the profiler or something to choose between cputime, wall-time, + // user-time, system-time, ... + double query_time (void) const; + + // Add the time elapsed since last_time to the function we're currently in. + // This is called from two different positions, thus it is useful to have + // it as a seperate function. + void add_current_time (void); + }; +} #endif
--- a/libinterp/parse-tree/pt-eval.cc Sat Jul 08 10:14:32 2017 -0400 +++ b/libinterp/parse-tree/pt-eval.cc Sat Jul 08 10:33:07 2017 -0400 @@ -220,8 +220,8 @@ if (b.is_defined ()) { - profile_data_accumulator::enter<tree_binary_expression> - block (profiler, expr); + profiler::enter<tree_binary_expression> + block (m_profiler, expr); // Note: The profiler does not catch the braindead // short-circuit evaluation code above, but that should be @@ -1969,8 +1969,7 @@ val = ref.value (); - profile_data_accumulator::enter<tree_postfix_expression> - block (profiler, expr); + profiler::enter<tree_postfix_expression> block (m_profiler, expr); ref.do_unary_op (etype); } @@ -1980,8 +1979,8 @@ if (op_val.is_defined ()) { - profile_data_accumulator::enter<tree_postfix_expression> - block (profiler, expr); + profiler::enter<tree_postfix_expression> + block (m_profiler, expr); val = ::do_unary_op (etype, op_val); } @@ -2006,8 +2005,7 @@ { octave_lvalue op_ref = op->lvalue (this); - profile_data_accumulator::enter<tree_prefix_expression> - block (profiler, expr); + profiler::enter<tree_prefix_expression> block (m_profiler, expr); op_ref.do_unary_op (etype); @@ -2019,8 +2017,8 @@ if (op_val.is_defined ()) { - profile_data_accumulator::enter<tree_prefix_expression> - block (profiler, expr); + profiler::enter<tree_prefix_expression> + block (m_profiler, expr); // Attempt to do the operation in-place if it is unshared // (a temporary expression).
--- a/libinterp/parse-tree/pt-eval.h Sat Jul 08 10:14:32 2017 -0400 +++ b/libinterp/parse-tree/pt-eval.h Sat Jul 08 10:33:07 2017 -0400 @@ -32,6 +32,7 @@ #include "call-stack.h" #include "ovl.h" +#include "profiler.h" #include "pt-exp.h" #include "pt-walk.h" @@ -114,7 +115,7 @@ tree_evaluator (interpreter& interp) : m_interpreter (interp), m_value_stack (), m_lvalue_list_stack (), - m_nargout_stack (), m_call_stack (interp), + m_nargout_stack (), m_call_stack (interp), m_profiler (), m_max_recursion_depth (256), m_silent_functions (false), m_string_fill_char (' '), m_PS4 ("+ "), m_echo (ECHO_OFF), m_echo_state (false), m_echo_file_name (), m_echo_file_pos (1), @@ -309,6 +310,8 @@ call_stack& get_call_stack (void) { return m_call_stack; } + profiler& get_profiler (void) { return m_profiler; } + int max_recursion_depth (void) const { return m_max_recursion_depth; } int max_recursion_depth (int n) @@ -426,6 +429,8 @@ call_stack m_call_stack; + profiler m_profiler; + // Maximum nesting level for functions, scripts, or sourced files // called recursively. int m_max_recursion_depth;