Skip to content
Snippets Groups Projects
Commit 9454bdfa authored by Marco Clemencic's avatar Marco Clemencic
Browse files

Gaudi service for Jemalloc profiling (JemallocProfileSvc)

Jemalloc profiler implemented as a GaudiService instead of an algorithm. This allows profiling without modifying the algorithm sequence.

See merge request !93

See LBCORE-1012.
parents d9055694 0fbbd604
No related branches found
No related tags found
No related merge requests found
...@@ -18,7 +18,10 @@ A Gaudi algorithm has also been developped to perform memory heap dumps at vario ...@@ -18,7 +18,10 @@ A Gaudi algorithm has also been developped to perform memory heap dumps at vario
and is configured using the StartFromEventN, StopAtEventN and DumpPeriod, as described and is configured using the StartFromEventN, StopAtEventN and DumpPeriod, as described
in the example below. in the example below.
Run A Gaudi service is also available to provide the same functionality, with the advantage
of being able to profile without modifying the algorithm sequence.
Running with the JemallocProfile algorithm
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
### Change Options File ### Change Options File
...@@ -47,6 +50,36 @@ Please note the the `--profilerName=jemalloc` to enbale the profiling, and the ` ...@@ -47,6 +50,36 @@ Please note the the `--profilerName=jemalloc` to enbale the profiling, and the `
a file containing information useful to interpret the results (process id of the Gaudi job, and the absolute path a file containing information useful to interpret the results (process id of the Gaudi job, and the absolute path
of the executable, necessary to run the pprof analysis tool). of the executable, necessary to run the pprof analysis tool).
Running with the JemallocProfileSvc service
--------------------------------------------------------------------------------
### Change Options File
Simple example of using the JemallocProfileSvc service in a Gaudi configurable:
~~~~~~~{.py}
#!/usr/bin/env gaudirun.py
from Configurables import JemallocProfileSvc
#...
ApplicationMgr().ExtSvc += { "JemallocProfileSvc" }
JemallocProfileSvc().StartFromEventN=3
JemallocProfileSvc().StopAtEventN=7
JemallocProfileSvc().OutputLevel=DEBUG
~~~~~~~
It is also possible to trigger the profiling using incidents:
~~~~~~~{.py}
from Configurables import JemallocProfileSvc
ApplicationMgr().ExtSvc += { "JemallocProfileSvc" }
JemallocProfileSvc().StartFromIncidents= [ "MyStartIncident1", "MyStartIncident2" ]
JemallocProfileSvc().StopAtIncidents= [ "MyStopIncident" ]
~~~~~~~
### Run the job
This is identical as for the algorithm version.
Analyze Analyze
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
### With text output ### With text output
......
// Include files
#include "GaudiKernel/Service.h"
#include "GaudiKernel/IIncidentListener.h"
#include "GaudiKernel/IIncidentSvc.h"
#include <iostream>
#include <climits>
// local
#include "JemallocProfileSvc.h"
// including jemmalloc.h is difficult as the malloc signature is not exactly identical
// to the system one (issue with throw).
// We therefore declare mallctl here.
extern "C"
{
int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
}
//-----------------------------------------------------------------------------
// Implementation file for class : JemallocProfileSvc
//
// 2016-01-11 : Ben Couturier
//-----------------------------------------------------------------------------
//=============================================================================
// Standard constructor, initializes variables
//=============================================================================
JemallocProfileSvc::JemallocProfileSvc(const std::string& name, ISvcLocator* svcLoc):
base_class(name, svcLoc), m_eventNumber(0), m_startFromIncidents({}),
m_stopAtIncidents({}), m_hasStartIncident(false), m_hasStopIncident(false),
m_profiling(false) {
declareProperty("StartFromEventN", m_nStartFromEvent = 0,
"After what event we start profiling. "
);
declareProperty("StartFromIncidents", m_startFromIncidents = {},
"Incidents that trigger profiling start"
);
declareProperty("StopAtEventN", m_nStopAtEvent = 0,
"After what event we stop profiling. "
"If 0 than we also profile finalization stage. Default = 0."
);
declareProperty("StopAtIncidents", m_stopAtIncidents = {},
"Incidents that trigger profiling start"
);
declareProperty("DumpPeriod", m_dumpPeriod = 100,
"Period for dumping head to a file. Default=100"
);
}
//=============================================================================
// Initializer
//=============================================================================
StatusCode JemallocProfileSvc::initialize() {
StatusCode sc = base_class::initialize();
if (sc.isFailure()) return sc;
// register to the incident service
static const std::string serviceName = "IncidentSvc";
m_incidentSvc = serviceLocator()->service(serviceName);
if ( ! m_incidentSvc ) {
error() << "Cannot retrieve " << serviceName << endmsg;
return StatusCode::FAILURE;
}
debug() << "Register to the IncidentSvc" << endmsg;
m_incidentSvc->addListener(this, IncidentType::BeginEvent);
m_incidentSvc->addListener(this, IncidentType::EndEvent);
for (std::string incident: m_startFromIncidents)
{
m_incidentSvc->addListener(this, incident);
}
for (std::string incident: m_stopAtIncidents)
{
m_incidentSvc->addListener(this, incident);
}
// Resetting the event counter
m_eventNumber = 0;
m_profiling = false;
// Cache whether we have start/stop incidents
m_hasStartIncident = (m_startFromIncidents.size() > 0);
m_hasStopIncident = (m_stopAtIncidents.size() > 0);
// Checking the consistency of the start/stop events
if (m_nStartFromEvent == 0 && !m_hasStartIncident
&& (m_hasStopIncident || m_nStopAtEvent > 0))
{
info() << "Stop profiling trigger was specified but no start. Defaulting to first events" << endmsg;
m_nStartFromEvent = 1;
}
return StatusCode::SUCCESS;
}
// Finalization of the service.
StatusCode JemallocProfileSvc::finalize() {
// unregistering from the IncidentSvc
m_incidentSvc->removeListener(this, IncidentType::BeginEvent);
m_incidentSvc->removeListener(this, IncidentType::EndEvent);
m_incidentSvc.reset();
return base_class::finalize();
}
//=============================================================================
// Event handling methods
//=============================================================================
// Handler for incidents
void JemallocProfileSvc::handle(const Incident& incident)
{
if (IncidentType::BeginEvent == incident.type())
{
handleBegin();
} else if (IncidentType::EndEvent == incident.type())
{
handleEnd();
}
// If already processing we can ignore the incidents for start
if (!m_profiling && m_hasStartIncident)
{
for(std::string startincident: m_startFromIncidents)
{
if (startincident == incident.type())
{
info() << "Starting Jemalloc profile at incident "
<< incident.type() << endmsg;
startProfiling();
break;
}
} // Loop on incidents
} // If checking incidents to start
// If already processing we can ignore the incidents for start
if (m_profiling && m_hasStopIncident)
{
for(std::string stopincident: m_stopAtIncidents)
{
if (stopincident == incident.type())
{
info() << "Stopping Jemalloc profile at incident "
<< incident.type() << endmsg;
stopProfiling();
break;
}
} // Loop on incidents
} // If checking incidents to stop
}
// Handler for incidents
// Called on at begin events
inline void JemallocProfileSvc::handleBegin()
{
m_eventNumber += 1;
if (m_eventNumber == m_nStartFromEvent)
{
startProfiling();
}
}
// Handler for incidents
// Called on at End events
inline void JemallocProfileSvc::handleEnd()
{
if (m_profiling
&& m_eventNumber != m_nStartFromEvent
&& ((m_eventNumber - m_nStartFromEvent) % m_dumpPeriod == 0))
{
dumpProfile();
}
if (m_eventNumber == m_nStopAtEvent)
{
stopProfiling();
}
}
//=============================================================================
// Utilities calling mallctl
//=============================================================================
/**
* Utility method to start profiling with jemalloc
*/
inline void JemallocProfileSvc::startProfiling()
{
m_profiling = true;
info() << "Starting Jemalloc profile at event "
<< m_eventNumber << endmsg;
mallctl("prof.dump", NULL, NULL, NULL, 0);
}
/**
* Utility method to stop profiling with jemalloc
*/
inline void JemallocProfileSvc::stopProfiling()
{
m_profiling = false;
dumpProfile();
}
/**
* Utility method to dump profile with jemalloc
*/
inline void JemallocProfileSvc::dumpProfile()
{
info() << "Dumping Jemalloc profile at event "
<< m_eventNumber << endmsg;
mallctl("prof.dump", NULL, NULL, NULL, 0);
}
//=============================================================================
// Destructor
//=============================================================================
JemallocProfileSvc::~JemallocProfileSvc() {}
//=============================================================================
// Declaration of the factory
DECLARE_COMPONENT(JemallocProfileSvc)
#ifndef JEMALLOC_JEMALLOCPROFILESVC_H
#define JEMALLOC_JEMALLOCPROFILESVC_H 1
// Include files
#include "GaudiKernel/Service.h"
#include "GaudiKernel/IIncidentListener.h"
/** @class JemallocProfileSvc JemallocProfileSvc.h jemalloc/JemallocProfileSvc.h
*
* Service that enables the Jemalloc profiler on demand.
* By default, the profiling is diabled, the user needs
* to set incidents at which to start/stop the profiling,
* or specify incidents for that purpose.
*
* @author Ben Couturier
* @date 2016-01-12
*/
class JemallocProfileSvc : public extends1<Service, IIncidentListener> {
public:
/// Standard constructor
JemallocProfileSvc(const std::string &name, ISvcLocator *svcLoc);
/// Initializer
StatusCode initialize();
/// Finalizer
StatusCode finalize();
// Handler for incident
void handle(const Incident &incident);
///< Destructor
virtual ~JemallocProfileSvc();
protected:
void handleBegin();
void handleEnd();
void startProfiling();
void stopProfiling();
void dumpProfile();
private:
/// Start, End event and counter
int m_nStartFromEvent; // Event to start profiling at
int m_nStopAtEvent; // Event to stop profiling at
int m_dumpPeriod; // Period at which to dump the heap
int m_eventNumber; // Current event number
std::vector<std::string> m_startFromIncidents; // Incidents to use as trigger
std::vector<std::string> m_stopAtIncidents; // Incidents to use as trigger
bool m_hasStartIncident;
bool m_hasStopIncident;
/// Status of the profiling
bool m_profiling;
/// Pointer to the incident service.
SmartIF<IIncidentSvc> m_incidentSvc;
};
#endif // JEMALLOC_JEMALLOCPROFILESVC_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment