From a541c6b0e921681dbabd579b8f2ba712343ddad1 Mon Sep 17 00:00:00 2001
From: Gerardo Tauriello <gerardo.tauriello@unibas.ch>
Date: Mon, 23 May 2016 19:57:57 +0200
Subject: [PATCH] SCHWED-785: added scoped profiler for easier use.

---
 core/doc/index.rst                     | 11 ++++++++
 core/pymod/export_runtime_profiling.cc | 11 ++++++++
 core/src/runtime_profiling.hh          | 39 ++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/core/doc/index.rst b/core/doc/index.rst
index 6de77f72..ba72bef4 100644
--- a/core/doc/index.rst
+++ b/core/doc/index.rst
@@ -110,6 +110,17 @@ Runtime profiling
     :param level: Timer only started if level <= ``PM3_RUNTIME_PROFILING_LEVEL``
     :type level:  :class:`int`
 
+  .. staticmethod:: StartScoped(id, level=1)
+
+    Start a timer for the given `id` as in :meth:`Start`, but this will stop it
+    automatically when the returned variable goes out of scope.
+
+    :param id: Identifier for this timer.
+    :type id:  :class:`str`
+    :param level: Timer only started if level <= ``PM3_RUNTIME_PROFILING_LEVEL``
+    :type level:  :class:`int`
+    :return: Object that will call :meth:`Stop` when it goes out of scope
+
   .. staticmethod:: Stop(id, level=1)
 
     Stop the currently running timer. If a timer was paused when starting this
diff --git a/core/pymod/export_runtime_profiling.cc b/core/pymod/export_runtime_profiling.cc
index 92918357..5e25ceb8 100644
--- a/core/pymod/export_runtime_profiling.cc
+++ b/core/pymod/export_runtime_profiling.cc
@@ -1,4 +1,7 @@
 #include <boost/python.hpp>
+#include <boost/python/register_ptr_to_python.hpp>
+#include <boost/shared_ptr.hpp>
+
 #include <promod3/core/runtime_profiling.hh>
 
 using namespace promod3::core;
@@ -9,9 +12,16 @@ bool IsEnabled() { return (PM3_RUNTIME_PROFILING_LEVEL > 0); }
 }
 
 void export_runtime_profiling() {
+  
+  class_<ScopedRuntimeProfiler>("ScopedRuntimeProfiler", no_init);
+  register_ptr_to_python<ScopedRuntimeProfilerPtr>();
+
   class_<StaticRuntimeProfiler>("StaticRuntimeProfiler", no_init)
     .def("Start", &StaticRuntimeProfiler::Start, (arg("id"), arg("level")=1))
     .staticmethod("Start")
+    .def("StartScoped", &StaticRuntimeProfiler::StartScoped,
+         (arg("id"), arg("level")=1))
+    .staticmethod("StartScoped")
     .def("Stop", &StaticRuntimeProfiler::Stop, (arg("level")=1))
     .staticmethod("Stop")
     .def("PrintSummary", &StaticRuntimeProfiler::PrintSummary)
@@ -19,4 +29,5 @@ void export_runtime_profiling() {
     .def("IsEnabled", &IsEnabled)
     .staticmethod("IsEnabled")
   ;
+
 }
diff --git a/core/src/runtime_profiling.hh b/core/src/runtime_profiling.hh
index 67930003..3f6d2c42 100644
--- a/core/src/runtime_profiling.hh
+++ b/core/src/runtime_profiling.hh
@@ -8,15 +8,22 @@
 #include <iostream>
 #include <promod3/config.hh>
 #include <ost/base.hh>
+#include <boost/shared_ptr.hpp>
 
 // define dummies if PM3 profiling disabled
 #if PM3_RUNTIME_PROFILING_LEVEL==0 || defined(WIN32)
 
 namespace promod3 { namespace core {
 
+class ScopedRuntimeProfiler { };
+typedef boost::shared_ptr<ScopedRuntimeProfiler> ScopedRuntimeProfilerPtr;
+
 class StaticRuntimeProfiler {
 public:
   static void Start(const String& id, int level=1) { }
+  static ScopedRuntimeProfilerPtr StartScoped(const String& id, int level=1) {
+    return ScopedRuntimeProfilerPtr();
+  }
   static void Stop(int level=1) { }
   static void PrintSummary() { }
 };
@@ -90,6 +97,10 @@ private:
   uint num_runs_;
 };
 
+// fw decl. needed for RuntimeProfiler
+class ScopedRuntimeProfiler;
+typedef boost::shared_ptr<ScopedRuntimeProfiler> ScopedRuntimeProfilerPtr;
+
 /// \brief Keep track of multiple profiled entried (identified by a String).
 ///
 /// Usage:
@@ -123,6 +134,8 @@ public:
     watches_.back().second.Start();
   }
 
+  ScopedRuntimeProfilerPtr StartScoped(const String& id);
+
   // note: no check done! Something must have been running!
   void Stop() {
     // stop whatever is running
@@ -187,6 +200,25 @@ private:
   std::vector< std::pair<RuntimeProfilerEntry*, Stopwatch> > watches_;
 };
 
+/// \brief Helper for StartScoped
+class ScopedRuntimeProfiler {
+public:
+  ScopedRuntimeProfiler(RuntimeProfiler* rp, const String& id) {
+    rp_ = rp;
+    rp->Start(id);
+  }
+  ~ScopedRuntimeProfiler() {
+    rp_->Stop();
+  }
+private:
+  RuntimeProfiler* rp_;
+};
+
+// circular use RuntimeProfiler<->ScopedRuntimeProfiler, this must be here!
+inline ScopedRuntimeProfilerPtr RuntimeProfiler::StartScoped(const String& id) {
+  return ScopedRuntimeProfilerPtr(new ScopedRuntimeProfiler(this, id));
+}
+
 /// \brief Wrapper for RuntimeProfiler with static access.
 /// This makes sure we can remove all profiling stuff at compile-time.
 class StaticRuntimeProfiler {
@@ -194,6 +226,13 @@ public:
   static void Start(const String& id, int level=1) {
     if (level <= PM3_RUNTIME_PROFILING_LEVEL) { GetInstance_().Start(id); }
   }
+  static ScopedRuntimeProfilerPtr StartScoped(const String& id, int level=1) {
+    if (level <= PM3_RUNTIME_PROFILING_LEVEL) { 
+      return GetInstance_().StartScoped(id);
+    } else {
+      return ScopedRuntimeProfilerPtr();
+    }
+  }
   static void Stop(int level=1) {
     if (level <= PM3_RUNTIME_PROFILING_LEVEL) { GetInstance_().Stop(); }
   }
-- 
GitLab