profiler.h

Go to the documentation of this file.
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
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines