8585#include < valgrind/callgrind.h>
8686#endif
8787
88+ #ifdef WITH_GPERFTOOLS
89+ #include < gperftools/profiler.h>
90+ #endif
91+
8892// option to enable compilation with FairMQ support
8993#ifdef WITH_FAIRMQ
9094#include < InfoLogger/InfoLoggerFMQ.hxx>
@@ -108,6 +112,7 @@ using namespace AliceO2::Common;
108112
109113// some constants
110114const char * envRunNumber = " O2_RUN" ; // env var name for run number store
115+ const char * gperfOutputFile = " /tmp/readout.gperf" ; // path to output file when gperf profiling enabled
111116
112117// set log environment before theLog is initialized
113118TtyChecker theTtyChecker;
@@ -412,6 +417,11 @@ int Readout::init(int argc, char* argv[])
412417 #else
413418 theLog.log (LogInfoDevel, " ZMQ : no" );
414419 #endif
420+ #ifdef WITH_GPERFTOOLS
421+ theLog.log (LogInfoDevel, " GPERFTOOLS : yes" );
422+ #else
423+ theLog.log (LogInfoDevel, " GPERFTOOLS : no" );
424+ #endif
415425 }
416426
417427 // report cached logs
@@ -468,6 +478,11 @@ int Readout::init(int argc, char* argv[])
468478 }
469479 }
470480
481+ // print some built-in constants
482+ if (cfgVerbose) {
483+ // theLog.log(LogInfoDevel, "DataBlockHeader size = %d", (int)sizeof(DataBlockHeader));
484+ }
485+
471486 return 0 ;
472487}
473488
@@ -847,12 +862,22 @@ int Readout::configure(const boost::property_tree::ptree& properties)
847862
848863 // instanciate consumer of appropriate type
849864 std::unique_ptr<Consumer> newConsumer = nullptr ;
865+ int cfgNumaNode = -1 ;
850866 try {
851867 // configuration parameter: | consumer-* | consumerType | string | | The type of consumer to be instanciated. One of:stats, FairMQDevice, DataSampling, FairMQChannel, fileRecorder, checker, processor, tcp. |
852868 std::string cfgType = " " ;
853869 cfgType = cfg.getValue <std::string>(kName + " .consumerType" );
854870 theLog.log (LogInfoDevel, " Configuring consumer %s: %s" , kName .c_str (), cfgType.c_str ());
855871
872+ #ifdef WITH_NUMA
873+ // configuration parameter: | consumer-* | numaNode | int | -1 | If set (>=0), memory / thread will try to use given NUMA node. |
874+ cfg.getOptionalValue <int >(kName + " .numaNode" , cfgNumaNode);
875+ if (cfgNumaNode >= 0 ) {
876+ theLog.log (LogInfoDevel_ (3008 ), " Preferred NUMA node = %d" , cfgNumaNode);
877+ numaBind (cfgNumaNode);
878+ }
879+ #endif
880+
856881 if (!cfgType.compare (" stats" )) {
857882 newConsumer = getUniqueConsumerStats (cfg, kName );
858883 } else if (!cfgType.compare (" FairMQDevice" )) {
@@ -906,11 +931,17 @@ int Readout::configure(const boost::property_tree::ptree& properties)
906931 theLog.log (LogErrorSupport_ (3100 ), " Failed to configure consumer %s" , kName .c_str ());
907932 }
908933
934+ #ifdef WITH_NUMA
935+ // reset settings after instanciating consumer
936+ if (cfgNumaNode >= 0 ) {
937+ numaBind (-1 );
938+ }
939+ #endif
940+
909941 if (newConsumer != nullptr ) {
910942 if (cfgOutput.length () > 0 ) {
911943 consumersOutput.insert (std::pair<Consumer*, std::string>(newConsumer.get (), cfgOutput));
912944 }
913- newConsumer->name = kName ;
914945 if (cfgStopOnError) {
915946 newConsumer->stopOnError = 1 ;
916947 }
@@ -1160,15 +1191,33 @@ int Readout::start()
11601191 return 0 ;
11611192}
11621193
1194+ std::thread::id mainThreadId;
1195+ int isMainThread (void *) {
1196+ if (std::this_thread::get_id () == mainThreadId) {
1197+ return 1 ;
1198+ }
1199+ return 0 ;
1200+ }
1201+
11631202void Readout::loopRunning ()
11641203{
1204+ setThreadName (" loopRunning" );
11651205
11661206 theLog.log (LogInfoDevel, " Entering main loop" );
11671207#ifdef CALLGRIND
11681208 theLog.log (LogInfoDevel, " Starting callgrind instrumentation" );
11691209 CALLGRIND_START_INSTRUMENTATION;
11701210#endif
11711211
1212+ #ifdef WITH_GPERFTOOLS
1213+ theLog.log (LogInfoDevel, " Starting gperftools instrumentation" );
1214+
1215+ mainThreadId = std::this_thread::get_id ();
1216+ struct ProfilerOptions gperfopt = { &isMainThread, 0 };
1217+ ProfilerStartWithOptions (gperfOutputFile.c_str (), &gperfopt);
1218+ // ProfilerStart(gperfOutputFile.c_str());
1219+ #endif
1220+
11721221 for (;;) {
11731222 if ((!isRunning) && ((cfgFlushEquipmentTimeout <= 0 ) || (stopTimer.isTimeout ()))) {
11741223 break ;
@@ -1236,6 +1285,11 @@ void Readout::loopRunning()
12361285 CALLGRIND_DUMP_STATS;
12371286 theLog.log (LogInfoDevel, " Stopping callgrind instrumentation" );
12381287#endif
1288+ #ifdef WITH_GPERFTOOLS
1289+ theLog.log (LogInfoDevel, " Stopping gperftools instrumentation" );
1290+ ProfilerStop ();
1291+ #endif
1292+
12391293 theLog.log (LogInfoDevel, " Exiting main loop" );
12401294}
12411295
0 commit comments