00001 /* 00002 00003 Copyright (C) 2012 Daniel Kraft 00004 00005 This file is part of Octave. 00006 00007 Octave is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License as published by the 00009 Free Software Foundation; either version 3 of the License, or (at your 00010 option) any later version. 00011 00012 Octave is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00015 for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with Octave; see the file COPYING. If not, see 00019 <http://www.gnu.org/licenses/>. 00020 00021 */ 00022 00023 #if !defined (octave_profiler_h) 00024 #define octave_profiler_h 1 00025 00026 #include <cstddef> 00027 #include <map> 00028 #include <set> 00029 #include <string> 00030 #include <vector> 00031 00032 class octave_value; 00033 00034 class 00035 OCTINTERP_API 00036 profile_data_accumulator 00037 { 00038 public: 00039 00040 // This is a utility class that can be used to call the enter/exit 00041 // functions in a manner protected from stack unwinding. 00042 class enter 00043 { 00044 private: 00045 00046 profile_data_accumulator& acc; 00047 std::string fcn; 00048 00049 public: 00050 00051 enter (profile_data_accumulator&, const std::string&); 00052 virtual ~enter (void); 00053 00054 private: 00055 00056 // No copying! 00057 enter (const enter&); 00058 enter& operator = (const enter&); 00059 }; 00060 00061 profile_data_accumulator (void); 00062 virtual ~profile_data_accumulator (); 00063 00064 bool is_active (void) const { return enabled; } 00065 void set_active (bool); 00066 00067 void reset (void); 00068 00069 octave_value get_flat (void) const; 00070 octave_value get_hierarchical (void) const; 00071 00072 private: 00073 00074 // One entry in the flat profile (i.e., a collection of data for a single 00075 // function). This is filled in when building the flat profile from the 00076 // hierarchical call tree. 00077 struct stats 00078 { 00079 stats (); 00080 00081 double time; 00082 unsigned calls; 00083 00084 bool recursive; 00085 00086 typedef std::set<octave_idx_type> function_set; 00087 function_set parents; 00088 function_set children; 00089 00090 // Convert a function_set list to an Octave array of indices. 00091 static octave_value function_set_value (const function_set&); 00092 }; 00093 00094 typedef std::vector<stats> flat_profile; 00095 00096 // Store data for one node in the call-tree of the hierarchical profiler 00097 // data we collect. 00098 class tree_node 00099 { 00100 public: 00101 00102 tree_node (tree_node*, octave_idx_type); 00103 virtual ~tree_node (); 00104 00105 void add_time (double dt) { time += dt; } 00106 00107 // Enter a child function. It is created in the list of children if it 00108 // wasn't already there. The now-active child node is returned. 00109 tree_node* enter (octave_idx_type); 00110 00111 // Exit function. As a sanity-check, it is verified that the currently 00112 // active function actually is the one handed in here. Returned is the 00113 // then-active node, which is our parent. 00114 tree_node* exit (octave_idx_type); 00115 00116 void build_flat (flat_profile&) const; 00117 00118 // Get the hierarchical profile for this node and its children. If total 00119 // is set, accumulate total time of the subtree in that variable as 00120 // additional return value. 00121 octave_value get_hierarchical (double* total = NULL) const; 00122 00123 private: 00124 00125 tree_node* parent; 00126 octave_idx_type fcn_id; 00127 00128 typedef std::map<octave_idx_type, tree_node*> child_map; 00129 child_map children; 00130 00131 // This is only time spent *directly* on this level, excluding children! 00132 double time; 00133 00134 unsigned calls; 00135 00136 // No copying! 00137 tree_node (const tree_node&); 00138 tree_node& operator = (const tree_node&); 00139 }; 00140 00141 // Each function we see in the profiler is given a unique index (which 00142 // simply counts starting from 1). We thus have to map profiler-names to 00143 // those indices. For all other stuff, we identify functions by their index. 00144 00145 typedef std::vector<std::string> function_set; 00146 typedef std::map<std::string, octave_idx_type> fcn_index_map; 00147 00148 function_set known_functions; 00149 fcn_index_map fcn_index; 00150 00151 bool enabled; 00152 00153 tree_node* call_tree; 00154 tree_node* active_fcn; 00155 00156 // Store last timestamp we had, when the currently active function was called. 00157 double last_time; 00158 00159 // These are private as only the unwind-protecting inner class enter 00160 // should be allowed to call them. 00161 void enter_function (const std::string&); 00162 void exit_function (const std::string&); 00163 00164 // Query a timestamp, used for timing calls (obviously). 00165 // This is not static because in the future, maybe we want a flag 00166 // in the profiler or something to choose between cputime, wall-time, 00167 // user-time, system-time, ... 00168 double query_time () const; 00169 00170 // Add the time elapsed since last_time to the function we're currently in. 00171 // This is called from two different positions, thus it is useful to have 00172 // it as a seperate function. 00173 void add_current_time (void); 00174 00175 // No copying! 00176 profile_data_accumulator (const profile_data_accumulator&); 00177 profile_data_accumulator& operator = (const profile_data_accumulator&); 00178 }; 00179 00180 // The instance used. 00181 extern OCTINTERP_API profile_data_accumulator profiler; 00182 00183 // Helper macro to profile a block of code. 00184 #define BEGIN_PROFILER_BLOCK(name) \ 00185 { \ 00186 profile_data_accumulator::enter pe (profiler, (name)); 00187 #define END_PROFILER_BLOCK \ 00188 } 00189 00190 #endif