Mercurial > octave-nkf
view src/profiler.cc @ 12870:39d813616c8f
Restore the docstrings for internal profiler functions as C++ comments
author | Jordi Gutiérrez Hermoso <jordigh@gmail.com> |
---|---|
date | Fri, 22 Jul 2011 00:57:38 -0500 |
parents | de9a9719e594 |
children | 5d18231eee00 |
line wrap: on
line source
/* Copyright (C) 2011 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/>. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <iostream> #include "defun.h" #include "oct-time.h" #include "ov-fcn.h" #include "ov-struct.h" #include "pager.h" #include "profiler.h" profile_data_accumulator::enter::enter (profile_data_accumulator& a, const octave_function& f) : acc (a) { if (acc.is_active ()) { fcn = &f; acc.enter_function (*fcn); } else fcn = NULL; } profile_data_accumulator::enter::~enter () { if (fcn) acc.exit_function (*fcn); } profile_data_accumulator::stats::stats () : time (0.0), calls (0), recursive (false), parents (), children () {} // With the help of a mapping name -> index, convert a function_set list // to an Octave array of indices. octave_value profile_data_accumulator::stats::function_set_value (const function_set& list, const fcn_index_map& idx) { const octave_idx_type n = list.size (); RowVector retval (n); octave_idx_type i = 0; for (function_set::const_iterator p = list.begin (); p != list.end (); ++p) { fcn_index_map::const_iterator q = idx.find (*p); assert (q != idx.end ()); retval (i) = q->second; ++i; } assert (i == n); return retval; } profile_data_accumulator::profile_data_accumulator () : enabled (false), call_stack (), data (), last_time (-1.0) {} void profile_data_accumulator::set_active (bool value) { // If we enable, clear the call-stack. This ensures we freshly start // with collecting times now. if (value) { while (!call_stack.empty ()) call_stack.pop_back (); } enabled = value; } void profile_data_accumulator::enter_function (const octave_function& fcn) { // The enter class will check and only call us if the profiler is active. assert (is_active ()); // If there is already an active function, add to its time before // pushing the new one. if (!call_stack.empty ()) add_current_time (); // Update non-timing related data for the function entered. const std::string name = fcn.profiler_name (); stats& entry = data[name]; ++entry.calls; if (!call_stack.empty ()) { const std::string parent_name = call_stack.back ()->profiler_name (); entry.parents.insert (parent_name); data[parent_name].children.insert (name); } if (!entry.recursive) for (call_stack_type::iterator i = call_stack.begin (); i != call_stack.end (); ++i) if (*i == &fcn) { entry.recursive = true; break; } call_stack.push_back (&fcn); last_time = query_time (); } void profile_data_accumulator::exit_function (const octave_function& fcn) { assert (!call_stack.empty ()); assert (&fcn == call_stack.back ()); // 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 (); call_stack.pop_back (); // 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."); return; } data.clear (); last_time = -1.0; } octave_value profile_data_accumulator::get_data (void) const { const octave_idx_type n = data.size (); // For the parent/child data, we need to map function key-names // to the indices they correspond to in the output array. Find them out // in a preparation step. fcn_index_map fcn_indices; octave_idx_type i = 0; for (stats_map::const_iterator p = data.begin (); p != data.end (); ++p) { fcn_indices[p->first] = i + 1; ++i; } assert (i == n); 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); i = 0; for (stats_map::const_iterator p = data.begin (); p != data.end (); ++p) { const stats& entry = p->second; rv_names (i) = octave_value (p->first); rv_times (i) = octave_value (entry.time); rv_calls (i) = octave_value (entry.calls); rv_recursive (i) = octave_value (entry.recursive); rv_parents (i) = stats::function_set_value (entry.parents, fcn_indices); rv_children (i) = stats::function_set_value (entry.children, fcn_indices); ++i; } assert (i == n); Octave_map retval; retval.assign ("FunctionName", rv_names); retval.assign ("TotalTime", rv_times); retval.assign ("NumCalls", rv_calls); retval.assign ("IsRecursive", rv_recursive); retval.assign ("Parents", rv_parents); retval.assign ("Children", rv_children); return retval; } double profile_data_accumulator::query_time (void) const { octave_time now; return now.double_value (); } void profile_data_accumulator::add_current_time (void) { const double t = query_time (); assert (last_time >= 0.0 && last_time <= t); assert (!call_stack.empty ()); const std::string name = call_stack.back ()->profiler_name (); // The entry for this function should already be created; namely // when entering the function via the non-timing data collection! stats_map::iterator pos = data.find (name); assert (pos != data.end ()); pos->second.time += t - last_time; } profile_data_accumulator profiler; // Enable or disable the profiler data collection. DEFUN (__profiler_enable, args, , "-*- texinfo -*-\n\ @deftypefn {Function File} __profiler_enable ()\n\ Undocumented internal function.\n\ @end deftypefn") { octave_value_list retval; const int nargin = args.length (); if (nargin > 0) { if (nargin > 1) { print_usage (); return retval; } profiler.set_active (args(0).bool_value ()); } retval(0) = profiler.is_active (); return retval; } // Clear all collected profiling data. DEFUN (__profiler_reset, args, , "-*- texinfo -*-\n\ @deftypefn {Function File} __profiler_reset ()\n\ Undocumented internal function.\n\ @end deftypefn") { octave_value_list retval; const int nargin = args.length (); if (nargin > 0) warning ("profiler_reset: ignoring extra arguments"); profiler.reset (); return retval; } // Query the timings collected by the profiler. DEFUN (__profiler_data, args, , "-*- texinfo -*-\n\ @deftypefn {Function File} __profiler_data ()\n\ Undocumented internal function.\n\ @end deftypefn") { octave_value_list retval; const int nargin = args.length (); if (nargin > 0) warning ("profiler_data: ignoring extra arguments"); retval(0) = profiler.get_data (); return retval; }