Skip to content

Commit 5036b36

Browse files
Adjusting cluster output of the CA racker
Sending out the updated transport format which will allow to transport the data between devices without copy. For the moment, the CA tracker copies the data into the output message, but the GPU worker will be changed to write directly to the provided buffer. Further improvements to the input handling in the CA tracker spec: - Get rid of the fixed arrays for collecting the input objects - Adjusting cluster completeness check in the TPC CA tracker to use the sector bitmask from the sector header The check can be dropped in the future as it is the task of the completion policy to provide complete data sets. We keep it as a check for a while during the hot development phase.
1 parent 7fc6a4c commit 5036b36

1 file changed

Lines changed: 50 additions & 38 deletions

File tree

Detectors/TPC/workflow/src/CATrackerSpec.cxx

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,13 @@ DataProcessorSpec getCATrackerSpec(ca::Config const& specconfig, std::vector<int
310310
// FIXME cleanup almost duplicated code
311311
auto& validMcInputs = processAttributes->validMcInputs;
312312
using CachedMCLabelContainer = decltype(std::declval<InputRecord>().get<MCLabelContainer*>(DataRef{nullptr, nullptr, nullptr}));
313-
std::array<CachedMCLabelContainer, NSectors> mcInputs;
314-
std::array<gsl::span<const char>, NSectors> inputs;
313+
std::vector<CachedMCLabelContainer> mcInputs;
314+
std::vector<gsl::span<const char>> inputs;
315+
struct InputRef {
316+
DataRef data;
317+
DataRef labels;
318+
};
319+
std::map<int, InputRef> inputrefs;
315320
o2::gpu::GPUTrackingInOutZS tpcZS;
316321
std::vector<const void*> tpcZSmetaPointers[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS];
317322
std::vector<unsigned int> tpcZSmetaSizes[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS];
@@ -339,28 +344,23 @@ DataProcessorSpec getCATrackerSpec(ca::Config const& specconfig, std::vector<int
339344
if (sector < 0) {
340345
continue;
341346
}
342-
// the TPCSectorHeader now allows to transport information for more than one sector,
343-
// e.g. for transporting clusters in one single data block. For the moment, the
344-
// implemenation here requires single sectors
345-
if (sector >= TPCSectorHeader::NSectors) {
346-
throw std::runtime_error("Expecting data for single sectors");
347-
}
348-
if (validMcInputs.test(sector)) {
347+
std::bitset<NSectors> sectorMask(sectorHeader->sectorBits);
348+
if ((validMcInputs & sectorMask).any()) {
349349
// have already data for this sector, this should not happen in the current
350350
// sequential implementation, for parallel path merged at the tracker stage
351351
// multiple buffers need to be handled
352352
throw std::runtime_error("can only have one MC data set per sector");
353353
}
354+
inputrefs[sector].labels = ref;
354355
if (caClusterer) {
355356
inputDigitsMC[sector] = std::move(pc.inputs().get<const MCLabelContainer*>(ref));
356357
} else {
357-
mcInputs[sector] = std::move(pc.inputs().get<const MCLabelContainer*>(ref));
358358
}
359-
validMcInputs.set(sector);
359+
validMcInputs |= sectorMask;
360360
activeSectors |= sectorHeader->activeSectors;
361361
if (verbosity > 1) {
362362
LOG(INFO) << "received " << *(ref.spec) << " MC label containers"
363-
<< " for sector " << sector //
363+
<< " for sectors " << sectorMask //
364364
<< std::endl //
365365
<< " mc input status: " << validMcInputs //
366366
<< std::endl //
@@ -371,7 +371,6 @@ DataProcessorSpec getCATrackerSpec(ca::Config const& specconfig, std::vector<int
371371

372372
auto& validInputs = processAttributes->validInputs;
373373
int operation = 0;
374-
std::map<int, DataRef> datarefs;
375374
std::vector<InputSpec> filter = {
376375
{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITS"}, Lifetime::Timeframe},
377376
{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "CLUSTERNATIVE"}, Lifetime::Timeframe},
@@ -384,24 +383,18 @@ DataProcessorSpec getCATrackerSpec(ca::Config const& specconfig, std::vector<int
384383
}
385384
const int sector = sectorHeader->sector();
386385
if (sector < 0) {
387-
//throw std::runtime_error("lagacy input, custom eos is not expected anymore")
388386
continue;
389387
}
390-
// the TPCSectorHeader now allows to transport information for more than one sector,
391-
// e.g. for transporting clusters in one single data block. For the moment, the
392-
// implemenation here requires single sectors
393-
if (sector >= TPCSectorHeader::NSectors) {
394-
throw std::runtime_error("Expecting data for single sectors");
395-
}
396-
if (validInputs.test(sector)) {
388+
std::bitset<NSectors> sectorMask(sectorHeader->sectorBits);
389+
if ((validInputs & sectorMask).any()) {
397390
// have already data for this sector, this should not happen in the current
398391
// sequential implementation, for parallel path merged at the tracker stage
399392
// multiple buffers need to be handled
400393
throw std::runtime_error("can only have one cluster data set per sector");
401394
}
402395
activeSectors |= sectorHeader->activeSectors;
403-
validInputs.set(sector);
404-
datarefs[sector] = ref;
396+
validInputs |= sectorMask;
397+
inputrefs[sector].data = ref;
405398
if (caClusterer && !zsOnTheFly) {
406399
inputDigits[sector] = pc.inputs().get<gsl::span<o2::tpc::Digit>>(ref);
407400
LOG(INFO) << "GOT SPAN FOR SECTOR " << sector << " -> " << inputDigits[sector].size();
@@ -538,12 +531,20 @@ DataProcessorSpec getCATrackerSpec(ca::Config const& specconfig, std::vector<int
538531
throw std::runtime_error("Incomplete mc label input, expecting complete data set, buffering has been removed");
539532
}
540533
assert(processMC == false || validMcInputs == validInputs);
541-
for (auto const& refentry : datarefs) {
534+
for (auto const& refentry : inputrefs) {
542535
auto& sector = refentry.first;
543-
auto& ref = refentry.second;
544-
inputs[sector] = gsl::span(ref.payload, DataRefUtils::getPayloadSize(ref));
536+
auto& ref = refentry.second.data;
537+
if (ref.payload == nullptr) {
538+
// skip zero-length message
539+
continue;
540+
}
541+
if (refentry.second.labels.header != nullptr && refentry.second.labels.payload != nullptr) {
542+
mcInputs.emplace_back(std::move(pc.inputs().get<const MCLabelContainer*>(refentry.second.labels)));
543+
}
544+
inputs.emplace_back(gsl::span(ref.payload, DataRefUtils::getPayloadSize(ref)));
545545
printInputLog(ref, "received", sector);
546546
}
547+
assert(mcInputs.size() == 0 || mcInputs.size() == inputs.size());
547548
if (verbosity > 0) {
548549
// make human readable information from the bitfield
549550
std::string bitInfo;
@@ -680,15 +681,27 @@ DataProcessorSpec getCATrackerSpec(ca::Config const& specconfig, std::vector<int
680681
activeSectors |= 0x1 << sector;
681682
}
682683
}
683-
for (auto const& sector : processAttributes->clusterOutputIds) {
684-
o2::tpc::TPCSectorHeader header{sector};
685-
o2::header::DataHeader::SubSpecificationType subspec = sector;
684+
// previously, clusters have been published individually for the enabled sectors
685+
// clusters are now published as one block, subspec is NSectors
686+
if (processAttributes->clusterOutputIds.size() > 0) {
687+
o2::tpc::TPCSectorHeader header{0};
688+
header.sectorBits = activeSectors;
689+
// subspecs [0, NSectors - 1] are used to identify sector data, we use NSectors
690+
// to indicate the full TPC
691+
o2::header::DataHeader::SubSpecificationType subspec = NSectors;
686692
header.activeSectors = activeSectors;
693+
// doing a copy for now, in the future the tracker uses the output buffer directly
687694
auto& target = pc.outputs().make<std::vector<char>>({gDataOriginTPC, "CLUSTERNATIVE", subspec, Lifetime::Timeframe, {header}});
688-
std::vector<MCLabelContainer> labels;
689-
ClusterNativeHelper::copySectorData(*ptrs.clusters, sector, target, labels);
690-
if (pc.outputs().isAllowed({gDataOriginTPC, "CLNATIVEMCLBL", subspec})) {
691-
pc.outputs().snapshot({gDataOriginTPC, "CLNATIVEMCLBL", subspec, Lifetime::Timeframe, {header}}, labels);
695+
ClusterNativeAccess const& accessIndex = *ptrs.clusters;
696+
size_t outputSize = accessIndex.nClustersTotal * sizeof(ClusterNative) + sizeof(ClusterCountIndex);
697+
target.resize(outputSize);
698+
ClusterCountIndex* outIndex = reinterpret_cast<ClusterCountIndex*>(target.data());
699+
ClusterNative* outClusters = reinterpret_cast<ClusterNative*>(target.data() + sizeof(ClusterCountIndex));
700+
static_assert(sizeof(ClusterCountIndex) == sizeof(accessIndex.nClusters));
701+
memcpy(outIndex, &accessIndex.nClusters[0][0], sizeof(ClusterCountIndex));
702+
memcpy(outClusters, accessIndex.clustersLinear, accessIndex.nClustersTotal * sizeof(ClusterNative));
703+
if (pc.outputs().isAllowed({gDataOriginTPC, "CLNATIVEMCLBL", subspec}) && accessIndex.clustersMCTruth) {
704+
pc.outputs().snapshot({gDataOriginTPC, "CLNATIVEMCLBL", subspec, Lifetime::Timeframe, {header}}, *accessIndex.clustersMCTruth);
692705
}
693706
}
694707

@@ -763,12 +776,11 @@ DataProcessorSpec getCATrackerSpec(ca::Config const& specconfig, std::vector<int
763776
}
764777
if (specconfig.outputCAClusters) {
765778
for (auto const& sector : tpcsectors) {
766-
o2::header::DataHeader::SubSpecificationType id = sector;
767-
outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", id, Lifetime::Timeframe);
768779
processAttributes->clusterOutputIds.emplace_back(sector);
769-
if (specconfig.processMC) {
770-
outputSpecs.emplace_back(OutputSpec{gDataOriginTPC, "CLNATIVEMCLBL", id, Lifetime::Timeframe});
771-
}
780+
}
781+
outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", NSectors, Lifetime::Timeframe);
782+
if (specconfig.processMC) {
783+
outputSpecs.emplace_back(OutputSpec{gDataOriginTPC, "CLNATIVEMCLBL", NSectors, Lifetime::Timeframe});
772784
}
773785
}
774786
return std::move(outputSpecs);

0 commit comments

Comments
 (0)