# HG changeset patch
# User Julien Bect <julien.bect@supelec.fr>
# Date 1403541992 -7200
#      lun. juin 23 18:46:32 2014 +0200
# Node ID 50c4fa2f07ce079d33e084cdfdee31996d26e5da
# Parent  50922b1c74df83761a2612e6c80715965c8c40ac
Reduce profiling overhead using inlining and templates.

* profiler.cc (profile_data_accumulator::enter::enter): Remove function.

* profiler.h: Make class "enter" a templated class.  Have enter constructor
check whether profiling is active before calling the expensive profiler_name()
function.  Redefine BEGIN_PROFILER_BLOCK macro to call
profile_data_accumulator::enter with a classname argument to template.

* ov-builtin.cc (octave_builtin::do_multi_index_op): Use new
BEGIN_PROFILER_BLOCK macro.

* ov-mex-fcn.cc (octave_mex_function::do_multi_index_op): Use new
BEGIN_PROFILER_BLOCK macro.

* ov-usr-fcn.cc (octave_user_script::do_multi_index_op,
octave_user_function::do_multi_index_op): Use new BEGIN_PROFILER_BLOCK macro.

* pt-binop.cc (tree_binary_expression::rvalue1): Use new BEGIN_PROFILER_BLOCK
macro.

* pt-binop.h (profiler_name): New function to return profiler name for class
tree_binary_expression.

* pt-unop.cc (tree_prefix_expression::rvalue1,
tree_postfix_expression::rvalue1): Use new BEGIN_PROFILER_BLOCK macro.

* pt-binop.h (profiler_name): New function to return profiler name for class
tree_prefix_expression and tree_postfix_expression.

diff -r 50922b1c74df -r 50c4fa2f07ce libinterp/corefcn/profiler.cc
--- a/libinterp/corefcn/profiler.cc	lun. nov. 10 23:11:20 2014 +0000
+++ b/libinterp/corefcn/profiler.cc	lun. juin 23 18:46:32 2014 +0200
@@ -1,5 +1,6 @@
 /*
 
+Copyright (C) 2014 Julien Bect
 Copyright (C) 2012-2013 Daniel Kraft
 
 This file is part of Octave.
@@ -32,29 +33,6 @@
 #include "pager.h"
 #include "profiler.h"
 
-profile_data_accumulator::enter::enter (profile_data_accumulator& a,
-                                        const std::string& f)
-  : acc (a)
-{
-  // FIXME: Add test for f != "" to prevent a blank line showing up
-  //        in profiler statistics.  See bug #39524.  The root cause
-  //        is that the function name is not set for the recurring readline
-  //        hook function.
-  if (acc.is_active () && f != "")
-    {
-      fcn = f;
-      acc.enter_function (fcn);
-    }
-  else
-    fcn = "";
-}
-
-profile_data_accumulator::enter::~enter ()
-{
-  if (fcn != "")
-    acc.exit_function (fcn);
-}
-
 profile_data_accumulator::stats::stats ()
   : time (0.0), calls (0), recursive (false),
     parents (), children ()
diff -r 50922b1c74df -r 50c4fa2f07ce libinterp/corefcn/profiler.h
--- a/libinterp/corefcn/profiler.h	lun. nov. 10 23:11:20 2014 +0000
+++ b/libinterp/corefcn/profiler.h	lun. juin 23 18:46:32 2014 +0200
@@ -1,5 +1,6 @@
 /*
 
+Copyright (C) 2014 Julien Bect
 Copyright (C) 2012-2013 Daniel Kraft
 
 This file is part of Octave.
@@ -39,17 +40,40 @@
 
   // This is a utility class that can be used to call the enter/exit
   // functions in a manner protected from stack unwinding.
-  class enter
+  template<class T> class enter
   {
   private:
 
     profile_data_accumulator& acc;
     std::string fcn;
+    bool is_active;
 
   public:
 
-    enter (profile_data_accumulator&, const std::string&);
-    virtual ~enter (void);
+    enter (profile_data_accumulator& a, const T& t) : acc (a)
+    {
+      // A profiling block cannot be active if the profiler is not
+      is_active = acc.is_active ();
+
+      if (is_active)
+        {
+          fcn = t.profiler_name ();
+
+          // NOTE: The test f != "" must be kept to prevent a blank line showing
+          //  up in profiler statistics.  See bug #39524.  The root cause is that
+          //  the function name is not set for the recurring readline hook function.
+          if (fcn == "")
+            is_active = false;  // Inactive profiling block
+          else
+            acc.enter_function (fcn);
+        }
+    }
+
+    ~enter ()
+    {
+      if (is_active)
+        acc.exit_function (fcn);
+    }
 
   private:
 
@@ -181,10 +205,12 @@
 extern OCTINTERP_API profile_data_accumulator profiler;
 
 // Helper macro to profile a block of code.
-#define BEGIN_PROFILER_BLOCK(name) \
+
+#define BEGIN_PROFILER_BLOCK(classname)	\
   { \
-    profile_data_accumulator::enter pe (profiler, (name));
+    profile_data_accumulator::enter<classname> pe (profiler, *this);
+
 #define END_PROFILER_BLOCK \
-  }
+  }  // end of block => call pe's destructor
 
 #endif
diff -r 50922b1c74df -r 50c4fa2f07ce libinterp/octave-value/ov-builtin.cc
--- a/libinterp/octave-value/ov-builtin.cc	lun. nov. 10 23:11:20 2014 +0000
+++ b/libinterp/octave-value/ov-builtin.cc	lun. juin 23 18:46:32 2014 +0200
@@ -127,7 +127,7 @@
 
       try
         {
-          BEGIN_PROFILER_BLOCK (profiler_name ())
+          BEGIN_PROFILER_BLOCK (octave_builtin)
 
           retval = (*f) (args, nargout);
           // Do not allow null values to be returned from functions.
diff -r 50922b1c74df -r 50c4fa2f07ce libinterp/octave-value/ov-mex-fcn.cc
--- a/libinterp/octave-value/ov-mex-fcn.cc	lun. nov. 10 23:11:20 2014 +0000
+++ b/libinterp/octave-value/ov-mex-fcn.cc	lun. juin 23 18:46:32 2014 +0200
@@ -148,8 +148,10 @@
 
       try
         {
-          BEGIN_PROFILER_BLOCK (profiler_name ())
+          BEGIN_PROFILER_BLOCK (octave_mex_function)
+
           retval = call_mex (have_fmex, mex_fcn_ptr, args, nargout, this);
+
           END_PROFILER_BLOCK
         }
       catch (octave_execution_exception)
diff -r 50922b1c74df -r 50c4fa2f07ce libinterp/octave-value/ov-usr-fcn.cc
--- a/libinterp/octave-value/ov-usr-fcn.cc	lun. nov. 10 23:11:20 2014 +0000
+++ b/libinterp/octave-value/ov-usr-fcn.cc	lun. juin 23 18:46:32 2014 +0200
@@ -149,8 +149,10 @@
                   frame.protect_var (tree_evaluator::statement_context);
                   tree_evaluator::statement_context = tree_evaluator::script;
 
-                  BEGIN_PROFILER_BLOCK (profiler_name ())
+                  BEGIN_PROFILER_BLOCK (octave_user_script)
+
                   cmd_list->accept (*current_evaluator);
+
                   END_PROFILER_BLOCK
 
                   if (tree_return_command::returning)
@@ -614,7 +616,7 @@
   frame.protect_var (tree_evaluator::statement_context);
   tree_evaluator::statement_context = tree_evaluator::function;
 
-  BEGIN_PROFILER_BLOCK (profiler_name ())
+  BEGIN_PROFILER_BLOCK (octave_user_function)
 
   if (is_special_expr ())
     {
diff -r 50922b1c74df -r 50c4fa2f07ce libinterp/parse-tree/pt-binop.cc
--- a/libinterp/parse-tree/pt-binop.cc	lun. nov. 10 23:11:20 2014 +0000
+++ b/libinterp/parse-tree/pt-binop.cc	lun. juin 23 18:46:32 2014 +0200
@@ -135,7 +135,7 @@
 
           if (! error_state && b.is_defined ())
             {
-              BEGIN_PROFILER_BLOCK ("binary " + oper ())
+              BEGIN_PROFILER_BLOCK (tree_binary_expression)
 
               // Note: The profiler does not catch the braindead
               // short-circuit evaluation code above, but that should be
diff -r 50922b1c74df -r 50c4fa2f07ce libinterp/parse-tree/pt-binop.h
--- a/libinterp/parse-tree/pt-binop.h	lun. nov. 10 23:11:20 2014 +0000
+++ b/libinterp/parse-tree/pt-binop.h	lun. juin 23 18:46:32 2014 +0200
@@ -100,6 +100,9 @@
 
   void accept (tree_walker& tw);
 
+  std::string profiler_name (void) const { return "binary " + oper (); }
+
+
 protected:
 
   // The operands for the expression.
diff -r 50922b1c74df -r 50c4fa2f07ce libinterp/parse-tree/pt-unop.cc
--- a/libinterp/parse-tree/pt-unop.cc	lun. nov. 10 23:11:20 2014 +0000
+++ b/libinterp/parse-tree/pt-unop.cc	lun. juin 23 18:46:32 2014 +0200
@@ -73,8 +73,8 @@
 
           if (! error_state)
             {
-              BEGIN_PROFILER_BLOCK ("prefix " + oper ())
-
+              BEGIN_PROFILER_BLOCK (tree_prefix_expression)
+              
               ref.do_unary_op (etype);
 
               if (! error_state)
@@ -89,7 +89,7 @@
 
           if (! error_state && val.is_defined ())
             {
-              BEGIN_PROFILER_BLOCK ("prefix " + oper ())
+              BEGIN_PROFILER_BLOCK (tree_prefix_expression)
 
               // Attempt to do the operation in-place if it is unshared
               // (a temporary expression).
@@ -101,7 +101,7 @@
               if (error_state)
                 retval = octave_value ();
 
-              END_PROFILER_BLOCK
+              END_PROFILER_BLOCK;
             }
         }
     }
@@ -162,9 +162,11 @@
             {
               retval = ref.value ();
 
-              BEGIN_PROFILER_BLOCK ("postfix " + oper ())
+              BEGIN_PROFILER_BLOCK (tree_postfix_expression)
+
               ref.do_unary_op (etype);
-              END_PROFILER_BLOCK
+
+              END_PROFILER_BLOCK;
             }
         }
       else
@@ -173,14 +175,14 @@
 
           if (! error_state && val.is_defined ())
             {
-              BEGIN_PROFILER_BLOCK ("postfix " + oper ())
+              BEGIN_PROFILER_BLOCK (tree_postfix_expression)
 
               retval = ::do_unary_op (etype, val);
 
               if (error_state)
                 retval = octave_value ();
 
-              END_PROFILER_BLOCK
+              END_PROFILER_BLOCK;
             }
         }
     }
diff -r 50922b1c74df -r 50c4fa2f07ce libinterp/parse-tree/pt-unop.h
--- a/libinterp/parse-tree/pt-unop.h	lun. nov. 10 23:11:20 2014 +0000
+++ b/libinterp/parse-tree/pt-unop.h	lun. juin 23 18:46:32 2014 +0200
@@ -108,6 +108,9 @@
 
   void accept (tree_walker& tw);
 
+  std::string profiler_name (void) const { return "prefix " + oper (); }
+
+
 private:
 
   // No copying!
@@ -145,6 +148,8 @@
 
   void accept (tree_walker& tw);
 
+  std::string profiler_name (void) const { return "postfix " + oper (); }
+
 private:
 
   // No copying!
