Gaudi Framework, version v23r4

Home   Generated: Mon Sep 17 2012

IntelProfilerAuditor.cpp

Go to the documentation of this file.
00001 // ## Includes.
00002 // * Standard libraries.
00003 #include <algorithm>
00004 #include <vector>
00005 #include <stack>
00006 #include <string>
00007 #include <utility>
00008 #include <memory>
00009 #include <iomanip>
00010 #include <sstream>
00011 
00012 // * Boost
00013 #include <boost/foreach.hpp>
00014 
00015 // * Gaudi libraries.
00016 #include "GaudiKernel/AudFactory.h"
00017 #include "GaudiKernel/Auditor.h"
00018 #include "GaudiKernel/IAuditorSvc.h"
00019 #include "GaudiKernel/GaudiException.h"
00020 #include "GaudiKernel/MsgStream.h"
00021 #include "GaudiKernel/IIncidentListener.h"
00022 #include "GaudiKernel/IIncidentSvc.h"
00023 
00024 // * Intel User API
00025 #ifdef __GNUC__
00026 #pragma GCC diagnostic ignored "-Wunused-function"
00027 #endif
00028 #include "ittnotify.h"
00029 
00030 typedef std::map<std::string, __itt_event> TaskTypes;
00031 
00032 // Gaudi profiling auditor. The auditor use Intel API for control profiling
00033 // flow. We need to run profiling  throw Intel Amplifier amplxe-cl command
00034 // line tool.
00035 class IntelProfilerAuditor: public Auditor, virtual public IIncidentListener {
00036 public:
00037   // ## Public functions.
00038   IntelProfilerAuditor(const std::string& name, ISvcLocator* pSvcLocator);
00039   StatusCode initialize();
00040   // Overridden functions.
00041   void handle(const Incident& incident);
00042   using Auditor::before; // avoid hiding base-class methods
00043   void before(StandardEventType type, INamedInterface* i);
00044   using Auditor::after; // avoid hiding base-class methods
00045   void after(StandardEventType type, INamedInterface* i, const StatusCode& sc);
00046 // ## Private attributes.
00047 private:
00048   // Stack for store current component(algorithm) chain with useful
00049   // information for the auditor.
00050   struct stack_entity {
00051     stack_entity(const std::string& name_, bool status_,
00052       const __itt_event event_ = 0, const __itt_event parent_event_ = 0):
00053         name(name_),
00054         status(status_),
00055         event(event_),
00056         parent_event(parent_event_){}
00057     // Name of the component.
00058     std::string name;
00059     // Running status: on/off.
00060     bool status;
00061     // Task type holder.
00062     __itt_event event;
00063     // Parent task type.
00064     __itt_event parent_event;
00065   };
00066 private:
00067   // From what event to start profiling. Default = 1.
00068   int m_nStartFromEvent;
00069   // After what event we stop profiling. If 0 than we also profile finalization
00070   // stage. Default = 0.
00071   int m_nStopAtEvent;
00072    // Names of excluded algorithms.
00073   std::vector<std::string> m_excluded;
00074   // Names of included algorithms.
00075   std::vector<std::string> m_included;
00076   // Algorithm name, for which intel amplifier event type will be created.
00077   std::vector<std::string> m_algs_for_tasktypes;
00078   // The String delimiter between sequences/algorithms names in
00079   // "Task Type" grouping at Amplifier.
00080   std::string m_alg_delim;
00081   // Enable frames (needed for detecting slow events).
00082   bool m_enable_frames;
00083   // Frames rate. The recommended maximum rate for calling the Frame API is
00084   // 1000 frames (events) per second. A higher rate may result in large product
00085   // memory consumption and slow finalization.
00086   // You need update "slow-frames-threshold" and "fast-frames-threshold"
00087   // parameters of amplxe-cl tool to separate slow, medium and fast events.
00088   int m_frames_rate;
00089 private:
00090   // Logger.
00091   MsgStream m_log;
00092   // Events counter.
00093   int m_nEvents;
00094   // Domain for event loop.
00095   __itt_domain* domain;
00096   // True if profiler is started.
00097   bool m_isStarted;
00098   // Current stack of sequences/algorithms.
00099   std::vector<stack_entity> m_stack;
00100   // Mapping of task type name to Amplifier event .
00101   TaskTypes m_tasktypes;
00102 private:
00103   // ## Private functions.
00104   void start_profiling_component(const std::string& name);
00105   void skip_profiling_component(const std::string& name);
00106 
00107   void start();
00108   void pause();
00109   void resume();
00110   void stop();
00111 
00112   bool hasIncludes() const;
00113   bool isIncluded(const std::string& name) const;
00114   bool isExcluded(const std::string& name) const;
00115   bool isRunning() const;
00116 
00117   int  stackLevel() const;
00118   std::string stackIndent(bool newLevel = false) const;
00119   std::string taskTypeName(const std::string& component_name) const;
00120 };
00121 // ## Implementation.
00122 // Constructor
00123 IntelProfilerAuditor::IntelProfilerAuditor(const std::string& name,
00124   ISvcLocator* pSvcLocator) : Auditor(name, pSvcLocator), m_log(msgSvc(), name)
00125     ,m_nEvents(0), m_isStarted(false) {
00126   // ## Properties
00127   declareProperty("IncludeAlgorithms", m_included,
00128     "Names of included algorithms."
00129   );
00130   declareProperty("ExcludeAlgorithms", m_excluded,
00131     "Names of excluded algorithms."
00132   );
00133   declareProperty("StartFromEventN", m_nStartFromEvent = 1,
00134     "After what event we stop profiling. "
00135     "If 0 than we also profile finalization stage."
00136   );
00137   declareProperty("StopAtEventN", m_nStopAtEvent = 0,
00138     "After what event we stop profiling. "
00139     "If 0 than we also profile finalization stage. Default = 0."
00140   );
00141   declareProperty("ComponentsForTaskTypes", m_algs_for_tasktypes,
00142     "Algorithm name, for which intel amplifier task type will be created."
00143     "By default all algorithms have a corresponding task type.");
00144   declareProperty("TaskTypeNameDelimeter", m_alg_delim = " ",
00145     "The String delimiter between sequences/algorithms names in "
00146     "\"Task Type\" grouping at Amplifier. Default=\" \"."
00147   );
00148   declareProperty("EnableFrames", m_enable_frames = false,
00149     "Enable frames (needed for detecting slow events). Default=false."
00150   );
00151   declareProperty("FramesRate", m_frames_rate = 100,
00152     "Frames rate. The recommended maximum rate for calling the Frame API is "
00153     "1000 frames (events) per second. A higher rate may result in large product"
00154     " memory consumption and slow finalization. "
00155     "You need update \"slow-frames-threshold\" and \"fast-frames-threshold\" "
00156     "parameters of amplxe-cl tool to separate slow, medium and fast events. "
00157     "For use frames you need to switch on \"EnableFrames\". "
00158     "Default=100"
00159   );
00160 }
00161 
00162 void IntelProfilerAuditor::start() {
00163   m_isStarted = true;
00164   __itt_resume();
00165 }
00166 
00167 void IntelProfilerAuditor::start_profiling_component(const std::string& name) {
00168   if (!m_isStarted) return;
00169   std::string typeName = taskTypeName(name);
00170   __itt_event taskId = 0;
00171   TaskTypes::const_iterator iter = m_tasktypes.find(typeName);
00172   if( iter != m_tasktypes.end()) {
00173     taskId = iter->second;
00174   }
00175 
00176   if(!taskId && m_algs_for_tasktypes.empty()) {
00177     // Create event
00178     taskId = __itt_event_create(typeName.c_str(), typeName.size());
00179     m_tasktypes.insert(TaskTypes::value_type(typeName, taskId));
00180   }
00181 
00182   stack_entity state = stack_entity(name, true, taskId);
00183   stack_entity* parent = !m_stack.empty()?&m_stack.back():NULL;
00184 
00185   if (parent != NULL) {
00186     if (parent->event) {
00187        state.parent_event = parent->event;
00188     } else {
00189       state.parent_event = parent->parent_event;
00190     }
00191   }
00192 
00193   if (taskId && state.parent_event) {
00194     m_log << MSG::DEBUG << stackIndent() << "Pause event " <<
00195       state.parent_event << endmsg;
00196     __itt_event_end(state.parent_event);
00197   }
00198   m_stack.push_back(state);
00199 
00200   m_log << MSG::DEBUG << stackIndent() << "Start profiling component "
00201     << typeName << endmsg;
00202 
00203   if (taskId) {
00204      // Start event
00205     m_log << MSG::DEBUG << stackIndent() << "Start event type "
00206       << state.event << " for "  << typeName << endmsg;
00207     __itt_event_start(state.event);
00208   }
00209 
00210   __itt_resume();
00211 }
00212 
00213 void IntelProfilerAuditor::resume() {
00214   if (!m_isStarted) return;
00215   m_log << MSG::DEBUG << stackIndent() << "Resume" << endmsg;
00216   __itt_resume();
00217 }
00218 
00219 void IntelProfilerAuditor::pause() {
00220   if (!m_isStarted) return;
00221   m_log << MSG::DEBUG << stackIndent() << "Pause" << endmsg;
00222   __itt_pause();
00223 }
00224 
00225 void IntelProfilerAuditor::skip_profiling_component(const std::string& name) {
00226   if (!m_isStarted) return;
00227   m_stack.push_back(stack_entity(name, false));
00228   m_log << MSG::DEBUG << stackIndent() << "Skip component "
00229     << name << endmsg;
00230 }
00231 
00232 void IntelProfilerAuditor::stop() {
00233   if (!m_isStarted) return;
00234   m_isStarted = false;
00235   __itt_pause();
00236 }
00237 
00238 bool IntelProfilerAuditor::hasIncludes() const {
00239   return !m_included.empty();
00240 }
00241 
00242 bool IntelProfilerAuditor::isIncluded(const std::string& name) const {
00243   return std::find(m_included.begin(), m_included.end(), name) !=
00244     m_included.end();
00245 }
00246 
00247 bool IntelProfilerAuditor::isExcluded(const std::string& name) const {
00248   return std::find(m_excluded.begin(), m_excluded.end(), name) !=
00249     m_excluded.end();
00250 }
00251 
00252 bool IntelProfilerAuditor::isRunning() const {
00253   return !m_stack.empty() && m_stack.back().status;
00254 }
00255 
00256 int IntelProfilerAuditor::stackLevel() const {
00257   return m_stack.size();
00258 }
00259 
00260 std::string IntelProfilerAuditor::stackIndent(bool newLevel) const{
00261   std::stringstream indent(std::stringstream::out);
00262   indent << std::setw(stackLevel()*2+(newLevel?2:0)) << " ";
00263   return indent.str();
00264 }
00265 
00266 std::string
00267 IntelProfilerAuditor::taskTypeName(const std::string& component_name) const {
00268   std::string result;
00269   std::string delim = "";
00270   BOOST_FOREACH(const stack_entity& value,
00271      m_stack) {
00272     result += delim+value.name;
00273     delim = m_alg_delim;
00274   }
00275   return result+m_alg_delim+component_name;
00276 }
00277 
00278 StatusCode IntelProfilerAuditor::initialize() {
00279   m_log.setLevel(outputLevel());
00280   m_log << MSG::INFO << "Initialised" << endmsg;
00281 
00282   IIncidentSvc * inSvc = NULL;
00283   const StatusCode sc = serviceLocator()->service("IncidentSvc", inSvc);
00284   if (sc.isFailure())
00285     return sc;
00286   // Useful to start profiling only after some event, we don't need profile
00287   // initialization stage. For that we need to count events with BeginEvent
00288   // listener.
00289   inSvc->addListener(this, IncidentType::BeginEvent);
00290   // If the end event number don't setup we finish profiling at the end
00291   // of loop. We don't need profiling finalization stage.
00292   inSvc->addListener(this, IncidentType::EndProcessing);
00293 
00294   std::string str_excluded, str_included, str_eventtypes;
00295   BOOST_FOREACH(const std::string& name, m_excluded)
00296   {
00297     str_excluded += " " + name;
00298   }
00299   BOOST_FOREACH(const std::string& name, m_included)
00300   {
00301     str_included += " " + name;
00302   }
00303 
00304   BOOST_FOREACH(const std::string& name, m_algs_for_tasktypes)
00305   {
00306     str_eventtypes += " " + name;
00307   }
00308 
00309   if (!m_included.empty()) {
00310     m_log << MSG::INFO << "Included algorithms (" << m_included.size()
00311       << "): " << str_included << endmsg;
00312   }
00313 
00314   if (!m_excluded.empty()){
00315     m_log << MSG::INFO << "Excluded algorithms (" << m_excluded.size()
00316       << "): " << str_excluded << endmsg;
00317   }
00318 
00319   if (!m_algs_for_tasktypes.empty()){
00320     m_log << MSG::INFO << "Event types (" << m_algs_for_tasktypes.size()
00321       << "): " << str_eventtypes << endmsg;
00322   }
00323 
00324   // Create a profiler domain for detection of slow events.
00325   domain = __itt_domain_create("Event loop");
00326   domain->flags = m_enable_frames;
00327 
00328   return StatusCode::SUCCESS;
00329 }
00330 
00331 
00332 
00333 void IntelProfilerAuditor::handle(const Incident& incident) {
00334   if (IncidentType::BeginEvent != incident.type()) return;
00335   // Increment the event counter
00336   ++m_nEvents;
00337 
00338   if (m_nStartFromEvent == m_nEvents) {
00339     m_log << MSG::INFO << "Start profiling (event #" << m_nEvents << ")"
00340         << endmsg;
00341     start();
00342   }
00343 
00344   if (m_nStopAtEvent == m_nEvents) {
00345     m_log << MSG::INFO << "Stop profiling (event #" << m_nEvents << ")"
00346         << endmsg;
00347     stop();
00348   }
00349 }
00350 
00351 void IntelProfilerAuditor::before(StandardEventType type, INamedInterface* i) {
00352   // Skip unnecessary event types.
00353   if (!((type == IAuditor::Execute) && m_isStarted)) return;
00354 
00355   // Name of the current component.
00356   const std::string& name = i->name();
00357   //m_log << MSG::DEBUG <<  "Before: " << name << " " << type << endmsg;
00358 
00359   if (isRunning()) {
00360     if (isExcluded(name)) {
00361       // If profiling is running and component is explicitly excluded
00362       // then skip component.
00363       skip_profiling_component(name);
00364     }else{
00365       // If profiling is running and component is'not explicitly excluded
00366       // then start profiling for component (add to stack).
00367       start_profiling_component(name);
00368     }
00369   }else {
00370     if (hasIncludes()) {
00371       // If the profiling is not running and  "includes" is explicitly defined ...
00372       if (isIncluded(name)) {
00373         // and the current component is in the include's list then start the
00374         // component profiling.
00375         start_profiling_component(name);
00376       } else{
00377         // and the current component is not in the includes list then skip
00378         // a profiling of the component.
00379         skip_profiling_component(name);
00380       }
00381     }else {
00382         // If "Includes" property isn't present and the component is ...
00383         if (isExcluded(name)) {
00384           // in the excludes list then skip a profiling
00385           skip_profiling_component(name);
00386         }else{
00387           // not in the exclude list then start a profiling
00388           start_profiling_component(name);
00389         }
00390     }
00391   }
00392   if (m_nEvents % m_frames_rate == 0) {
00393     __itt_frame_begin_v3(domain, NULL);
00394   }
00395 
00396 }
00397 
00398 void IntelProfilerAuditor::after(StandardEventType type,
00399   INamedInterface* i, const StatusCode&/* sc*/) {
00400   // Skip unnecessary event types
00401   if (!((type == IAuditor::Execute) && m_isStarted)) return;
00402 
00403   if ((m_nEvents+1) % m_frames_rate == 0) {
00404     __itt_frame_end_v3(domain, NULL);
00405   }
00406 
00407   // Name of the current component
00408   const std::string& name = i->name();
00409   stack_entity state = m_stack.back();
00410   // Remove component from stack.
00411   m_stack.pop_back();
00412 
00413 
00414   if (state.event != 0) {
00415      m_log << MSG::DEBUG << stackIndent(true) << "End event for "
00416       << name << endmsg;
00417     __itt_event_end(state.event);
00418 
00419     if (state.parent_event != 0) {
00420       m_log << MSG::DEBUG << stackIndent() << "Resume event for "
00421         << state.parent_event << endmsg;
00422       __itt_event_start(state.parent_event);
00423     }
00424   }
00425 
00426   if (m_stack.empty()) {
00427     // Pause if there are no parent components (top algorithm).
00428     pause();
00429   } else if (state.status) {
00430     // If the profiling is running and we have parent component that is
00431     // paused then pause the profiling.
00432     if (!m_stack.back().status) {
00433       pause();
00434     }
00435   }else {
00436     // If the profiling was stopped, but the parent component should be profiled
00437     // then resume profiling.
00438     if (m_stack.back().status) {
00439       resume();
00440     }
00441   }
00442 }
00443 
00444 // Register the auditor
00445 DECLARE_AUDITOR_FACTORY(IntelProfilerAuditor)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Mon Sep 17 2012 13:49:35 for Gaudi Framework, version v23r4 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004