LCOV - code coverage report
Current view: top level - nntrainer/utils - profiler.h (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 0.0 % 19 0
Test Date: 2025-12-14 20:38:17 Functions: 0.0 % 4 0

            Line data    Source code
       1              : // SPDX-License-Identifier: Apache-2.0
       2              : /**
       3              :  * Copyright (C) 2020 Jihoon Lee <jhoon.it.lee@samsung.com>
       4              :  *
       5              :  * @file   profiler.h
       6              :  * @date   09 December 2020
       7              :  * @brief  Profiler related codes to be used to benchmark things
       8              :  * @see    https://github.com/nnstreamer/nntrainer
       9              :  * @author Jihoon Lee <jhoon.it.lee@samsung.com>
      10              :  * @bug    No known bugs except for NYI items
      11              :  *
      12              :  */
      13              : #ifndef __PROFILER_H__
      14              : #define __PROFILER_H__
      15              : 
      16              : #include <chrono>
      17              : #include <future>
      18              : #include <iosfwd>
      19              : #include <list>
      20              : #include <mutex>
      21              : #include <set>
      22              : #include <string>
      23              : #include <unordered_map>
      24              : #include <unordered_set>
      25              : #include <vector>
      26              : 
      27              : #include "singleton.h"
      28              : 
      29              : using timepoint = std::chrono::time_point<std::chrono::steady_clock>;
      30              : 
      31              : #ifndef PROFILE
      32              : 
      33              : #define PROFILE_TIME_START(event_key)
      34              : #define PROFILE_TIME_END(event_key)
      35              : #define PROFILE_TIME_REGISTER_EVENT(event_key, event_str)
      36              : #define PROFILE_MEM_ALLOC(ptr, size, str)
      37              : #define PROFILE_MEM_DEALLOC(ptr)
      38              : #define PROFILE_CACHE_ALLOC(ptr, size, str, policy, fsu)
      39              : #define PROFILE_CACHE_DEALLOC(ptr, policy, fsu)
      40              : #define PROFILE_BEGIN(listener)
      41              : #define PROFILE_END(listener)
      42              : #define PROFILE_MEM_ANNOTATE(str)
      43              : 
      44              : #else /** PROFILE */
      45              : 
      46              : #define PROFILE_TIME_START(event_key)                                          \
      47              :   nntrainer::profile::Profiler::Global().start(event_key)
      48              : 
      49              : #define PROFILE_TIME_END(event_key)                                            \
      50              :   nntrainer::profile::Profiler::Global().end(event_key)
      51              : 
      52              : #define PROFILE_TIME_REGISTER_EVENT(event_key, event_str)                      \
      53              :   do {                                                                         \
      54              :     event_key =                                                                \
      55              :       nntrainer::profile::Profiler::Global().registerTimeItem(event_str);      \
      56              :   } while (0)
      57              : 
      58              : #define PROFILE_MEM_ALLOC(ptr, size, str)                                      \
      59              :   nntrainer::profile::Profiler::Global().alloc(ptr, size, str)
      60              : 
      61              : #define PROFILE_MEM_DEALLOC(ptr)                                               \
      62              :   nntrainer::profile::Profiler::Global().dealloc(ptr)
      63              : 
      64              : #define PROFILE_CACHE_ALLOC(ptr, size, str, policy, fsu)                       \
      65              :   nntrainer::profile::Profiler::Global().alloc(ptr, size, str, policy, fsu)
      66              : 
      67              : #define PROFILE_CACHE_DEALLOC(ptr, policy, fsu)                                \
      68              :   nntrainer::profile::Profiler::Global().dealloc(ptr, policy, fsu)
      69              : 
      70              : #define PROFILE_BEGIN(listener)                                                \
      71              :   do {                                                                         \
      72              :     nntrainer::profile::Profiler::Global().subscribe(listener);                \
      73              :   } while (0)
      74              : 
      75              : #define PROFILE_END(listener)                                                  \
      76              :   do {                                                                         \
      77              :     std::cout << *listener;                                                    \
      78              :   } while (0)
      79              : 
      80              : #define PROFILE_MEM_ANNOTATE(str)                                              \
      81              :   nntrainer::profile::Profiler::Global().annotate(str)
      82              : 
      83              : #endif /** PROFILE */
      84              : 
      85              : namespace nntrainer {
      86              : 
      87              : namespace profile {
      88              : 
      89              : enum PROFILE_EVENT {
      90              :   EVENT_TIME_START = 0,
      91              :   EVENT_TIME_END = 1,
      92              :   EVENT_MEM_ALLOC = 2,
      93              :   EVENT_MEM_DEALLOC = 3,
      94              :   EVENT_MEM_ANNOTATE = 4,
      95              : };
      96              : 
      97              : /**
      98              :  * @brief Data for each profile event
      99              :  *
     100              :  */
     101            0 : struct ProfileEventData {
     102              : public:
     103              :   /**
     104              :    * @brief Construct a new ProfileEventData struct
     105              :    *
     106              :    */
     107            0 :   ProfileEventData(int item, size_t cur, size_t total, std::string str,
     108            0 :                    std::chrono::microseconds dur) :
     109            0 :     time_item(item),
     110            0 :     alloc_current(cur),
     111            0 :     alloc_total(total),
     112            0 :     cache_fsu(false),
     113            0 :     event_str(str),
     114            0 :     duration(dur) {}
     115              : 
     116              :   /**
     117              :    * @brief Construct a new ProfileEventData struct
     118              :    *
     119              :    */
     120            0 :   ProfileEventData(int item, size_t cur, size_t total, std::string str,
     121              :                    std::chrono::microseconds dur, std::string policy,
     122            0 :                    bool fsu) :
     123            0 :     time_item(item),
     124            0 :     alloc_current(cur),
     125            0 :     alloc_total(total),
     126            0 :     cache_policy(policy),
     127            0 :     cache_fsu(fsu),
     128            0 :     event_str(str),
     129            0 :     duration(dur) {}
     130              : 
     131              :   /* for time profile */
     132              :   int time_item;
     133              : 
     134              :   /* current allocation size */
     135              :   size_t alloc_current;
     136              : 
     137              :   /* total allocation size */
     138              :   size_t alloc_total;
     139              : 
     140              :   std::string cache_policy;
     141              :   bool cache_fsu;
     142              : 
     143              :   /* common data */
     144              :   std::string event_str;
     145              :   std::chrono::microseconds duration;
     146              : };
     147              : 
     148              : class Profiler;
     149              : 
     150              : /**
     151              :  * @brief Generic profile listener class to attach to a profiler,
     152              :  * this can be inherited to create a custom profile listener
     153              :  */
     154              : class ProfileListener {
     155              : public:
     156              :   /**
     157              :    * @brief Construct a new Profile Listener object
     158              :    *
     159              :    */
     160              :   explicit ProfileListener() = default;
     161              : 
     162              :   /**
     163              :    * @brief Destroy the Base Profile Listener object
     164              :    *
     165              :    */
     166              :   virtual ~ProfileListener() noexcept = default;
     167              : 
     168              :   /**
     169              :    * @brief A callback function to be called from a profiler
     170              :    *
     171              :    * @param event event type
     172              :    * @param data event data
     173              :    */
     174              :   virtual void notify(PROFILE_EVENT event,
     175              :                       const std::shared_ptr<ProfileEventData> data) = 0;
     176              : 
     177              :   /**
     178              :    * @brief resets the listener to the inital state for a particular key
     179              :    *
     180              :    * @param time_item time item which will be reset
     181              :    */
     182              :   virtual void reset(const int time_item, const std::string &str) = 0;
     183              : 
     184              :   /**
     185              :    * @brief get the latest result of a event
     186              :    *
     187              :    * @param time_item time item to query the result
     188              :    * @return const std::chrono::microseconds
     189              :    */
     190              :   virtual const std::chrono::microseconds result(const int time_item) = 0;
     191              : 
     192              :   /**
     193              :    * @brief report the result
     194              :    *
     195              :    * @param out outstream object to make a report
     196              :    */
     197              :   virtual void report(std::ostream &out) const = 0;
     198              : };
     199              : 
     200              : /**
     201              :  * @brief Generic Profiler Listener
     202              :  *
     203              :  */
     204              : class GenericProfileListener : public ProfileListener {
     205              : public:
     206              :   /**
     207              :    * @brief Construct a new GenericProfile Listener object
     208              :    *
     209              :    * @param warmups_ ignore first @a warmups_ records when making time report
     210              :    */
     211              :   explicit GenericProfileListener(int warmups_ = 0) :
     212              :     ProfileListener(),
     213              :     start_time(std::chrono::steady_clock::now()),
     214              :     warmups(warmups_),
     215              :     mem_max(0),
     216              :     mem_sum(0),
     217              :     mem_average(0),
     218              :     mem_count(0) {}
     219              : 
     220              :   /**
     221              :    * @brief Destroy the Generic Profile Listener object
     222              :    *
     223              :    */
     224            0 :   virtual ~GenericProfileListener() = default;
     225              : 
     226              :   /**
     227              :    * @brief A callback function to be called from a profiler
     228              :    *
     229              :    * @param event event type
     230              :    * @param data event data
     231              :    */
     232              :   virtual void notify(PROFILE_EVENT event,
     233              :                       const std::shared_ptr<ProfileEventData> data) override;
     234              : 
     235              :   /**
     236              :    * @copydoc ProfileListener::reset(const int time_item)
     237              :    */
     238              :   virtual void reset(const int time_item, const std::string &str) override;
     239              : 
     240              :   /**
     241              :    * @copydoc ProfileListener::result(const int event)
     242              :    */
     243              :   virtual const std::chrono::microseconds result(const int event) override;
     244              : 
     245              :   /**
     246              :    * @copydoc ProfileListener::report(std::ostream &out)
     247              :    */
     248              :   virtual void report(std::ostream &out) const override;
     249              : 
     250              : private:
     251              :   /**
     252              :    * @brief Called when time event occurs
     253              :    *
     254              :    */
     255              :   void onNotifyTimeEvent(PROFILE_EVENT event, const int time_item,
     256              :                          const std::string &str,
     257              :                          const std::chrono::microseconds &duration);
     258              : 
     259              :   /**
     260              :    * @brief Called when memory event occurs
     261              :    *
     262              :    */
     263              :   void onNotifyMemoryEvent(PROFILE_EVENT event, const size_t alloc_current,
     264              :                            const size_t alloc_total, const std::string &str,
     265              :                            const std::chrono::microseconds &duration,
     266              :                            const std::string &policy, bool fsu);
     267              : 
     268              :   std::chrono::time_point<std::chrono::steady_clock> start_time;
     269              :   unsigned int warmups;
     270              : 
     271              :   static constexpr int CUR = 0;
     272              :   static constexpr int MIN = 1;
     273              :   static constexpr int MAX = 2;
     274              :   static constexpr int SUM = 3;
     275              :   static constexpr int CNT = 4;
     276              : 
     277              :   std::unordered_map<int, std::tuple<std::chrono::microseconds, /** CUR */
     278              :                                      std::chrono::microseconds, /** MIN */
     279              :                                      std::chrono::microseconds, /** MAX */
     280              :                                      std::chrono::microseconds, /** SUM */
     281              :                                      unsigned int /** CNT */>>
     282              :     time_taken;
     283              : 
     284              :   std::list<std::tuple<PROFILE_EVENT, size_t, size_t, std::string,
     285              :                        std::chrono::microseconds, std::string, bool>>
     286              :     mem_taken; /**< taken memory information <event, current, total, str, dur,
     287              :                   policy, fsu> */
     288              :   size_t mem_max;     /**< memory max size */
     289              :   size_t mem_sum;     /**< memory sum */
     290              :   size_t mem_average; /**< memory average */
     291              :   size_t mem_count;   /**< memory count */
     292              : 
     293              :   std::unordered_map<int, std::string> names;
     294              : };
     295              : 
     296              : /**
     297              :  * @brief   Overriding output stream for layers and it's derived class
     298              :  */
     299              : template <typename T,
     300              :           typename std::enable_if_t<std::is_base_of<ProfileListener, T>::value,
     301              :                                     T> * = nullptr>
     302              : std::ostream &operator<<(std::ostream &out, T &l) {
     303              :   l.report(out);
     304              :   return out;
     305              : }
     306              : 
     307              : /**
     308              :  * @brief Profiler object
     309              :  *
     310              :  */
     311              : class Profiler : public Singleton<Profiler> {
     312              : public:
     313              :   /**
     314              :    * @brief start time profile
     315              :    *
     316              :    * @param time_item time item to be recorded
     317              :    */
     318              :   void start(const int time_item);
     319              : 
     320              :   /**
     321              :    * @brief end time profile and notify to the listeners
     322              :    *
     323              :    * @param time_item time item to be finished
     324              :    */
     325              :   void end(const int time_item);
     326              : 
     327              :   /**
     328              :    * @brief trace memory allocation
     329              :    *
     330              :    * @param ptr allocated memory pointer
     331              :    * @param size amount of allocated memory
     332              :    * @param str information string
     333              :    */
     334              :   void alloc(const void *ptr, size_t size, const std::string &str,
     335              :              const std::string &policy = "", bool fsu = false);
     336              : 
     337              :   /**
     338              :    * @brief trace memory de-allocation
     339              :    *
     340              :    * @param ptr de-allocated memory pointer
     341              :    */
     342              :   void dealloc(const void *ptr, const std::string &policy = "",
     343              :                bool fsu = false);
     344              : 
     345              :   /**
     346              :    * @brief add annotation on memory profile data
     347              :    *
     348              :    * @param str annotate message
     349              :    */
     350              :   void annotate(const std::string &str);
     351              : 
     352              :   /**
     353              :    * @brief subscribe a listener to the profiler
     354              :    *
     355              :    * @param listener listener to register, listener must call unsubscribe on
     356              :    * destruction
     357              :    * @param events event listeners are subscribing, if empty listener subscribes
     358              :    * to all events
     359              :    * @throw std::invalid_argument if listener is already registered
     360              :    */
     361              :   void subscribe(std::shared_ptr<ProfileListener> listener,
     362              :                  const std::set<int> &time_item = {});
     363              : 
     364              :   /**
     365              :    * @brief unsubscribe a listener from the profiler
     366              :    *
     367              :    * @param listener listener to unsubscribe
     368              :    */
     369              :   void unsubscribe(std::shared_ptr<ProfileListener> listener);
     370              : 
     371              :   /**
     372              :    * @brief registerEvent to record.
     373              :    * @note Call to the function shouldn't be inside a critical path
     374              :    *
     375              :    * @return int return NEGATIVE integer to distinguish from reserved events
     376              :    */
     377              :   int registerTimeItem(const std::string &name);
     378              : 
     379              : private:
     380              :   /**
     381              :    * @brief notify the result
     382              :    *
     383              :    * @param event event to notify
     384              :    * @param value measured value from the profiler
     385              :    */
     386              :   void notifyListeners(PROFILE_EVENT event,
     387              :                        const std::shared_ptr<ProfileEventData> data);
     388              : 
     389              :   std::unordered_set<std::shared_ptr<ProfileListener>>
     390              :     listeners; /**< event listeners */
     391              : 
     392              :   std::unordered_map<int, std::string>
     393              :     time_item_names; /**< registered item names (time_item, string) */
     394              :   std::unordered_map<int, timepoint>
     395              :     time_item_times; /**< registered time items (time_item, time) */
     396              :   std::unordered_map<int, std::set<std::shared_ptr<ProfileListener>>>
     397              :     time_item_listeners;
     398              :   /**< registered listeners for each itemtems (time_item, listeners) */
     399              : 
     400              :   std::unordered_map<const void *, std::tuple<size_t, timepoint, std::string>>
     401              :     allocates; /**< allocated memory information (ptr, (size, time, info) */
     402              : 
     403              :   std::atomic<std::size_t> total_size = 0; /**< total allocated memory size */
     404              : 
     405              :   std::mutex listeners_mutex; /**< protect listeners */
     406              :   std::mutex allocates_mutex; /**< protect allocates */
     407              :   std::mutex registr_mutex;   /**< protect custom event registration */
     408              : };
     409              : 
     410              : } // namespace profile
     411              : 
     412              : } // namespace nntrainer
     413              : 
     414              : #endif /** __PROFILER_H__ */
        

Generated by: LCOV version 2.0-1