Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • le.koch/cbmroot
  • patrick.pfistner_AT_kit.edu/cbmroot
  • lena.rossel_AT_stud.uni-frankfurt.de/cbmroot
  • i.deppner/cbmroot
  • fweig/cbmroot
  • karpushkin_AT_inr.ru/cbmroot
  • v.akishina/cbmroot
  • rishat.sultanov_AT_cern.ch/cbmroot
  • l_fabe01_AT_uni-muenster.de/cbmroot
  • pwg-c2f/cbmroot
  • j.decuveland/cbmroot
  • a.toia/cbmroot
  • i.vassiliev/cbmroot
  • n.herrmann/cbmroot
  • o.lubynets/cbmroot
  • se.gorbunov/cbmroot
  • cornelius.riesen_AT_physik.uni-giessen.de/cbmroot
  • zhangqn17_AT_mails.tsinghua.edu.cn/cbmroot
  • bartosz.sobol/cbmroot
  • ajit.kumar/cbmroot
  • computing/cbmroot
  • a.agarwal_AT_vecc.gov.in/cbmroot
  • osingh/cbmroot
  • wielanek_AT_if.pw.edu.pl/cbmroot
  • malgorzata.karabowicz.stud_AT_pw.edu.pl/cbmroot
  • m.shiroya/cbmroot
  • s.roy/cbmroot
  • p.-a.loizeau/cbmroot
  • a.weber/cbmroot
  • ma.beyer/cbmroot
  • d.klein/cbmroot
  • d.smith/cbmroot
  • mvdsoft/cbmroot
  • d.spicker/cbmroot
  • y.h.leung/cbmroot
  • m.deveaux/cbmroot
  • mkunold/cbmroot
  • h.darwish/cbmroot
  • f_fido01_AT_uni-muenster.de/cbmroot
  • g.kozlov/cbmroot
  • d.emschermann/cbmroot
  • evgeny.lavrik/cbmroot
  • v.friese/cbmroot
  • f.uhlig/cbmroot
  • ebechtel_AT_ikf.uni-frankfurt.de/cbmroot
  • a.senger/cbmroot
  • praisig/cbmroot
  • s.lebedev/cbmroot
  • redelbach_AT_compeng.uni-frankfurt.de/cbmroot
  • p.subramani/cbmroot
  • a_meye37_AT_uni-muenster.de/cbmroot
  • om/cbmroot
  • o.golosov/cbmroot
  • l.chlad/cbmroot
  • a.bercuci/cbmroot
  • d.ramirez/cbmroot
  • v.singhal/cbmroot
  • h.schiller/cbmroot
  • apuntke/cbmroot
  • f.zorn/cbmroot
  • rubio_AT_physi.uni-heidelberg.de/cbmroot
  • p.chudoba/cbmroot
  • apuntke/mcbmroot
  • r.karabowicz/cbmroot
64 results
Show changes
Showing
with 3080 additions and 1527 deletions
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
/**
......@@ -12,25 +12,30 @@
* @author D. Klein, A. Rybalchenko
*/
#include "runFairMQDevice.h"
#include "ParameterMQServer.h"
#include "runFairMQDevice.h"
namespace bpo = boost::program_options;
void addCustomOptions(bpo::options_description& options)
{
options.add_options()
("first-input-name", bpo::value<std::string>()->default_value("first_input.root"), "First input file name")
("first-input-type", bpo::value<std::string>()->default_value("ROOT"), "First input file type (ROOT/ASCII)")
("second-input-name", bpo::value<std::string>()->default_value(""), "Second input file name")
("second-input-type", bpo::value<std::string>()->default_value("ROOT"), "Second input file type (ROOT/ASCII)")
("libs-to-load", bpo::value<std::string>()->default_value(""), "List of libraries to load")
("output-name", bpo::value<std::string>()->default_value(""), "Output file name")
("output-type", bpo::value<std::string>()->default_value("ROOT"), "Output file type")
("channel-name", bpo::value<std::string>()->default_value("data"), "Output channel name");
options.add_options()("first-input-name", bpo::value<std::string>()->default_value("first_input.root"),
"First input file name");
options.add_options()("first-input-type", bpo::value<std::string>()->default_value("ROOT"),
"First input file type (ROOT/ASCII)");
options.add_options()("second-input-name", bpo::value<std::string>()->default_value(""), "Second input file name");
options.add_options()("second-input-type", bpo::value<std::string>()->default_value("ROOT"),
"Second input file type (ROOT/ASCII)");
options.add_options()("libs-to-load", bpo::value<std::string>()->default_value(""), "List of libraries to load");
options.add_options()("output-name", bpo::value<std::string>()->default_value(""), "Output file name");
options.add_options()("output-type", bpo::value<std::string>()->default_value("ROOT"), "Output file type");
options.add_options()("channel-name", bpo::value<std::string>()->default_value("data"), "Output channel name");
options.add_options()("setup", bpo::value<std::string>()->default_value(""), "Name/tag of the geomatry setup");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
{
return new ParameterMQServer();
}
\ No newline at end of file
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new ParameterMQServer(); }
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startMQSamplerSink.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startMQSamplerSink.sh)
set(INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/MQ/base
)
Set(SYSTEM_INCLUDE_DIRECTORIES
${SYSTEM_INCLUDE_DIRECTORIES}
${ZeroMQ_INCLUDE_DIR}
${Boost_INCLUDE_DIR}
${FAIRROOT_INCLUDE_DIR}
${FAIRMQ_INCLUDE_DIR}
${FAIRMQ_INCLUDE_DIR}/options
${IPC_INCLUDE_DIRECTORY}
${CBMROOT_SOURCE_DIR}/external/cppzmq
)
include_directories(${INCLUDE_DIRECTORIES})
include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
set(LINK_DIRECTORIES
${ROOT_LIBRARY_DIR}
${FAIRROOT_LIBRARY_DIR}
${Boost_LIBRARY_DIRS}
)
link_directories(${LINK_DIRECTORIES})
${CMAKE_CURRENT_SOURCE_DIR}
)
# Set the install path within the build directory
set(EXECUTABLE_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/MQ/sink")
# Set the install path within the installation directory
set(BIN_DESTINATION bin/MQ/sink)
Set(BOOST_LIBS
${Boost_SYSTEM_LIBRARY}
${Boost_SERIALIZATION_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_LOG_LIBRARY}
)
If(UNIX AND NOT APPLE)
List(APPEND BOOST_LIBS pthread)
EndIf()
set(FAIR_LIBS
FairMQ
)
set(PRIVATE_DEPS
CbmMQBase
external::fles_ipc
)
If(FAIRLOGGER_FOUND)
set(FAIR_LIBS
${FAIR_LIBS}
FairLogger
)
EndIf()
set(INTERFACE_DEPS
FairMQ::FairMQ
)
set(EXE_NAME DevNullSink)
set(SRCS CbmDevNullSink.cxx runDevNullSink.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
fles_ipc
)
GENERATE_EXECUTABLE()
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME TsaComponentSink)
set(SRCS CbmTsaComponentSink.cxx runTsaComponentSink.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
fles_ipc
)
GENERATE_EXECUTABLE()
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
# Install scripts and input file
if(EXISTS ${VMCWORKDIR}/input/tofget4_hd2018.tsa)
install(FILES ${VMCWORKDIR}/input/tofget4_hd2018.tsa
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/cbmroot/input
)
endif()
# Set the correct variables for the installation
set(VMCWORKDIR ${CMAKE_INSTALL_PREFIX}/share/cbmroot)
set(MY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_CURRENT_SOURCE_DIR ${VMCWORKDIR}/input)
set(TMPDIR "${CMAKE_BINARY_DIR}")
set(CMAKE_BINARY_DIR ${CMAKE_INSTALL_PREFIX})
# Configure file for installation directory
configure_file(${MY_SOURCE_DIR}/startMQSamplerSink.sh.in ${TMPDIR}/bin/MQ/topologies/install/startMQSamplerSink.sh)
install(PROGRAMS ${TMPDIR}/bin/MQ/topologies/install/startMQSamplerSink.sh
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin/MQ/topologies
)
/* Copyright (C) 2017-2019 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
/**
* CbmDevNullSink.cxx
*
......@@ -6,28 +10,22 @@
*/
#include "CbmDevNullSink.h"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairMQProgOptions.h" // device->fConfig
using namespace std;
CbmDevNullSink::CbmDevNullSink()
: FairMQDevice{}
, fNumMessages{0}
{
}
CbmDevNullSink::CbmDevNullSink() : FairMQDevice {}, fNumMessages {0} {}
void CbmDevNullSink::Init()
{
}
void CbmDevNullSink::Init() {}
void CbmDevNullSink::InitTask()
{
// register a handler for data arriving on any channel
int noChannel = fChannels.size();
LOG(info) << "Number of defined input channels: " << noChannel;
for(auto const &entry : fChannels) {
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
OnData(entry.first, &CbmDevNullSink::HandleData);
}
......@@ -36,15 +34,12 @@ void CbmDevNullSink::InitTask()
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool CbmDevNullSink::HandleData(FairMQMessagePtr& msg, int /*index*/)
{
// Don't do anything with the data
// Maybe add an message counter which counts the incomming messages and add
// an output
fNumMessages++;
LOG(info) << "Received message number "<< fNumMessages
<< " with size " << msg->GetSize();
return true;
// Don't do anything with the data
// Maybe add an message counter which counts the incomming messages and add
// an output
fNumMessages++;
LOG(info) << "Received message number " << fNumMessages << " with size " << msg->GetSize();
return true;
}
CbmDevNullSink::~CbmDevNullSink()
{
}
CbmDevNullSink::~CbmDevNullSink() {}
/* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
/**
* CbmDevNullSink.h
*
......@@ -10,19 +14,18 @@
#include "FairMQDevice.h"
class CbmDevNullSink : public FairMQDevice
{
public:
CbmDevNullSink();
virtual ~CbmDevNullSink();
class CbmDevNullSink : public FairMQDevice {
public:
CbmDevNullSink();
virtual ~CbmDevNullSink();
protected:
virtual void InitTask();
virtual void Init();
bool HandleData(FairMQMessagePtr&, int);
protected:
virtual void InitTask();
virtual void Init();
bool HandleData(FairMQMessagePtr&, int);
private:
uint64_t fNumMessages;
private:
uint64_t fNumMessages;
};
#endif /* CBMDEVNULLSINK_H_ */
/* Copyright (C) 2018-2019 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
/**
* CbmTsaComponentSink.cxx
*
......@@ -6,46 +10,45 @@
*/
#include "CbmTsaComponentSink.h"
#include "CbmMQDefs.h"
#include "StorableTimeslice.hpp"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairMQProgOptions.h" // device->fConfig
#include <boost/archive/binary_iarchive.hpp>
#include <string>
#include <stdexcept>
struct InitTaskError : std::runtime_error { using std::runtime_error::runtime_error; };
#include <string>
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
using namespace std;
CbmTsaComponentSink::CbmTsaComponentSink()
: fNumMessages(0)
{
}
CbmTsaComponentSink::CbmTsaComponentSink() : fNumMessages(0) {}
void CbmTsaComponentSink::InitTask()
try
{
// Get the information about created channels from the device
// Check if the defined channels from the topology (by name)
// are in the list of channels which are possible/allowed
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
int noChannel = fChannels.size();
LOG(info) << "Number of defined input channels: " << noChannel;
for(auto const &entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
OnData(entry.first, &CbmTsaComponentSink::HandleData);
}
} catch (InitTaskError& e) {
try {
// Get the information about created channels from the device
// Check if the defined channels from the topology (by name)
// are in the list of channels which are possible/allowed
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
int noChannel = fChannels.size();
LOG(info) << "Number of defined input channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
OnData(entry.first, &CbmTsaComponentSink::HandleData);
}
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
......@@ -54,41 +57,37 @@ try
bool CbmTsaComponentSink::IsChannelNameAllowed(std::string channelName)
{
for(auto const &entry : fAllowedChannels) {
for (auto const& entry : fAllowedChannels) {
std::size_t pos1 = channelName.find(entry);
if (pos1!=std::string::npos) {
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fAllowedChannels.begin(), fAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos-fAllowedChannels.begin();
std::find(fAllowedChannels.begin(), fAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName
<< " found in list of allowed channel names at position " << idx;
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
return true;
}
}
LOG(info) << "Channel name " << channelName
<< " not found in list of allowed channel names.";
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool CbmTsaComponentSink::HandleData(FairMQMessagePtr& msg, int /*index*/)
{
// Don't do anything with the data
// Maybe add an message counter which counts the incomming messages and add
// an output
// Don't do anything with the data
// Maybe add an message counter which counts the incomming messages and add
// an output
fNumMessages++;
LOG(info) << "Received message number "<< fNumMessages
<< " with size " << msg->GetSize();
LOG(info) << "Received message number " << fNumMessages << " with size " << msg->GetSize();
std::string msgStr(static_cast<char*>(msg->GetData()), msg->GetSize());
std::istringstream iss(msgStr);
boost::archive::binary_iarchive inputArchive(iss);
fles::StorableTimeslice component{0};
fles::StorableTimeslice component {0};
inputArchive >> component;
CheckTimeslice(component);
......@@ -96,22 +95,16 @@ bool CbmTsaComponentSink::HandleData(FairMQMessagePtr& msg, int /*index*/)
return true;
}
CbmTsaComponentSink::~CbmTsaComponentSink()
{
}
CbmTsaComponentSink::~CbmTsaComponentSink() {}
void CbmTsaComponentSink::PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc)
{
LOG(info) << "Header ID: Ox" << std::hex << static_cast<int>(mdsc.hdr_id)
<< std::dec;
LOG(info) << "Header version: Ox" << std::hex << static_cast<int>(mdsc.hdr_ver)
<< std::dec;
LOG(info) << "Header ID: Ox" << std::hex << static_cast<int>(mdsc.hdr_id) << std::dec;
LOG(info) << "Header version: Ox" << std::hex << static_cast<int>(mdsc.hdr_ver) << std::dec;
LOG(info) << "Equipement ID: " << mdsc.eq_id;
LOG(info) << "Flags: " << mdsc.flags;
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(mdsc.sys_id)
<< std::dec;
LOG(info) << "Sys version: Ox" << std::hex << static_cast<int>(mdsc.sys_ver)
<< std::dec;
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(mdsc.sys_id) << std::dec;
LOG(info) << "Sys version: Ox" << std::hex << static_cast<int>(mdsc.sys_ver) << std::dec;
LOG(info) << "Microslice Idx: " << mdsc.idx;
LOG(info) << "Checksum: " << mdsc.crc;
LOG(info) << "Size: " << mdsc.size;
......@@ -120,22 +113,18 @@ void CbmTsaComponentSink::PrintMicroSliceDescriptor(const fles::MicrosliceDescri
bool CbmTsaComponentSink::CheckTimeslice(const fles::Timeslice& ts)
{
if ( 0 == ts.num_components() ) {
if (0 == ts.num_components()) {
LOG(error) << "No Component in TS " << ts.index();
return 1;
}
LOG(info) << "Found " << ts.num_components()
<< " different components in timeslice";
LOG(info) << "Found " << ts.num_components() << " different components in timeslice";
for (size_t c = 0; c < ts.num_components(); ++c) {
LOG(info) << "Found " << ts.num_microslices(c)
<< " microslices in component " << c;
LOG(info) << "Component " << c << " has a size of "
<< ts.size_component(c) << " bytes";
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(ts.descriptor(0,0).sys_id)
<< std::dec;
/*
LOG(info) << "Found " << ts.num_microslices(c) << " microslices in component " << c;
LOG(info) << "Component " << c << " has a size of " << ts.size_component(c) << " bytes";
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(ts.descriptor(0, 0).sys_id) << std::dec;
/*
for (size_t m = 0; m < ts.num_microslices(c); ++m) {
PrintMicroSliceDescriptor(ts.descriptor(c,m));
}
......
/* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
/**
* CbmTsaComponentSink.h
*
......@@ -8,30 +12,28 @@
#ifndef CBMTSACOMPONENTSINK_H_
#define CBMTSACOMPONENTSINK_H_
#include "FairMQDevice.h"
#include "Timeslice.hpp"
#include "MicrosliceDescriptor.hpp"
#include "Timeslice.hpp"
#include "FairMQDevice.h"
class CbmTsaComponentSink: public FairMQDevice
{
public:
CbmTsaComponentSink();
virtual ~CbmTsaComponentSink();
class CbmTsaComponentSink : public FairMQDevice {
public:
CbmTsaComponentSink();
virtual ~CbmTsaComponentSink();
protected:
virtual void InitTask();
bool HandleData(FairMQMessagePtr&, int);
protected:
virtual void InitTask();
bool HandleData(FairMQMessagePtr&, int);
private:
uint64_t fNumMessages;
private:
uint64_t fNumMessages;
std::vector<std::string> fAllowedChannels
= {"stscomponent","tofcomponent","trdcomponent"};
std::vector<std::string> fAllowedChannels = {"stscomponent", "tofcomponent", "trdcomponent"};
bool CheckTimeslice(const fles::Timeslice& ts);
void PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc);
bool IsChannelNameAllowed(std::string channelName);
bool CheckTimeslice(const fles::Timeslice& ts);
void PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc);
bool IsChannelNameAllowed(std::string channelName);
};
#endif /* CBMTSACOMPONENTSINK_H_ */
#include "runFairMQDevice.h"
/* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
#include "CbmDevNullSink.h"
#include "runFairMQDevice.h"
namespace bpo = boost::program_options;
void addCustomOptions(bpo::options_description& /*options*/)
{
// options.add_options()
// ("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
// options.add_options()
// ("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
{
return new CbmDevNullSink();
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDevNullSink(); }
#include "runFairMQDevice.h"
/* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
#include "CbmTsaComponentSink.h"
#include "runFairMQDevice.h"
namespace bpo = boost::program_options;
void addCustomOptions(bpo::options_description& /*options*/)
{
}
void addCustomOptions(bpo::options_description& /*options*/) {}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
{
return new CbmTsaComponentSink();
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmTsaComponentSink(); }
#!/bin/bash
$FAIRROOTPATH/bin/shmmonitor --cleanup
if [ -e @SIMPATH@/bin/fairmq-shmmonitor ]; then
@SIMPATH@/bin/fairmq-shmmonitor --cleanup
fi
if [ -z "$1" ]; then
if [ -z "$1" ]; then
# _filename=@VMCWORKDIR@/input/stsxyter_cosy2018.tsa
_filename=@VMCWORKDIR@/input/tofget4_hd2018.tsa
else
else
_filename=$1
fi
......
......@@ -2,146 +2,132 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startMQInfo.sh.in ${CMAKE_BINARY_DIR}
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startMQSampler.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startMQSampler.sh)
set(INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/MQ/base
${CBMBASE_DIR}
${CBMDATA_DIR}
${CBMDATA_DIR}/base
${CBMDATA_DIR}/mvd
${CBMDATA_DIR}/sts
${CBMDATA_DIR}/rich
${CBMDATA_DIR}/much
${CBMDATA_DIR}/trd
${CBMDATA_DIR}/tof
# ${CBMDATA_DIR}/ecal
${CBMDATA_DIR}/psd
)
Set(SYSTEM_INCLUDE_DIRECTORIES
${SYSTEM_INCLUDE_DIRECTORIES}
${ZeroMQ_INCLUDE_DIR}
${Boost_INCLUDE_DIR}
${FAIRROOT_INCLUDE_DIR}
${FAIRMQ_INCLUDE_DIR}
${FAIRMQ_INCLUDE_DIR}/options
${IPC_INCLUDE_DIRECTORY}
${CBMROOT_SOURCE_DIR}/external/cppzmq
)
include_directories(${INCLUDE_DIRECTORIES})
include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
set(LINK_DIRECTORIES
${ROOT_LIBRARY_DIR}
${FAIRROOT_LIBRARY_DIR}
${Boost_LIBRARY_DIRS}
)
link_directories(${LINK_DIRECTORIES})
${CMAKE_CURRENT_SOURCE_DIR}
)
# Set the install path within the build directory
set(EXECUTABLE_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/MQ/source")
# Set the install path within the installation directory
set(BIN_DESTINATION bin/MQ/source)
Set(BOOST_LIBS
${Boost_SYSTEM_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_SERIALIZATION_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_LOG_LIBRARY}
${Boost_REGEX_LIBRARY}
)
If(UNIX AND NOT APPLE)
List(APPEND BOOST_LIBS pthread)
EndIf()
set(FAIR_LIBS
FairMQ
)
set(PUBLIC_DEPS
CbmMQBase
)
If(FAIRLOGGER_FOUND)
set(FAIR_LIBS
${FAIR_LIBS}
FairLogger
)
EndIf()
set(PRIVATE_DEPS
CbmBase
CbmData
CbmFlibFlesTools
external::fles_logging
cppzmq
FairRoot::Base
FairRoot::ParBase
)
set(INTERFACE_DEPS
FairMQ::FairMQ
)
set(EXE_NAME TsaSampler)
set(SRCS CbmMQTsaSampler.cxx runTsaSampler.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
fles_ipc
CbmMQBase
)
GENERATE_EXECUTABLE()
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME MultiTsaSampler)
set(SRCS CbmMQTsaMultiSampler.cxx runTsaMultiSampler.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
fles_ipc
CbmMQBase
)
GENERATE_EXECUTABLE()
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME RepReqTsSampler)
set(SRCS CbmMQTsSamplerRepReq.cxx runTsSamplerRepReq.cxx)
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME TsaSamplerTof)
set(SRCS CbmMQTsaSamplerTof.cxx runTsaSamplerTof.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
fles_ipc
CbmMQBase
)
GENERATE_EXECUTABLE()
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME TsaMultiSamplerTof)
set(SRCS CbmMQTsaMultiSamplerTof.cxx runTsaMultiSamplerTof.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
fles_ipc
CbmMQBase
)
GENERATE_EXECUTABLE()
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME TsaInfo)
set(SRCS CbmMQTsaInfo.cxx runTsaInfo.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
fles_ipc
CbmMQBase
)
GENERATE_EXECUTABLE()
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
set(EXE_NAME StsDigiSource)
set(SRCS CbmStsDigiSource.cxx runStsDigiSource.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
CbmBase
Core
CbmMQBase
)
GENERATE_EXECUTABLE()
set(EXE_NAME MCPointSource)
set(SRCS CbmMCPointSource.cxx runMCPointSource.cxx)
set(DEPENDENCIES
${DEPENDENCIES}
${FAIR_LIBS}
${BOOST_LIBS}
CbmBase
Core
CbmMQBase
)
GENERATE_EXECUTABLE()
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
#set(EXE_NAME MCPointSource)
#set(SRCS CbmMCPointSource.cxx runMCPointSource.cxx)
#set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
#set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
#set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
# generate_cbm_executable()
set(EXE_NAME TsConsumerReqExample)
set(SRCS CbmTsConsumerReqDevExample.cxx runTsConsumerReqExample.cxx)
set(PUBLIC_DEPENDENCIES ${PUBLIC_DEPS})
set(PRIVATE_DEPENDENCIES ${PRIVATE_DEPS})
set(INTERFACE_DEPENDENCIES ${INTERFACE_DEPS})
generate_cbm_executable()
# Install scripts and input file
if(EXISTS ${VMCWORKDIR}/input/tofget4_hd2018.tsa)
install(FILES ${VMCWORKDIR}/input/tofget4_hd2018.tsa
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/cbmroot/input
)
endif()
# Set the correct variables for the installation
set(VMCWORKDIR ${CMAKE_INSTALL_PREFIX}/share/cbmroot)
set(MY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_CURRENT_SOURCE_DIR ${VMCWORKDIR}/input)
set(TMPDIR "${CMAKE_BINARY_DIR}")
set(CMAKE_BINARY_DIR ${CMAKE_INSTALL_PREFIX})
# Configure file for installation directory
configure_file(${MY_SOURCE_DIR}/startMQInfo.sh.in ${TMPDIR}/bin/MQ/topologies/install/startMQInfo.sh)
configure_file(${MY_SOURCE_DIR}/startMQSampler.sh.in ${TMPDIR}/bin/MQ/topologies/install/startMQSampler.sh)
install(PROGRAMS ${TMPDIR}/bin/MQ/topologies/install/startMQInfo.sh
${TMPDIR}/bin/MQ/topologies/install/startMQSampler.sh
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin/MQ/topologies
)
/* Copyright (C) 2019-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
/**
* CbmMCPointSource.cpp
*
......@@ -6,23 +10,22 @@
*/
#include "CbmMCPointSource.h"
#include "CbmMQDefs.h"
#include "CbmMQDefs.h"
#include "CbmMuchPoint.h"
#include "CbmMvdPoint.h"
#include "CbmStsPoint.h"
#include "CbmRichPoint.h"
#include "CbmMuchPoint.h"
#include "CbmTrdPoint.h"
#include "CbmStsPoint.h"
#include "CbmTofPoint.h"
#include "CbmTrdPoint.h"
//#include "CbmEcalPoint.h"
#include "CbmPsdPoint.h"
#include "FairFileSource.h"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairMQProgOptions.h" // device->fConfig
#include "FairRootManager.h"
#include "FairRunAna.h"
#include "FairFileSource.h"
#include "TClonesArray.h"
......@@ -30,37 +33,41 @@
// include this header to serialize vectors
//#include <boost/serialization/vector.hpp>
#include <stdio.h>
#include <ctime>
#include <thread> // this_thread::sleep_for
#include <thread> // this_thread::sleep_for
#include <chrono>
#include <ctime>
#include <stdexcept>
#include <stdio.h>
using namespace std;
struct InitTaskError : std::runtime_error { using std::runtime_error::runtime_error; };
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
void CbmMCPointSource::InitTask()
try
{
try {
// Get the values from the command line options (via fConfig)
fFileName = fConfig->GetValue<string>("filename");
fFileName = fConfig->GetValue<string>("filename");
fMaxEvents = fConfig->GetValue<uint64_t>("max-events");
LOG(info) << "Filename: " << fFileName;
LOG(info) << "MaxEvents: " << fMaxEvents;
// Check if the defined channels from the topology (by name)
// are in the list of channels which are allowed
fChan.CheckChannels(this);
fChan.CheckChannels(this);
fComponentsToSend = fChan.GetComponentsToSend();
fChannelsToSend = fChan.GetChannelsToSend();
for(auto const& value: fComponentsToSend) {
fChannelsToSend = fChan.GetChannelsToSend();
for (auto const& value : fComponentsToSend) {
if (value > 1) {
throw InitTaskError("Sending same data to more than one output channel not implemented yet.");
throw InitTaskError("Sending same data to more than one output channel "
"not implemented yet.");
}
}
......@@ -71,26 +78,22 @@ try
FairRunAna* ana = new FairRunAna();
ana->SetContainerStatic();
FairRootManager* rootman = FairRootManager::Instance();
if ( 0 != fFileName.size() ) {
if (0 != fFileName.size()) {
LOG(info) << "Open the ROOT input file " << fFileName;
// Check if the input file exist
FILE* inputFile = fopen(fFileName.c_str(), "r");
if ( ! inputFile ) {
throw InitTaskError("Input file doesn't exist.");
}
if (!inputFile) { throw InitTaskError("Input file doesn't exist."); }
fclose(inputFile);
FairFileSource* source = new FairFileSource(fFileName);
if ( !source) {
throw InitTaskError("Could not open input file.");
}
FairFileSource* source = new FairFileSource(fFileName);
if (!source) { throw InitTaskError("Could not open input file."); }
rootman->SetSource(source);
rootman->InitSource();
for (unsigned i=0; i < fComponentsToSend.size(); i++) {
if (1 == fComponentsToSend.at(i)) { // there is a device connected which consumes data of this type
std::vector<std::string> channel_name = fChannelsToSend.at(i);
for (unsigned i = 0; i < fComponentsToSend.size(); i++) {
if (1 == fComponentsToSend.at(i)) { // there is a device connected which consumes data of this type
std::vector<std::string> channel_name = fChannelsToSend.at(i);
LOG(info) << channel_name.at(0);
ConnectChannelIfNeeded(i, channel_name.at(0), "MvdPoint", rootman);
ConnectChannelIfNeeded(i, channel_name.at(0), "StsPoint", rootman);
......@@ -98,54 +101,57 @@ try
ConnectChannelIfNeeded(i, channel_name.at(0), "MuchPoint", rootman);
ConnectChannelIfNeeded(i, channel_name.at(0), "TrdPoint", rootman);
ConnectChannelIfNeeded(i, channel_name.at(0), "TofPoint", rootman);
// ConnectChannelIfNeeded(i, channel_name.at(0), "EcalPoint", rootman);
// ConnectChannelIfNeeded(i, channel_name.at(0), "EcalPoint", rootman);
ConnectChannelIfNeeded(i, channel_name.at(0), "PsdPoint", rootman);
} else {
}
else {
fArrays.at(i) = nullptr;
}
}
} else {
throw InitTaskError("No input file specified");
}
else {
throw InitTaskError("No input file specified");
}
Int_t MaxAllowed=FairRootManager::Instance()->CheckMaxEventNo(fMaxEvents);
if ( MaxAllowed != -1 ) {
if (fMaxEvents == 0) {
fMaxEvents = MaxAllowed;
} else {
Int_t MaxAllowed = FairRootManager::Instance()->CheckMaxEventNo(fMaxEvents);
if (MaxAllowed != -1) {
if (fMaxEvents == 0) { fMaxEvents = MaxAllowed; }
else {
if (static_cast<Int_t>(fMaxEvents) > MaxAllowed) {
LOG(warn) << "-------------------Warning---------------------------";
LOG(warn) << " File has less events than requested!!";
LOG(warn) << " File contains : " << MaxAllowed << " Events";
LOG(warn) << " Requested number of events = " << fMaxEvents << " Events";
LOG(warn) << " File contains : " << MaxAllowed << " Events";
LOG(warn) << " Requested number of events = " << fMaxEvents << " Events";
LOG(warn) << " The number of events is set to " << MaxAllowed << " Events";
LOG(warn) << "-----------------------------------------------------";
fMaxEvents = MaxAllowed;
}
}
LOG(info) << "After checking, the run will run from event 0 " << " to " << fMaxEvents << ".";
} else {
LOG(info) << "continue running without stop";
LOG(info) << "After checking, the run will run from event 0 "
<< " to " << fMaxEvents << ".";
}
else {
LOG(info) << "continue running without stop";
}
fTime = std::chrono::steady_clock::now();
} catch (InitTaskError& e) {
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
}
void CbmMCPointSource::ConnectChannelIfNeeded(int chan_number,
std::string channel_name, std::string branchname,
FairRootManager* rootman)
void CbmMCPointSource::ConnectChannelIfNeeded(int chan_number, std::string channel_name, std::string branchname,
FairRootManager* rootman)
{
if ( 0 == channel_name.compare(branchname) ) {
if (0 == channel_name.compare(branchname)) {
LOG(info) << "Found expected data type " << branchname;
TClonesArray* arr = static_cast<TClonesArray*>(rootman->GetObject(branchname.c_str()));
if (!arr) {
LOG(info) << "Consuming device connected but no " << branchname << " array in input file!";
fComponentsToSend.at(chan_number) = 0; // Don't send to connected device since needed data is not in input
fComponentsToSend.at(chan_number) = 0; // Don't send to connected device since needed data is not in input
}
fArrays.at(chan_number) = arr;
}
......@@ -157,75 +163,70 @@ bool CbmMCPointSource::ConditionalRun()
Int_t readEventReturn = FairRootManager::Instance()->ReadEvent(fEventCounter);
// LOG(info) <<"Return value: " << readEventReturn;
if ( readEventReturn != 0 ) {
LOG(warn) << "FairRootManager::Instance()->ReadEvent(" << fEventCounter << ") returned "
<< readEventReturn << ". Breaking the event loop";
if (readEventReturn != 0) {
LOG(warn) << "FairRootManager::Instance()->ReadEvent(" << fEventCounter << ") returned " << readEventReturn
<< ". Breaking the event loop";
CalcRuntime();
return false;
}
for (unsigned i=0; i < fComponentsToSend.size(); i++) {
for (unsigned i = 0; i < fComponentsToSend.size(); i++) {
bool result = true;
if (1 == fComponentsToSend.at(i)) { // there is a device connected which consumes data of this type
if (1 == fComponentsToSend.at(i)) { // there is a device connected which consumes data of this type
if (0 == fChannelsToSend.at(i).at(0).compare("MvdPoint")) {
result = ConvertAndSend<CbmMvdPoint>(fArrays.at(i), i);
result = ConvertAndSend<CbmMvdPoint>(fArrays.at(i), i);
}
if (0 == fChannelsToSend.at(i).at(0).compare("StsPoint")) {
result = ConvertAndSend<CbmStsPoint>(fArrays.at(i), i);
result = ConvertAndSend<CbmStsPoint>(fArrays.at(i), i);
}
if (0 == fChannelsToSend.at(i).at(0).compare("RichPoint")) {
result = ConvertAndSend<CbmRichPoint>(fArrays.at(i), i);
result = ConvertAndSend<CbmRichPoint>(fArrays.at(i), i);
}
if (0 == fChannelsToSend.at(i).at(0).compare("MuchPoint")) {
result = ConvertAndSend<CbmMuchPoint>(fArrays.at(i), i);
result = ConvertAndSend<CbmMuchPoint>(fArrays.at(i), i);
}
if (0 == fChannelsToSend.at(i).at(0).compare("TrdPoint")) {
result = ConvertAndSend<CbmTrdPoint>(fArrays.at(i), i);
result = ConvertAndSend<CbmTrdPoint>(fArrays.at(i), i);
}
if (0 == fChannelsToSend.at(i).at(0).compare("TofPoint")) {
result = ConvertAndSend<CbmTofPoint>(fArrays.at(i),i );
result = ConvertAndSend<CbmTofPoint>(fArrays.at(i), i);
}
/*
/*
if (0 == fChannelsToSend.at(i).at(0).compare("EcalPoint")) {
result = ConvertAndSend<CbmEcalPoint>(fArrays.at(i),i );
}
*/
if (0 == fChannelsToSend.at(i).at(0).compare("PsdPoint")) {
result = ConvertAndSend<CbmPsdPoint>(fArrays.at(i), i);
result = ConvertAndSend<CbmPsdPoint>(fArrays.at(i), i);
}
if (!result) {
LOG(error) << "Problem sending data";
return false;
LOG(error) << "Problem sending data";
return false;
}
}
}
if (fEventCounter % 10000 == 0) LOG(info) << "Analyse Event " << fEventCounter;
if (fEventCounter % 10000 == 0) LOG(info) << "Analyse Event " << fEventCounter;
fEventCounter++;
// LOG(info) << "Counter: " << fEventCounter << " Events: " << fMaxEvents;
if (fEventCounter < fMaxEvents) {
return true;
} else {
// LOG(info) << "Counter: " << fEventCounter << " Events: " << fMaxEvents;
if (fEventCounter < fMaxEvents) { return true; }
else {
CalcRuntime();
return false;
}
}
CbmMCPointSource::~ CbmMCPointSource()
{
}
CbmMCPointSource::~CbmMCPointSource() {}
void CbmMCPointSource::CalcRuntime()
{
std::chrono::duration<double> run_time =
std::chrono::steady_clock::now() - fTime;
std::chrono::duration<double> run_time = std::chrono::steady_clock::now() - fTime;
LOG(info) << "Runtime: " << run_time.count();
LOG(info) << "No more input data";
}
/* Copyright (C) 2019-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
/**
* CbmMCPointSource.h
*
......@@ -8,17 +12,17 @@
#ifndef CBMMCPOINTSOURCE_H_
#define CBMMCPOINTSOURCE_H_
#include "FairMQDevice.h"
#include "CbmMQChannels.h"
#include "FairMQDevice.h"
#include "TClonesArray.h"
#include <boost/archive/binary_oarchive.hpp>
#include <ctime>
#include <string>
#include <vector>
#include <ctime>
#include <boost/archive/binary_oarchive.hpp>
// include this header to serialize vectors
#include <boost/serialization/vector.hpp>
......@@ -26,126 +30,126 @@ class CbmMCPoint;
class FairRootManager;
class TClonesArray;
class CbmMCPointSource : public FairMQDevice
{
public:
CbmMCPointSource() = default;
virtual ~CbmMCPointSource();
protected:
uint64_t fMaxEvents {0};
std::string fFileName {""};
std::vector<std::string> fInputFileList {}; ///< List of input files
uint64_t fFileCounter {};
uint64_t fEventNumber {0};
uint64_t fEventCounter {0};
uint64_t fMessageCounter {0};
int fMaxMemory {0};
virtual void InitTask();
virtual bool ConditionalRun();
private:
bool SendData();
void CalcRuntime();
void ConnectChannelIfNeeded(int, std::string, std::string, FairRootManager*);
template <class T>
void PrintMCPoint(TClonesArray* arr) {
Int_t entries = arr->GetEntriesFast();
if (entries > 0) {
T* point = static_cast<T*>(arr->At(0));
LOG(info) << "Entries in TCA for data type " << point->GetName() << ": " << entries;
}
for(int i=0; i< entries; ++i) {
T* point = static_cast<T*>(arr->At(i));
point->Print("");
}
class CbmMCPointSource : public FairMQDevice {
public:
CbmMCPointSource() = default;
virtual ~CbmMCPointSource();
protected:
uint64_t fMaxEvents {0};
std::string fFileName {""};
std::vector<std::string> fInputFileList {}; ///< List of input files
uint64_t fFileCounter {};
uint64_t fEventNumber {0};
uint64_t fEventCounter {0};
uint64_t fMessageCounter {0};
int fMaxMemory {0};
virtual void InitTask();
virtual bool ConditionalRun();
private:
bool SendData();
void CalcRuntime();
void ConnectChannelIfNeeded(int, std::string, std::string, FairRootManager*);
template<class T>
void PrintMCPoint(TClonesArray* arr)
{
Int_t entries = arr->GetEntriesFast();
if (entries > 0) {
T* point = static_cast<T*>(arr->At(0));
LOG(info) << "Entries in TCA for data type " << point->GetName() << ": " << entries;
}
for (int i = 0; i < entries; ++i) {
T* point = static_cast<T*>(arr->At(i));
point->Print("");
}
}
template<class T>
std::vector<T> Convert(TClonesArray* arr)
{
template <class T>
std::vector<T> Convert(TClonesArray* arr) {
std::vector<T> vec;
Int_t entries = arr->GetEntriesFast();
if (entries > 0) {
T* point = static_cast<T*>(arr->At(0));
LOG(info) << "Entries in TCA for data type " << point->GetName() << ": " << entries;
}
for(int i=0; i< entries; ++i) {
T* point = static_cast<T*>(arr->At(i));
vec.emplace_back(*point);
}
return vec;
std::vector<T> vec;
Int_t entries = arr->GetEntriesFast();
if (entries > 0) {
T* point = static_cast<T*>(arr->At(0));
LOG(info) << "Entries in TCA for data type " << point->GetName() << ": " << entries;
}
for (int i = 0; i < entries; ++i) {
T* point = static_cast<T*>(arr->At(i));
vec.emplace_back(*point);
}
return vec;
}
template <class T>
bool ConvertAndSend(TClonesArray* arr, int i) {
std::vector<T> vec;
Int_t entries = arr->GetEntriesFast();
if (entries > 0) {
T* point = static_cast<T*>(arr->At(0));
LOG(info) << "Entries in TCA for data type " << point->GetName() << ": " << entries;
}
for(int iEntries=0; iEntries< entries; ++iEntries) {
T* point = static_cast<T*>(arr->At(iEntries));
vec.emplace_back(*point);
}
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << vec;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object){ delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// TODO: Implement sending same data to more than one channel
// Need to create new message (copy message??)
if (fComponentsToSend.at(i)>1) {
LOG(info) << "Need to copy FairMessage";
}
// in case of error or transfer interruption,
// return false to go to IDLE state
// successfull transfer will return number of bytes
// transfered (can be 0 if sending an empty message).
LOG(info) << "Send data to channel " << fChannelsToSend.at(i).at(0);
if (Send(msg, fChannelsToSend.at(i).at(0)) < 0) {
LOG(error) << "Problem sending data";
return false;
}
return true;
template<class T>
bool ConvertAndSend(TClonesArray* arr, int i)
{
std::vector<T> vec;
Int_t entries = arr->GetEntriesFast();
if (entries > 0) {
T* point = static_cast<T*>(arr->At(0));
LOG(info) << "Entries in TCA for data type " << point->GetName() << ": " << entries;
}
std::chrono::steady_clock::time_point fTime {};
std::vector<std::string> fAllowedChannels
= {"MvdPoint", "StsPoint", "RichPoint", "MuchPoint",
"Trdpoint", "TofPoint", "PsdPoint"};
for (int iEntries = 0; iEntries < entries; ++iEntries) {
T* point = static_cast<T*>(arr->At(iEntries));
vec.emplace_back(*point);
}
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << vec;
std::string* strMsg = new std::string(oss.str());
/*
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// TODO: Implement sending same data to more than one channel
// Need to create new message (copy message??)
if (fComponentsToSend.at(i) > 1) { LOG(info) << "Need to copy FairMessage"; }
// in case of error or transfer interruption,
// return false to go to IDLE state
// successfull transfer will return number of bytes
// transfered (can be 0 if sending an empty message).
LOG(info) << "Send data to channel " << fChannelsToSend.at(i).at(0);
if (Send(msg, fChannelsToSend.at(i).at(0)) < 0) {
LOG(error) << "Problem sending data";
return false;
}
return true;
}
std::chrono::steady_clock::time_point fTime {};
std::vector<std::string> fAllowedChannels = {"MvdPoint", "StsPoint", "RichPoint", "MuchPoint",
"Trdpoint", "TofPoint", "PsdPoint"};
/*
std::vector<std::string> fAllowedChannels
= {"MvdPoint", "StsPoint", "RichPoint", "MuchPoint",
"Trdpoint", "TofPoint", "EcalPoint", "PsdPoint"};
*/
CbmMQChannels fChan{fAllowedChannels};
std::vector<int> fComponentsToSend {};
std::vector<std::vector<std::string>> fChannelsToSend { {} };
std::vector<TClonesArray*> fArrays {fAllowedChannels.size(), nullptr};
CbmMQChannels fChan {fAllowedChannels};
std::vector<int> fComponentsToSend {};
std::vector<std::vector<std::string>> fChannelsToSend {{}};
std::vector<TClonesArray*> fArrays {fAllowedChannels.size(), nullptr};
};
#endif /* CBMMCPOINTSOURCE_H_ */
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
#include "CbmMQTsSamplerRepReq.h"
#include "CbmFlesCanvasTools.h"
#include "CbmFormatDecHexPrintout.h"
#include "TimesliceInputArchive.hpp"
#include "TimesliceMultiInputArchive.hpp"
#include "TimesliceMultiSubscriber.hpp"
#include "TimesliceSubscriber.hpp"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include <TCanvas.h>
#include <TH1F.h>
#include <TH1I.h>
#include <TProfile.h>
#include "BoostSerializer.h"
#include <boost/algorithm/string.hpp>
#include <boost/archive/binary_oarchive.hpp>
//#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
#include <boost/serialization/utility.hpp>
#include "RootSerializer.h"
//namespace filesys = boost::filesystem;
#include <thread> // this_thread::sleep_for
#include <algorithm>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <string>
#include <stdio.h>
using namespace std;
#include <stdexcept>
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
CbmMQTsSamplerRepReq::CbmMQTsSamplerRepReq()
: FairMQDevice()
, fTime()
, fLastPublishTime {std::chrono::system_clock::now()}
{
}
void CbmMQTsSamplerRepReq::InitTask()
try {
// Get the values from the command line options (via fConfig)
fsFileName = fConfig->GetValue<string>("filename");
fsDirName = fConfig->GetValue<string>("dirname");
fsHost = fConfig->GetValue<string>("fles-host");
fusPort = fConfig->GetValue<uint16_t>("fles-port");
fulHighWaterMark = fConfig->GetValue<uint64_t>("high-water-mark");
fulMaxTimeslices = fConfig->GetValue<uint64_t>("max-timeslices");
fsChannelNameTsRequest = fConfig->GetValue<std::string>("ChNameTsReq");
fbNoSplitTs = fConfig->GetValue<bool>("no-split-ts");
fbSendTsPerSysId = fConfig->GetValue<bool>("send-ts-per-sysid");
fbSendTsPerBlock = fConfig->GetValue<bool>("send-ts-per-block");
fsChannelNameMissedTs = fConfig->GetValue<std::string>("ChNameMissTs");
fsChannelNameCommands = fConfig->GetValue<std::string>("ChNameCmds");
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
fsHistosSuffix = fConfig->GetValue<std::string>("HistosSuffix");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
if (fbNoSplitTs) {
if (fbSendTsPerSysId) {
if (fbSendTsPerBlock) {
LOG(warning) << "Both no-split-ts, send-ts-per-sysid and send-ts-per-block options used => "
<< " second and third one will be ignored!!!!";
} // if( fbSendTsPerBlock )
else
LOG(warning) << "Both no-split-ts and send-ts-per-sysid options used => "
<< " second one will be ignored!!!!";
} // if( fbSendTsPerSysId )
else if (fbSendTsPerBlock) {
LOG(warning) << "Both no-split-ts and send-ts-per-block options used => "
<< " second one will be ignored!!!!";
} // else if( fbSendTsPerSysId ) of if( fbSendTsPerSysId )
else
LOG(debug) << "Running in no-split-ts mode!";
} // if( fbNoSplitTs )
else if (fbSendTsPerBlock) {
if (fbSendTsPerSysId) {
LOG(warning) << "Both send-ts-per-sysid and send-ts-per-block options used => "
<< " second one will be ignored!!!!";
} // if (fbSendTsPerSysId)
else
LOG(debug) << "Running in send-ts-per-block mode!";
} // else if( fbSendTsPerBlock ) of if( fbNoSplitTs )
else if (fbSendTsPerSysId) {
LOG(debug) << "Running in send-ts-per-sysid mode!";
} // else if (fbSendTsPerSysId) else if( fbSendTsPerBlock ) of if( fbNoSplitTs )
else {
LOG(debug) << "Running in no-split-ts mode by default!";
fbNoSplitTs = true;
} // else of else if (fbSendTsPerSysId) else if( fbSendTsPerBlock ) of if( fbNoSplitTs )
/// Extract SysId and channel information if provided in the binary options
std::vector<std::string> vSysIdBlockPairs = fConfig->GetValue<std::vector<std::string>>("block-sysid");
for (uint32_t uPair = 0; uPair < vSysIdBlockPairs.size(); ++uPair) {
const size_t sep = vSysIdBlockPairs[uPair].find(':');
if (string::npos == sep || 0 == sep || vSysIdBlockPairs[uPair].size() == sep) {
LOG(info) << vSysIdBlockPairs[uPair];
throw InitTaskError("Provided pair of Block name + SysId is missing a : or an argument.");
} // if( string::npos == sep || 0 == sep || vSysIdBlockPairs[ uPair ].size() == sep )
/// Extract Block name
std::string sBlockName = vSysIdBlockPairs[uPair].substr(0, sep);
/// Extract SysId
/// TODO: or component name
std::string sSysId = vSysIdBlockPairs[uPair].substr(sep + 1);
const size_t hexPos = sSysId.find("0x");
uint16_t usSysId;
if (string::npos == hexPos) usSysId = std::stoi(sSysId);
else
usSysId = std::stoi(sSysId.substr(hexPos + 2), nullptr, 16);
LOG(debug) << "Extracted block info from pair \"" << vSysIdBlockPairs[uPair] << "\": name is " << sBlockName
<< " and SysId is " << usSysId << " extracted from " << sSysId;
/// Check if SysId already in use
uint32_t uSysIdIdx = 0;
for (; uSysIdIdx < fSysId.size() && fSysId[uSysIdIdx] != usSysId; ++uSysIdIdx) {}
if (uSysIdIdx == fSysId.size()) { throw InitTaskError("Unknown System ID for " + vSysIdBlockPairs[uPair]); }
else if (true == fComponentActive[uSysIdIdx]) {
throw InitTaskError("System ID already in use by another block for " + vSysIdBlockPairs[uPair]);
}
fComponentActive[uSysIdIdx] = true;
/// Look if Block is already defined
auto itBlock = fvBlocksToSend.begin();
for (; itBlock != fvBlocksToSend.end(); ++itBlock) {
if ((*itBlock).first == sBlockName) break;
} // for( ; itBlock != fvBlocksToSend.end(); ++itBlock)
if (fvBlocksToSend.end() != itBlock) {
/// Block already there, add the SysId to its list
(*itBlock).second.insert(usSysId);
} // if( fvBlocksToSend.end() != itBlock )
else {
/// Block unknown yet, add both Block and First SysId
fvBlocksToSend.push_back(std::pair<std::string, std::set<uint16_t>>(sBlockName, {usSysId}));
fvvCompPerBlock.push_back(std::vector<uint32_t>({}));
} // else of if( fSysId.end() != pos )
LOG(info) << vSysIdBlockPairs[uPair] << " Added SysId 0x" << std::hex << usSysId << std::dec << " to "
<< sBlockName;
} // for( uint32_t uPair = 0; uPair < vSysIdBlockPairs.size(); ++uPair )
if (0 == fulMaxTimeslices) fulMaxTimeslices = UINT_MAX;
// Check which input is defined
// Possibilities:
// filename && ! dirname : single file
// filename with wildcards && dirname : all files with filename regex in the directory
// host && port : connect to the flesnet server
bool isGoodInputCombi {false};
if (0 != fsFileName.size() && 0 == fsDirName.size() && 0 == fsHost.size() && 0 == fusPort) {
isGoodInputCombi = true;
fvsInputFileList.push_back(fsFileName);
}
else if (0 != fsFileName.size() && 0 != fsDirName.size() && 0 == fsHost.size() && 0 == fusPort) {
isGoodInputCombi = true;
fvsInputFileList.push_back(fsFileName);
}
else if (0 == fsFileName.size() && 0 == fsDirName.size() && 0 != fsHost.size() && 0 != fusPort) {
isGoodInputCombi = true;
LOG(info) << "Host: " << fsHost;
LOG(info) << "Port: " << fusPort;
}
else if (0 == fsFileName.size() && 0 == fsDirName.size() && 0 != fsHost.size() && 0 == fusPort) {
isGoodInputCombi = true;
LOG(info) << "Host string: " << fsHost;
}
else {
isGoodInputCombi = false;
}
if (!isGoodInputCombi) {
throw InitTaskError("Wrong combination of inputs. Either file or wildcard file + directory "
"or host + port are allowed combination.");
}
LOG(info) << "MaxTimeslices: " << fulMaxTimeslices;
if (0 == fsFileName.size() && 0 != fsHost.size() && 0 != fusPort) {
// Don't add the protocol since this is done now in the TimesliceMultiSubscriber
//std::string connector = "tcp://" + fsHost + ":" + std::to_string(fusPort);
std::string connector = fsHost + ":" + std::to_string(fusPort);
LOG(info) << "Open TSPublisher at " << connector;
fSource = new fles::TimesliceMultiSubscriber(connector, fulHighWaterMark);
}
else if (0 == fsFileName.size() && 0 != fsHost.size()) {
std::string connector = fsHost;
LOG(info) << "Open TSPublisher with host string: " << connector;
fSource = new fles::TimesliceMultiSubscriber(connector, fulHighWaterMark);
}
else {
// Create a ";" separated string with all file names
std::string fileList {""};
for (const auto& obj : fvsInputFileList) {
std::string fileName = obj;
fileList += fileName;
fileList += ";";
}
fileList.pop_back(); // Remove the last ;
LOG(info) << "Input File String: " << fileList;
fSource = new fles::TimesliceMultiInputArchive(fileList, fsDirName);
if (!fSource) { throw InitTaskError("Could open files from file list."); }
}
LOG(info) << "High-Water Mark: " << fulHighWaterMark;
LOG(info) << "Max. Timeslices: " << fulMaxTimeslices;
if (fbNoSplitTs) { LOG(info) << "Sending TS copies in no-split mode"; } // if( fbNoSplitTs )
else if (fbSendTsPerSysId) {
LOG(info) << "Sending components in separate TS per SysId";
} // else if( fbSendTsPerSysId ) of if( fbNoSplitTs )
else if (fbSendTsPerBlock) {
LOG(info) << "Sending components in separate TS per block (multiple SysId)";
} // else if( fbSendTsPerBlock ) of if( fbSendTsPerSysId ) of if( fbNoSplitTs )
OnData(fsChannelNameTsRequest, &CbmMQTsSamplerRepReq::HandleRequest);
fTime = std::chrono::steady_clock::now();
}
catch (InitTaskError& e) {
LOG(error) << e.what();
ChangeState(fair::mq::Transition::ErrorFound);
}
catch (boost::bad_any_cast& e) {
LOG(error) << "Error during InitTask: " << e.what();
ChangeState(fair::mq::Transition::ErrorFound);
}
bool CbmMQTsSamplerRepReq::InitHistograms()
{
LOG(info) << "Histograms publication frequency in TS: " << fuPublishFreqTs;
LOG(info) << "Histograms publication min. interval in s: " << fdMinPublishTime;
LOG(info) << "Histograms publication max. interval in s: " << fdMaxPublishTime;
if ("" != fsHistosSuffix) { //
LOG(info) << "Suffix added to folders, histograms and canvas names: " << fsHistosSuffix;
}
/// Vector of pointers on each histo (+ optionally desired folder)
std::vector<std::pair<TNamed*, std::string>> vHistos = {};
/// Vector of pointers on each canvas (+ optionally desired folder)
std::vector<std::pair<TCanvas*, std::string>> vCanvases = {};
/// Histos creation and obtain pointer on them
/* clang-format off */
fhTsRate = new TH1I(Form("TsRate%s", fsHistosSuffix.data()),
"TS rate; t [s]",
1800, 0., 1800.);
fhTsSize = new TH1I(Form("TsSize%s", fsHistosSuffix.data()),
"Size of TS; Size [MB]",
15000, 0., 15000.);
fhTsSizeEvo = new TProfile(Form("TsSizeEvo%s", fsHistosSuffix.data()),
"Evolution of the TS Size; t [s]; Mean size [MB]",
1800, 0., 1800.);
fhTsMaxSizeEvo = new TH1F(Form("TsMaxSizeEvo%s", fsHistosSuffix.data()),
"Evolution of maximal TS Size; t [s]; Max size [MB]",
1800, 0., 1800.);
fhMissedTS = new TH1I(Form("MissedTs%s", fsHistosSuffix.data()),
"Missed TS",
2, -0.5, 1.5);
fhMissedTSEvo = new TProfile(Form("MissedTsEvo%s", fsHistosSuffix.data()),
"Missed TS evolution; t [s]",
1800, 0., 1800.);
/* clang-format on */
/// Add histo pointers to the histo vector
std::string sFolder = std::string("Sampler") + fsHistosSuffix;
vHistos.push_back(std::pair<TNamed*, std::string>(fhTsRate, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTsSize, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTsSizeEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTsMaxSizeEvo, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhMissedTS, sFolder));
vHistos.push_back(std::pair<TNamed*, std::string>(fhMissedTSEvo, sFolder));
/// Canvases creation
Double_t w = 10;
Double_t h = 10;
fcSummary = new TCanvas(Form("cSampSummary%s", fsHistosSuffix.data()), "Sampler monitoring plots", w, h);
fcSummary->Divide(2, 3);
fcSummary->cd(1);
gPad->SetGridx();
gPad->SetGridy();
fhTsRate->Draw("hist");
fcSummary->cd(2);
gPad->SetGridx();
gPad->SetGridy();
gPad->SetLogx();
gPad->SetLogy();
fhTsSize->Draw("hist");
fcSummary->cd(3);
gPad->SetGridx();
gPad->SetGridy();
fhTsSizeEvo->Draw("hist");
fcSummary->cd(4);
gPad->SetGridx();
gPad->SetGridy();
fhTsMaxSizeEvo->Draw("hist");
fcSummary->cd(5);
gPad->SetGridx();
gPad->SetGridy();
fhMissedTS->Draw("hist");
fcSummary->cd(6);
gPad->SetGridx();
gPad->SetGridy();
fhMissedTSEvo->Draw("el");
/// Add canvas pointers to the canvas vector
vCanvases.push_back(std::pair<TCanvas*, std::string>(fcSummary, std::string("canvases") + fsHistosSuffix));
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add(vHistos[uHisto].first);
std::pair<std::string, std::string> psHistoConfig(vHistos[uHisto].first->GetName(), vHistos[uHisto].second);
fvpsHistosFolder.push_back(psHistoConfig);
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
return true;
}
bool CbmMQTsSamplerRepReq::HandleRequest(FairMQMessagePtr& msgReq, int)
{
/// Initialize the histograms
if (0 < fuPublishFreqTs && 0 == fulTsCounter) { InitHistograms(); } // if( 0 < fuPublishFreqTs )
if (fbEofFound) {
/// Ignore all requests if EOS reached
return true;
}
/// TODO: add support for alternative request with "system name" instead of "system ID"
std::string reqStr(static_cast<char*>(msgReq->GetData()), msgReq->GetSize());
if ("SendFirstTimesliceIndex" == reqStr) {
if (0 == fulFirstTsIndex) { //
GetNewTs();
}
if (!SendFirstTsIndex() && !fbEofFound) { //
return false;
}
return true;
}
if (fbNoSplitTs) {
if (!CreateAndSendFullTs() && !fbEofFound) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return false;
} // if( !CreateAndSendFullTs( ts ) && !fbEofFound)
} // if( fbNoSplitTs )
else if (fbSendTsPerSysId) {
/// TODO: add support for alternative request with "system name" instead of "system ID"
int iSysId = std::stoi(reqStr);
LOG(debug) << "Received TS SysId component request from client: 0x" << std::hex << iSysId << std::dec;
/// This assumes that the order of the components does NOT change after the first TS
/// That should be the case as the component index correspond to a physical link idx
if (!CreateCombinedComponentsPerSysId(iSysId) && !fbEofFound) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return false;
} // if(!CreateAndCombineComponentsPerSysId(iSysId) && !fbEofFound)
} // else if( fbSendTsPerSysId && fbSendTsPerSysId ) of if( fbNoSplitTs
else if (fbSendTsPerBlock) {
LOG(debug) << "Received TS components block request from client: " << reqStr;
/// This assumes that the order of the components does NOT change after the first TS
/// That should be the case as the component index correspond to a physical link idx
if (!CreateCombinedComponentsPerBlock(reqStr) && !fbEofFound) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return false;
} // if( !CreateAndCombineComponentsPerChannel(reqStr) && !fbEofFound)
} // else if( fbSendTsPerSysId && fbSendTsPerSysId ) of if( fbNoSplitTs )
/// Send histograms each 100 time slices. Should be each ~1s
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fulMessageCounter % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
if (!fbConfigSent) {
// Send the configuration only once per run!
fbConfigSent = SendHistoConfAndData();
} // if( !fbConfigSent )
else
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fulMessageCounter % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
return true;
}
std::unique_ptr<fles::Timeslice> CbmMQTsSamplerRepReq::GetNewTs()
{
/// Initialize the source (connect to emitter, ...)
if (0 == fulTsCounter && nullptr != dynamic_cast<fles::TimesliceMultiSubscriber*>(fSource)) {
dynamic_cast<fles::TimesliceMultiSubscriber*>(fSource)->InitTimesliceSubscriber();
} // if( 0 == fulTsCounter && nullptr != dynamic_cast< fles::TimesliceMultiSubscriber >(fSource) )
std::unique_ptr<fles::Timeslice> timeslice = fSource->get();
if (timeslice) {
if (fulTsCounter < fulMaxTimeslices) {
const fles::Timeslice& ts = *timeslice;
uint64_t uTsIndex = ts.index();
if (0 == fulFirstTsIndex) { //
fulFirstTsIndex = ts.descriptor(0, 0).idx;
}
if (0 < fuPublishFreqTs) {
uint64_t uTsTime = ts.descriptor(0, 0).idx;
if (0 == fuStartTime) { //
fuStartTime = uTsTime;
} // if( 0 == fuStartTime )
fdTimeToStart = static_cast<double_t>(uTsTime - fuStartTime) / 1e9;
uint64_t uSizeMb = 0;
for (uint64_t uComp = 0; uComp < ts.num_components(); ++uComp) {
uSizeMb += ts.size_component(uComp) / (1024 * 1024);
} // for( uint_t uComp = 0; uComp < ts.num_components(); ++uComp )
fhTsRate->Fill(fdTimeToStart);
fhTsSize->Fill(uSizeMb);
fhTsSizeEvo->Fill(fdTimeToStart, uSizeMb);
/// Fill max size per s (assumes the histo binning is 1 second!)
if (0. == fdLastMaxTime) {
fdLastMaxTime = fdTimeToStart;
fdTsMaxSize = uSizeMb;
} // if( 0. == fdLastMaxTime )
else if (1. <= fdTimeToStart - fdLastMaxTime) {
fhTsMaxSizeEvo->Fill(fdLastMaxTime, fdTsMaxSize);
fdLastMaxTime = fdTimeToStart;
fdTsMaxSize = uSizeMb;
} // else if if( 1 <= fdTimeToStart - fdLastMaxTime )
else if (fdTsMaxSize < uSizeMb) {
fdTsMaxSize = uSizeMb;
} // else if( fdTsMaxSize < uSizeMb )
} // if( 0 < fuPublishFreqTs )
/// Missed TS detection (only if output channel name defined by user)
if ((uTsIndex != (fulPrevTsIndex + 1)) && !(0 == fulPrevTsIndex && 0 == uTsIndex && 0 == fulTsCounter)) {
LOG(debug) << "Missed Timeslices. Old TS Index was " << fulPrevTsIndex << " New TS Index is " << uTsIndex
<< " diff is " << uTsIndex - fulPrevTsIndex << " Missing are " << uTsIndex - fulPrevTsIndex - 1;
if ("" != fsChannelNameMissedTs) {
/// Add missing TS indices to a vector and send it in appropriate channel
std::vector<uint64_t> vulMissedIndices;
if (0 == fulPrevTsIndex && 0 == fulTsCounter) {
/// Catch case where we do not start with the first TS but in the middle of a run
vulMissedIndices.emplace_back(0);
}
/// Standard cases starting with first TS after the last transmitted one
for (uint64_t ulMiss = fulPrevTsIndex + 1; ulMiss < uTsIndex; ++ulMiss) {
vulMissedIndices.emplace_back(ulMiss);
} // for( uint64_t ulMiss = fulPrevTsIndex + 1; ulMiss < uTsIndex; ++ulMiss )
if (!SendMissedTsIdx(vulMissedIndices)) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return nullptr;
} // if( !SendMissedTsIdx( vulMissedIndices ) )
} // if( "" != fsChannelNameMissedTs )
if (0 < fuPublishFreqTs) {
fhMissedTS->Fill(1, uTsIndex - fulPrevTsIndex - 1);
fhMissedTSEvo->Fill(fdTimeToStart, 1, uTsIndex - fulPrevTsIndex - 1);
} // if( 0 < fuPublishFreqTs )
} // if( ( uTsIndex != ( fulPrevTsIndex + 1 ) ) && !( 0 == fulPrevTsIndex && 0 == uTsIndex ) )
if (0 < fuPublishFreqTs) {
fhMissedTS->Fill(0);
fhMissedTSEvo->Fill(fdTimeToStart, 0, 1);
} // else if( 0 < fuPublishFreqTs )
fulTsCounter++;
fulPrevTsIndex = uTsIndex;
if (fulTsCounter % 10000 == 0) { LOG(info) << "Received TS " << fulTsCounter << " with index " << uTsIndex; }
LOG(debug) << "Found " << ts.num_components() << " different components in timeslice";
return timeslice;
} // if (fulTsCounter < fulMaxTimeslices)
else {
CalcRuntime();
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending an EOF to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::seconds(10));
std::string sCmd = "EOF ";
sCmd += FormatDecPrintout(fulPrevTsIndex);
sCmd += " ";
sCmd += FormatDecPrintout(fulTsCounter);
SendCommand(sCmd);
} // if( "" != fsChannelNameCommands )
fbEofFound = true;
return nullptr;
} // else of if (fulTsCounter < fulMaxTimeslices)
} // if (timeslice)
else {
CalcRuntime();
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending an EOF to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::seconds(10));
std::string sCmd = "EOF ";
sCmd += FormatDecPrintout(fulPrevTsIndex);
sCmd += " ";
sCmd += FormatDecPrintout(fulTsCounter);
SendCommand(sCmd);
} // if( "" != fsChannelNameCommands )
fbEofFound = true;
return nullptr;
} // else of if (timeslice)
}
bool CbmMQTsSamplerRepReq::AddNewTsInBuffer()
{
/// Remove the first TS(s) in buffer if we reached the HighWater mark
while (fulHighWaterMark <= fdpTimesliceBuffer.size()) {
fdpTimesliceBuffer.pop_front();
fdbCompSentFlags.pop_front();
} // while( fulHighWaterMark <= fdpTimesliceBuffer.size() )
/// Add a new TS and "fail" if we did not get it
fdpTimesliceBuffer.push_back(GetNewTs());
if (nullptr == fdpTimesliceBuffer.back()) {
fdpTimesliceBuffer.pop_back();
return false;
} // if(nullptr == fdpTimesliceBuffer[fdpTimesliceBuffer.size() - 1])
/// Now that we got the TS, we can add the corresponding list of "Sent" flags,
/// with the proper dimension
if (fbSendTsPerBlock) { fdbCompSentFlags.push_back(std::vector<bool>(fvBlocksToSend.size(), false)); }
else {
fdbCompSentFlags.push_back(std::vector<bool>(fComponentActive.size(), false));
}
return true;
}
bool CbmMQTsSamplerRepReq::CreateAndSendFullTs()
{
std::unique_ptr<fles::Timeslice> timeslice = GetNewTs();
if (timeslice) {
/// Send full TS as response to the request
const fles::Timeslice& ts = *timeslice;
fles::StorableTimeslice fullTs {ts};
if (!SendData(fullTs)) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return false;
} // if (!SendData(fullTs, uChanIdx))
return true;
} // if (timeslice)
else {
return false;
} // else of if (timeslice)
}
bool CbmMQTsSamplerRepReq::PrepareCompListPerSysId()
{
if (false == fbListCompPerSysIdReady) {
/// Check if already at least one TS in the buffer (should not be the case
/// => if not, add one
if (0 == fdpTimesliceBuffer.size()) {
if (!AddNewTsInBuffer()) return false;
} // if( 0 == fdpTimesliceBuffer.size() )
if (nullptr == fdpTimesliceBuffer.front()) return false;
for (uint32_t uCompIdx = 0; uCompIdx < fdpTimesliceBuffer.front()->num_components(); ++uCompIdx) {
uint16_t usMsSysId = fdpTimesliceBuffer.front()->descriptor(uCompIdx, 0).sys_id;
const vector<int>::const_iterator pos = std::find(fSysId.begin(), fSysId.end(), usMsSysId);
if (fSysId.end() != pos) {
const vector<std::string>::size_type idx = pos - fSysId.begin();
fvvCompPerSysId[idx].push_back(uCompIdx);
} // if( fSysId.end() != pos )
} // for( uint32_t uCompIdx = 0; uCompIdx < ts.num_components(); ++uCompIdx )
for (uint32_t uSysIdx = 0; uSysIdx < fComponents.size(); ++uSysIdx) {
std::stringstream ss;
ss << "Found " << std::setw(2) << fvvCompPerSysId[uSysIdx].size() << " components for SysId 0x" << std::hex
<< std::setw(2) << fSysId[uSysIdx] << std::dec << " :";
for (uint32_t uComp = 0; uComp < fvvCompPerSysId[uSysIdx].size(); ++uComp) {
ss << " " << std::setw(3) << fvvCompPerSysId[uSysIdx][uComp];
} // for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ uSysIdx ].size(); ++uComp )
LOG(info) << ss.str();
} // for( uint32_t uSysId = 0; uSysId < fSysId.size(); ++uSysId )
fbListCompPerSysIdReady = true;
} // if( false == fbListCompPerSysIdReady )
return true;
}
bool CbmMQTsSamplerRepReq::CreateCombinedComponentsPerSysId(std::string sSystemName)
{
/// Check if the requested System name is in the list of known components
/// 1) First build the list of components for each SysId if it was not already done
if (!PrepareCompListPerSysId()) return false;
/// 2) Search for requested System name is in the list of known components, get its index and then send the TS
const vector<std::string>::const_iterator pos = std::find(fComponents.begin(), fComponents.end(), sSystemName);
if (fComponents.end() != pos) {
const vector<std::string>::size_type idx = pos - fComponents.begin();
return CreateCombinedComponentsPerSysId(static_cast<uint32_t>(idx));
} // if (fComponents.end() != pos)
else {
LOG(error) << "Did not find " << sSystemName << " in the list of known systems";
return false;
} // else of if (fComponents.end() != pos)
}
bool CbmMQTsSamplerRepReq::CreateCombinedComponentsPerSysId(int iSysId)
{
/// Check if the requested System ID is in the list of known components
/// 1) First build the list of components for each SysId if it was not already done
if (!PrepareCompListPerSysId()) return false;
/// 2) Search for requested System ID is in the list of known components, get its index and then send the TS
const vector<int>::const_iterator pos = std::find(fSysId.begin(), fSysId.end(), iSysId);
if (fSysId.end() != pos) {
const vector<int>::size_type idx = pos - fSysId.begin();
return CreateCombinedComponentsPerSysId(static_cast<uint32_t>(idx));
} // if (fSysId.end() != pos)
else {
LOG(error) << "Did not find 0x" << std::hex << iSysId << std::dec << " in the list of known systems";
return false;
} // else of if (fSysId.end() != pos)
}
bool CbmMQTsSamplerRepReq::CreateCombinedComponentsPerSysId(uint uCompIndex)
{
/// Then loop on all possible SysId and send TS with their respective components if needed
LOG(debug) << "Create timeslice with components for SysId " << std::hex << fSysId[uCompIndex] << std::dec;
if (0 < fvvCompPerSysId[uCompIndex].size()) {
/// Search if TS in buffer where all components for this system where not sent yet
uint32_t uTsIndex = 0;
for (; uTsIndex < fdpTimesliceBuffer.size(); ++uTsIndex) {
if (false == fdbCompSentFlags[uTsIndex][uCompIndex]) break;
} // for( ; uTsIndex < fdpTimesliceBuffer.size(); ++uTsIndex )
/// If all TS in buffer have sent this one, get a new TS
if (fdpTimesliceBuffer.size() == uTsIndex) {
--uTsIndex;
if (!AddNewTsInBuffer()) return false;
} // if( fdpTimesliceBuffer.size() == uTsIndex )
/// Prepare the custom TS and send it
fles::StorableTimeslice component {static_cast<uint32_t>(fdpTimesliceBuffer[uTsIndex]->num_core_microslices()),
fdpTimesliceBuffer[uTsIndex]->index()};
for (uint32_t uComp = 0; uComp < fvvCompPerSysId[uCompIndex].size(); ++uComp) {
uint32_t uNumMsInComp = fdpTimesliceBuffer[uTsIndex]->num_microslices(fvvCompPerSysId[uCompIndex][uComp]);
component.append_component(uNumMsInComp);
LOG(debug) << "Add components to TS for SysId " << std::hex << fSysId[uCompIndex] << std::dec << " TS "
<< fdpTimesliceBuffer[uTsIndex]->index() << " Comp " << fvvCompPerSysId[uCompIndex][uComp];
for (size_t m = 0; m < uNumMsInComp; ++m) {
component.append_microslice(uComp, m,
fdpTimesliceBuffer[uTsIndex]->descriptor(fvvCompPerSysId[uCompIndex][uComp], m),
fdpTimesliceBuffer[uTsIndex]->content(fvvCompPerSysId[uCompIndex][uComp], m));
} // for( size_t m = 0; m < uNumMsInComp; ++m )
} // for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ uCompIndex ].size(); ++uComp )
LOG(debug) << "Prepared timeslice for SysId " << std::hex << fSysId[uCompIndex] << std::dec << " with "
<< component.num_components() << " components";
if (!SendData(component)) return false;
fdbCompSentFlags[uTsIndex][uCompIndex] = true;
} // if (0 < fvvCompPerSysId[uCompIndex].size())
return true;
}
bool CbmMQTsSamplerRepReq::PrepareCompListPerBlock()
{
if (false == fbListCompPerBlockReady) {
/// 1) First build the list of components for each SysId if it was not already done
if (!PrepareCompListPerSysId()) return false;
/// 2) Build the list of components for each block, based on its list of system IDs
for (auto itBlock = fvBlocksToSend.begin(); itBlock != fvBlocksToSend.end(); ++itBlock) {
auto uBlockIdx = itBlock - fvBlocksToSend.begin();
for (auto itSys = (itBlock->second).begin(); itSys != (itBlock->second).end(); ++itSys) {
/// Check if this system ID is existing
const vector<int>::const_iterator pos = std::find(fSysId.begin(), fSysId.end(), *itSys);
if (fSysId.end() != pos) {
const vector<int>::size_type idxSys = pos - fSysId.begin();
/// Add all components to the list
for (uint32_t uComp = 0; uComp < fvvCompPerSysId[idxSys].size(); ++uComp) {
fvvCompPerBlock[uBlockIdx].push_back(fvvCompPerSysId[idxSys][uComp]);
} // for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ idxSys ].size(); ++uComp )
} // if (fSysId.end() != pos)
else {
LOG(error) << "Error when building the components list for block " << itBlock->first;
LOG(error) << "Did not find 0x" << std::hex << *itSys << std::dec << " in the list of known systems";
return false;
} // else of if (fSysId.end() != pos)
} // for( auto itSys = (itBlock->second).begin(); itSys != (itBlock->second).end(); ++itSys )
} // for( auto itBlock = fvBlocksToSend.begin(); itBlock != fvBlocksToSend.end(); ++itBlock)
fbListCompPerBlockReady = true;
} // if( false == fbListCompPerBlockReady )
return true;
}
bool CbmMQTsSamplerRepReq::CreateCombinedComponentsPerBlock(std::string sBlockName)
{
/// Check if the requested Block is in the list of known blocks
/// 1) First build the list of components for each block if it was not already done
if (!PrepareCompListPerBlock()) return false;
/// 2) Search for requested block is in the list of known blocks, get its index and then send the TS
for (auto itKnownBlock = fvBlocksToSend.begin(); itKnownBlock != fvBlocksToSend.end(); ++itKnownBlock) {
if ((*itKnownBlock).first == sBlockName) {
auto uBlockIdx = itKnownBlock - fvBlocksToSend.begin();
/// Search if TS in buffer where all components for this system where not sent yet
uint32_t uTsIndex = 0;
for (; uTsIndex < fdpTimesliceBuffer.size(); ++uTsIndex) {
if (false == fdbCompSentFlags[uTsIndex][uBlockIdx]) break;
} // for( ; uTsIndex < fdpTimesliceBuffer.size(); ++uTsIndex )
/// If all TS in buffer have sent this one, get a new TS
if (fdpTimesliceBuffer.size() == uTsIndex) {
--uTsIndex;
if (!AddNewTsInBuffer()) return false;
} // if( fdpTimesliceBuffer.size() == uTsIndex )
/// Prepare the custom TS and send it
fles::StorableTimeslice component {static_cast<uint32_t>(fdpTimesliceBuffer[uTsIndex]->num_core_microslices()),
fdpTimesliceBuffer[uTsIndex]->index()};
for (uint32_t uComp = 0; uComp < fvvCompPerBlock[uBlockIdx].size(); ++uComp) {
uint32_t uNumMsInComp = fdpTimesliceBuffer[uTsIndex]->num_microslices(fvvCompPerBlock[uBlockIdx][uComp]);
component.append_component(uNumMsInComp);
LOG(debug) << "Add components to TS for Block " << sBlockName << " TS " << fdpTimesliceBuffer[uTsIndex]->index()
<< " Comp " << fvvCompPerBlock[uBlockIdx][uComp];
for (size_t m = 0; m < uNumMsInComp; ++m) {
component.append_microslice(uComp, m,
fdpTimesliceBuffer[uTsIndex]->descriptor(fvvCompPerBlock[uBlockIdx][uComp], m),
fdpTimesliceBuffer[uTsIndex]->content(fvvCompPerBlock[uBlockIdx][uComp], m));
} // for( size_t m = 0; m < uNumMsInComp; ++m )
} // for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ uCompIndex ].size(); ++uComp )
LOG(debug) << "Prepared timeslice for Block " << sBlockName << " with " << component.num_components()
<< " components";
if (!SendData(component)) return false;
fdbCompSentFlags[uTsIndex][uBlockIdx] = true;
return true;
} // if( (*itKnownBlock).first == sBlockName )
} // for( auto itKnownBlock = fvBlocksToSend.begin(); itKnownBlock != fvBlocksToSend.end(); ++itKnownBlock)
/// Should reach here only if the block name was not found in the list!
LOG(error) << "Requested block " << sBlockName << " not found in the list of known blocks";
return false;
}
bool CbmMQTsSamplerRepReq::SendFirstTsIndex()
{
// create the message with the first timeslice index
std::string sIndex = FormatDecPrintout(fulFirstTsIndex);
// serialize the vector and create the message
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << sIndex;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// in case of error or transfer interruption,
// return false to go to IDLE state
// successfull transfer will return number of bytes
// transfered (can be 0 if sending an empty message).
if (Send(msg, fsChannelNameTsRequest) < 0) {
LOG(error) << "Problem sending reply with first TS index";
return false;
}
fulMessageCounter++;
LOG(debug) << "Send message " << fulMessageCounter << " with a size of " << msg->GetSize();
return true;
}
bool CbmMQTsSamplerRepReq::SendData(const fles::StorableTimeslice& component)
{
// serialize the timeslice and create the message
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << component;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// in case of error or transfer interruption,
// return false to go to IDLE state
// successfull transfer will return number of bytes
// transfered (can be 0 if sending an empty message).
if (Send(msg, fsChannelNameTsRequest) < 0) {
LOG(error) << "Problem sending data";
return false;
}
fulMessageCounter++;
LOG(debug) << "Send message " << fulMessageCounter << " with a size of " << msg->GetSize();
return true;
}
bool CbmMQTsSamplerRepReq::SendMissedTsIdx(std::vector<uint64_t> vIndices)
{
// serialize the vector and create the message
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << vIndices;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// in case of error or transfer interruption,
// return false to go to IDLE state
// successfull transfer will return number of bytes
// transfered (can be 0 if sending an empty message).
LOG(debug) << "Send data to channel " << fsChannelNameMissedTs;
if (Send(msg, fsChannelNameMissedTs) < 0) {
LOG(error) << "Problem sending missed TS indices to channel " << fsChannelNameMissedTs;
return false;
} // if( Send( msg, fsChannelNameMissedTs ) < 0 )
return true;
}
bool CbmMQTsSamplerRepReq::SendCommand(std::string sCommand)
{
// serialize the vector and create the message
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << sCommand;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// FairMQMessagePtr msg( NewMessage( const_cast<char*>( sCommand.c_str() ), // data
// sCommand.length(), // size
// []( void* /*data*/, void* object ){ delete static_cast< std::string * >( object ); },
// &sCommand ) ); // object that manages the data
// in case of error or transfer interruption,
// return false to go to IDLE state
// successfull transfer will return number of bytes
// transfered (can be 0 if sending an empty message).
LOG(debug) << "Send data to channel " << fsChannelNameCommands;
if (Send(msg, fsChannelNameCommands) < 0) {
LOG(error) << "Problem sending missed TS indices to channel " << fsChannelNameCommands;
return false;
} // if( Send( msg, fsChannelNameMissedTs ) < 0 )
return true;
}
bool CbmMQTsSamplerRepReq::SendHistoConfAndData()
{
/// Prepare multiparts message and header
std::pair<uint32_t, uint32_t> pairHeader(fvpsHistosFolder.size(), fvpsCanvasConfig.size());
FairMQMessagePtr messageHeader(NewMessage());
// Serialize<BoostSerializer<std::pair<uint32_t, uint32_t>>>(*messageHeader, pairHeader);
BoostSerializer<std::pair<uint32_t, uint32_t>>().Serialize(*messageHeader, pairHeader);
FairMQParts partsOut;
partsOut.AddPart(std::move(messageHeader));
for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto) {
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, fvpsHistosFolder[uHisto]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, fvpsHistosFolder[uHisto]);
partsOut.AddPart(std::move(messageHist));
} // for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto)
/// Catch case where no histos are registered!
/// => Add empty message
if (0 == fvpsHistosFolder.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, fvpsCanvasConfig[uCanv]);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, fvpsCanvasConfig[uCanv]);
partsOut.AddPart(std::move(messageCan));
} // for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv)
/// Catch case where no Canvases are registered!
/// => Add empty message
if (0 == fvpsCanvasConfig.size()) {
FairMQMessagePtr messageHist(NewMessage());
partsOut.AddPart(std::move(messageHist));
}
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr msgHistos(NewMessage());
// Serialize<RootSerializer>(*msgHistos, &fArrayHisto);
RootSerializer().Serialize(*msgHistos, &fArrayHisto);
partsOut.AddPart(std::move(msgHistos));
/// Send the multi-parts message to the common histogram messages queue
if (Send(partsOut, fsChannelNameHistosInput) < 0) {
LOG(error) << "CbmMQTsSamplerRepReq::SendHistoConfAndData => Problem sending data";
return false;
} // if( Send( partsOut, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
ResetHistograms();
return true;
}
bool CbmMQTsSamplerRepReq::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
ResetHistograms();
return true;
}
bool CbmMQTsSamplerRepReq::ResetHistograms()
{
fhTsRate->Reset();
fhTsSize->Reset();
fhTsSizeEvo->Reset();
fhTsMaxSizeEvo->Reset();
fhMissedTS->Reset();
fhMissedTSEvo->Reset();
return true;
}
CbmMQTsSamplerRepReq::~CbmMQTsSamplerRepReq() {}
void CbmMQTsSamplerRepReq::CalcRuntime()
{
std::chrono::duration<double> run_time = std::chrono::steady_clock::now() - fTime;
LOG(info) << "Runtime: " << run_time.count();
LOG(info) << "No more input data";
}
/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau [committer] */
/********
* TODO:
* Remove mode "Full TS spreading to multiple outputs"
* Keep track of components sent in split TS mode
* HW mark when sending independent components
* Use exceptions + try/catch instead of boolean return values
********/
#ifndef CBMMQTSSAMPLERREPREQ_H_
#define CBMMQTSSAMPLERREPREQ_H_
#include "MicrosliceDescriptor.hpp"
#include "StorableTimeslice.hpp"
#include "Timeslice.hpp"
#include "TimesliceSource.hpp"
#include "FairMQDevice.h"
class TCanvas;
class TH1F;
class TH1I;
class TProfile;
#include <TObjArray.h>
#include <ctime>
#include <deque>
#include <string>
#include <utility>
#include <vector>
class CbmMQTsSamplerRepReq : public FairMQDevice {
public:
CbmMQTsSamplerRepReq();
virtual ~CbmMQTsSamplerRepReq();
protected:
uint64_t fulMaxTimeslices;
std::string fsFileName = "";
std::string fsDirName = "";
std::vector<std::string> fvsInputFileList = {}; ///< List of input files
std::string fsHost = "";
uint16_t fusPort = 0;
uint64_t fulHighWaterMark = 10;
std::string fsChannelNameTsRequest = "ts-request";
bool fbNoSplitTs = true;
bool fbSendTsPerSysId = false;
bool fbSendTsPerBlock = false;
std::string fsChannelNameHistosInput = "histogram-in";
uint32_t fuPublishFreqTs = 0;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5;
std::string fsHistosSuffix = "";
uint64_t fulFirstTsIndex = 0;
uint64_t fulPrevTsIndex = 0;
uint64_t fulTsCounter = 0;
uint64_t fulMessageCounter = 0;
virtual void InitTask();
bool HandleRequest(FairMQMessagePtr&, int);
private:
void CalcRuntime();
bool IsChannelNameAllowed(std::string);
std::unique_ptr<fles::Timeslice> GetNewTs();
bool AddNewTsInBuffer();
bool CreateAndSendFullTs();
bool PrepareCompListPerSysId();
bool CreateCombinedComponentsPerSysId(std::string sSystemName);
bool CreateCombinedComponentsPerSysId(int iSysId);
bool CreateCombinedComponentsPerSysId(uint uCompIndex);
bool PrepareCompListPerBlock();
bool CreateCombinedComponentsPerBlock(std::string sBlockName);
bool SendFirstTsIndex();
bool SendData(const fles::StorableTimeslice& component);
bool SendMissedTsIdx(std::vector<uint64_t> vIndices);
bool SendCommand(std::string sCommand);
bool InitHistograms();
bool SendHistoConfAndData();
bool SendHistograms();
bool ResetHistograms();
fles::TimesliceSource* fSource = nullptr; //!
std::chrono::steady_clock::time_point fTime;
std::chrono::system_clock::time_point fLastPublishTime;
// The vector fAllowedChannels contain the list of defined components names
// which are used for connecting the different devices. A request
// using the name stscomponent will receive timeslices containing the
// sts component only. The corresponding system ids are defined in the
// vector fSysId.
// The Blocks are defined by the user by combining a name with a list of components,
// either by name or by SysId
// A components can only be added to one block, attempts to double book will throw
// an init error
std::vector<std::string> fComponents = {"mvdcomponent", "stscomponent", "richcomponent", "muchcomponent",
"trdcomponent", "tofcomponent", "psdcomponent", "t0component"};
std::vector<int> fSysId = {0x20, 0x10, 0x30, 0x50, 0x40, 0x60, 0x80, 0x90};
std::vector<bool> fComponentActive = {false, false, false, false, false, false, false, false};
bool fbListCompPerSysIdReady = false;
std::vector<std::vector<uint32_t>> fvvCompPerSysId = {{}, {}, {}, {}, {}, {}, {}, {}};
bool fbListCompPerBlockReady = false;
std::vector<std::pair<std::string, std::set<uint16_t>>> fvBlocksToSend = {};
std::vector<std::vector<uint32_t>> fvvCompPerBlock = {};
/// Buffering of partially sent timeslices, limited by fulHighWaterMark
std::deque<std::unique_ptr<fles::Timeslice>> fdpTimesliceBuffer = {};
std::deque<std::vector<bool>> fdbCompSentFlags = {};
/// Flag indicating the EOF was reached to avoid sending an emergency STOP
bool fbEofFound = false;
std::string fsChannelNameMissedTs = "";
std::string fsChannelNameCommands = "";
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
/// Flag indicating whether the histograms and canvases configurations were already published
bool fbConfigSent = false;
/// Histograms
TH1I* fhTsRate = nullptr;
TH1I* fhTsSize = nullptr;
TProfile* fhTsSizeEvo = nullptr;
TH1F* fhTsMaxSizeEvo = nullptr;
TH1I* fhMissedTS = nullptr;
TProfile* fhMissedTSEvo = nullptr;
TCanvas* fcSummary = nullptr;
uint64_t fuStartTime = 0;
double_t fdTimeToStart = 0.;
double_t fdLastMaxTime = 0.;
double_t fdTsMaxSize = 0.;
};
#endif /* CBMMQTSASAMPLER_H_ */
/* Copyright (C) 2017-2019 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
/**
* CbmMQTsaInfo.cpp
*
......@@ -7,97 +11,96 @@
#include "CbmMQTsaInfo.h"
#include "CbmMQDefs.h"
#include "TimesliceInputArchive.hpp"
#include "TimesliceSubscriber.hpp"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "FairMQProgOptions.h" // device->fConfig
#include "TimesliceSubscriber.hpp"
#include "TimesliceInputArchive.hpp"
#include <thread> // this_thread::sleep_for
#include <boost/archive/binary_oarchive.hpp>
#include <stdio.h>
#include <ctime>
#include <thread> // this_thread::sleep_for
#include <chrono>
#include <ctime>
#include <stdio.h>
using namespace std;
#include <stdexcept>
struct InitTaskError : std::runtime_error { using std::runtime_error::runtime_error; };
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
CbmMQTsaInfo::CbmMQTsaInfo()
: FairMQDevice()
, fMaxTimeslices(0)
, fFileName("")
, fInputFileList()
, fFileCounter(0)
, fHost("")
, fPort(0)
, fTSNumber(0)
, fTSCounter(0)
, fMessageCounter(0)
, fTime()
: FairMQDevice()
, fMaxTimeslices(0)
, fFileName("")
, fInputFileList()
, fFileCounter(0)
, fHost("")
, fPort(0)
, fTSNumber(0)
, fTSCounter(0)
, fMessageCounter(0)
, fTime()
{
}
void CbmMQTsaInfo::InitTask()
try
{
// Get the values from the command line options (via fConfig)
fFileName = fConfig->GetValue<string>("filename");
fHost = fConfig->GetValue<string>("flib-host");
fPort = fConfig->GetValue<uint64_t>("flib-port");
fMaxTimeslices = fConfig->GetValue<uint64_t>("max-timeslices");
LOG(info) << "Filename: " << fFileName;
LOG(info) << "Host: " << fHost;
LOG(info) << "Port: " << fPort;
LOG(info) << "MaxTimeslices: " << fMaxTimeslices;
// Get the information about created channels from the device
// Check if the defined channels from the topology (by name)
// are in the list of channels which are possible/allowed
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
int noChannel = fChannels.size();
LOG(info) << "Number of defined output channels: " << noChannel;
for(auto const &entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
}
try {
// Get the values from the command line options (via fConfig)
fFileName = fConfig->GetValue<string>("filename");
fHost = fConfig->GetValue<string>("flib-host");
fPort = fConfig->GetValue<uint64_t>("flib-port");
fMaxTimeslices = fConfig->GetValue<uint64_t>("max-timeslices");
LOG(info) << "Filename: " << fFileName;
LOG(info) << "Host: " << fHost;
LOG(info) << "Port: " << fPort;
LOG(info) << "MaxTimeslices: " << fMaxTimeslices;
// Get the information about created channels from the device
// Check if the defined channels from the topology (by name)
// are in the list of channels which are possible/allowed
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
int noChannel = fChannels.size();
LOG(info) << "Number of defined output channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
}
if ( 0 == fFileName.size() && 0 != fHost.size() ) {
if (0 == fFileName.size() && 0 != fHost.size()) {
std::string connector = "tcp://" + fHost + ":" + std::to_string(fPort);
LOG(info) << "Open TSPublisher at " << connector;
fSource = new fles::TimesliceSubscriber(connector);
if ( !fSource) {
throw InitTaskError("Could not connect to publisher.");
}
} else {
fSource = new fles::TimesliceSubscriber(connector, 1);
if (!fSource) { throw InitTaskError("Could not connect to publisher."); }
}
else {
LOG(info) << "Open the Flib input file " << fFileName;
// Check if the input file exist
FILE* inputFile = fopen(fFileName.c_str(), "r");
if ( ! inputFile ) {
throw InitTaskError("Input file doesn't exist.");
}
if (!inputFile) { throw InitTaskError("Input file doesn't exist."); }
fclose(inputFile);
fSource = new fles::TimesliceInputArchive(fFileName);
if ( !fSource) {
throw InitTaskError("Could not open input file.");
}
if (!fSource) { throw InitTaskError("Could not open input file."); }
}
fTime = std::chrono::steady_clock::now();
} catch (InitTaskError& e) {
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
......@@ -105,14 +108,12 @@ try
bool CbmMQTsaInfo::IsChannelNameAllowed(std::string channelName)
{
if ( std::find(fAllowedChannels.begin(), fAllowedChannels.end(),
channelName) != fAllowedChannels.end() ) {
LOG(info) << "Channel name " << channelName
<< " found in list of allowed channel names.";
if (std::find(fAllowedChannels.begin(), fAllowedChannels.end(), channelName) != fAllowedChannels.end()) {
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names.";
return true;
} else {
LOG(info) << "Channel name " << channelName
<< " not found in list of allowed channel names.";
}
else {
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
......@@ -125,59 +126,49 @@ bool CbmMQTsaInfo::ConditionalRun()
auto timeslice = fSource->get();
if (timeslice) {
fTSCounter++;
if (fTSCounter % 10000 == 0) LOG(info) << "Analyse Event " << fTSCounter;
if (fTSCounter % 10000 == 0) LOG(info) << "Analyse Event " << fTSCounter;
const fles::Timeslice& ts = *timeslice;
// auto tsIndex = ts.index();
// auto tsIndex = ts.index();
LOG(info) << "Found " << ts.num_components()
<< " different components in timeslice";
LOG(info) << "Found " << ts.num_components() << " different components in timeslice";
CheckTimeslice(ts);
if (fTSCounter < fMaxTimeslices) {
return true;
} else {
if (fTSCounter < fMaxTimeslices) { return true; }
else {
CalcRuntime();
return false;
}
} else {
}
else {
CalcRuntime();
return false;
}
}
CbmMQTsaInfo::~ CbmMQTsaInfo()
{
}
CbmMQTsaInfo::~CbmMQTsaInfo() {}
void CbmMQTsaInfo::CalcRuntime()
{
std::chrono::duration<double> run_time =
std::chrono::steady_clock::now() - fTime;
std::chrono::duration<double> run_time = std::chrono::steady_clock::now() - fTime;
LOG(info) << "Runtime: " << run_time.count();
LOG(info) << "No more input data";
}
void CbmMQTsaInfo::PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc)
{
LOG(info) << "Header ID: Ox" << std::hex << static_cast<int>(mdsc.hdr_id)
<< std::dec;
LOG(info) << "Header version: Ox" << std::hex << static_cast<int>(mdsc.hdr_ver)
<< std::dec;
LOG(info) << "Header ID: Ox" << std::hex << static_cast<int>(mdsc.hdr_id) << std::dec;
LOG(info) << "Header version: Ox" << std::hex << static_cast<int>(mdsc.hdr_ver) << std::dec;
LOG(info) << "Equipement ID: " << mdsc.eq_id;
LOG(info) << "Flags: " << mdsc.flags;
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(mdsc.sys_id)
<< std::dec;
LOG(info) << "Sys version: Ox" << std::hex << static_cast<int>(mdsc.sys_ver)
<< std::dec;
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(mdsc.sys_id) << std::dec;
LOG(info) << "Sys version: Ox" << std::hex << static_cast<int>(mdsc.sys_ver) << std::dec;
LOG(info) << "Microslice Idx: " << mdsc.idx;
LOG(info) << "Checksum: " << mdsc.crc;
LOG(info) << "Size: " << mdsc.size;
......@@ -186,23 +177,19 @@ void CbmMQTsaInfo::PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& m
bool CbmMQTsaInfo::CheckTimeslice(const fles::Timeslice& ts)
{
if ( 0 == ts.num_components() ) {
if (0 == ts.num_components()) {
LOG(error) << "No Component in TS " << ts.index();
return 1;
}
LOG(info) << "Found " << ts.num_components()
<< " different components in timeslice";
LOG(info) << "Found " << ts.num_components() << " different components in timeslice";
for (size_t c = 0; c < ts.num_components(); ++c) {
LOG(info) << "Found " << ts.num_microslices(c)
<< " microslices in component " << c;
LOG(info) << "Component " << c << " has a size of "
<< ts.size_component(c) << " bytes";
LOG(info) << "Component " << c << " has the system id 0x"
<< std::hex << static_cast<int>(ts.descriptor(c,0).sys_id)
<< std::dec;
/*
LOG(info) << "Found " << ts.num_microslices(c) << " microslices in component " << c;
LOG(info) << "Component " << c << " has a size of " << ts.size_component(c) << " bytes";
LOG(info) << "Component " << c << " has the system id 0x" << std::hex
<< static_cast<int>(ts.descriptor(c, 0).sys_id) << std::dec;
/*
for (size_t m = 0; m < ts.num_microslices(c); ++m) {
PrintMicroSliceDescriptor(ts.descriptor(c,m));
}
......
/* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer] */
/**
* CbmMQTsaInfo.h
*
......@@ -9,55 +13,52 @@
#define CBMMQTSAINFO_H_
#include "TimesliceSource.hpp"
#include "Timeslice.hpp"
#include "StorableTimeslice.hpp"
#include "MicrosliceDescriptor.hpp"
#include "StorableTimeslice.hpp"
#include "Timeslice.hpp"
#include "TimesliceSource.hpp"
//#include "Message.hpp"
#include "FairMQDevice.h"
#include <ctime>
#include <string>
#include <vector>
#include <ctime>
class CbmMQTsaInfo : public FairMQDevice
{
public:
CbmMQTsaInfo();
virtual ~CbmMQTsaInfo();
protected:
uint64_t fMaxTimeslices;
class CbmMQTsaInfo : public FairMQDevice {
public:
CbmMQTsaInfo();
virtual ~CbmMQTsaInfo();
std::string fFileName;
std::vector<std::string> fInputFileList; ///< List of input files
uint64_t fFileCounter;
std::string fHost;
uint64_t fPort;
protected:
uint64_t fMaxTimeslices;
uint64_t fTSNumber;
uint64_t fTSCounter;
uint64_t fMessageCounter;
std::string fFileName;
std::vector<std::string> fInputFileList; ///< List of input files
uint64_t fFileCounter;
std::string fHost;
uint64_t fPort;
int fMaxMemory = 0;
uint64_t fTSNumber;
uint64_t fTSCounter;
uint64_t fMessageCounter;
virtual void InitTask();
virtual bool ConditionalRun();
int fMaxMemory = 0;
private:
bool CheckTimeslice(const fles::Timeslice& ts);
void PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc);
bool SendData(const fles::StorableTimeslice& component);
void CalcRuntime();
bool IsChannelNameAllowed(std::string);
virtual void InitTask();
virtual bool ConditionalRun();
fles::TimesliceSource* fSource; //!
std::chrono::steady_clock::time_point fTime;
private:
bool CheckTimeslice(const fles::Timeslice& ts);
void PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc);
bool SendData(const fles::StorableTimeslice& component);
void CalcRuntime();
bool IsChannelNameAllowed(std::string);
std::vector<std::string> fAllowedChannels
= {"stscomponent","trdcomponent","tofcomponent"};
fles::TimesliceSource* fSource; //!
std::chrono::steady_clock::time_point fTime;
std::vector<std::string> fAllowedChannels = {"stscomponent", "trdcomponent", "tofcomponent"};
};
#endif /* CBMMQTSAINFO_H_ */
/* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Pierre-Alain Loizeau, Florian Uhlig [committer] */
/**
* CbmMQTsaMultiSampler.cpp
*
......@@ -8,337 +12,622 @@
#include "CbmMQTsaMultiSampler.h"
#include "CbmMQDefs.h"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "CbmFlesCanvasTools.h"
#include "CbmFormatDecHexPrintout.h"
#include "TimesliceSubscriber.hpp"
#include "TimesliceMultiSubscriber.hpp"
#include "TimesliceInputArchive.hpp"
#include "TimesliceMultiInputArchive.hpp"
#include "TimesliceMultiSubscriber.hpp"
#include "TimesliceSubscriber.hpp"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include <TCanvas.h>
#include <TH1F.h>
#include <TH1I.h>
#include <TProfile.h>
#include "BoostSerializer.h"
#include <boost/algorithm/string.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/serialization/utility.hpp>
#include "RootSerializer.h"
namespace filesys = boost::filesystem;
#include <sstream>
#include <iomanip>
#include <stdio.h>
#include <ctime>
#include <thread> // this_thread::sleep_for
#include <chrono>
#include <thread> // this_thread::sleep_for
#include <algorithm>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <string>
#include <stdio.h>
using namespace std;
#include <stdexcept>
struct InitTaskError : std::runtime_error { using std::runtime_error::runtime_error; };
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
CbmMQTsaMultiSampler::CbmMQTsaMultiSampler()
: FairMQDevice()
, fMaxTimeslices(0)
, fFileName("")
, fDirName("")
, fInputFileList()
, fFileCounter(0)
, fHost("")
, fPort(0)
, fHighWaterMark(1)
, fTSNumber(0)
, fTSCounter(0)
, fMessageCounter(0)
, fSource(nullptr)
, fTime()
: FairMQDevice()
, fMaxTimeslices(0)
, fFileName("")
, fDirName("")
, fInputFileList()
, fFileCounter(0)
, fHost("")
, fPort(0)
, fHighWaterMark(1)
, fTSCounter(0)
, fMessageCounter(0)
, fSource(nullptr)
, fTime()
, fLastPublishTime {std::chrono::system_clock::now()}
{
}
void CbmMQTsaMultiSampler::InitTask()
try
{
// Get the values from the command line options (via fConfig)
fFileName = fConfig->GetValue<string>("filename");
fDirName = fConfig->GetValue<string>("dirname");
fHost = fConfig->GetValue<string>("flib-host");
fPort = fConfig->GetValue<uint64_t>("flib-port");
fHighWaterMark = fConfig->GetValue<uint64_t>("high-water-mark");
fMaxTimeslices = fConfig->GetValue<uint64_t>("max-timeslices");
fbNoSplitTs = fConfig->GetValue<bool>("no-split-ts");
fbSendTsPerSysId = fConfig->GetValue<bool>("send-ts-per-sysid");
fbSendTsPerChannel = fConfig->GetValue<bool>("send-ts-per-channel");
if( fbNoSplitTs )
{
if( fbSendTsPerSysId )
{
if( fbSendTsPerChannel )
{
LOG(warning) << "Both no-split-ts, send-ts-per-sysid and send-ts-per-channel options used => "
<< " second and third one will be ignored!!!!";
} // if( fbSendTsPerSysId )
else LOG(warning) << "Both no-split-ts and send-ts-per-sysid options used => "
<< " second one will be ignored!!!!";
} // if( fbSendTsPerSysId )
else if( fbSendTsPerChannel )
{
LOG(warning) << "Both no-split-ts and send-ts-per-channel options used => "
try {
// Get the values from the command line options (via fConfig)
fFileName = fConfig->GetValue<string>("filename");
fDirName = fConfig->GetValue<string>("dirname");
fHost = fConfig->GetValue<string>("flib-host");
fPort = fConfig->GetValue<uint64_t>("flib-port");
fHighWaterMark = fConfig->GetValue<uint64_t>("high-water-mark");
fMaxTimeslices = fConfig->GetValue<uint64_t>("max-timeslices");
fbNoSplitTs = fConfig->GetValue<bool>("no-split-ts");
fbSendTsPerSysId = fConfig->GetValue<bool>("send-ts-per-sysid");
fbSendTsPerChannel = fConfig->GetValue<bool>("send-ts-per-channel");
fsChannelNameMissedTs = fConfig->GetValue<std::string>("ChNameMissTs");
fsChannelNameCommands = fConfig->GetValue<std::string>("ChNameCmds");
fuPublishFreqTs = fConfig->GetValue<uint32_t>("PubFreqTs");
fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
fsChannelNameHistosConfig = fConfig->GetValue<std::string>("ChNameHistCfg");
fsChannelNameCanvasConfig = fConfig->GetValue<std::string>("ChNameCanvCfg");
if (fbNoSplitTs) {
if (fbSendTsPerSysId) {
if (fbSendTsPerChannel) {
LOG(warning) << "Both no-split-ts, send-ts-per-sysid and "
"send-ts-per-channel options used => "
<< " second and third one will be ignored!!!!";
} // if( fbSendTsPerSysId )
else
LOG(warning) << "Both no-split-ts and send-ts-per-sysid options used => "
<< " second one will be ignored!!!!";
} // else if( fbSendTsPerSysId ) of if( fbSendTsPerSysId )
} // if( fbNoSplitTs )
else if( fbSendTsPerSysId && fbSendTsPerChannel )
{
LOG(warning) << "Both send-ts-per-sysid and send-ts-per-channel options used => "
<< " second one will be ignored!!!!";
} // else if( fbSendTsPerSysId && fbSendTsPerSysId ) of if( fbNoSplitTs )
std::vector< std::string > vSysIdChanPairs = fConfig->GetValue< std::vector< std::string > >("sysid-chan");
for( uint32_t uPair = 0; uPair < vSysIdChanPairs.size(); ++uPair )
{
const size_t sep = vSysIdChanPairs[ uPair ].find(':');
if( string::npos == sep || 0 == sep || vSysIdChanPairs[ uPair ].size() == sep )
{
LOG(info) << vSysIdChanPairs[ uPair ];
throw InitTaskError("Provided pair of SysId + Channel name is missing a : or an argument.");
} // if( string::npos == sep || 0 == sep || vSysIdChanPairs[ uPair ].size() == sep )
/// Extract SysId
std::string sSysId = vSysIdChanPairs[ uPair ].substr( 0, sep );
const size_t hexPos = sSysId.find("0x");
int iSysId;
if( string::npos == hexPos )
iSysId = std::stoi( sSysId );
else iSysId = std::stoi( sSysId.substr( hexPos + 2 ), nullptr, 16 );
/// Extract Channel name
std::string sChannelName = vSysIdChanPairs[ uPair ].substr( sep + 1 );
/// Look if SysId is already defined
const vector< int >::const_iterator pos = std::find( fSysId.begin(), fSysId.end(), iSysId );
if( fSysId.end() != pos )
{
/// SysId already there, redefine the corresponding channel name
const vector<std::string>::size_type idx = pos - fSysId.begin();
fAllowedChannels[ idx ] = sChannelName;
} // if( fSysId.end() != pos )
else
{
/// SysId unknown yet, add both SysId and channe name at end of respective vectors
fSysId.push_back( iSysId );
fAllowedChannels.push_back( sChannelName );
} // else of if( fSysId.end() != pos )
LOG(info) << vSysIdChanPairs[ uPair ] << " " << iSysId << " " << sChannelName;
} // for( uint32_t uPair = 0; uPair < vSysIdChanPairs.size(); ++uPair )
if (0 == fMaxTimeslices) fMaxTimeslices = UINT_MAX;
// Check which input is defined
// Posibilities
// filename && ! dirname : single file
// filename with wildcards && diranme : all files with filename regex in the directory
// host && port : connect to the flim server
bool isGoodInputCombi{false};
if ( 0 != fFileName.size() && 0 == fDirName.size() && 0 == fHost.size() && 0 == fPort ) {
isGoodInputCombi=true;
fInputFileList.push_back(fFileName);
} else if ( 0 != fFileName.size() && 0 != fDirName.size() && 0 == fHost.size() && 0 == fPort ) {
isGoodInputCombi=true;
fInputFileList.push_back(fFileName);
} else if ( 0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 != fPort) {
isGoodInputCombi=true;
LOG(info) << "Host: " << fHost;
LOG(info) << "Port: " << fPort;
} else if ( 0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 == fPort) {
isGoodInputCombi=true;
LOG(info) << "Host string: " << fHost;
} else {
isGoodInputCombi=false;
}
} // if( fbSendTsPerSysId )
else if (fbSendTsPerChannel) {
LOG(warning) << "Both no-split-ts and send-ts-per-channel options used => "
<< " second one will be ignored!!!!";
} // else if( fbSendTsPerSysId ) of if( fbSendTsPerSysId )
} // if( fbNoSplitTs )
else if (fbSendTsPerSysId && fbSendTsPerChannel) {
LOG(warning) << "Both send-ts-per-sysid and send-ts-per-channel options used => "
<< " second one will be ignored!!!!";
} // else if( fbSendTsPerSysId && fbSendTsPerSysId ) of if( fbNoSplitTs )
/// Extract SysId and channel information if provided in the binary options
std::vector<std::string> vSysIdChanPairs = fConfig->GetValue<std::vector<std::string>>("sysid-chan");
for (uint32_t uPair = 0; uPair < vSysIdChanPairs.size(); ++uPair) {
const size_t sep = vSysIdChanPairs[uPair].find(':');
if (string::npos == sep || 0 == sep || vSysIdChanPairs[uPair].size() == sep) {
LOG(info) << vSysIdChanPairs[uPair];
throw InitTaskError("Provided pair of SysId + Channel name is missing a : or an argument.");
} // if( string::npos == sep || 0 == sep || vSysIdChanPairs[ uPair ].size() == sep )
/// Extract SysId
std::string sSysId = vSysIdChanPairs[uPair].substr(0, sep);
const size_t hexPos = sSysId.find("0x");
int iSysId;
if (string::npos == hexPos) iSysId = std::stoi(sSysId);
else
iSysId = std::stoi(sSysId.substr(hexPos + 2), nullptr, 16);
/// Extract Channel name
std::string sChannelName = vSysIdChanPairs[uPair].substr(sep + 1);
/// Look if SysId is already defined
const vector<int>::const_iterator pos = std::find(fSysId.begin(), fSysId.end(), iSysId);
if (fSysId.end() != pos) {
/// SysId already there, redefine the corresponding channel name
const vector<std::string>::size_type idx = pos - fSysId.begin();
fAllowedChannels[idx] = sChannelName;
} // if( fSysId.end() != pos )
else {
/// SysId unknown yet, add both SysId and channe name at end of respective vectors
fSysId.push_back(iSysId);
fAllowedChannels.push_back(sChannelName);
} // else of if( fSysId.end() != pos )
LOG(info) << vSysIdChanPairs[uPair] << " " << iSysId << " " << sChannelName;
} // for( uint32_t uPair = 0; uPair < vSysIdChanPairs.size(); ++uPair )
if (0 == fMaxTimeslices) fMaxTimeslices = UINT_MAX;
// Check which input is defined
// Posibilities
// filename && ! dirname : single file
// filename with wildcards && diranme : all files with filename regex in the directory
// host && port : connect to the flim server
bool isGoodInputCombi {false};
if (0 != fFileName.size() && 0 == fDirName.size() && 0 == fHost.size() && 0 == fPort) {
isGoodInputCombi = true;
fInputFileList.push_back(fFileName);
}
else if (0 != fFileName.size() && 0 != fDirName.size() && 0 == fHost.size() && 0 == fPort) {
isGoodInputCombi = true;
fInputFileList.push_back(fFileName);
}
else if (0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 != fPort) {
isGoodInputCombi = true;
LOG(info) << "Host: " << fHost;
LOG(info) << "Port: " << fPort;
}
else if (0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 == fPort) {
isGoodInputCombi = true;
LOG(info) << "Host string: " << fHost;
}
else {
isGoodInputCombi = false;
}
if (!isGoodInputCombi) {
throw InitTaskError("Wrong combination of inputs. Either file or wildcard file + directory or host + port are allowed combination.");
}
if (!isGoodInputCombi) {
throw InitTaskError("Wrong combination of inputs. Either file or wildcard file + directory "
"or host + port are allowed combination.");
}
LOG(info) << "MaxTimeslices: " << fMaxTimeslices;
// Get the information about created channels from the device
// Check if the defined channels from the topology (by name)
// are in the list of channels which are possible/allowed
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
int noChannel = fChannels.size();
LOG(info) << "Number of defined output channels: " << noChannel;
for(auto const &entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
}
LOG(info) << "MaxTimeslices: " << fMaxTimeslices;
// Get the information about created channels from the device
// Check if the defined channels from the topology (by name)
// are in the list of channels which are possible/allowed
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
int noChannel = fChannels.size();
LOG(info) << "Number of defined output channels: " << noChannel;
for (auto const& entry : fChannels) {
/// Catches and ignores the channels for missing TS indices and commands
/// Same for the histogram channels
if (entry.first == fsChannelNameMissedTs || entry.first == fsChannelNameCommands
|| (0 < fuPublishFreqTs
&& (entry.first == fsChannelNameHistosInput || entry.first == fsChannelNameHistosConfig
|| entry.first == fsChannelNameCanvasConfig))) {
continue;
} // if( entry.first == fsChannelNameMissedTs || entry.first == fsChannelNameCommands || histo channels name)
LOG(info) << "Channel name: " << entry.first;
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
}
for(auto const& value: fComponentsToSend) {
LOG(info) << "Value : " << value;
if (value > 1) {
throw InitTaskError("Sending same data to more than one output channel not implemented yet.");
}
for (auto const& value : fComponentsToSend) {
LOG(info) << "Value : " << value;
if (value > 1) {
throw InitTaskError("Sending same data to more than one output channel "
"not implemented yet.");
}
}
if ( 0 == fFileName.size() && 0 != fHost.size() && 0 != fPort ) {
if (0 == fFileName.size() && 0 != fHost.size() && 0 != fPort) {
// Don't add the protocol since this is done now in the TimesliceMultiSubscriber
//std::string connector = "tcp://" + fHost + ":" + std::to_string(fPort);
std::string connector = fHost + ":" + std::to_string(fPort);
LOG(info) << "Open TSPublisher at " << connector;
fSource = new fles::TimesliceMultiSubscriber(connector);
} else if ( 0 == fFileName.size() && 0 != fHost.size() ) {
}
else if (0 == fFileName.size() && 0 != fHost.size()) {
std::string connector = fHost;
LOG(info) << "Open TSPublisher with host string: " << connector;
fSource = new fles::TimesliceMultiSubscriber(connector, fHighWaterMark);
} else {
}
else {
// Create a ";" separated string with all file names
std::string fileList{""};
for(const auto obj: fInputFileList) {
std::string fileList {""};
for (const auto& obj : fInputFileList) {
std::string fileName = obj;
fileList += fileName;
fileList += ";";
}
fileList.pop_back(); // Remove the last ;
fileList.pop_back(); // Remove the last ;
LOG(info) << "Input File String: " << fileList;
fSource = new fles::TimesliceMultiInputArchive(fileList, fDirName);
if ( !fSource) {
throw InitTaskError("Could open files from file list.");
}
if (!fSource) { throw InitTaskError("Could open files from file list."); }
}
LOG( info ) << "High-Water Mark: " << fHighWaterMark;
LOG( info ) << "Max. Timeslices: " << fMaxTimeslices;
if( fbNoSplitTs )
{
LOG(info) << "Sending TS copies in no-split mode";
} // if( fbNoSplitTs )
else if( fbSendTsPerSysId )
{
LOG(info) << "High-Water Mark: " << fHighWaterMark;
LOG(info) << "Max. Timeslices: " << fMaxTimeslices;
if (fbNoSplitTs) { LOG(info) << "Sending TS copies in no-split mode"; } // if( fbNoSplitTs )
else if (fbSendTsPerSysId) {
LOG(info) << "Sending components in separate TS per SysId";
} // else if( fbSendTsPerSysId && fbSendTsPerSysId ) of if( fbNoSplitTs
else if( fbSendTsPerChannel )
{
} // else if( fbSendTsPerSysId && fbSendTsPerSysId ) of if( fbNoSplitTs
else if (fbSendTsPerChannel) {
LOG(info) << "Sending components in separate TS per channel";
} // else if( fbSendTsPerSysId && fbSendTsPerSysId ) of if( fbNoSplitTs )
} // else if( fbSendTsPerSysId && fbSendTsPerSysId ) of if( fbNoSplitTs )
fTime = std::chrono::steady_clock::now();
} catch (InitTaskError& e) {
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
ChangeState(fair::mq::Transition::ErrorFound);
}
bool CbmMQTsaMultiSampler::IsChannelNameAllowed(std::string channelName)
{
/// If sending full TS, accept any name!
if (fbNoSplitTs) {
fComponentsToSend[0]++;
fChannelsToSend[0].push_back(channelName);
return true;
} // if( fbNoSplitTs )
bool bFoundMatch = false;
// for(auto const &entry : fAllowedChannels) {
for( uint32_t idx = 0; idx < fAllowedChannels.size(); ++idx )
{
auto const &entry = fAllowedChannels[ idx ];
// for(auto const &entry : fAllowedChannels) {
for (uint32_t idx = 0; idx < fAllowedChannels.size(); ++idx) {
auto const& entry = fAllowedChannels[idx];
LOG(info) << "Looking for name " << channelName << " in " << entry;
std::size_t pos1 = channelName.find(entry);
if (pos1!=std::string::npos) {
/*
if (pos1 != std::string::npos) {
/*
const vector<std::string>::const_iterator pos =
std::find(fAllowedChannels.begin(), fAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos-fAllowedChannels.begin();
*/
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName
<< " found in list of allowed channel names at position " << idx
<< " (SysId 0x" << std::hex << fSysId[ idx ] << std::dec << ")";
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx
<< " (SysId 0x" << std::hex << fSysId[idx] << std::dec << ")";
fComponentsToSend[idx]++;
fChannelsToSend[idx].push_back(channelName);
/// If sending per channel, do not stop the loop as we allow more than 1 comp type per channel
if( fbSendTsPerChannel )
bFoundMatch = true;
else return true;
} // if (pos1!=std::string::npos)
if (fbSendTsPerChannel) bFoundMatch = true;
else
return true;
} // if (pos1!=std::string::npos)
}
/// If sending per channel, do not stop the loop but still check if at least 1 match found
if( fbSendTsPerChannel && bFoundMatch )
return true;
if (fbSendTsPerChannel && bFoundMatch) return true;
LOG(info) << "Channel name " << channelName
<< " not found in list of allowed channel names.";
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
bool CbmMQTsaMultiSampler::InitHistograms()
{
LOG(info) << "Histograms publication frequency in TS: " << fuPublishFreqTs;
LOG(info) << "Histograms publication min. interval in s: " << fdMinPublishTime;
LOG(info) << "Histograms publication max. interval in s: " << fdMaxPublishTime;
/// Vector of pointers on each histo (+ optionally desired folder)
std::vector<std::pair<TNamed*, std::string>> vHistos = {};
/// Vector of pointers on each canvas (+ optionally desired folder)
std::vector<std::pair<TCanvas*, std::string>> vCanvases = {};
/// Histos creation and obtain pointer on them
fhTsRate = new TH1I("TsRate", "TS rate; t [s]", 1800, 0., 1800.);
fhTsSize = new TH1I("TsSize", "Size of TS; Size [MB]", 15000, 0., 15000.);
fhTsSizeEvo = new TProfile("TsSizeEvo", "Evolution of the TS Size; t [s]; Mean size [MB]", 1800, 0., 1800.);
fhTsMaxSizeEvo = new TH1F("TsMaxSizeEvo", "Evolution of maximal TS Size; t [s]; Max size [MB]", 1800, 0., 1800.);
fhMissedTS = new TH1I("Missed_TS", "Missed TS", 2, -0.5, 1.5);
fhMissedTSEvo = new TProfile("Missed_TS_Evo", "Missed TS evolution; t [s]", 1800, 0., 1800.);
/// Add histo pointers to the histo vector
vHistos.push_back(std::pair<TNamed*, std::string>(fhTsRate, "Sampler"));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTsSize, "Sampler"));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTsSizeEvo, "Sampler"));
vHistos.push_back(std::pair<TNamed*, std::string>(fhTsMaxSizeEvo, "Sampler"));
vHistos.push_back(std::pair<TNamed*, std::string>(fhMissedTS, "Sampler"));
vHistos.push_back(std::pair<TNamed*, std::string>(fhMissedTSEvo, "Sampler"));
/// Canvases creation
Double_t w = 10;
Double_t h = 10;
fcSummary = new TCanvas("cSampSummary", "Sampler monitoring plots", w, h);
fcSummary->Divide(2, 3);
fcSummary->cd(1);
gPad->SetGridx();
gPad->SetGridy();
fhTsRate->Draw("hist");
fcSummary->cd(2);
gPad->SetGridx();
gPad->SetGridy();
gPad->SetLogx();
gPad->SetLogy();
fhTsSize->Draw("hist");
fcSummary->cd(3);
gPad->SetGridx();
gPad->SetGridy();
fhTsSizeEvo->Draw("hist");
fcSummary->cd(4);
gPad->SetGridx();
gPad->SetGridy();
fhTsMaxSizeEvo->Draw("hist");
fcSummary->cd(5);
gPad->SetGridx();
gPad->SetGridy();
fhMissedTS->Draw("hist");
fcSummary->cd(6);
gPad->SetGridx();
gPad->SetGridy();
fhMissedTSEvo->Draw("el");
/// Add canvas pointers to the canvas vector
vCanvases.push_back(std::pair<TCanvas*, std::string>(fcSummary, "canvases"));
/// Add pointers to each histo in the histo array
/// Create histo config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Histo name, Folder >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
// LOG(info) << "Registering " << vHistos[ uHisto ].first->GetName()
// << " in " << vHistos[ uHisto ].second.data()
// ;
fArrayHisto.Add(vHistos[uHisto].first);
std::pair<std::string, std::string> psHistoConfig(vHistos[uHisto].first->GetName(), vHistos[uHisto].second);
fvpsHistosFolder.push_back(psHistoConfig);
/// Serialize the vector of histo config into a single MQ message
FairMQMessagePtr messageHist(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, psHistoConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, psHistoConfig);
/// Send message to the common histogram config messages queue
if (Send(messageHist, fsChannelNameHistosConfig) < 0) {
LOG(fatal) << "Problem sending histo config";
} // if( Send( messageHist, fsChannelNameHistosConfig ) < 0 )
LOG(info) << "Config of hist " << psHistoConfig.first.data() << " in folder " << psHistoConfig.second.data();
} // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
/// Create canvas config vector
/// ===> Use an std::vector< std::pair< std::string, std::string > > with < Canvas name, config >
/// and send it through a separate channel using the BoostSerializer
for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) {
// LOG(info) << "Registering " << vCanvases[ uCanv ].first->GetName()
// << " in " << vCanvases[ uCanv ].second.data();
std::string sCanvName = (vCanvases[uCanv].first)->GetName();
std::string sCanvConf = GenerateCanvasConfigString(vCanvases[uCanv].first);
std::pair<std::string, std::string> psCanvConfig(sCanvName, sCanvConf);
fvpsCanvasConfig.push_back(psCanvConfig);
/// Serialize the vector of canvas config into a single MQ message
FairMQMessagePtr messageCan(NewMessage());
// Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, psCanvConfig);
BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, psCanvConfig);
/// Send message to the common canvas config messages queue
if (Send(messageCan, fsChannelNameCanvasConfig) < 0) {
LOG(fatal) << "Problem sending canvas config";
} // if( Send( messageCan, fsChannelNameCanvasConfig ) < 0 )
LOG(info) << "Config string of Canvas " << psCanvConfig.first.data() << " is " << psCanvConfig.second.data();
} // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv )
return true;
}
bool CbmMQTsaMultiSampler::ConditionalRun()
{
if (0 < fuPublishFreqTs && 0 == fTSCounter) { InitHistograms(); } // if( 0 < fuPublishFreqTs )
/// initialize the source (connect to emitter, ...)
if (0 == fTSCounter && nullptr != dynamic_cast<fles::TimesliceMultiSubscriber*>(fSource)) {
dynamic_cast<fles::TimesliceMultiSubscriber*>(fSource)->InitTimesliceSubscriber();
} // if( 0 == fTSCounter && nullptr != dynamic_cast< fles::TimesliceMultiSubscriber >(fSource) )
auto timeslice = fSource->get();
if (timeslice) {
if (fTSCounter < fMaxTimeslices) {
fTSCounter++;
if (fTSCounter % 10000 == 0) {
LOG(info) << "Analyse Event " << fTSCounter;
}
const fles::Timeslice& ts = *timeslice;
// auto tsIndex = ts.index();
LOG(debug) << "Found " << ts.num_components()
<< " different components in timeslice";
// CheckTimeslice(ts);
if( fbNoSplitTs )
{
/// This is a special case for the TOF + T0
uint64_t uTsIndex = ts.index();
if (0 < fuPublishFreqTs) {
uint64_t uTsTime = ts.descriptor(0, 0).idx;
if (0 == fuStartTime) { fuStartTime = uTsTime; } // if( 0 == fuStartTime )
fdTimeToStart = static_cast<double_t>(uTsTime - fuStartTime) / 1e9;
uint64_t uSizeMb = 0;
for (uint64_t uComp = 0; uComp < ts.num_components(); ++uComp) {
uSizeMb += ts.size_component(uComp) / (1024 * 1024);
} // for( uint_t uComp = 0; uComp < ts.num_components(); ++uComp )
fhTsRate->Fill(fdTimeToStart);
fhTsSize->Fill(uSizeMb);
fhTsSizeEvo->Fill(fdTimeToStart, uSizeMb);
/// Fill max size per s (assumes the histo binning is 1 second!)
if (0. == fdLastMaxTime) {
fdLastMaxTime = fdTimeToStart;
fdTsMaxSize = uSizeMb;
} // if( 0. == fdLastMaxTime )
else if (1. <= fdTimeToStart - fdLastMaxTime) {
fhTsMaxSizeEvo->Fill(fdLastMaxTime, fdTsMaxSize);
fdLastMaxTime = fdTimeToStart;
fdTsMaxSize = uSizeMb;
} // else if if( 1 <= fdTimeToStart - fdLastMaxTime )
else if (fdTsMaxSize < uSizeMb) {
fdTsMaxSize = uSizeMb;
} // else if( fdTsMaxSize < uSizeMb )
} // if( 0 < fuPublishFreqTs )
/// Missed TS detection (only if output channel name defined by user)
if ((uTsIndex != (fuPrevTsIndex + 1)) && !(0 == fuPrevTsIndex && 0 == uTsIndex)) {
LOG(info) << "Missed Timeslices. Old TS Index was " << fuPrevTsIndex << " New TS Index is " << uTsIndex
<< " diff is " << uTsIndex - fuPrevTsIndex << " Missing are " << uTsIndex - fuPrevTsIndex - 1;
if ("" != fsChannelNameMissedTs) {
/// Add missing TS indices to a vector and send it in appropriate channel
std::vector<uint64_t> vulMissedIndices;
for (uint64_t ulMiss = fuPrevTsIndex + 1; ulMiss < uTsIndex; ++ulMiss) {
vulMissedIndices.emplace_back(ulMiss);
} // for( uint64_t ulMiss = fuPrevTsIndex + 1; ulMiss < uTsIndex; ++ulMiss )
if (!SendMissedTsIdx(vulMissedIndices)) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return false;
} // if( !SendMissedTsIdx( vulMissedIndices ) )
} // if( "" != fsChannelNameMissedTs )
if (0 < fuPublishFreqTs) {
fhMissedTS->Fill(1, uTsIndex - fuPrevTsIndex - 1);
fhMissedTSEvo->Fill(fdTimeToStart, 1, uTsIndex - fuPrevTsIndex - 1);
} // if( 0 < fuPublishFreqTs )
} // if( ( uTsIndex != ( fuPrevTsIndex + 1 ) ) && !( 0 == fuPrevTsIndex && 0 == uTsIndex ) )
if (0 < fuPublishFreqTs) {
fhMissedTS->Fill(0);
fhMissedTSEvo->Fill(fdTimeToStart, 0, 1);
} // else if( 0 < fuPublishFreqTs )
fuPrevTsIndex = uTsIndex;
if (fTSCounter % 10000 == 0) { LOG(info) << "Received TS " << fTSCounter << " with index " << uTsIndex; }
LOG(debug) << "Found " << ts.num_components() << " different components in timeslice";
// CheckTimeslice(ts);
if (fbNoSplitTs) {
/// This is a special case for the TOF + Bmon
/// => Inefficient as copy the TS as many times as need!
if( !CreateAndSendFullTs( ts ) )
if (!CreateAndSendFullTs(ts)) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return false;
} // if( fbNoSplitTs )
else if( fbSendTsPerSysId )
{
} // if( !CreateAndSendFullTs( ts ) )
} // if( fbNoSplitTs )
else if (fbSendTsPerSysId) {
/// This assumes that the order of the components does NOT change after the first TS
/// That should be the case as the component index correspond to a physical link idx
if( !CreateAndCombineComponentsPerSysId( ts ) )
if (!CreateAndCombineComponentsPerSysId(ts)) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return false;
} // else if( fbSendTsPerSysId ) of if( fbNoSplitTs )
else if( fbSendTsPerChannel )
{
} // if( !CreateAndCombineComponentsPerSysId( ts ) )
} // else if( fbSendTsPerSysId ) of if( fbNoSplitTs )
else if (fbSendTsPerChannel) {
/// This assumes that the order of the components does NOT change after the first TS
/// That should be the case as the component index correspond to a physical link idx
if( !CreateAndCombineComponentsPerChannel( ts ) )
if (!CreateAndCombineComponentsPerChannel(ts)) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return false;
} // else if( fbSendTsPerChannel ) of if( fbSendTsPerSysId )
else
{
for (unsigned int nrComp = 0; nrComp < ts.num_components(); ++nrComp) {
if( !CreateAndSendComponent(ts, nrComp) )
return false;
}
} // else of if( fbSendTsPerSysId )
} // if( !CreateAndCombineComponentsPerChannel( ts ) )
} // else if( fbSendTsPerChannel ) of if( fbSendTsPerSysId )
else {
for (unsigned int nrComp = 0; nrComp < ts.num_components(); ++nrComp) {
if (!CreateAndSendComponent(ts, nrComp)) {
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending a STOP to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
SendCommand("STOP");
} // if( "" != fsChannelNameCommands )
return false;
} // if( !CreateAndSendComponent(ts, nrComp) )
} // for (unsigned int nrComp = 0; nrComp < ts.num_components(); ++nrComp)
} // else of if( fbSendTsPerSysId )
if (0 < fuPublishFreqTs) {
/// Send histograms periodically.
/// Use also runtime checker to trigger sending after M s if
/// processing too slow or delay sending if processing too fast
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
std::chrono::duration<double_t> elapsedSeconds = currentTime - fLastPublishTime;
if ((fdMaxPublishTime < elapsedSeconds.count())
|| (0 == fTSCounter % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count())) {
SendHistograms();
fLastPublishTime = std::chrono::system_clock::now();
} // if( ( fdMaxPublishTime < elapsedSeconds.count() ) || ( 0 == fTSCounter % fuPublishFreqTs && fdMinPublishTime < elapsedSeconds.count() ) )
} // if( 0 < fuPublishFreqTs )
return true;
} else {
} // if (fTSCounter < fMaxTimeslices)
else {
CalcRuntime();
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending an EOF to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::seconds(10));
std::string sCmd = "EOF ";
sCmd += FormatDecPrintout(fuPrevTsIndex);
sCmd += " ";
sCmd += FormatDecPrintout(fTSCounter);
SendCommand(sCmd);
} // if( "" != fsChannelNameCommands )
return false;
}
} else {
} // else of if (fTSCounter < fMaxTimeslices)
} // if (timeslice)
else {
CalcRuntime();
return false;
}
/// If command channel defined, send command to all "slaves"
if ("" != fsChannelNameCommands) {
/// Wait 1 s before sending an EOF to let all slaves finish processing previous data
std::this_thread::sleep_for(std::chrono::seconds(10));
std::string sCmd = "EOF ";
sCmd += FormatDecPrintout(fuPrevTsIndex);
sCmd += " ";
sCmd += FormatDecPrintout(fTSCounter);
SendCommand(sCmd);
} // if( "" != fsChannelNameCommands )
return false;
} // else of if (timeslice)
}
bool CbmMQTsaMultiSampler::CreateAndSendComponent(const fles::Timeslice& ts, int nrComp)
......@@ -348,241 +637,198 @@ bool CbmMQTsaMultiSampler::CreateAndSendComponent(const fles::Timeslice& ts, int
// is connected create the new timeslice and send it to the
// correct channel
LOG(debug) << "SysID: " << static_cast<int>(ts.descriptor(nrComp,0).sys_id);
LOG(debug) << "SysID: " << static_cast<int>(ts.descriptor(nrComp, 0).sys_id);
const vector<int>::const_iterator pos =
std::find(fSysId.begin(), fSysId.end(), static_cast<int>(ts.descriptor(nrComp,0).sys_id));
if (pos != fSysId.end() ) {
const vector<std::string>::size_type idx = pos-fSysId.begin();
if (fComponentsToSend[idx]>0) {
std::find(fSysId.begin(), fSysId.end(), static_cast<int>(ts.descriptor(nrComp, 0).sys_id));
if (pos != fSysId.end()) {
const vector<std::string>::size_type idx = pos - fSysId.begin();
if (fComponentsToSend[idx] > 0) {
LOG(debug) << "Create timeslice component for link " << nrComp;
fles::StorableTimeslice component{static_cast<uint32_t>(ts.num_core_microslices()), ts.index()};
fles::StorableTimeslice component {static_cast<uint32_t>(ts.num_core_microslices()), ts.index()};
component.append_component(ts.num_microslices(0));
for (size_t m = 0; m < ts.num_microslices(nrComp); ++m) {
component.append_microslice( 0, m, ts.descriptor(nrComp, m), ts.content(nrComp, m) );
component.append_microslice(0, m, ts.descriptor(nrComp, m), ts.content(nrComp, m));
}
/*
/*
LOG(info) << "Number of core microslices before: " << ts.num_core_microslices();
LOG(info) << "Number of core microslices after : " << component.num_core_microslices();
LOG(info) << "Number of microslices: " << component.num_microslices(0);
*/
if ( ! SendData(component, idx) ) return false;
if (!SendData(component, idx)) return false;
return true;
}
}
return true;
}
bool CbmMQTsaMultiSampler::CreateAndCombineComponentsPerSysId( const fles::Timeslice& ts )
bool CbmMQTsaMultiSampler::CreateAndCombineComponentsPerSysId(const fles::Timeslice& ts)
{
/// First build the list of components for each SysId if it was not already done
if( false == fbListCompPerSysIdReady )
{
for( uint32_t uCompIdx = 0; uCompIdx < ts.num_components(); ++uCompIdx )
{
uint16_t usSysId = ts.descriptor( uCompIdx, 0 ).sys_id;
const vector<int>::const_iterator pos = std::find( fSysId.begin(), fSysId.end(), usSysId );
if( fSysId.end() != pos )
{
if (false == fbListCompPerSysIdReady) {
for (uint32_t uCompIdx = 0; uCompIdx < ts.num_components(); ++uCompIdx) {
uint16_t usSysId = ts.descriptor(uCompIdx, 0).sys_id;
const vector<int>::const_iterator pos = std::find(fSysId.begin(), fSysId.end(), usSysId);
if (fSysId.end() != pos) {
const vector<std::string>::size_type idx = pos - fSysId.begin();
fvvCompPerSysId[ idx ].push_back( uCompIdx );
} // if( fSysId.end() != pos )
} // for( uint32_t uNrComp = 0; uNrComp < ts.num_components(); ++uNrComp )
fvvCompPerSysId[idx].push_back(uCompIdx);
} // if( fSysId.end() != pos )
} // for( uint32_t uNrComp = 0; uNrComp < ts.num_components(); ++uNrComp )
for( uint32_t uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx )
{
for (uint32_t uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx) {
std::stringstream ss;
ss << "Found " << std::setw( 2 ) << fvvCompPerSysId[ uSysIdx ].size()
<< " components for SysId 0x"
<< std::hex << std::setw( 2 ) << fSysId[ uSysIdx ] << std::dec << " :";
ss << "Found " << std::setw(2) << fvvCompPerSysId[uSysIdx].size() << " components for SysId 0x" << std::hex
<< std::setw(2) << fSysId[uSysIdx] << std::dec << " :";
for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ uSysIdx ].size(); ++uComp )
{
ss << " " << std::setw( 3 ) << fvvCompPerSysId[ uSysIdx ][ uComp ];
} // for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ uSysIdx ].size(); ++uComp )
for (uint32_t uComp = 0; uComp < fvvCompPerSysId[uSysIdx].size(); ++uComp) {
ss << " " << std::setw(3) << fvvCompPerSysId[uSysIdx][uComp];
} // for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ uSysIdx ].size(); ++uComp )
LOG(info) << ss.str();
} // for( uint32_t uSysId = 0; uSysId < fSysId.size(); ++uSysId )
} // for( uint32_t uSysId = 0; uSysId < fSysId.size(); ++uSysId )
fbListCompPerSysIdReady = true;
} // if( false == fbListCompPerSysIdReady )
} // if( false == fbListCompPerSysIdReady )
/// Then loop on all possible SysId and send TS with their respective components if needed
for( uint32_t uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx )
{
if( 0 < fComponentsToSend[ uSysIdx ] )
{
LOG(debug) << "Create timeslice with components for SysId "
<< std::hex << fSysId[ uSysIdx ] << std::dec;
if( 0 < fvvCompPerSysId[ uSysIdx ].size() )
{
fles::StorableTimeslice component{ static_cast<uint32_t>( ts.num_core_microslices() ), ts.index() };
for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ uSysIdx ].size(); ++uComp )
{
uint32_t uNumMsInComp = ts.num_microslices( fvvCompPerSysId[ uSysIdx ][ uComp ] );
component.append_component( uNumMsInComp );
LOG(debug) << "Add components to TS for SysId "
<< std::hex << fSysId[ uSysIdx ] << std::dec
<< " TS " << ts.index()
<< " Comp " << fvvCompPerSysId[ uSysIdx ][ uComp ];
for( size_t m = 0; m < uNumMsInComp; ++m )
{
component.append_microslice( uComp, m,
ts.descriptor( fvvCompPerSysId[ uSysIdx ][ uComp ], m ),
ts.content( fvvCompPerSysId[ uSysIdx ][ uComp ], m ) );
} // for( size_t m = 0; m < uNumMsInComp; ++m )
} // for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ uSysIdx ].size(); ++uComp )
LOG(debug) << "Prepared timeslice for SysId "
<< std::hex << fSysId[ uSysIdx ] << std::dec
<< " with " << component.num_components() << " components";
if( !SendData( component, uSysIdx ) )
return false;
} // if( 0 < fvvCompPerSysId[ uSysIdx ].size() )
} // if( 0 < fComponentsToSend[ uSysIdx ] )
} // for( uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx )
for (uint32_t uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx) {
if (0 < fComponentsToSend[uSysIdx]) {
LOG(debug) << "Create timeslice with components for SysId " << std::hex << fSysId[uSysIdx] << std::dec;
if (0 < fvvCompPerSysId[uSysIdx].size()) {
fles::StorableTimeslice component {static_cast<uint32_t>(ts.num_core_microslices()), ts.index()};
for (uint32_t uComp = 0; uComp < fvvCompPerSysId[uSysIdx].size(); ++uComp) {
uint32_t uNumMsInComp = ts.num_microslices(fvvCompPerSysId[uSysIdx][uComp]);
component.append_component(uNumMsInComp);
LOG(debug) << "Add components to TS for SysId " << std::hex << fSysId[uSysIdx] << std::dec << " TS "
<< ts.index() << " Comp " << fvvCompPerSysId[uSysIdx][uComp];
for (size_t m = 0; m < uNumMsInComp; ++m) {
component.append_microslice(uComp, m, ts.descriptor(fvvCompPerSysId[uSysIdx][uComp], m),
ts.content(fvvCompPerSysId[uSysIdx][uComp], m));
} // for( size_t m = 0; m < uNumMsInComp; ++m )
} // for( uint32_t uComp = 0; uComp < fvvCompPerSysId[ uSysIdx ].size(); ++uComp )
LOG(debug) << "Prepared timeslice for SysId " << std::hex << fSysId[uSysIdx] << std::dec << " with "
<< component.num_components() << " components";
if (!SendData(component, uSysIdx)) return false;
} // if( 0 < fvvCompPerSysId[ uSysIdx ].size() )
} // if( 0 < fComponentsToSend[ uSysIdx ] )
} // for( uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx )
return true;
}
bool CbmMQTsaMultiSampler::CreateAndCombineComponentsPerChannel( const fles::Timeslice& ts )
bool CbmMQTsaMultiSampler::CreateAndCombineComponentsPerChannel(const fles::Timeslice& ts)
{
/// First build the list of components for each channel name if it was not already done
if( false == fbListCompPerChannelReady )
{
if (false == fbListCompPerChannelReady) {
/// First add each channel enabled for sending to the list of channels we will use
for( uint32_t uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx )
{
if( 0 < fComponentsToSend[ uSysIdx ] )
{
for( uint32_t uChan = 0; uChan < fChannelsToSend[ uSysIdx ].size(); ++ uChan )
{
const vector<std::string>::const_iterator pos = std::find( fvChannelsToSend.begin(), fvChannelsToSend.end(),
fChannelsToSend[ uSysIdx ][ uChan ] );
if( fvChannelsToSend.end() == pos )
{
fvChannelsToSend.push_back( fChannelsToSend[ uSysIdx ][ uChan ] );
fvvCompPerChannel.push_back( std::vector< uint32_t >() );
for (uint32_t uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx) {
if (0 < fComponentsToSend[uSysIdx]) {
for (uint32_t uChan = 0; uChan < fChannelsToSend[uSysIdx].size(); ++uChan) {
const vector<std::string>::const_iterator pos =
std::find(fvChannelsToSend.begin(), fvChannelsToSend.end(), fChannelsToSend[uSysIdx][uChan]);
if (fvChannelsToSend.end() == pos) {
fvChannelsToSend.push_back(fChannelsToSend[uSysIdx][uChan]);
fvvCompPerChannel.push_back(std::vector<uint32_t>());
}
} // for( uChan = 0; uChan < fChannelsToSend[ uSysIdx ].size(); ++ uChan )
} // if( 0 < fComponentsToSend[ uSysIdx ] )
} // for( uint32_t uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx )
} // for( uChan = 0; uChan < fChannelsToSend[ uSysIdx ].size(); ++ uChan )
} // if( 0 < fComponentsToSend[ uSysIdx ] )
} // for( uint32_t uSysIdx = 0; uSysIdx < fComponentsToSend.size(); ++uSysIdx )
/// Now resize the vector in which we will store fo each sending channel the list of components
fvvCompPerChannel.resize( fvChannelsToSend.size() );
fvvCompPerChannel.resize(fvChannelsToSend.size());
/// Check for each component if its system is enabled and if the name of its channel(s) is in the list
/// If yes, add it to the vector of the corresponding channel
for( uint32_t uCompIdx = 0; uCompIdx < ts.num_components(); ++uCompIdx )
{
uint16_t usSysId = ts.descriptor( uCompIdx, 0 ).sys_id;
for (uint32_t uCompIdx = 0; uCompIdx < ts.num_components(); ++uCompIdx) {
uint16_t usSysId = ts.descriptor(uCompIdx, 0).sys_id;
const vector<int>::const_iterator pos = std::find( fSysId.begin(), fSysId.end(), usSysId );
if( fSysId.end() != pos )
{
const vector<int>::const_iterator pos = std::find(fSysId.begin(), fSysId.end(), usSysId);
if (fSysId.end() != pos) {
const vector<std::string>::size_type idxSys = pos - fSysId.begin();
if( 0 < fComponentsToSend[ idxSys ] )
{
for( uint32_t uChan = 0; uChan < fChannelsToSend[ idxSys ].size(); ++ uChan )
{
const vector<std::string>::const_iterator posCh = std::find( fvChannelsToSend.begin(), fvChannelsToSend.end(),
fChannelsToSend[ idxSys ][ uChan ] );
if( fvChannelsToSend.end() != posCh )
{
if (0 < fComponentsToSend[idxSys]) {
for (uint32_t uChan = 0; uChan < fChannelsToSend[idxSys].size(); ++uChan) {
const vector<std::string>::const_iterator posCh =
std::find(fvChannelsToSend.begin(), fvChannelsToSend.end(), fChannelsToSend[idxSys][uChan]);
if (fvChannelsToSend.end() != posCh) {
const vector<std::string>::size_type idxChan = posCh - fvChannelsToSend.begin();
fvvCompPerChannel[ idxChan ].push_back( uCompIdx );
} // if( fvChannelsToSend.end() != posCh )
} // for( uChan = 0; uChan < fChannelsToSend[ idxSys ].size(); ++ uChan )
} // if( 0 < fComponentsToSend[ uSysIdx ] )
} // if( fSysId.end() != pos )
} // for( uint32_t uNrComp = 0; uNrComp < ts.num_components(); ++uNrComp )
for( uint32_t uChanIdx = 0; uChanIdx < fvChannelsToSend.size(); ++uChanIdx )
{
fvvCompPerChannel[idxChan].push_back(uCompIdx);
} // if( fvChannelsToSend.end() != posCh )
} // for( uChan = 0; uChan < fChannelsToSend[ idxSys ].size(); ++ uChan )
} // if( 0 < fComponentsToSend[ uSysIdx ] )
} // if( fSysId.end() != pos )
} // for( uint32_t uNrComp = 0; uNrComp < ts.num_components(); ++uNrComp )
for (uint32_t uChanIdx = 0; uChanIdx < fvChannelsToSend.size(); ++uChanIdx) {
std::stringstream ss;
ss << "Found " << std::setw( 2 ) << fvvCompPerChannel[ uChanIdx ].size()
<< " components for channel " << fvChannelsToSend[ uChanIdx ] << " :";
ss << "Found " << std::setw(2) << fvvCompPerChannel[uChanIdx].size() << " components for channel "
<< fvChannelsToSend[uChanIdx] << " :";
for( uint32_t uComp = 0; uComp < fvvCompPerChannel[ uChanIdx ].size(); ++uComp )
{
ss << " " << std::setw( 3 ) << fvvCompPerChannel[ uChanIdx ][ uComp ];
} // for( uint32_t uComp = 0; uComp < fvvCompPerChannel[ uChanIdx ].size(); ++uComp )
for (uint32_t uComp = 0; uComp < fvvCompPerChannel[uChanIdx].size(); ++uComp) {
ss << " " << std::setw(3) << fvvCompPerChannel[uChanIdx][uComp];
} // for( uint32_t uComp = 0; uComp < fvvCompPerChannel[ uChanIdx ].size(); ++uComp )
LOG(info) << ss.str();
} // for( uint32_t uChanIdx = 0; uChanIdx < fvChannelsToSend.size(); ++uChanIdx )
} // for( uint32_t uChanIdx = 0; uChanIdx < fvChannelsToSend.size(); ++uChanIdx )
fbListCompPerChannelReady = true;
} // if( false == fbListCompPerSysIdReady )
} // if( false == fbListCompPerSysIdReady )
/// Loop on channels
/// Loop on possible SysId and check channels
/// Loop on possible SysId and check channels
/// Then loop on all possible channels and send TS with their respective components if needed
for( uint32_t uChanIdx = 0; uChanIdx < fvChannelsToSend.size(); ++uChanIdx )
{
LOG(debug) << "Create timeslice with components for channel "
<< fvChannelsToSend[ uChanIdx ];
if( 0 < fvvCompPerChannel[ uChanIdx ].size() )
{
fles::StorableTimeslice component{ static_cast<uint32_t>( ts.num_core_microslices() ), ts.index() };
for( uint32_t uComp = 0; uComp < fvvCompPerChannel[ uChanIdx ].size(); ++uComp )
{
uint32_t uNumMsInComp = ts.num_microslices( fvvCompPerChannel[ uChanIdx ][ uComp ] );
component.append_component( uNumMsInComp );
LOG(debug) << "Add components to TS for SysId "
<< std::hex
<< static_cast< uint16_t >( ts.descriptor( fvvCompPerChannel[ uChanIdx ][ uComp ], 0).sys_id )
<< std::dec
<< " TS " << ts.index()
<< " Comp " << fvvCompPerChannel[ uChanIdx ][ uComp ];
for( size_t m = 0; m < uNumMsInComp; ++m )
{
component.append_microslice( uComp, m,
ts.descriptor( fvvCompPerChannel[ uChanIdx ][ uComp ], m ),
ts.content( fvvCompPerChannel[ uChanIdx ][ uComp ], m ) );
} // for( size_t m = 0; m < uNumMsInComp; ++m )
} // for( uint32_t uComp = 0; uComp < fvvCompPerChannel[ uChanIdx ].size(); ++uComp )
LOG(debug) << "Prepared timeslice for channel "
<< fvChannelsToSend[ uChanIdx ]
<< " with " << component.num_components() << " components";
if( !SendData( component, fvChannelsToSend[ uChanIdx ] ) )
return false;
} // if( 0 < fvvCompPerSysId[ uSysIdx ].size() )
} // for( uChanIdx = 0; uChanIdx < fvChannelsToSend.size(); ++uChanIdx )
for (uint32_t uChanIdx = 0; uChanIdx < fvChannelsToSend.size(); ++uChanIdx) {
LOG(debug) << "Create timeslice with components for channel " << fvChannelsToSend[uChanIdx];
if (0 < fvvCompPerChannel[uChanIdx].size()) {
fles::StorableTimeslice component {static_cast<uint32_t>(ts.num_core_microslices()), ts.index()};
for (uint32_t uComp = 0; uComp < fvvCompPerChannel[uChanIdx].size(); ++uComp) {
uint32_t uNumMsInComp = ts.num_microslices(fvvCompPerChannel[uChanIdx][uComp]);
component.append_component(uNumMsInComp);
LOG(debug) << "Add components to TS for SysId " << std::hex
<< static_cast<uint16_t>(ts.descriptor(fvvCompPerChannel[uChanIdx][uComp], 0).sys_id) << std::dec
<< " TS " << ts.index() << " Comp " << fvvCompPerChannel[uChanIdx][uComp];
for (size_t m = 0; m < uNumMsInComp; ++m) {
component.append_microslice(uComp, m, ts.descriptor(fvvCompPerChannel[uChanIdx][uComp], m),
ts.content(fvvCompPerChannel[uChanIdx][uComp], m));
} // for( size_t m = 0; m < uNumMsInComp; ++m )
} // for( uint32_t uComp = 0; uComp < fvvCompPerChannel[ uChanIdx ].size(); ++uComp )
LOG(debug) << "Prepared timeslice for channel " << fvChannelsToSend[uChanIdx] << " with "
<< component.num_components() << " components";
if (!SendData(component, fvChannelsToSend[uChanIdx])) return false;
} // if( 0 < fvvCompPerSysId[ uSysIdx ].size() )
} // for( uChanIdx = 0; uChanIdx < fvChannelsToSend.size(); ++uChanIdx )
return true;
}
bool CbmMQTsaMultiSampler::CreateAndSendFullTs( const fles::Timeslice& ts )
bool CbmMQTsaMultiSampler::CreateAndSendFullTs(const fles::Timeslice& ts)
{
/// Send full TS to all enabled channels
for( uint32_t uChanIdx = 0; uChanIdx < fChannelsToSend.size(); ++uChanIdx )
{
if( 0 < fComponentsToSend[ uChanIdx ] )
{
LOG(debug) << "Copy timeslice component for channel " << fChannelsToSend[ uChanIdx ][ 0 ];
fles::StorableTimeslice fullTs{ ts };
if ( ! SendData( fullTs, uChanIdx ) )
return false;
} // if( 0 < fComponentsToSend[ uChanIdx ] )
} // for( uint32_t uChanIdx = 0; uChanIdx < fChannelsToSend.size(); ++uChanIdx )
for (uint32_t uChanIdx = 0; uChanIdx < fChannelsToSend.size(); ++uChanIdx) {
if (0 < fComponentsToSend[uChanIdx]) {
LOG(debug) << "Copy timeslice component for channel " << fChannelsToSend[uChanIdx][0];
fles::StorableTimeslice fullTs {ts};
if (!SendData(fullTs, uChanIdx)) return false;
} // if( 0 < fComponentsToSend[ uChanIdx ] )
} // for( uint32_t uChanIdx = 0; uChanIdx < fChannelsToSend.size(); ++uChanIdx )
return true;
}
......@@ -594,16 +840,15 @@ bool CbmMQTsaMultiSampler::SendData(const fles::StorableTimeslice& component, in
oa << component;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object){ delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// TODO: Implement sending same data to more than one channel
// Need to create new message (copy message??)
if (fComponentsToSend[idx]>1) {
LOG(info) << "Need to copy FairMessage";
}
if (fComponentsToSend[idx] > 1) { LOG(info) << "Need to copy FairMessage"; }
// in case of error or transfer interruption,
// return false to go to IDLE state
......@@ -617,13 +862,12 @@ bool CbmMQTsaMultiSampler::SendData(const fles::StorableTimeslice& component, in
}
fMessageCounter++;
LOG(debug) << "Send message " << fMessageCounter << " with a size of "
<< msg->GetSize();
LOG(debug) << "Send message " << fMessageCounter << " with a size of " << msg->GetSize();
return true;
}
bool CbmMQTsaMultiSampler::SendData(const fles::StorableTimeslice& component, std::string sChannel )
bool CbmMQTsaMultiSampler::SendData(const fles::StorableTimeslice& component, std::string sChannel)
{
// serialize the timeslice and create the message
std::stringstream oss;
......@@ -631,10 +875,11 @@ bool CbmMQTsaMultiSampler::SendData(const fles::StorableTimeslice& component, st
oa << component;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object){ delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// in case of error or transfer interruption,
// return false to go to IDLE state
......@@ -647,40 +892,119 @@ bool CbmMQTsaMultiSampler::SendData(const fles::StorableTimeslice& component, st
}
fMessageCounter++;
LOG(debug) << "Send message " << fMessageCounter << " with a size of "
<< msg->GetSize();
LOG(debug) << "Send message " << fMessageCounter << " with a size of " << msg->GetSize();
return true;
}
bool CbmMQTsaMultiSampler::SendMissedTsIdx(std::vector<uint64_t> vIndices)
{
// serialize the vector and create the message
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << vIndices;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// in case of error or transfer interruption,
// return false to go to IDLE state
// successfull transfer will return number of bytes
// transfered (can be 0 if sending an empty message).
LOG(debug) << "Send data to channel " << fsChannelNameMissedTs;
if (Send(msg, fsChannelNameMissedTs) < 0) {
LOG(error) << "Problem sending missed TS indices to channel " << fsChannelNameMissedTs;
return false;
} // if( Send( msg, fsChannelNameMissedTs ) < 0 )
CbmMQTsaMultiSampler::~ CbmMQTsaMultiSampler()
return true;
}
bool CbmMQTsaMultiSampler::SendCommand(std::string sCommand)
{
// serialize the vector and create the message
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << sCommand;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// FairMQMessagePtr msg( NewMessage( const_cast<char*>( sCommand.c_str() ), // data
// sCommand.length(), // size
// []( void* /*data*/, void* object ){ delete static_cast< std::string * >( object ); },
// &sCommand ) ); // object that manages the data
// in case of error or transfer interruption,
// return false to go to IDLE state
// successfull transfer will return number of bytes
// transfered (can be 0 if sending an empty message).
LOG(debug) << "Send data to channel " << fsChannelNameCommands;
if (Send(msg, fsChannelNameCommands) < 0) {
LOG(error) << "Problem sending missed TS indices to channel " << fsChannelNameCommands;
return false;
} // if( Send( msg, fsChannelNameMissedTs ) < 0 )
return true;
}
bool CbmMQTsaMultiSampler::SendHistograms()
{
/// Serialize the array of histos into a single MQ message
FairMQMessagePtr message(NewMessage());
// Serialize<RootSerializer>(*message, &fArrayHisto);
RootSerializer().Serialize(*message, &fArrayHisto);
/// Send message to the common histogram messages queue
if (Send(message, fsChannelNameHistosInput) < 0) {
LOG(error) << "Problem sending data";
return false;
} // if( Send( message, fsChannelNameHistosInput ) < 0 )
/// Reset the histograms after sending them (but do not reset the time)
ResetHistograms();
return true;
}
bool CbmMQTsaMultiSampler::ResetHistograms()
{
fhTsRate->Reset();
fhTsSize->Reset();
fhTsSizeEvo->Reset();
fhTsMaxSizeEvo->Reset();
fhMissedTS->Reset();
fhMissedTSEvo->Reset();
return true;
}
CbmMQTsaMultiSampler::~CbmMQTsaMultiSampler() {}
void CbmMQTsaMultiSampler::CalcRuntime()
{
std::chrono::duration<double> run_time =
std::chrono::steady_clock::now() - fTime;
std::chrono::duration<double> run_time = std::chrono::steady_clock::now() - fTime;
LOG(info) << "Runtime: " << run_time.count();
LOG(info) << "No more input data";
}
void CbmMQTsaMultiSampler::PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc)
{
LOG(info) << "Header ID: Ox" << std::hex << static_cast<int>(mdsc.hdr_id)
<< std::dec;
LOG(info) << "Header version: Ox" << std::hex << static_cast<int>(mdsc.hdr_ver)
<< std::dec;
LOG(info) << "Header ID: Ox" << std::hex << static_cast<int>(mdsc.hdr_id) << std::dec;
LOG(info) << "Header version: Ox" << std::hex << static_cast<int>(mdsc.hdr_ver) << std::dec;
LOG(info) << "Equipement ID: " << mdsc.eq_id;
LOG(info) << "Flags: " << mdsc.flags;
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(mdsc.sys_id)
<< std::dec;
LOG(info) << "Sys version: Ox" << std::hex << static_cast<int>(mdsc.sys_ver)
<< std::dec;
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(mdsc.sys_id) << std::dec;
LOG(info) << "Sys version: Ox" << std::hex << static_cast<int>(mdsc.sys_ver) << std::dec;
LOG(info) << "Microslice Idx: " << mdsc.idx;
LOG(info) << "Checksum: " << mdsc.crc;
LOG(info) << "Size: " << mdsc.size;
......@@ -689,25 +1013,20 @@ void CbmMQTsaMultiSampler::PrintMicroSliceDescriptor(const fles::MicrosliceDescr
bool CbmMQTsaMultiSampler::CheckTimeslice(const fles::Timeslice& ts)
{
if ( 0 == ts.num_components() ) {
if (0 == ts.num_components()) {
LOG(error) << "No Component in TS " << ts.index();
return 1;
}
LOG(info) << "Found " << ts.num_components()
<< " different components in timeslice";
LOG(info) << "Found " << ts.num_components() << " different components in timeslice";
for (size_t c = 0; c < ts.num_components(); ++c) {
LOG(info) << "Found " << ts.num_microslices(c)
<< " microslices in component " << c;
LOG(info) << "Component " << c << " has a size of "
<< ts.size_component(c) << " bytes";
LOG(info) << "Component " << c << " has the system id 0x"
<< std::hex << static_cast<int>(ts.descriptor(c,0).sys_id)
<< std::dec;
LOG(info) << "Component " << c << " has the system id 0x"
<< static_cast<int>(ts.descriptor(c,0).sys_id);
/*
LOG(info) << "Found " << ts.num_microslices(c) << " microslices in component " << c;
LOG(info) << "Component " << c << " has a size of " << ts.size_component(c) << " bytes";
LOG(info) << "Component " << c << " has the system id 0x" << std::hex
<< static_cast<int>(ts.descriptor(c, 0).sys_id) << std::dec;
LOG(info) << "Component " << c << " has the system id 0x" << static_cast<int>(ts.descriptor(c, 0).sys_id);
/*
for (size_t m = 0; m < ts.num_microslices(c); ++m) {
PrintMicroSliceDescriptor(ts.descriptor(c,m));
}
......
/* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Florian Uhlig [committer], Pierre-Alain Loizeau */
/**
* CbmMQTsaSampler.h
*
......@@ -9,93 +13,134 @@
#define CBMMQTSAMULTISAMPLER_H_
#include "TimesliceSource.hpp"
#include "Timeslice.hpp"
#include "StorableTimeslice.hpp"
#include "MicrosliceDescriptor.hpp"
#include "StorableTimeslice.hpp"
#include "Timeslice.hpp"
#include "TimesliceSource.hpp"
#include "FairMQDevice.h"
class TCanvas;
class TH1F;
class TH1I;
class TProfile;
#include <TObjArray.h>
#include <ctime>
#include <string>
#include <utility>
#include <vector>
#include <ctime>
class CbmMQTsaMultiSampler : public FairMQDevice
{
public:
CbmMQTsaMultiSampler();
virtual ~CbmMQTsaMultiSampler();
protected:
uint64_t fMaxTimeslices;
std::string fFileName;
std::string fDirName;
std::vector<std::string> fInputFileList; ///< List of input files
uint64_t fFileCounter;
std::string fHost;
uint64_t fPort;
uint64_t fHighWaterMark;
bool fbNoSplitTs = false;
bool fbSendTsPerSysId = false;
bool fbSendTsPerChannel = false;
uint64_t fTSNumber;
uint64_t fTSCounter;
uint64_t fMessageCounter;
int fMaxMemory = 0;
virtual void InitTask();
virtual bool ConditionalRun();
private:
bool OpenNextFile();
bool CheckTimeslice(const fles::Timeslice& ts);
void PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc);
bool SendData(const fles::StorableTimeslice& component);
void CalcRuntime();
bool IsChannelNameAllowed(std::string);
bool CreateAndSendComponent(const fles::Timeslice&, int);
bool CreateAndCombineComponentsPerSysId( const fles::Timeslice& );
bool CreateAndCombineComponentsPerChannel( const fles::Timeslice& );
bool CreateAndSendFullTs( const fles::Timeslice& );
bool SendData(const fles::StorableTimeslice&, int);
bool SendData(const fles::StorableTimeslice&, std::string);
fles::TimesliceSource* fSource; //!
std::chrono::steady_clock::time_point fTime;
// The vector fAllowedChannels contain the list of defined channel names
// which are used for connecting the different devices. For the time
// being the correct connection are done checking the names. A connection
// using the name stscomponent will receive timeslices containing the
// sts component only. The corresponding system ids are defined in the
// vector fSysId. At startup it is checked which channels are defined
// in the startup script such that later on only timeslices whith the
// corresponding data are send to the correct channels.
// TODO: Up to now we have three disconnected vectors which is very
// error prone. Find a better solution
std::vector<std::string> fAllowedChannels
= {"stscomponent","richcomponent","trdcomponent","muchcomponent","tofcomponent","t0component"};
// std::vector<int> fSysId = {16, 48, 64, 96, 144, 80};
std::vector<int> fSysId = {0x10, 0x30, 0x40, 0x50, 0x60, 0x90};
std::vector<int> fComponentsToSend = {0, 0, 0, 0, 0, 0};
std::vector<std::vector<std::string>> fChannelsToSend = { {}, {}, {}, {}, {}, {} };
bool fbListCompPerSysIdReady = false;
std::vector< std::vector< uint32_t > > fvvCompPerSysId= { {}, {}, {}, {}, {}, {} };
bool fbListCompPerChannelReady = false;
std::vector< std::string > fvChannelsToSend= {};
std::vector< std::vector< uint32_t > > fvvCompPerChannel= {};
class CbmMQTsaMultiSampler : public FairMQDevice {
public:
CbmMQTsaMultiSampler();
virtual ~CbmMQTsaMultiSampler();
protected:
uint64_t fMaxTimeslices;
std::string fFileName;
std::string fDirName;
std::vector<std::string> fInputFileList; ///< List of input files
uint64_t fFileCounter;
std::string fHost;
uint64_t fPort;
uint64_t fHighWaterMark;
bool fbNoSplitTs = false;
bool fbSendTsPerSysId = false;
bool fbSendTsPerChannel = false;
std::string fsChannelNameHistosInput = "histogram-in";
std::string fsChannelNameHistosConfig = "histo-conf";
std::string fsChannelNameCanvasConfig = "canvas-conf";
uint32_t fuPublishFreqTs = 0;
double_t fdMinPublishTime = 0.5;
double_t fdMaxPublishTime = 5;
uint64_t fuPrevTsIndex = 0;
uint64_t fTSCounter;
uint64_t fMessageCounter;
int fMaxMemory = 0;
virtual void InitTask();
virtual bool ConditionalRun();
private:
bool InitHistograms();
bool CheckTimeslice(const fles::Timeslice& ts);
void PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc);
void CalcRuntime();
bool IsChannelNameAllowed(std::string);
bool CreateAndSendComponent(const fles::Timeslice&, int);
bool CreateAndCombineComponentsPerSysId(const fles::Timeslice&);
bool CreateAndCombineComponentsPerChannel(const fles::Timeslice&);
bool CreateAndSendFullTs(const fles::Timeslice&);
bool SendData(const fles::StorableTimeslice&, int);
bool SendData(const fles::StorableTimeslice&, std::string);
bool SendMissedTsIdx(std::vector<uint64_t> vIndices);
bool SendCommand(std::string sCommand);
bool SendHistograms();
bool ResetHistograms();
fles::TimesliceSource* fSource; //!
std::chrono::steady_clock::time_point fTime;
std::chrono::system_clock::time_point fLastPublishTime;
// The vector fAllowedChannels contain the list of defined channel names
// which are used for connecting the different devices. For the time
// being the correct connection are done checking the names. A connection
// using the name stscomponent will receive timeslices containing the
// sts component only. The corresponding system ids are defined in the
// vector fSysId. At startup it is checked which channels are defined
// in the startup script such that later on only timeslices whith the
// corresponding data are send to the correct channels.
// TODO: Up to now we have three disconnected vectors which is very
// error prone. Find a better solution
std::vector<std::string> fAllowedChannels = {"stscomponent", "richcomponent", "trdcomponent", "muchcomponent",
"tofcomponent", "t0component", "psdcomponent"};
// std::vector<int> fSysId = {16, 48, 64, 96, 144, 80};
std::vector<int> fSysId = {0x10, 0x30, 0x40, 0x50, 0x60, 0x90, 0x80};
std::vector<int> fComponentsToSend = {0, 0, 0, 0, 0, 0, 0};
std::vector<std::vector<std::string>> fChannelsToSend = {{}, {}, {}, {}, {}, {}, {}};
bool fbListCompPerSysIdReady = false;
std::vector<std::vector<uint32_t>> fvvCompPerSysId = {{}, {}, {}, {}, {}, {}, {}};
bool fbListCompPerChannelReady = false;
std::vector<std::string> fvChannelsToSend = {};
std::vector<std::vector<uint32_t>> fvvCompPerChannel = {};
std::string fsChannelNameMissedTs = "";
std::string fsChannelNameCommands = "";
/// Array of histograms to send to the histogram server
TObjArray fArrayHisto = {};
/// Vector of string pairs with ( HistoName, FolderPath ) to send to the histogram server
std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
/// Vector of string pairs with ( CanvasName, CanvasConfig ) to send to the histogram server
/// Format of Can config is "NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
/// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
/// Histograms
TH1I* fhTsRate = nullptr;
TH1I* fhTsSize = nullptr;
TProfile* fhTsSizeEvo = nullptr;
TH1F* fhTsMaxSizeEvo = nullptr;
TH1I* fhMissedTS = nullptr;
TProfile* fhMissedTSEvo = nullptr;
TCanvas* fcSummary = nullptr;
uint64_t fuStartTime = 0;
double_t fdTimeToStart = 0.;
double_t fdLastMaxTime = 0.;
double_t fdTsMaxSize = 0.;
};
#endif /* CBMMQTSASAMPLER_H_ */
/* Copyright (C) 2017-2021 PI-UHd, GSI
SPDX-License-Identifier: GPL-3.0-only
Authors: Norbert Herrmann [committer], Florian Uhlig */
/**
* CbmMQTsaMultiSampler.cpp
*
......@@ -7,158 +11,170 @@
#include "CbmMQTsaMultiSamplerTof.h"
#include "CbmMQDefs.h"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include "CbmMQDefs.h"
#include "TimesliceSubscriber.hpp"
#include "TimesliceMultiSubscriber.hpp"
#include "StorableTimeslice.hpp"
#include "TimesliceInputArchive.hpp"
#include "TimesliceMultiInputArchive.hpp"
#include "StorableTimeslice.hpp"
#include "TimesliceMultiSubscriber.hpp"
#include "TimesliceSubscriber.hpp"
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" // device->fConfig
#include <boost/algorithm/string.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
namespace filesys = boost::filesystem;
#include <stdio.h>
#include <ctime>
#include <thread> // this_thread::sleep_for
#include <chrono>
#include <thread> // this_thread::sleep_for
#include <algorithm>
#include <chrono>
#include <ctime>
#include <string>
#include <stdio.h>
using namespace std;
#include <stdexcept>
static uint fiSelectComponents(0);
struct InitTaskError : std::runtime_error { using std::runtime_error::runtime_error; };
struct InitTaskError : std::runtime_error {
using std::runtime_error::runtime_error;
};
CbmMQTsaMultiSamplerTof::CbmMQTsaMultiSamplerTof()
: FairMQDevice()
, fMaxTimeslices(0)
, fFileName("")
, fDirName("")
, fInputFileList()
, fFileCounter(0)
, fHost("")
, fPort(0)
, fHighWaterMark(1)
, fTSNumber(0)
, fTSCounter(0)
, fMessageCounter(0)
, fSource(nullptr)
, fTime()
: FairMQDevice()
, fMaxTimeslices(0)
, fFileName("")
, fDirName("")
, fInputFileList()
, fFileCounter(0)
, fHost("")
, fPort(0)
, fHighWaterMark(1)
, fTSNumber(0)
, fTSCounter(0)
, fMessageCounter(0)
, fSource(nullptr)
, fTime()
{
}
void CbmMQTsaMultiSamplerTof::InitTask()
try
{
// Get the values from the command line options (via fConfig)
fFileName = fConfig->GetValue<string>("filename");
fDirName = fConfig->GetValue<string>("dirname");
fHost = fConfig->GetValue<string>("flib-host");
fPort = fConfig->GetValue<uint64_t>("flib-port");
fHighWaterMark = fConfig->GetValue<uint64_t>("high-water-mark");
fMaxTimeslices = fConfig->GetValue<uint64_t>("max-timeslices");
if (0 == fMaxTimeslices) fMaxTimeslices = UINT_MAX;
fiSelectComponents = fConfig->GetValue<uint64_t>("SelectComponents");
if (0 == fMaxTimeslices) fMaxTimeslices = UINT_MAX;
// Check which input is defined
// Posibilities
// filename && ! dirname : single file
// filename with wildcards && diranme : all files with filename regex in the directory
// host && port : connect to the flim server
bool isGoodInputCombi{false};
if ( 0 != fFileName.size() && 0 == fDirName.size() && 0 == fHost.size() && 0 == fPort ) {
isGoodInputCombi=true;
fInputFileList.push_back(fFileName);
} else if ( 0 != fFileName.size() && 0 != fDirName.size() && 0 == fHost.size() && 0 == fPort ) {
isGoodInputCombi=true;
fInputFileList.push_back(fFileName);
} else if ( 0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 != fPort) {
isGoodInputCombi=true;
LOG(info) << "Host: " << fHost;
LOG(info) << "Port: " << fPort;
} else if ( 0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 == fPort) {
isGoodInputCombi=true;
LOG(info) << "Host string: " << fHost;
} else if ( 0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 == fPort) {
isGoodInputCombi=true;
LOG(INFO) << "Host string: " << fHost;
} else {
isGoodInputCombi=false;
}
try {
// Get the values from the command line options (via fConfig)
fFileName = fConfig->GetValue<string>("filename");
fDirName = fConfig->GetValue<string>("dirname");
fHost = fConfig->GetValue<string>("flib-host");
fPort = fConfig->GetValue<uint64_t>("flib-port");
fHighWaterMark = fConfig->GetValue<uint64_t>("high-water-mark");
fMaxTimeslices = fConfig->GetValue<uint64_t>("max-timeslices");
if (0 == fMaxTimeslices) fMaxTimeslices = UINT_MAX;
fiSelectComponents = fConfig->GetValue<uint64_t>("SelectComponents");
if (0 == fMaxTimeslices) fMaxTimeslices = UINT_MAX;
// Check which input is defined
// Posibilities
// filename && ! dirname : single file
// filename with wildcards && diranme : all files with filename regex in the directory
// host && port : connect to the flim server
bool isGoodInputCombi {false};
if (0 != fFileName.size() && 0 == fDirName.size() && 0 == fHost.size() && 0 == fPort) {
isGoodInputCombi = true;
fInputFileList.push_back(fFileName);
}
else if (0 != fFileName.size() && 0 != fDirName.size() && 0 == fHost.size() && 0 == fPort) {
isGoodInputCombi = true;
fInputFileList.push_back(fFileName);
}
else if (0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 != fPort) {
isGoodInputCombi = true;
LOG(info) << "Host: " << fHost;
LOG(info) << "Port: " << fPort;
}
else if (0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 == fPort) {
isGoodInputCombi = true;
LOG(info) << "Host string: " << fHost;
}
else if (0 == fFileName.size() && 0 == fDirName.size() && 0 != fHost.size() && 0 == fPort) {
isGoodInputCombi = true;
LOG(info) << "Host string: " << fHost;
}
else {
isGoodInputCombi = false;
}
if (!isGoodInputCombi) {
throw InitTaskError("Wrong combination of inputs. Either file or wildcard file + directory or host + port are allowed combination.");
}
if (!isGoodInputCombi) {
throw InitTaskError("Wrong combination of inputs. Either file or wildcard file + directory "
"or host + port are allowed combination.");
}
LOG(info) << "MaxTimeslices: " << fMaxTimeslices;
// Get the information about created channels from the device
// Check if the defined channels from the topology (by name)
// are in the list of channels which are possible/allowed
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
int noChannel = fChannels.size();
LOG(info) << "Number of defined output channels: " << noChannel;
for(auto const &entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
}
for(auto const& value: fComponentsToSend) {
LOG(info) << "Value : " << value;
if (value > 1) {
throw InitTaskError("Sending same data to more than one output channel not implemented yet.");
}
LOG(info) << "MaxTimeslices: " << fMaxTimeslices;
// Get the information about created channels from the device
// Check if the defined channels from the topology (by name)
// are in the list of channels which are possible/allowed
// for the device
// The idea is to check at initilization if the devices are
// properly connected. For the time beeing this is done with a
// nameing convention. It is not avoided that someone sends other
// data on this channel.
int noChannel = fChannels.size();
LOG(info) << "Number of defined output channels: " << noChannel;
for (auto const& entry : fChannels) {
LOG(info) << "Channel name: " << entry.first;
if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
}
for (auto const& value : fComponentsToSend) {
LOG(info) << "Value : " << value;
if (value > 1) {
throw InitTaskError("Sending same data to more than one output channel "
"not implemented yet.");
}
}
if ( 0 == fFileName.size() && 0 != fHost.size() && 0 != fPort ) {
if (0 == fFileName.size() && 0 != fHost.size() && 0 != fPort) {
// Don't add the protocol since this is done now in the TimesliceMultiSubscriber
//std::string connector = "tcp://" + fHost + ":" + std::to_string(fPort);
std::string connector = fHost + ":" + std::to_string(fPort);
LOG(info) << "Open TSPublisher at " << connector;
fSource = new fles::TimesliceMultiSubscriber(connector);
} else if ( 0 == fFileName.size() && 0 != fHost.size() ) {
}
else if (0 == fFileName.size() && 0 != fHost.size()) {
std::string connector = fHost;
LOG(info) << "Open TSPublisher with host string: " << connector;
fSource = new fles::TimesliceMultiSubscriber(connector, fHighWaterMark);
} else {
// Create a ";" separated string with all file names
std::string fileList{""};
for(const auto obj: fInputFileList) {
}
else {
// Create a ";" separated string with all file names
std::string fileList {""};
for (const auto& obj : fInputFileList) {
std::string fileName = obj;
fileList += fileName;
fileList += fileName;
fileList += ";";
}
fileList.pop_back(); // Remove the last ;
fileList.pop_back(); // Remove the last ;
LOG(info) << "Input File String: " << fileList;
fSource = new fles::TimesliceMultiInputArchive(fileList, fDirName);
if ( !fSource) {
throw InitTaskError("Could open files from file list.");
}
if (!fSource) { throw InitTaskError("Could open files from file list."); }
}
fTime = std::chrono::steady_clock::now();
} catch (InitTaskError& e) {
}
catch (InitTaskError& e) {
LOG(error) << e.what();
// Wrapper defined in CbmMQDefs.h to support different FairMQ versions
cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
......@@ -167,42 +183,38 @@ try
bool CbmMQTsaMultiSamplerTof::IsChannelNameAllowed(std::string channelName)
{
for(auto const &entry : fAllowedChannels) {
LOG(info) << "Looking for name " << channelName << " in " << entry;
for (auto const& entry : fAllowedChannels) {
LOG(info) << "Looking for name " << channelName << " in " << entry;
std::size_t pos1 = channelName.find(entry);
if (pos1!=std::string::npos) {
if (pos1 != std::string::npos) {
const vector<std::string>::const_iterator pos =
std::find(fAllowedChannels.begin(), fAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos-fAllowedChannels.begin();
std::find(fAllowedChannels.begin(), fAllowedChannels.end(), entry);
const vector<std::string>::size_type idx = pos - fAllowedChannels.begin();
LOG(info) << "Found " << entry << " in " << channelName;
LOG(info) << "Channel name " << channelName
<< " found in list of allowed channel names at position " << idx;
if(idx<3) { //FIXME, hardwired constant!!!
fComponentsToSend[idx]++;
fChannelsToSend[idx].push_back(channelName);
LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
if (idx < 3) { //FIXME, hardwired constant!!!
fComponentsToSend[idx]++;
fChannelsToSend[idx].push_back(channelName);
}
return true;
}
}
LOG(info) << "Channel name " << channelName
<< " not found in list of allowed channel names.";
LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
LOG(error) << "Stop device.";
return false;
}
bool CbmMQTsaMultiSamplerTof::IsChannelUp(std::string channelName)
{
for(auto const &entry : fChannels) {
for (auto const& entry : fChannels) {
LOG(info) << "Inspect " << entry.first;
std::size_t pos1 = channelName.find(entry.first);
if (pos1!=std::string::npos) {
LOG(info) << "Channel name " << channelName
<< " found in list of defined channel names ";
if (pos1 != std::string::npos) {
LOG(info) << "Channel name " << channelName << " found in list of defined channel names ";
return true;
}
}
LOG(info) << "Channel name " << channelName
<< " not found in list of defined channel names.";
LOG(info) << "Channel name " << channelName << " not found in list of defined channel names.";
LOG(error) << "Stop device.";
return false;
}
......@@ -215,14 +227,12 @@ bool CbmMQTsaMultiSamplerTof::ConditionalRun()
fTSCounter++;
const fles::Timeslice& ts = *timeslice;
auto tsIndex = ts.index();
auto tsIndex = ts.index();
if (fTSCounter % 10000 == 0)
LOG(info) << "Sample TimeSlice " << fTSCounter<<", Index "<< tsIndex;
if (fTSCounter % 10000 == 0) LOG(info) << "Sample TimeSlice " << fTSCounter << ", Index " << tsIndex;
LOG(debug) << "Found " << ts.num_components()
<< " different components in timeslice "
<< fTSCounter << ", index "<< tsIndex;
LOG(debug) << "Found " << ts.num_components() << " different components in timeslice " << fTSCounter << ", index "
<< tsIndex;
CheckTimeslice(ts);
......@@ -236,106 +246,105 @@ bool CbmMQTsaMultiSamplerTof::ConditionalRun()
std::vector<bool> bparts;
parts.resize(fComponentsToSend.size());
bparts.resize(parts.size());
for(uint i=0; i<bparts.size(); i++) bparts[i]=false;
switch(fiSelectComponents) {
case 0: {// send complete timeslice
int iSysId=0x60;
const vector<int>::const_iterator pos = std::find(fSysId.begin(), fSysId.end(), iSysId);
if (pos != fSysId.end() ) {
const vector<std::string>::size_type idx = pos-fSysId.begin();
if (fComponentsToSend[idx]>0) {
fles::StorableTimeslice tss = fles::StorableTimeslice( ts );
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << tss;
std::string* strMsg = new std::string(oss.str());
LOG(debug) << "AddPart "<<idx<<" with length "<<strMsg->length();
parts[idx].AddPart(NewMessage(const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object){ delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
LOG(debug)<<"AddParts to "<<idx<<": current size "<<parts[idx].Size();
bparts[idx]=true;
}
}
for (uint i = 0; i < bparts.size(); i++)
bparts[i] = false;
switch (fiSelectComponents) {
case 0: { // send complete timeslice
int iSysId = 0x60;
const vector<int>::const_iterator pos = std::find(fSysId.begin(), fSysId.end(), iSysId);
if (pos != fSysId.end()) {
const vector<std::string>::size_type idx = pos - fSysId.begin();
if (fComponentsToSend[idx] > 0) {
fles::StorableTimeslice tss = fles::StorableTimeslice(ts);
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << tss;
std::string* strMsg = new std::string(oss.str());
LOG(debug) << "AddPart " << idx << " with length " << strMsg->length();
parts[idx].AddPart(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
LOG(debug) << "AddParts to " << idx << ": current size " << parts[idx].Size();
bparts[idx] = true;
}
}
} break;
case 1: {
LOG(debug) << "parts with size " << parts.size() << ", #components: " << ts.num_components();
for (uint nrComp = 0; nrComp < ts.num_components(); ++nrComp) {
// CreateAndCombineComponents(ts, nrComp);
LOG(debug) << "nrComp " << nrComp << ", SysID: " << static_cast<int>(ts.descriptor(nrComp, 0).sys_id);
int iSysId = static_cast<int>(ts.descriptor(nrComp, 0).sys_id);
if (iSysId == 0x90 || iSysId == 0x91) iSysId = 0x60; // treat t0 like tof
const vector<int>::const_iterator pos = std::find(fSysId.begin(), fSysId.end(), iSysId);
if (pos != fSysId.end()) {
const vector<std::string>::size_type idx = pos - fSysId.begin();
if (fComponentsToSend[idx] > 0) {
LOG(debug) << "Append timeslice component of link " << nrComp << " to idx " << idx;
fles::StorableTimeslice component {static_cast<uint32_t>(ts.num_core_microslices()), ts.index()};
component.append_component(ts.num_microslices(0));
for (size_t m = 0; m < ts.num_microslices(nrComp); ++m) {
component.append_microslice(0, m, ts.descriptor(nrComp, m), ts.content(nrComp, m));
}
//LOG(debug)<<"Parts size available for "<<idx<<": "<<parts.size();
//if(idx > parts.size()-1) parts.resize(idx+1);
//if ( !AppendData(component, idx) ) return false;
// serialize the timeslice and create the message
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << component;
std::string* strMsg = new std::string(oss.str());
LOG(debug) << "AddParts to " << idx << ": current size " << parts[idx].Size();
parts[idx].AddPart(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
bparts[idx] = true;
}
}
}
} break;
default:;
}
break;
case 1: {
LOG(debug) << "parts with size "<<parts.size()<<", #components: "<<ts.num_components();
for (uint nrComp = 0; nrComp < ts.num_components(); ++nrComp) {
// CreateAndCombineComponents(ts, nrComp);
LOG(debug) <<"nrComp "<< nrComp<< ", SysID: " << static_cast<int>(ts.descriptor(nrComp,0).sys_id);
int iSysId = static_cast<int>(ts.descriptor(nrComp,0).sys_id);
if ( iSysId == 0x90 || iSysId == 0x91 ) iSysId=0x60; // treat t0 like tof
const vector<int>::const_iterator pos =
std::find(fSysId.begin(), fSysId.end(), iSysId);
if (pos != fSysId.end() ) {
const vector<std::string>::size_type idx = pos-fSysId.begin();
if (fComponentsToSend[idx]>0) {
LOG(debug) << "Append timeslice component of link " << nrComp<< " to idx "<<idx;
fles::StorableTimeslice component{static_cast<uint32_t>(ts.num_microslices(nrComp), ts.index())};
component.append_component(ts.num_microslices(0));
for (size_t m = 0; m < ts.num_microslices(nrComp); ++m) {
component.append_microslice( 0, m, ts.descriptor(nrComp, m), ts.content(nrComp, m) );
}
//LOG(debug)<<"Parts size available for "<<idx<<": "<<parts.size();
//if(idx > parts.size()-1) parts.resize(idx+1);
//if ( !AppendData(component, idx) ) return false;
// serialize the timeslice and create the message
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << component;
std::string* strMsg = new std::string(oss.str());
LOG(debug)<<"AddParts to "<<idx<<": current size "<<parts[idx].Size();
parts[idx].AddPart(NewMessage(const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object){ delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
bparts[idx]=true;
}
}
}
}
break;
default:
;
}
for (uint idx=0; idx<parts.size(); idx++)
if(bparts[idx]){
LOG(debug) << "Send parts with size "<< parts[idx].Size()
<<" to channel " << fChannelsToSend[idx][0];
if (Send(parts[idx], fChannelsToSend[idx][0]) < 0) {
LOG(error) << "Problem sending data";
return false;
}
LOG(debug) << "Sent message " << fMessageCounter << " with a size of "
<< parts[idx].Size();
fMessageCounter++;
}
//if(!SendTs()) return false;
for (uint idx = 0; idx < parts.size(); idx++)
if (bparts[idx]) {
LOG(debug) << "Send parts with size " << parts[idx].Size() << " to channel " << fChannelsToSend[idx][0];
if (Send(parts[idx], fChannelsToSend[idx][0]) < 0) {
LOG(error) << "Problem sending data";
return false;
}
LOG(debug) << "Sent message " << fMessageCounter << " with a size of " << parts[idx].Size();
fMessageCounter++;
}
//if(!SendTs()) return false;
return true;
} else {
}
else {
LOG(info) << " Number of requested time slices reached, exiting ";
SendSysCmdStop();
return false;
return false;
}
} else {
}
else {
LOG(info) << " No more data, exiting ";
SendSysCmdStop();
return false;
......@@ -356,7 +365,7 @@ bool CbmMQTsaMultiSamplerTof::CreateAndCombineComponents(const fles::Timeslice&
if (fComponentsToSend[idx]>0) {
LOG(debug) << "Append timeslice component of link " << nrComp<< " to idx "<<idx;
fles::StorableTimeslice component{static_cast<uint32_t>(ts.num_microslices(nrComp), ts.index())};
fles::StorableTimeslice component{static_cast<uint32_t>(ts.num_core_microslices()), ts.index()};
component.append_component(ts.num_microslices(0));
for (size_t m = 0; m < ts.num_microslices(nrComp); ++m) {
......@@ -376,7 +385,7 @@ bool CbmMQTsaMultiSamplerTof::CreateAndCombineComponents(const fles::Timeslice&
}
bool CbmMQTsaMultiSamplerTof::AppendData(const fles::StorableTimeslice& /*component*/, int /*idx*/)
{
{
// serialize the timeslice and create the message
/*
std::stringstream oss;
......@@ -395,9 +404,9 @@ bool CbmMQTsaMultiSamplerTof::AppendData(const fles::StorableTimeslice& /*compon
}
bool CbmMQTsaMultiSamplerTof::SendTs()
{
{
/*
for (int idx=0; idx<parts.size(); idx++)
for (int idx=0; idx<parts.size(); idx++)
if(bparts[idx]){
LOG(debug) << "Send data to channel " << fChannelsToSend[idx][0];
if (Send(parts[idx], fChannelsToSend[idx][0]) < 0) {
......@@ -410,7 +419,7 @@ bool CbmMQTsaMultiSamplerTof::SendTs()
<< parts[idx].Size();
}
*/
return true;
return true;
}
bool CbmMQTsaMultiSamplerTof::CreateAndSendComponent(const fles::Timeslice& ts, int nrComp)
......@@ -420,21 +429,21 @@ bool CbmMQTsaMultiSamplerTof::CreateAndSendComponent(const fles::Timeslice& ts,
// is connected create the new timeslice and send it to the
// correct channel
LOG(debug) << "SysID: " << static_cast<int>(ts.descriptor(nrComp,0).sys_id);
LOG(debug) << "SysID: " << static_cast<int>(ts.descriptor(nrComp, 0).sys_id);
const vector<int>::const_iterator pos =
std::find(fSysId.begin(), fSysId.end(), static_cast<int>(ts.descriptor(nrComp,0).sys_id));
if (pos != fSysId.end() ) {
const vector<std::string>::size_type idx = pos-fSysId.begin();
if (fComponentsToSend[idx]>0) {
std::find(fSysId.begin(), fSysId.end(), static_cast<int>(ts.descriptor(nrComp, 0).sys_id));
if (pos != fSysId.end()) {
const vector<std::string>::size_type idx = pos - fSysId.begin();
if (fComponentsToSend[idx] > 0) {
LOG(debug) << "Create timeslice component for link " << nrComp;
fles::StorableTimeslice component{static_cast<uint32_t>(ts.num_core_microslices()), ts.index()};
fles::StorableTimeslice component {static_cast<uint32_t>(ts.num_core_microslices()), ts.index()};
component.append_component(ts.num_microslices(nrComp));
for (size_t m = 0; m < ts.num_microslices(nrComp); ++m) {
component.append_microslice( 0, m, ts.descriptor(nrComp, m), ts.content(nrComp, m) );
component.append_microslice(0, m, ts.descriptor(nrComp, m), ts.content(nrComp, m));
}
if ( ! SendData(component, idx) ) return false;
if (!SendData(component, idx)) return false;
return true;
}
}
......@@ -442,23 +451,22 @@ bool CbmMQTsaMultiSamplerTof::CreateAndSendComponent(const fles::Timeslice& ts,
}
bool CbmMQTsaMultiSamplerTof::SendData(const fles::StorableTimeslice& component, int idx)
{
{
// serialize the timeslice and create the message
std::stringstream oss;
boost::archive::binary_oarchive oa(oss);
oa << component;
std::string* strMsg = new std::string(oss.str());
FairMQMessagePtr msg(NewMessage(const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object){ delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
FairMQMessagePtr msg(NewMessage(
const_cast<char*>(strMsg->c_str()), // data
strMsg->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
strMsg)); // object that manages the data
// TODO: Implement sending same data to more than one channel
// Need to create new message (copy message??)
if (fComponentsToSend[idx]>1) {
LOG(debug) << "Need to copy FairMessage";
}
if (fComponentsToSend[idx] > 1) { LOG(debug) << "Need to copy FairMessage"; }
// in case of error or transfer interruption,
// return false to go to IDLE state
......@@ -472,40 +480,31 @@ bool CbmMQTsaMultiSamplerTof::SendData(const fles::StorableTimeslice& component,
}
fMessageCounter++;
LOG(debug) << "Send message " << fMessageCounter << " with a size of "
<< msg->GetSize();
LOG(debug) << "Send message " << fMessageCounter << " with a size of " << msg->GetSize();
return true;
}
CbmMQTsaMultiSamplerTof::~ CbmMQTsaMultiSamplerTof()
{
}
CbmMQTsaMultiSamplerTof::~CbmMQTsaMultiSamplerTof() {}
void CbmMQTsaMultiSamplerTof::CalcRuntime()
{
std::chrono::duration<double> run_time =
std::chrono::steady_clock::now() - fTime;
std::chrono::duration<double> run_time = std::chrono::steady_clock::now() - fTime;
LOG(info) << "Runtime: " << run_time.count();
LOG(info) << "No more input data";
}
void CbmMQTsaMultiSamplerTof::PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc)
{
LOG(info) << "Header ID: Ox" << std::hex << static_cast<int>(mdsc.hdr_id)
<< std::dec;
LOG(info) << "Header version: Ox" << std::hex << static_cast<int>(mdsc.hdr_ver)
<< std::dec;
LOG(info) << "Header ID: Ox" << std::hex << static_cast<int>(mdsc.hdr_id) << std::dec;
LOG(info) << "Header version: Ox" << std::hex << static_cast<int>(mdsc.hdr_ver) << std::dec;
LOG(info) << "Equipement ID: " << mdsc.eq_id;
LOG(info) << "Flags: " << mdsc.flags;
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(mdsc.sys_id)
<< std::dec;
LOG(info) << "Sys version: Ox" << std::hex << static_cast<int>(mdsc.sys_ver)
<< std::dec;
LOG(info) << "Sys ID: Ox" << std::hex << static_cast<int>(mdsc.sys_id) << std::dec;
LOG(info) << "Sys version: Ox" << std::hex << static_cast<int>(mdsc.sys_ver) << std::dec;
LOG(info) << "Microslice Idx: " << mdsc.idx;
LOG(info) << "Checksum: " << mdsc.crc;
LOG(info) << "Size: " << mdsc.size;
......@@ -514,23 +513,19 @@ void CbmMQTsaMultiSamplerTof::PrintMicroSliceDescriptor(const fles::MicrosliceDe
bool CbmMQTsaMultiSamplerTof::CheckTimeslice(const fles::Timeslice& ts)
{
if ( 0 == ts.num_components() ) {
if (0 == ts.num_components()) {
LOG(error) << "No Component in TS " << ts.index();
return 1;
}
LOG(debug) << "Found " << ts.num_components()
<< " different components in timeslice";
LOG(debug) << "Found " << ts.num_components() << " different components in timeslice";
for (size_t c = 0; c < ts.num_components(); ++c) {
LOG(debug) << "Found " << ts.num_microslices(c)
<< " microslices in component " << c;
LOG(debug) << "Component " << c << " has a size of "
<< ts.size_component(c) << " bytes";
LOG(debug) << "Component " << c << " has the system id 0x"
<< std::hex << static_cast<int>(ts.descriptor(c,0).sys_id)
<< std::dec;
LOG(debug) << "Found " << ts.num_microslices(c) << " microslices in component " << c;
LOG(debug) << "Component " << c << " has a size of " << ts.size_component(c) << " bytes";
LOG(debug) << "Component " << c << " has the system id 0x" << std::hex
<< static_cast<int>(ts.descriptor(c, 0).sys_id) << std::dec;
/*
if(ts.descriptor(c,0).sys_id == 0x90 ) { // found a t0 - timeslice
if(ts.descriptor(c,0).sys_id == 0x90 ) { // found a t0 - timeslice
ts.descriptor(c,0).sys_id = 0x60; // rename t0 to tof , not allowed
}
*/
......@@ -538,7 +533,7 @@ bool CbmMQTsaMultiSamplerTof::CheckTimeslice(const fles::Timeslice& ts)
LOG(debug) << "Component " << c << " has the system id 0x"
<< static_cast<int>(ts.descriptor(c,0).sys_id);
*/
/*
/*
for (size_t m = 0; m < ts.num_microslices(c); ++m) {
PrintMicroSliceDescriptor(ts.descriptor(c,m));
}
......@@ -550,24 +545,18 @@ bool CbmMQTsaMultiSamplerTof::CheckTimeslice(const fles::Timeslice& ts)
void CbmMQTsaMultiSamplerTof::SendSysCmdStop()
{
if(IsChannelUp("syscmd")){
if (IsChannelUp("syscmd")) {
LOG(info) << "stop subscribers in 10 sec";
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
FairMQMessagePtr pub(NewSimpleMessage("STOP"));
if (Send(pub, "syscmd") < 0) {
LOG(error) << "Sending STOP message failed";
}
if (Send(pub, "syscmd") < 0) { LOG(error) << "Sending STOP message failed"; }
LOG(info) << "task reset subscribers in 1 sec";
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
FairMQMessagePtr task_reset(NewSimpleMessage("TASK_RESET"));
if (Send(task_reset, "syscmd") < 0) {
LOG(error) << "Sending Task_Reset message failed";
}
if (Send(task_reset, "syscmd") < 0) { LOG(error) << "Sending Task_Reset message failed"; }
}
// FairMQStateMachine::ChangeState(STOP);
}
/* Copyright (C) 2018-2019 PI-UHd, GSI
SPDX-License-Identifier: GPL-3.0-only
Authors: Norbert Herrmann [committer] */
/**
* CbmMQTsaMultiSamplerTof.h
*
......@@ -9,82 +13,80 @@
#define CBMMQTSAMULTISAMPLERTOF_H_
#include "TimesliceSource.hpp"
#include "Timeslice.hpp"
#include "StorableTimeslice.hpp"
#include "MicrosliceDescriptor.hpp"
#include "StorableTimeslice.hpp"
#include "Timeslice.hpp"
#include "TimesliceSource.hpp"
#include "FairMQDevice.h"
#include <ctime>
#include <string>
#include <vector>
#include <ctime>
class CbmMQTsaMultiSamplerTof : public FairMQDevice
{
public:
CbmMQTsaMultiSamplerTof();
virtual ~CbmMQTsaMultiSamplerTof();
protected:
uint64_t fMaxTimeslices;
std::string fFileName;
std::string fDirName;
std::vector<std::string> fInputFileList; ///< List of input files
uint64_t fFileCounter;
std::string fHost;
uint64_t fPort;
uint64_t fHighWaterMark;
uint64_t fTSNumber;
uint64_t fTSCounter;
uint64_t fMessageCounter;
int fMaxMemory = 0;
virtual void InitTask();
virtual bool ConditionalRun();
private:
bool OpenNextFile();
bool CheckTimeslice(const fles::Timeslice& ts);
void PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc);
bool SendData(const fles::StorableTimeslice& component);
void CalcRuntime();
bool IsChannelNameAllowed(std::string);
bool IsChannelUp(std::string);
bool CreateAndSendComponent(const fles::Timeslice&, int);
bool SendData(const fles::StorableTimeslice&, int);
bool CreateAndCombineComponents(const fles::Timeslice&, int);
bool AppendData(const fles::StorableTimeslice&, int);
bool SendTs();
void SendSysCmdStop();
fles::TimesliceSource* fSource; //!
std::chrono::steady_clock::time_point fTime;
// The vector fAllowedChannels contain the list of defined channel names
// which are used for connecting the different devices. For the time
// being the correct connection are done checking the names. A connection
// using the name stscomponent will receive timeslices containing the
// sts component only. The corresponding system ids are defined in the
// vector fSysId. At startup it is checked which channels are defined
// in the startup script such that later on only timeslices whith the
// corresponding data are send to the correct channels.
// TODO: Up to now we have three disconnected vectors which is very
// error prone. Find a better solution
std::vector<std::string> fAllowedChannels
= {"stscomponent","trdcomponent","tofcomponent","syscmd","syscmdin"};
std::vector<int> fSysId = {16, 64, 96};
std::vector<int> fComponentsToSend = {0, 0, 0};
std::vector<std::vector<std::string>> fChannelsToSend = { {},{},{} };
class CbmMQTsaMultiSamplerTof : public FairMQDevice {
public:
CbmMQTsaMultiSamplerTof();
virtual ~CbmMQTsaMultiSamplerTof();
protected:
uint64_t fMaxTimeslices;
std::string fFileName;
std::string fDirName;
std::vector<std::string> fInputFileList; ///< List of input files
uint64_t fFileCounter;
std::string fHost;
uint64_t fPort;
uint64_t fHighWaterMark;
uint64_t fTSNumber;
uint64_t fTSCounter;
uint64_t fMessageCounter;
int fMaxMemory = 0;
virtual void InitTask();
virtual bool ConditionalRun();
private:
bool OpenNextFile();
bool CheckTimeslice(const fles::Timeslice& ts);
void PrintMicroSliceDescriptor(const fles::MicrosliceDescriptor& mdsc);
bool SendData(const fles::StorableTimeslice& component);
void CalcRuntime();
bool IsChannelNameAllowed(std::string);
bool IsChannelUp(std::string);
bool CreateAndSendComponent(const fles::Timeslice&, int);
bool SendData(const fles::StorableTimeslice&, int);
bool CreateAndCombineComponents(const fles::Timeslice&, int);
bool AppendData(const fles::StorableTimeslice&, int);
bool SendTs();
void SendSysCmdStop();
fles::TimesliceSource* fSource; //!
std::chrono::steady_clock::time_point fTime;
// The vector fAllowedChannels contain the list of defined channel names
// which are used for connecting the different devices. For the time
// being the correct connection are done checking the names. A connection
// using the name stscomponent will receive timeslices containing the
// sts component only. The corresponding system ids are defined in the
// vector fSysId. At startup it is checked which channels are defined
// in the startup script such that later on only timeslices whith the
// corresponding data are send to the correct channels.
// TODO: Up to now we have three disconnected vectors which is very
// error prone. Find a better solution
std::vector<std::string> fAllowedChannels = {"stscomponent", "trdcomponent", "tofcomponent", "syscmd", "syscmdin"};
std::vector<int> fSysId = {16, 64, 96};
std::vector<int> fComponentsToSend = {0, 0, 0};
std::vector<std::vector<std::string>> fChannelsToSend = {{}, {}, {}};
};
#endif /* CBMMQTSAMULTISAMPLERTOF_H_ */