Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions devices/flp2epn-distributed/EPNReceiver.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct f2eHeader {

EPNReceiver::EPNReceiver()
: fHeartbeatIntervalInMs(3000)
, fBufferTimeoutInMs(1000)
, fBufferTimeoutInMs(5000)
, fNumFLPs(0)
, fTestMode(0)
, fTimeframeBuffer()
Expand All @@ -37,7 +37,7 @@ EPNReceiver::~EPNReceiver()
{
}

void EPNReceiver::PrintBuffer(unordered_map<uint16_t,timeframeBuffer>& buffer)
void EPNReceiver::PrintBuffer(const unordered_map<uint16_t, TFBuffer>& buffer) const
{
string header = "===== ";

Expand All @@ -51,7 +51,7 @@ void EPNReceiver::PrintBuffer(unordered_map<uint16_t,timeframeBuffer>& buffer)

for (auto& it : buffer) {
string stars = "";
for (int j = 1; j <= (it.second).count; ++j) {
for (int j = 1; j <= (it.second).parts.size(); ++j) {
stars += "*";
}
LOG(INFO) << setw(4) << it.first << ": " << stars;
Expand Down Expand Up @@ -132,7 +132,6 @@ void EPNReceiver::Run()
// if received ID is not yet in the buffer.
if (rcvDataSize > 0) {
// receive data, store it in the buffer, save the receive time.
fTimeframeBuffer[id].count = 1; // TODO: don't need this, use size()
fTimeframeBuffer[id].parts.push_back(dataPart);
fTimeframeBuffer[id].startTime = boost::posix_time::microsec_clock::local_time();
} else {
Expand All @@ -143,7 +142,6 @@ void EPNReceiver::Run()
} else {
// if received ID is already in the buffer
if (rcvDataSize > 0) {
fTimeframeBuffer[id].count++;
fTimeframeBuffer[id].parts.push_back(dataPart);
} else {
LOG(ERROR) << "no data received from input socket";
Expand All @@ -157,7 +155,7 @@ void EPNReceiver::Run()
delete dataPart;
}

if (fTimeframeBuffer[id].count == fNumFLPs) {
if (fTimeframeBuffer[id].parts.size() == fNumFLPs) {
// LOG(INFO) << "Collected all parts for timeframe #" << id;
// when all parts are collected send all except last one with 'snd-more' flag, and last one without the flag.
for (int i = 0; i < fNumFLPs - 1; ++i) {
Expand All @@ -170,7 +168,7 @@ void EPNReceiver::Run()
FairMQMessage* ack = fTransportFactory->CreateMessage(sizeof(uint16_t));
memcpy(ack->GetData(), &id, sizeof(uint16_t));

if (ackOutChannel.Send(ack, NOBLOCK) == 0) {
if (ackOutChannel.Send(ack, NOBLOCK) <= 0) {
LOG(ERROR) << "Could not send acknowledgement without blocking";
}

Expand Down
51 changes: 38 additions & 13 deletions devices/flp2epn-distributed/EPNReceiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,72 @@
namespace AliceO2 {
namespace Devices {

struct timeframeBuffer
/// Container for (sub-)timeframes

struct TFBuffer
{
int count;
std::vector<FairMQMessage*> parts;
boost::posix_time::ptime startTime;
boost::posix_time::ptime endTime;
};

/// Receives sub-timeframes from the flpSenders and merges these into full timeframes.

class EPNReceiver : public FairMQDevice
{
public:
/// Device properties
enum {
HeartbeatIntervalInMs = FairMQDevice::Last,
NumFLPs,
BufferTimeoutInMs,
TestMode,
NumFLPs = FairMQDevice::Last, ///< Number of flpSenders
BufferTimeoutInMs, ///< Time after which incomplete timeframes are dropped
TestMode, ///< Run the device in test mode
HeartbeatIntervalInMs, ///< Interval for sending heartbeats
Last
};

/// Default constructor
EPNReceiver();

/// Default destructor
virtual ~EPNReceiver();

void PrintBuffer(std::unordered_map<uint16_t, timeframeBuffer>& buffer);
/// Prints the contents of the timeframe container
void PrintBuffer(const std::unordered_map<uint16_t, TFBuffer>& buffer) const;
/// Discared incomplete timeframes after \p fBufferTimeoutInMs.
void DiscardIncompleteTimeframes();

/// Set device properties stored as strings
/// @param key Property key
/// @param value Property value
virtual void SetProperty(const int key, const std::string& value);
/// Get device properties stored as strings
/// @param key Property key
/// @param default_ not used
/// @return Property value
virtual std::string GetProperty(const int key, const std::string& default_ = "");
/// Set device properties stored as integers
/// @param key Property key
/// @param value Property value
virtual void SetProperty(const int key, const int value);
/// Get device properties stored as integers
/// @param key Property key
/// @param default_ not used
/// @return Property value
virtual int GetProperty(const int key, const int default_ = 0);

protected:
/// Overloads the Run() method of FairMQDevice
virtual void Run();
/// Sends heartbeats to flpSenders
void sendHeartbeats();

std::unordered_map<uint16_t, timeframeBuffer> fTimeframeBuffer;
std::unordered_set<uint16_t> fDiscardedSet;
std::unordered_map<uint16_t, TFBuffer> fTimeframeBuffer; ///< Stores (sub-)timeframes
std::unordered_set<uint16_t> fDiscardedSet; ///< Set containing IDs of dropped timeframes

int fNumFLPs;
int fBufferTimeoutInMs;
int fTestMode; // run in test mode
int fHeartbeatIntervalInMs;
int fNumFLPs; ///< Number of flpSenders
int fBufferTimeoutInMs; ///< Time after which incomplete timeframes are dropped
int fTestMode; ///< Run the device in test mode (only syncSampler+flpSender+epnReceiver)
int fHeartbeatIntervalInMs; ///< Interval for sending heartbeats
};

} // namespace Devices
Expand Down
25 changes: 16 additions & 9 deletions devices/flp2epn-distributed/FLPSender.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ void FLPSender::Run()
if (dataInChannel.Receive(idPart) > 0) {
h->timeFrameId = *(static_cast<uint16_t*>(idPart->GetData()));
h->flpIndex = fIndex;
} else {
// if nothing was received, try again
delete h;
continue;
}

delete idPart;
Expand All @@ -135,22 +139,25 @@ void FLPSender::Run()
}

FairMQMessage* headerPart = fTransportFactory->CreateMessage(h, sizeof(f2eHeader));

fHeaderBuffer.push(headerPart);
FairMQMessage* dataPart = fTransportFactory->CreateMessage();

// save the arrival time of the message.
fArrivalTime.push(boost::posix_time::microsec_clock::local_time());

if (fTestMode > 0) {
// test-mode: initialize and store data part in the buffer.
FairMQMessage* dataPart = fTransportFactory->CreateMessage();
dataPart->Copy(baseMsg);
fHeaderBuffer.push(headerPart);
fDataBuffer.push(dataPart);
} else {
// regular mode: receive data part from input
FairMQMessage* dataPart = fTransportFactory->CreateMessage();
dataInChannel.Receive(dataPart);
fDataBuffer.push(dataPart);
if (dataInChannel.Receive(dataPart) >= 0) {
fHeaderBuffer.push(headerPart);
fDataBuffer.push(dataPart);
} else {
// if nothing was received, try again
continue;
}
}

// LOG(INFO) << fDataBuffer.size();
Expand All @@ -159,7 +166,7 @@ void FLPSender::Run()
if (fSendOffset == 0 && fDataBuffer.size() > 0) {
sendFrontData();
} else if (fDataBuffer.size() > 0) {
size_t dataSize = fDataBuffer.front()->GetSize();
// size_t dataSize = fDataBuffer.front()->GetSize();
ptime now = boost::posix_time::microsec_clock::local_time();
if ((now - fArrivalTime.front()).total_milliseconds() >= (fSendDelay * fSendOffset)) {
sendFrontData();
Expand Down Expand Up @@ -200,10 +207,10 @@ inline void FLPSender::sendFrontData()
// fArrivalTime.pop();
// fDataBuffer.pop();
// } else { // if the heartbeat from the corresponding EPN is within timeout period, send the data.
if (fChannels.at("data-out").at(direction).Send(fHeaderBuffer.front(), fSndMoreFlag|fNoBlockFlag) == 0) {
if (fChannels.at("data-out").at(direction).Send(fHeaderBuffer.front(), fSndMoreFlag|fNoBlockFlag) <= 0) {
LOG(ERROR) << "Could not queue ID part of event #" << currentTimeframeId << " without blocking";
}
if (fChannels.at("data-out").at(direction).Send(fDataBuffer.front(), fNoBlockFlag) == 0) {
if (fChannels.at("data-out").at(direction).Send(fDataBuffer.front(), fNoBlockFlag) <= 0) {
LOG(ERROR) << "Could not send message with event #" << currentTimeframeId << " without blocking";
}
fHeaderBuffer.pop();
Expand Down
69 changes: 48 additions & 21 deletions devices/flp2epn-distributed/FLPSender.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,58 +14,85 @@

#include <boost/date_time/posix_time/posix_time.hpp>

#include "FairMQDevice.h" // for FairMQDevice, etc
#include "FairMQDevice.h"

namespace AliceO2 {
namespace Devices {

/// Sends sub-timframes to epnReceivers
///
/// Sub-timeframes are received from the previous step (or generated in test-mode)
/// and are sent to epnReceivers. Target epnReceiver is determined from the timeframe ID:
/// targetEpnReceiver = timeframeId % numEPNs (numEPNs is same for every flpSender, although some may be inactive).

class FLPSender : public FairMQDevice
{
public:
/// Device properties
enum {
HeartbeatTimeoutInMs = FairMQDevice::Last,
Index,
SendOffset,
SendDelay,
EventSize,
TestMode,
Index = FairMQDevice::Last, ///< Index of the flpSender amond other flpSenders
SendOffset, ///< Offset for staggering output
SendDelay, ///< Delay for staggering output
HeartbeatTimeoutInMs, ///< Heartbeat timeout for epnReceivers
EventSize, ///< Size of the sub-timeframe body (only for test mode)
TestMode, ///< Run the device in test mode (only syncSampler+flpSender+epnReceiver)
Last
};

/// Default constructor
FLPSender();
/// Default destructor
virtual ~FLPSender();

/// Set Device properties stored as strings
/// @param key Property key
/// @param value Property value
virtual void SetProperty(const int key, const std::string& value);
/// Get Device properties stored as strings
/// @param key Property key
/// @param default_ not used
/// @return Property value
virtual std::string GetProperty(const int key, const std::string& default_ = "");
/// Set Device properties stored as integers
/// @param key Property key
/// @param value Property value
virtual void SetProperty(const int key, const int value);
/// Get Device properties stored as integers
/// @param key Property key
/// @param default_ not used
/// @return Property value
virtual int GetProperty(const int key, const int default_ = 0);

protected:
/// Overloads the InitTask() method of FairMQDevice
virtual void InitTask();
/// Overloads the Run() method of FairMQDevice
virtual void Run();

private:
/// Receives heartbeats from epnReceivers
void receiveHeartbeats();
/// Sends the "oldest" element from the sub-timeframe container
void sendFrontData();

unsigned int fIndex;
unsigned int fSendOffset;
unsigned int fSendDelay;
std::queue<FairMQMessage*> fHeaderBuffer;
std::queue<FairMQMessage*> fDataBuffer;
std::queue<boost::posix_time::ptime> fArrivalTime;
std::queue<FairMQMessage*> fHeaderBuffer; ///< Stores sub-timeframe headers
std::queue<FairMQMessage*> fDataBuffer; ///< Stores sub-timeframe bodies
std::queue<boost::posix_time::ptime> fArrivalTime; ///< Stores arrival times of sub-timeframes

int fSndMoreFlag; // flag for multipart sending
int fNoBlockFlag; // flag for sending without blocking
int fNumEPNs; ///< Number of epnReceivers
unsigned int fIndex; ///< Index of the flpSender among other flpSenders
unsigned int fSendOffset; ///< Offset for staggering output
unsigned int fSendDelay; ///< Delay for staggering output

int fNumEPNs;
int fSndMoreFlag; ///< Flag for faster access to multipart sending
int fNoBlockFlag; ///< Flag for faster access to sending without blocking

int fHeartbeatTimeoutInMs;
std::unordered_map<std::string,boost::posix_time::ptime> fHeartbeats;
boost::shared_mutex fHeartbeatMutex;
int fEventSize; ///< Size of the sub-timeframe body (only for test mode)
int fTestMode; ///< Run the device in test mode (only syncSampler+flpSender+epnReceiver)

int fEventSize;
int fTestMode; // run in test mode
int fHeartbeatTimeoutInMs; ///< Heartbeat timeout for epnReceivers
std::unordered_map<std::string,boost::posix_time::ptime> fHeartbeats; ///< Stores heartbeats from epnReceiver
boost::shared_mutex fHeartbeatMutex; ///< Mutex for heartbeat synchronization
};

} // namespace Devices
Expand Down
33 changes: 29 additions & 4 deletions devices/flp2epn-distributed/FLPSyncSampler.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,63 @@
namespace AliceO2 {
namespace Devices {

/// Stores measurment for roundtrip time of a timeframe

struct timeframeDuration
{
boost::posix_time::ptime start;
boost::posix_time::ptime end;
};

/// Publishes timeframes IDs for flpSenders (used only in test mode)

class FLPSyncSampler : public FairMQDevice
{
public:
enum {
EventRate = FairMQDevice::Last,
EventRate = FairMQDevice::Last, ///< Publishing rate of the timeframe IDs
Last
};

/// Default constructor
FLPSyncSampler();

/// Default destructor
virtual ~FLPSyncSampler();

/// Controls the send rate of the timeframe IDs
void ResetEventCounter();
/// Listens for acknowledgements from the epnReceivers when they collected full timeframe
void ListenForAcks();

/// Set Device properties stored as strings
/// @param key Property key
/// @param value Property value
virtual void SetProperty(const int key, const std::string& value);
/// Get Device properties stored as strings
/// @param key Property key
/// @param default_ not used
/// @return Property value
virtual std::string GetProperty(const int key, const std::string& default_ = "");
/// Set Device properties stored as integers
/// @param key Property key
/// @param value Property value
virtual void SetProperty(const int key, const int value);
/// Get Device properties stored as integers
/// @param key Property key
/// @param default_ not used
/// @return Property value
virtual int GetProperty(const int key, const int default_ = 0);

protected:
/// Overloads the InitTask() method of FairMQDevice
virtual void InitTask();
/// Overloads the Run() method of FairMQDevice
virtual void Run();

std::array<timeframeDuration, UINT16_MAX> fTimeframeRTT;
int fEventRate;
int fEventCounter;
std::array<timeframeDuration, UINT16_MAX> fTimeframeRTT; ///< Container for the roundtrip values per timeframe ID
int fEventRate; ///< Publishing rate of the timeframe IDs
int fEventCounter; ///< Controls the send rate of the timeframe IDs
};

} // namespace Devices
Expand Down
Loading