00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #include <iostream>
00028
00029 #include "defun.h"
00030 #include "oct-time.h"
00031 #include "ov-struct.h"
00032 #include "pager.h"
00033 #include "profiler.h"
00034
00035 profile_data_accumulator::enter::enter (profile_data_accumulator& a,
00036 const std::string& f)
00037 : acc (a)
00038 {
00039 if (acc.is_active ())
00040 {
00041 fcn = f;
00042 acc.enter_function (fcn);
00043 }
00044 else
00045 fcn = "";
00046 }
00047
00048 profile_data_accumulator::enter::~enter ()
00049 {
00050 if (fcn != "")
00051 acc.exit_function (fcn);
00052 }
00053
00054 profile_data_accumulator::stats::stats ()
00055 : time (0.0), calls (0), recursive (false),
00056 parents (), children ()
00057 {}
00058
00059 octave_value
00060 profile_data_accumulator::stats::function_set_value (const function_set& list)
00061 {
00062 const octave_idx_type n = list.size ();
00063
00064 RowVector retval (n);
00065 octave_idx_type i = 0;
00066 for (function_set::const_iterator p = list.begin (); p != list.end (); ++p)
00067 {
00068 retval(i) = *p;
00069 ++i;
00070 }
00071 assert (i == n);
00072
00073 return retval;
00074 }
00075
00076 profile_data_accumulator::tree_node::tree_node (tree_node* p, octave_idx_type f)
00077 : parent (p), fcn_id (f), children (), time (0.0), calls (0)
00078 {}
00079
00080 profile_data_accumulator::tree_node::~tree_node ()
00081 {
00082 for (child_map::iterator i = children.begin (); i != children.end (); ++i)
00083 delete i->second;
00084 }
00085
00086 profile_data_accumulator::tree_node*
00087 profile_data_accumulator::tree_node::enter (octave_idx_type fcn)
00088 {
00089 tree_node* retval;
00090
00091 child_map::iterator pos = children.find (fcn);
00092 if (pos == children.end ())
00093 {
00094 retval = new tree_node (this, fcn);
00095 children[fcn] = retval;
00096 }
00097 else
00098 retval = pos->second;
00099
00100 ++retval->calls;
00101 return retval;
00102 }
00103
00104 profile_data_accumulator::tree_node*
00105 profile_data_accumulator::tree_node::exit (octave_idx_type fcn)
00106 {
00107 assert (parent);
00108 assert (fcn_id == fcn);
00109
00110 return parent;
00111 }
00112
00113 void
00114 profile_data_accumulator::tree_node::build_flat (flat_profile& data) const
00115 {
00116
00117 if (fcn_id != 0)
00118 {
00119 stats& entry = data[fcn_id - 1];
00120
00121 entry.time += time;
00122 entry.calls += calls;
00123
00124 assert (parent);
00125 if (parent->fcn_id != 0)
00126 {
00127 entry.parents.insert (parent->fcn_id);
00128 data[parent->fcn_id - 1].children.insert (fcn_id);
00129 }
00130
00131 if (!entry.recursive)
00132 for (const tree_node* i = parent; i; i = i->parent)
00133 if (i->fcn_id == fcn_id)
00134 {
00135 entry.recursive = true;
00136 break;
00137 }
00138 }
00139
00140
00141 for (child_map::const_iterator i = children.begin ();
00142 i != children.end (); ++i)
00143 i->second->build_flat (data);
00144 }
00145
00146 octave_value
00147 profile_data_accumulator::tree_node::get_hierarchical (double* total) const
00148 {
00149
00150
00151
00152
00153
00154 const octave_idx_type n = children.size ();
00155
00156 Cell rv_indices (n, 1);
00157 Cell rv_times (n, 1);
00158 Cell rv_totals (n, 1);
00159 Cell rv_calls (n, 1);
00160 Cell rv_children (n, 1);
00161
00162 octave_idx_type i = 0;
00163 for (child_map::const_iterator p = children.begin ();
00164 p != children.end (); ++p)
00165 {
00166 const tree_node& entry = *p->second;
00167 double child_total = entry.time;
00168
00169 rv_indices(i) = octave_value (p->first);
00170 rv_times(i) = octave_value (entry.time);
00171 rv_calls(i) = octave_value (entry.calls);
00172 rv_children(i) = entry.get_hierarchical (&child_total);
00173 rv_totals(i) = octave_value (child_total);
00174
00175 if (total)
00176 *total += child_total;
00177
00178 ++i;
00179 }
00180 assert (i == n);
00181
00182 octave_map retval;
00183
00184 retval.assign ("Index", rv_indices);
00185 retval.assign ("SelfTime", rv_times);
00186 retval.assign ("TotalTime", rv_totals);
00187 retval.assign ("NumCalls", rv_calls);
00188 retval.assign ("Children", rv_children);
00189
00190 return retval;
00191 }
00192
00193 profile_data_accumulator::profile_data_accumulator ()
00194 : known_functions (), fcn_index (),
00195 enabled (false), call_tree (NULL), last_time (-1.0)
00196 {}
00197
00198 profile_data_accumulator::~profile_data_accumulator ()
00199 {
00200 if (call_tree)
00201 delete call_tree;
00202 }
00203
00204 void
00205 profile_data_accumulator::set_active (bool value)
00206 {
00207 if (value)
00208 {
00209
00210 if (!call_tree)
00211 call_tree = new tree_node (NULL, 0);
00212
00213
00214
00215 active_fcn = call_tree;
00216 }
00217 else
00218 {
00219
00220 last_time = -1.0;
00221 }
00222
00223 enabled = value;
00224 }
00225
00226 void
00227 profile_data_accumulator::enter_function (const std::string& fcn)
00228 {
00229
00230 assert (is_active ());
00231 assert (call_tree);
00232
00233
00234
00235 if (active_fcn != call_tree)
00236 add_current_time ();
00237
00238
00239 octave_idx_type fcn_idx;
00240 fcn_index_map::iterator pos = fcn_index.find (fcn);
00241 if (pos == fcn_index.end ())
00242 {
00243 known_functions.push_back (fcn);
00244 fcn_idx = known_functions.size ();
00245 fcn_index[fcn] = fcn_idx;
00246 }
00247 else
00248 fcn_idx = pos->second;
00249
00250 active_fcn = active_fcn->enter (fcn_idx);
00251 last_time = query_time ();
00252 }
00253
00254 void
00255 profile_data_accumulator::exit_function (const std::string& fcn)
00256 {
00257 assert (call_tree);
00258 assert (active_fcn != call_tree);
00259
00260
00261
00262
00263 if (is_active ())
00264 add_current_time ();
00265
00266 fcn_index_map::iterator pos = fcn_index.find (fcn);
00267 assert (pos != fcn_index.end ());
00268 active_fcn = active_fcn->exit (pos->second);
00269
00270
00271
00272 last_time = query_time ();
00273 }
00274
00275 void
00276 profile_data_accumulator::reset (void)
00277 {
00278 if (is_active ())
00279 {
00280 error ("Can't reset active profiler.");
00281 return;
00282 }
00283
00284 known_functions.clear ();
00285 fcn_index.clear ();
00286
00287 if (call_tree)
00288 {
00289 delete call_tree;
00290 call_tree = NULL;
00291 }
00292
00293 last_time = -1.0;
00294 }
00295
00296 octave_value
00297 profile_data_accumulator::get_flat (void) const
00298 {
00299 octave_value retval;
00300
00301 const octave_idx_type n = known_functions.size ();
00302
00303 flat_profile flat (n);
00304
00305 if (call_tree)
00306 {
00307 call_tree->build_flat (flat);
00308
00309 Cell rv_names (n, 1);
00310 Cell rv_times (n, 1);
00311 Cell rv_calls (n, 1);
00312 Cell rv_recursive (n, 1);
00313 Cell rv_parents (n, 1);
00314 Cell rv_children (n, 1);
00315
00316 for (octave_idx_type i = 0; i != n; ++i)
00317 {
00318 rv_names(i) = octave_value (known_functions[i]);
00319 rv_times(i) = octave_value (flat[i].time);
00320 rv_calls(i) = octave_value (flat[i].calls);
00321 rv_recursive(i) = octave_value (flat[i].recursive);
00322 rv_parents(i) = stats::function_set_value (flat[i].parents);
00323 rv_children(i) = stats::function_set_value (flat[i].children);
00324 }
00325
00326 octave_map m;
00327
00328 m.assign ("FunctionName", rv_names);
00329 m.assign ("TotalTime", rv_times);
00330 m.assign ("NumCalls", rv_calls);
00331 m.assign ("IsRecursive", rv_recursive);
00332 m.assign ("Parents", rv_parents);
00333 m.assign ("Children", rv_children);
00334
00335 retval = m;
00336 }
00337 else
00338 {
00339 static const char *fn[] =
00340 {
00341 "FunctionName",
00342 "TotalTime",
00343 "NumCalls",
00344 "IsRecursive",
00345 "Parents",
00346 "Children",
00347 0
00348 };
00349
00350 static octave_map m (dim_vector (0, 1), string_vector (fn));
00351
00352 retval = m;
00353 }
00354
00355 return retval;
00356 }
00357
00358 octave_value
00359 profile_data_accumulator::get_hierarchical (void) const
00360 {
00361 octave_value retval;
00362
00363 if (call_tree)
00364 retval = call_tree->get_hierarchical ();
00365 else
00366 {
00367 static const char *fn[] =
00368 {
00369 "Index",
00370 "SelfTime",
00371 "NumCalls",
00372 "Children",
00373 0
00374 };
00375
00376 static octave_map m (dim_vector (0, 1), string_vector (fn));
00377
00378 retval = m;
00379 }
00380
00381 return retval;
00382 }
00383
00384 double
00385 profile_data_accumulator::query_time (void) const
00386 {
00387 octave_time now;
00388
00389
00390
00391 volatile double dnow = now.double_value ();
00392
00393 return dnow;
00394 }
00395
00396 void
00397 profile_data_accumulator::add_current_time (void)
00398 {
00399 const double t = query_time ();
00400 assert (last_time >= 0.0 && last_time <= t);
00401
00402 assert (call_tree && active_fcn != call_tree);
00403 active_fcn->add_time (t - last_time);
00404 }
00405
00406 profile_data_accumulator profiler;
00407
00408
00409 DEFUN (__profiler_enable__, args, ,
00410 "-*- texinfo -*-\n\
00411 @deftypefn {Function File} __profiler_enable ()\n\
00412 Undocumented internal function.\n\
00413 @end deftypefn")
00414 {
00415 octave_value_list retval;
00416
00417 const int nargin = args.length ();
00418 if (nargin > 0)
00419 {
00420 if (nargin > 1)
00421 {
00422 print_usage ();
00423 return retval;
00424 }
00425
00426 profiler.set_active (args(0).bool_value ());
00427 }
00428
00429 retval(0) = profiler.is_active ();
00430
00431 return retval;
00432 }
00433
00434
00435 DEFUN (__profiler_reset__, args, ,
00436 "-*- texinfo -*-\n\
00437 @deftypefn {Function File} __profiler_reset ()\n\
00438 Undocumented internal function.\n\
00439 @end deftypefn")
00440 {
00441 octave_value_list retval;
00442 const int nargin = args.length ();
00443
00444 if (nargin > 0)
00445 warning ("profiler_reset: ignoring extra arguments");
00446
00447 profiler.reset ();
00448
00449 return retval;
00450 }
00451
00452
00453 DEFUN (__profiler_data__, args, nargout,
00454 "-*- texinfo -*-\n\
00455 @deftypefn {Function File} __profiler_data ()\n\
00456 Undocumented internal function.\n\
00457 @end deftypefn")
00458 {
00459 octave_value_list retval;
00460 const int nargin = args.length ();
00461
00462 if (nargin > 0)
00463 warning ("profiler_data: ignoring extra arguments");
00464
00465 retval(0) = profiler.get_flat ();
00466 if (nargout > 1)
00467 retval(1) = profiler.get_hierarchical ();
00468
00469 return retval;
00470 }