GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
profiler.h
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2014-2017 Julien Bect
4 Copyright (C) 2012-2016 Daniel Kraft
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if ! defined (octave_profiler_h)
25 #define octave_profiler_h 1
26 
27 #include "octave-config.h"
28 
29 #include <cstddef>
30 #include <map>
31 #include <set>
32 #include <string>
33 #include <vector>
34 
35 class octave_value;
36 
37 class
40 {
41 public:
42 
43  // This is a utility class that can be used to call the enter/exit
44  // functions in a manner protected from stack unwinding.
45  template <typename T> class enter
46  {
47  private:
48 
51  bool is_active;
52 
53  public:
54 
55  enter (profile_data_accumulator& a, const T& t) : acc (a)
56  {
57  // A profiling block cannot be active if the profiler is not
58  is_active = acc.is_active ();
59 
60  if (is_active)
61  {
62  fcn = t.profiler_name ();
63 
64  // NOTE: The test f != "" must be kept to prevent a blank line showing
65  // up in profiler statistics. See bug #39524. The root cause is that
66  // the function name is not set for the recurring readline hook function.
67  if (fcn == "")
68  is_active = false; // Inactive profiling block
69  else
70  acc.enter_function (fcn);
71  }
72  }
73 
74  ~enter ()
75  {
76  if (is_active)
77  acc.exit_function (fcn);
78  }
79 
80  private:
81 
82  // No copying!
83  enter (const enter&);
84  enter& operator = (const enter&);
85  };
86 
88  virtual ~profile_data_accumulator ();
89 
90  bool is_active (void) const { return enabled; }
91  void set_active (bool);
92 
93  void reset (void);
94 
95  octave_value get_flat (void) const;
96  octave_value get_hierarchical (void) const;
97 
98 private:
99 
100  // One entry in the flat profile (i.e., a collection of data for a single
101  // function). This is filled in when building the flat profile from the
102  // hierarchical call tree.
103  struct stats
104  {
105  stats ();
106 
107  double time;
108  unsigned calls;
109 
110  bool recursive;
111 
112  typedef std::set<octave_idx_type> function_set;
113  function_set parents;
114  function_set children;
115 
116  // Convert a function_set list to an Octave array of indices.
117  static octave_value function_set_value (const function_set&);
118  };
119 
120  typedef std::vector<stats> flat_profile;
121 
122  // Store data for one node in the call-tree of the hierarchical profiler
123  // data we collect.
124  class tree_node
125  {
126  public:
127 
129  virtual ~tree_node ();
130 
131  void add_time (double dt) { time += dt; }
132 
133  // Enter a child function. It is created in the list of children if it
134  // wasn't already there. The now-active child node is returned.
136 
137  // Exit function. As a sanity-check, it is verified that the currently
138  // active function actually is the one handed in here. Returned is the
139  // then-active node, which is our parent.
140  tree_node* exit (octave_idx_type);
141 
142  void build_flat (flat_profile&) const;
143 
144  // Get the hierarchical profile for this node and its children. If total
145  // is set, accumulate total time of the subtree in that variable as
146  // additional return value.
147  octave_value get_hierarchical (double* total = 0) const;
148 
149  private:
150 
153 
154  typedef std::map<octave_idx_type, tree_node*> child_map;
155  child_map children;
156 
157  // This is only time spent *directly* on this level, excluding children!
158  double time;
159 
160  unsigned calls;
161 
162  // No copying!
163  tree_node (const tree_node&);
164  tree_node& operator = (const tree_node&);
165  };
166 
167  // Each function we see in the profiler is given a unique index (which
168  // simply counts starting from 1). We thus have to map profiler-names to
169  // those indices. For all other stuff, we identify functions by their index.
170 
171  typedef std::vector<std::string> function_set;
172  typedef std::map<std::string, octave_idx_type> fcn_index_map;
173 
174  function_set known_functions;
175  fcn_index_map fcn_index;
176 
177  bool enabled;
178 
181 
182  // Store last timestamp we had, when the currently active function was called.
183  double last_time;
184 
185  // These are private as only the unwind-protecting inner class enter
186  // should be allowed to call them.
187  void enter_function (const std::string&);
188  void exit_function (const std::string&);
189 
190  // Query a timestamp, used for timing calls (obviously).
191  // This is not static because in the future, maybe we want a flag
192  // in the profiler or something to choose between cputime, wall-time,
193  // user-time, system-time, ...
194  double query_time () const;
195 
196  // Add the time elapsed since last_time to the function we're currently in.
197  // This is called from two different positions, thus it is useful to have
198  // it as a seperate function.
199  void add_current_time (void);
200 
201  // No copying!
204 };
205 
206 // The instance used.
208 
209 // Helper macro to profile a block of code.
210 
211 #define BEGIN_PROFILER_BLOCK(classname) \
212  { \
213  profile_data_accumulator::enter<classname> pe (profiler, *this);
214 
215 #define END_PROFILER_BLOCK \
216  } // end of block => call pe's destructor
217 
218 #endif
function_set known_functions
Definition: profiler.h:174
std::map< std::string, octave_idx_type > fcn_index_map
Definition: profiler.h:172
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:935
enter(profile_data_accumulator &a, const T &t)
Definition: profiler.h:55
tree_node * call_tree
Definition: profiler.h:179
bool is_active(void) const
Definition: profiler.h:90
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:398
std::vector< std::string > function_set
Definition: profiler.h:171
#define OCTINTERP_API
Definition: mexproto.h:69
std::vector< stats > flat_profile
Definition: profiler.h:120
fcn_index_map fcn_index
Definition: profiler.h:175
void exit_function(const std::string &)
Definition: profiler.cc:228
std::set< octave_idx_type > function_set
Definition: profiler.h:112
OCTINTERP_API profile_data_accumulator profiler
Definition: profiler.cc:385
std::map< octave_idx_type, tree_node * > child_map
Definition: profiler.h:154
void enter_function(const std::string &)
Definition: profiler.cc:195
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
profile_data_accumulator & acc
Definition: profiler.h:49
tree_node * active_fcn
Definition: profiler.h:180