Skip to content

Commit bfad3df

Browse files
committed
Fix CMV handling for empty and stale TF batches, handle empty Huffman symbol streams in CMVContainer
1 parent 7d790ca commit bfad3df

3 files changed

Lines changed: 41 additions & 4 deletions

File tree

Detectors/TPC/calibration/src/CMVContainer.cxx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,15 @@ uint32_t decodeVarintLocal(const uint8_t*& data, const uint8_t* end)
124124
/// ceil(totalBits/8) bytes: MSB-first bitstream
125125
void huffmanEncode(const std::vector<uint32_t>& symbols, std::vector<uint8_t>& buf)
126126
{
127+
if (symbols.empty()) {
128+
// Write a valid empty Huffman stream: numSymbols=0, totalBits=0.
129+
// The decoder handles this correctly (returns an empty symbol vector).
130+
for (int i = 0; i < 12; ++i) {
131+
buf.push_back(0);
132+
}
133+
return;
134+
}
135+
127136
// Frequency count
128137
std::map<uint32_t, uint64_t> freq;
129138
for (const uint32_t z : symbols) {

Detectors/TPC/workflow/include/TPCWorkflow/TPCAggregateCMVSpec.h

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,31 @@ class TPCAggregateCMVDevice : public o2::framework::Task
156156
}
157157

158158
const long relTF = (currTF - mTFFirst) / mNTFsBuffer;
159-
if ((relTF < 0) || (relTF >= static_cast<long>(mTimeFrames))) {
160-
LOGP(warning, "relTF={} out of range [0, {}) for TF {}, skipping", relTF, mTimeFrames, currTF);
159+
if (relTF < 0) {
160+
LOGP(warning, "relTF={} < 0 for TF {}, skipping", relTF, currTF);
161+
return;
162+
}
163+
if (relTF >= static_cast<long>(mTimeFrames)) {
164+
// The distribute has advanced past this interval (empty CRU placeholders sent by checkMissingData
165+
// arrive with the triggering TF's context, not the missing batch's context).
166+
// Force-complete whatever was buffered so the next TF starts a fresh interval.
167+
LOGP(warning, "relTF={} out of range [0, {}) for TF {}: force-completing stale interval and resetting", relTF, mTimeFrames, currTF);
168+
if (mTimestampStart == 0) {
169+
mTimestampStart = static_cast<long>(pc.services().get<o2::framework::TimingInfo>().creation);
170+
}
171+
materializeBufferedTFs(true);
172+
sendOutput(pc.outputs());
173+
// Advance mTFFirst to the interval containing currTF so that after reset() clears it to -1
174+
// we can restore a valid value. Without this, the distribute won't resend CMVFIRSTTF (it was
175+
// already sent for the current interval), causing "firstTF not found" and further bad relTFs.
176+
long nextFirst = mIntervalFirstTF + static_cast<long>(mTimeFrames) * mNTFsBuffer;
177+
while (static_cast<long>(currTF) >= nextFirst + static_cast<long>(mTimeFrames) * mNTFsBuffer) {
178+
nextFirst += static_cast<long>(mTimeFrames) * mNTFsBuffer;
179+
}
180+
reset();
181+
mTFFirst = nextFirst;
182+
mIntervalFirstTF = nextFirst;
183+
mHasIntervalFirstTF = true;
161184
return;
162185
}
163186

@@ -338,10 +361,15 @@ class TPCAggregateCMVDevice : public o2::framework::Task
338361
/// orbitStep is the dynamically measured per-sub-TF stride; when non-zero it is preferred over the GRP NHBFPerTF for the orbit-offset calculation.
339362
void setTimestampCCDB(const long relTF, const uint32_t orbitStep, o2::framework::ProcessingContext& pc)
340363
{
364+
const auto& tinfo = pc.services().get<o2::framework::TimingInfo>();
341365
if (mUsePreciseTimestamp && !mTFInfo.second) {
366+
// Orbit-reset info (NHBFPerTF) not yet received from the distribute lane.
367+
// Fall back to DPL wall-clock creation time so mTimestampStart is never
368+
// left at 0, which would cause successive intervals to overwrite each other.
369+
mTimestampStart = tinfo.creation;
370+
LOGP(warning, "Orbit reset info not yet received; using DPL creation time {} ms as fallback timestamp for interval starting at TF {}", mTimestampStart, mTFFirst);
342371
return;
343372
}
344-
const auto& tinfo = pc.services().get<o2::framework::TimingInfo>();
345373
// prefer the measured stride; fall back to NHBFPerTF from GRPECS
346374
const int nHBFPerTF = (orbitStep > 0) ? static_cast<int>(orbitStep) : o2::base::GRPGeomHelper::instance().getNHBFPerTF();
347375
const auto nOrbitsOffset = (relTF * mNTFsBuffer + (mNTFsBuffer - 1)) * nHBFPerTF;

Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeCMVSpec.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ class TPCDistributeCMVSpec : public o2::framework::Task
390390
{
391391
for (int iTF = startTF; iTF < endTF; ++iTF) {
392392
if (mProcessedCRU[currentBuffer][iTF] != mCRUs.size()) {
393-
LOGP(warning, "CRUs for lane {} rel. TF: {} curr TF {} are missing! Processed {} CRUs out of {}", outLane, iTF, mTFStart[currentBuffer] + iTF, mProcessedCRU[currentBuffer][iTF], mCRUs.size());
393+
LOGP(warning, "CRUs for lane {} rel. TF: {} curr TF {} are missing! Processed {} CRUs out of {}", outLane, iTF, mTFStart[currentBuffer] + static_cast<long>(iTF) * mNTFsBuffer, mProcessedCRU[currentBuffer][iTF], mCRUs.size());
394394
++mProcessedTFs[currentBuffer];
395395
mProcessedCRU[currentBuffer][iTF] = mCRUs.size();
396396

0 commit comments

Comments
 (0)