Gaudi Framework, version v23r2p1

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

Generated at Fri Jun 29 2012 15:43:51 for Gaudi Framework, version v23r2p1 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004