GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
profiler.h
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2012-2026 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if ! defined (octave_profiler_h)
27#define octave_profiler_h 1
28
29#include "octave-config.h"
30
31#include <cstddef>
32#include <map>
33#include <set>
34#include <string>
35#include <vector>
36
37class octave_value;
38
40
41class OCTINTERP_API profiler
42{
43public:
44
45 // This is a utility class that can be used to call the enter/exit
46 // functions in a manner protected from stack unwinding.
47 template <typename T> class enter
48 {
49 public:
50
51 enter (profiler& p, const T& t) : m_profiler (p)
52 {
53 // A profiling block cannot be active if the profiler is not
54 m_enabled = m_profiler.enabled ();
55
56 if (m_enabled)
57 {
58 m_fcn = t.profiler_name ();
59
60 // NOTE: The test f != "" must be kept to prevent a blank
61 // line showing up in profiler statistics. See bug
62 // #39524. The root cause is that the function name is
63 // not set for the recurring readline hook function.
64 if (m_fcn == "")
65 m_enabled = false; // Inactive profiling block
66 else
67 m_profiler.enter_function (m_fcn);
68 }
69 }
70
71 OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (enter)
72
74 {
75 if (m_enabled)
76 m_profiler.exit_function (m_fcn);
77 }
78
79 private:
80
81 profiler& m_profiler;
82 std::string m_fcn;
83 bool m_enabled;
84 };
85
86 profiler ();
87
88 OCTAVE_DISABLE_COPY_MOVE (profiler)
89
90 virtual ~profiler ();
91
92 bool enabled () const { return m_enabled; }
93 void set_active (bool);
94
95 void reset ();
96
97 octave_value get_flat () const;
98 octave_value get_hierarchical () const;
99
100private:
101
102 // One entry in the flat profile (i.e., a collection of data for a single
103 // function). This is filled in when building the flat profile from the
104 // hierarchical call tree.
105 struct stats
106 {
107 public:
108
109 stats ();
110
111 OCTAVE_DEFAULT_COPY_MOVE_DELETE (stats)
112
113 typedef std::set<octave_idx_type> function_set;
114
115 // Convert a function_set list to an Octave array of indices.
116 static octave_value function_set_value (const function_set&);
117
118 //--------
119
120 double m_time;
121 std::size_t m_calls;
122
123 bool m_recursive;
124
125 function_set m_parents;
126 function_set m_children;
127 };
128
129 typedef std::vector<stats> flat_profile;
130
131 // Store data for one node in the call-tree of the hierarchical profiler
132 // data we collect.
133 class tree_node
134 {
135 public:
136
137 tree_node (tree_node *, octave_idx_type);
138
139 virtual ~tree_node ();
140
141 OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (tree_node)
142
143 void add_time (double dt) { m_time += dt; }
144
145 // Enter a child function. It is created in the list of children if it
146 // wasn't already there. The now-active child node is returned.
147 tree_node * enter (octave_idx_type);
148
149 // Exit function. As a sanity-check, it is verified that the currently
150 // active function actually is the one handed in here. Returned is the
151 // then-active node, which is our parent.
152 tree_node * exit (octave_idx_type);
153
154 void build_flat (flat_profile&) const;
155
156 // Get the hierarchical profile for this node and its children. If total
157 // is set, accumulate total time of the subtree in that variable as
158 // additional return value.
159 octave_value get_hierarchical (double *total = nullptr) const;
160
161 private:
162
163 tree_node *m_parent;
164 octave_idx_type m_fcn_id;
165
166 typedef std::map<octave_idx_type, tree_node *> child_map;
167 child_map m_children;
168
169 // This is only time spent *directly* on this level, excluding children!
170 double m_time;
171
172 std::size_t m_calls;
173 };
174
175 // These are private as only the unwind-protecting inner class enter
176 // should be allowed to call them.
177 void enter_function (const std::string&);
178 void exit_function (const std::string&);
179
180 // Query a timestamp, used for timing calls (obviously).
181 // This is not static because in the future, maybe we want a flag
182 // in the profiler or something to choose between cputime, wall-time,
183 // user-time, system-time, ...
184 double query_time () const;
185
186 // Add the time elapsed since last_time to the function we're currently in.
187 // This is called from two different positions, thus it is useful to have
188 // it as a separate function.
189 void add_current_time ();
190
191 //--------
192
193 // Each function we see in the profiler is given a unique index (which
194 // simply counts starting from 1). We thus have to map profiler-names to
195 // those indices. For all other stuff, we identify functions by their
196 // index.
197
198 typedef std::vector<std::string> function_set;
199 typedef std::map<std::string, octave_idx_type> fcn_index_map;
200
201 function_set m_known_functions;
202 fcn_index_map m_fcn_index;
203
204 bool m_enabled;
205
206 tree_node *m_call_tree;
207 tree_node *m_active_fcn;
208
209 // Store last timestamp we had, when the currently active function was
210 // called.
211 double m_last_time;
212};
213
214OCTAVE_END_NAMESPACE(octave)
215
216#endif
enter(profiler &p, const T &t)
Definition profiler.h:51
bool enabled() const
Definition profiler.h:92
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn