Skip to content
Snippets Groups Projects
Profiler.h 3.54 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Profiler.h
     *
     *  Created on: May 15, 2017
     *      Author: Martin Hierholzer
     */
    
    #ifndef CHIMERATK_PROFILER_H
    #define CHIMERATK_PROFILER_H
    
    
    #include <assert.h>
    
    #include <atomic>
    #include <chrono>
    #include <list>
    #include <mutex>
    
    #include <string>
    
      class Profiler {
       public:
        class ThreadData {
         public:
          /** Return the name of the thread */
          const std::string& getName() const { return name; }
    
          /** Return the integrated active time of the thread in microseconds. */
          uint64_t getIntegratedTime() const { return integratedTime; }
    
          /** Return the integrated active time of the thread in microseconds and
           * atomically reset the counter to 0. */
          uint64_t getAndResetIntegratedTime() {
            uint64_t time = integratedTime;
            integratedTime.fetch_sub(time);
            return time;
          }
    
         private:
          friend class Profiler;
    
          /** Copy of Application::threadName(), stored here to make it accessible
           * outside the thread */
          std::string name;
    
          /** Reference point for the time measurement */
          std::chrono::high_resolution_clock::time_point lastActiated;
    
          /** Flag whether this thread is currently active */
          bool isActive{false};
    
          /** Integrated time this thread was active in microseconds */
          std::atomic<uint64_t> integratedTime;
        };
    
        /** Register a thread in the profiler. This function must be called in each
         * thread before calling startMeasurement() and stopMeasurement() in the same
         * thread. The function must not be called twice in the same thread. The call
         * to this function implicitly triggers starting the time measurement (see
         * startMeasurement()) */
        static void registerThread(const std::string& name) {
          getThreadData().name = name;
          std::lock_guard<std::mutex> lock(threadDataList_mutex);
          threadDataList.emplace_back(&getThreadData());
          startMeasurement();
        }
    
        /** Obtain a list of ThreadData references for all threads registered with the
         * profiler. */
        static const std::list<ThreadData*>& getDataList() { return threadDataList; }
    
        /** Start the time measurement for the current thread. Call this immediately
         * after the thread woke up e.g. from blocking read. */
        static void startMeasurement() {
          if(getThreadData().isActive) return;
          getThreadData().isActive = true;
          getThreadData().lastActiated = std::chrono::high_resolution_clock::now();
    
        /** Stop the time measurement for the current thread. Call this right before
         * putting the thread to sleep e.g. before a blocking read. */
        static void stopMeasurement() {
          if(!getThreadData().isActive) return;
          getThreadData().isActive = false;
          auto duration = std::chrono::high_resolution_clock::now() - getThreadData().lastActiated;
          getThreadData().integratedTime += std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
        }
    
       private:
        /** Return the ThreadData object associated with the current thread. */
        static ThreadData& getThreadData() {
          thread_local static ThreadData data;
          return data;
        }
    
        /** List of ThreadData references registered with the profiler.  */
        static std::list<ThreadData*> threadDataList;
    
        /** Mutex for write access to the threadDataList member. Access to existing
         * list entries through the public member functions of ThreadData is allowed
         * without holding this mutex. */
        static std::mutex threadDataList_mutex;
    
    } // namespace ChimeraTK