diff --git a/DataFormats/Headers/include/Headers/DataHeader.h b/DataFormats/Headers/include/Headers/DataHeader.h index 3baf42d526302..a4741348685e5 100644 --- a/DataFormats/Headers/include/Headers/DataHeader.h +++ b/DataFormats/Headers/include/Headers/DataHeader.h @@ -839,6 +839,14 @@ static_assert(gSizeMagicString == sizeof(BaseHeader::magicStringInt), static_assert(sizeof(BaseHeader::sMagicString) == sizeof(BaseHeader::magicStringInt), "Inconsitent size of global magic identifier"); +template +struct is_descriptor : std::false_type { +}; + +template +struct is_descriptor> : std::true_type { +}; + } //namespace header } //namespace o2 diff --git a/DataFormats/Headers/include/Headers/DataHeaderHelpers.h b/DataFormats/Headers/include/Headers/DataHeaderHelpers.h new file mode 100644 index 0000000000000..c7f7eff3dbfd3 --- /dev/null +++ b/DataFormats/Headers/include/Headers/DataHeaderHelpers.h @@ -0,0 +1,85 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_BASE_DATA_HEADER_HELPERS_ +#define O2_BASE_DATA_HEADER_HELPERS_ + +#include "Headers/DataHeader.h" +#include + +template +struct fmt::formatter::value, char>> { + // Presentation format: 'f' - fixed, 'e' - exponential. + char presentation = 's'; + + // Parses format specifications of the form ['f' | 'e']. + constexpr auto parse(format_parse_context& ctx) + { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && (*it == 's')) { + presentation = *it++; + } + + // Check if reached the end of the range: + if (it != end && *it != '}') { + throw format_error("invalid pick format"); + } + + // Return an iterator past the end of the parsed range: + return it; + } + + template + auto format(const T& p, FormatContext& ctx) + { + return format_to(ctx.out(), "{}", p.template as()); + } +}; + +template <> +struct fmt::formatter { + // Presentation format: 'f' - fixed, 'e' - exponential. + char presentation = 's'; + + // Parses format specifications of the form ['f' | 'e']. + constexpr auto parse(format_parse_context& ctx) + { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && (*it == 's')) { + presentation = *it++; + } + + // Check if reached the end of the range: + if (it != end && *it != '}') { + throw format_error("invalid format"); + } + + // Return an iterator past the end of the parsed range: + return it; + } + + template + auto format(const o2::header::DataHeader& h, FormatContext& ctx) + { + auto res = fmt::format("Data header version %u, flags: %u\n", h.headerVersion, h.flags) + + fmt::format(" origin : {}\n", h.dataOrigin.str) + + fmt::format(" serialization: {}\n", h.payloadSerializationMethod.str) + + fmt::format(" description : {}\n", h.dataDescription.str) + + fmt::format(" sub spec. : {}\n", (long long unsigned int)h.subSpecification) + + fmt::format(" header size : {}\n", h.headerSize) + + fmt::format(" payloadSize : {}\n", (long long unsigned int)h.payloadSize) + + fmt::format(" firstTFOrbit : {}\n", h.firstTForbit) + + fmt::format(" tfCounter : {}\n", h.tfCounter) + + fmt::format(" runNumber : {}\n", h.runNumber); + return format_to(ctx.out(), "{}", res); + } +}; + +#endif // O2_BASE_DATA_HEADER_HELPERS_ diff --git a/DataFormats/Headers/test/testDataHeader.cxx b/DataFormats/Headers/test/testDataHeader.cxx index 6c41a77ea7779..37c7e3d34df50 100644 --- a/DataFormats/Headers/test/testDataHeader.cxx +++ b/DataFormats/Headers/test/testDataHeader.cxx @@ -15,6 +15,7 @@ #include #include #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "Headers/NameHeader.h" #include "Headers/Stack.h" @@ -247,6 +248,10 @@ BOOST_AUTO_TEST_CASE(DataHeader_test) BOOST_CHECK(!(dh4 == dh)); dh4 = dh; BOOST_CHECK(dh4 == dh); + DataHeader dh5{gDataDescriptionAny, gDataOriginAny, DataHeader::SubSpecificationType{1}, 1}; + BOOST_REQUIRE_EQUAL(fmt::format("{}", gDataOriginAny), "***"); + BOOST_REQUIRE_EQUAL(fmt::format("{}", gDataDescriptionAny), "***************"); + BOOST_REQUIRE_EQUAL(fmt::format("{}", DataHeader::SubSpecificationType{1}), "1"); } BOOST_AUTO_TEST_CASE(headerStack_test) @@ -345,5 +350,24 @@ BOOST_AUTO_TEST_CASE(Descriptor_benchmark) std::cout << nrolls << " operation(s): " << duration.count() << " ns" << std::endl; // there is not really a check at the moment } + +BOOST_AUTO_TEST_CASE(Descriptor_formatting) +{ + using TestDescriptor = Descriptor<8>; + TestDescriptor a("TESTDESC"); + TestDescriptor b(a); + + auto refTime = system_clock::now(); + const int nrolls = 1000000; + for (auto count = 0; count < nrolls; ++count) { + if (a == b) { + ++a.itg[0]; + ++b.itg[0]; + } + } + auto duration = std::chrono::duration_cast(std::chrono::system_clock::now() - refTime); + std::cout << nrolls << " operation(s): " << duration.count() << " ns" << std::endl; + // there is not really a check at the moment +} } // namespace header } // namespace o2 diff --git a/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h index 8b74f07c3ea26..87b2b708025ca 100644 --- a/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h +++ b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h @@ -115,8 +115,7 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp memcpy(hdMessage->GetData(), headerStack.data(), headerStack.size()); memcpy(plMessage->GetData(), it.second.data(), hdr.payloadSize); if (verbose) { - LOG(INFO) << "Pushing " << it.second.size() << " DPs to output " << it.first.as() << " for TimeSlice " << *timesliceId; - hdr.print(); + LOGP(INFO, "Pushing {} DPs to output for TimeSlice", it.second.size(), it.first, *timesliceId, hdr); } it.second.clear(); FairMQParts outParts; diff --git a/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx b/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx index 02a755a6bb9a9..71eb9fbf32259 100644 --- a/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx +++ b/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx @@ -25,6 +25,7 @@ #include "DCStoDPLconverter.h" #include "CCDB/BasicCCDBManager.h" #include "CCDB/CcdbApi.h" +#include "Headers/DataHeaderHelpers.h" #include #include #include diff --git a/Detectors/Raw/test/testRawReaderWriter.cxx b/Detectors/Raw/test/testRawReaderWriter.cxx index d11c7aba41e19..9643a5b1ac508 100644 --- a/Detectors/Raw/test/testRawReaderWriter.cxx +++ b/Detectors/Raw/test/testRawReaderWriter.cxx @@ -26,6 +26,7 @@ #include "CommonConstants/Triggers.h" #include "Framework/Logger.h" #include "Framework/InputRecord.h" +#include "Headers/DataHeaderHelpers.h" #include "DPLUtils/DPLRawParser.h" #include "CommonUtils/StringUtils.h" @@ -337,7 +338,7 @@ BOOST_AUTO_TEST_CASE(RawReaderWriter_CRU) } if (RDHUtils::getCRUID(*rdh) == NCRU - 1) { if (newLink) { - dh->print(); + LOGP(INFO, "{}", *dh); } RDHUtils::printRDH(rdh); if (RDHUtils::getMemorySize(*rdh) > sizeof(RDHAny) + RDHUtils::GBTWord) { // special CRU with predefined sizes diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCSectorCompletionPolicy.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCSectorCompletionPolicy.h index 52a38fb2cb2c3..9b8c3d4531183 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCSectorCompletionPolicy.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCSectorCompletionPolicy.h @@ -19,7 +19,9 @@ #include "Framework/InputSpec.h" #include "Framework/DeviceSpec.h" #include "DataFormatsTPC/TPCSectorHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "TPCBase/Sector.h" +#include #include #include #include @@ -114,10 +116,10 @@ class TPCSectorCompletionPolicy inputType = idx; } else if (inputType != idx) { std::stringstream error; - error << "routing error, input messages must all be of the same type previously bound to " - << inputMatchers[inputType] - << dh->dataOrigin.as() + "/" - << dh->dataDescription.as() + "/" + dh->subSpecification; + error << fmt::format("routing error, input messages must all be of the same type previously bound to {} {}/{}/{}", + inputMatchers[inputType], + dh->dataOrigin, + dh->dataDescription, dh->subSpecification); throw std::runtime_error(error.str()); } auto const* sectorHeader = framework::DataRefUtils::getHeader(ref); diff --git a/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx index 56c358db098f2..bc42e59097cd8 100644 --- a/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx +++ b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx @@ -16,6 +16,7 @@ #include "Framework/Logger.h" #include "DPLUtils/RawParser.h" #include "DetectorsRaw/RDHUtils.h" +#include "Headers/DataHeaderHelpers.h" #include "CommonConstants/LHCConstants.h" #include "TPCBase/RDHUtils.h" @@ -71,9 +72,9 @@ uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inp rdh_utils::FEEIDType cruID, linkID, endPoint; rdh_utils::getMapping(feeID, cruID, endPoint, linkID); const auto globalLinkID = linkID + endPoint * 12; - LOGP(debug, "Specifier: {}/{}/{}", dh->dataOrigin.as(), dh->dataDescription.as(), subSpecification); - LOGP(debug, "Payload size: {}", dh->payloadSize); - LOGP(debug, "CRU: {}; linkID: {}; endPoint: {}; globalLinkID: {}", cruID, linkID, endPoint, globalLinkID); + LOGP(info, "Specifier: {}/{}/{}", dh->dataOrigin, dh->dataDescription, subSpecification); + LOGP(info, "Payload size: {}", dh->payloadSize); + LOGP(info, "CRU: {}; linkID: {}; endPoint: {}; globalLinkID: {}", cruID, linkID, endPoint, globalLinkID); // ^^^^^^ // TODO: exception handling needed? diff --git a/Detectors/TPC/workflow/src/LinkZSToDigitsSpec.cxx b/Detectors/TPC/workflow/src/LinkZSToDigitsSpec.cxx index cfb3905b3b3c1..9403cba5f4959 100644 --- a/Detectors/TPC/workflow/src/LinkZSToDigitsSpec.cxx +++ b/Detectors/TPC/workflow/src/LinkZSToDigitsSpec.cxx @@ -18,6 +18,7 @@ #include "Framework/Logger.h" #include "DPLUtils/RawParser.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "DataFormatsTPC/TPCSectorHeader.h" #include "DataFormatsTPC/ZeroSuppressionLinkBased.h" #include "DataFormatsTPC/Digit.h" @@ -140,7 +141,7 @@ o2::framework::DataProcessorSpec getLinkZSToDigitsSpec(int channel, const std::s processAttributes->activeSectors |= (0x1 << sector); - LOGP(debug, "Specifier: {}/{}/{}", dh->dataOrigin.as(), dh->dataDescription.as(), dh->subSpecification); + LOGP(debug, "Specifier: {}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification); LOGP(debug, "Payload size: {}", dh->payloadSize); LOGP(debug, "CRU: {}; linkID: {}; dataWrapperID: {}; globalLinkID: {}", cruID, linkID, dataWrapperID, globalLinkID); diff --git a/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx b/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx index 07cfed0f9ef65..97fc95a4dbda1 100644 --- a/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx +++ b/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx @@ -22,6 +22,7 @@ #include "DataFormatsTPC/TPCSectorHeader.h" #include "Algorithm/RangeTokenizer.h" #include "CommonUtils/ConfigurableParam.h" +#include "Headers/DataHeaderHelpers.h" #include "TPCWorkflow/TrackReaderSpec.h" diff --git a/Detectors/ZDC/raw/src/raw-parser.cxx b/Detectors/ZDC/raw/src/raw-parser.cxx index 408d3a73d60bf..3af0d877544bb 100644 --- a/Detectors/ZDC/raw/src/raw-parser.cxx +++ b/Detectors/ZDC/raw/src/raw-parser.cxx @@ -16,6 +16,7 @@ #include "Framework/ConfigParamSpec.h" #include "DPLUtils/DPLRawParser.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "DataFormatsZDC/RawEventData.h" #include "ZDCSimulation/Digits2Raw.h" #include "ZDCRaw/DumpRaw.h" @@ -67,9 +68,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) if (dh != lastDataHeader) { // print the DataHeader information only for the first part or if we have high verbosity if (loglevel > 1 || dh->splitPayloadIndex == 0) { - rdhprintout << dh->dataOrigin.as() << "/" - << dh->dataDescription.as() << "/" - << dh->subSpecification << " "; + rdhprintout << fmt::format("{}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification) + << " "; // at high verbosity print part number, otherwise only the total number of parts if (loglevel > 1) { rdhprintout << "part " + std::to_string(dh->splitPayloadIndex) + " of " + std::to_string(dh->splitPayloadParts); diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 535e8e45b3cc3..3e7e898fbabfa 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -940,7 +940,7 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context, if (header.get() == nullptr) { // FIXME: this should not happen, however it's actually harmless and // we can simply discard it for the moment. - // LOG(ERROR) << "Missing header! " << dh->dataDescription.as(); + // LOG(ERROR) << "Missing header! " << dh->dataDescription; continue; } auto fdph = o2::header::get(header.get()->GetData()); diff --git a/Framework/Core/src/DataRelayer.cxx b/Framework/Core/src/DataRelayer.cxx index 7ec35d32538b2..3ff3dfdaa60de 100644 --- a/Framework/Core/src/DataRelayer.cxx +++ b/Framework/Core/src/DataRelayer.cxx @@ -24,8 +24,11 @@ #include "DataProcessingStatus.h" #include "DataRelayerHelpers.h" +#include "Headers/DataHeaderHelpers.h" + #include +#include #include #include #include @@ -345,7 +348,7 @@ DataRelayer::RelayChoice std::string error; const auto* dh = o2::header::get(header->GetData()); if (dh) { - error += dh->dataOrigin.as() + "/" + dh->dataDescription.as() + "/" + dh->subSpecification; + error += fmt::format("{}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification); } else { error += "invalid header"; } diff --git a/Framework/Core/test/test_InputRecordWalker.cxx b/Framework/Core/test/test_InputRecordWalker.cxx index 719626c7a0a82..eb73434d10ec7 100644 --- a/Framework/Core/test/test_InputRecordWalker.cxx +++ b/Framework/Core/test/test_InputRecordWalker.cxx @@ -17,6 +17,7 @@ #include "Framework/WorkflowSpec.h" // o2::framework::select #include "Framework/DataRefUtils.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "Headers/Stack.h" #include #include @@ -81,7 +82,7 @@ DataSet createData() DataSet::Messages messages; auto createMessage = [&messages, &checkValues](DataHeader dh) { - checkValues.emplace_back(dh.dataOrigin.as() + "_" + dh.dataDescription.as() + "_" + std::to_string(dh.subSpecification)); + checkValues.emplace_back(fmt::format("{}_{}_{}", dh.dataOrigin, dh.dataDescription, dh.subSpecification)); std::string const& data = checkValues.back(); dh.payloadSize = data.size(); DataProcessingHeader dph{0, 1}; diff --git a/Framework/TestWorkflows/src/flpQualification.cxx b/Framework/TestWorkflows/src/flpQualification.cxx index 22d6d32aab9b5..6d889204ecdbe 100644 --- a/Framework/TestWorkflows/src/flpQualification.cxx +++ b/Framework/TestWorkflows/src/flpQualification.cxx @@ -37,6 +37,7 @@ void customize(std::vector& workflowOptions) #include "Framework/ReadoutAdapter.h" #include "Framework/Logger.h" +#include "Headers/DataHeaderHelpers.h" #include @@ -65,9 +66,7 @@ DataProcessorSpec templateProcessor(std::string const& inputType) size_t index = parallelInfo.index1D(); const auto* dh = DataRefUtils::getHeader(values); if (dh) { - LOG(INFO) << "some-processor" << index << ": " - << dh->dataOrigin.as() << "/" << dh->dataDescription.as() << "/" - << dh->subSpecification << " payload size " << dh->payloadSize; + LOGP(INFO, "some-processor {}: {}/{}/{} payload size {}", index, dh->dataOrigin, dh->dataDescription, dh->subSpecification, dh->payloadSize); } auto aData = outputs.make(Output{"TST", "P", static_cast(index)}, 1); diff --git a/Framework/Utils/src/raw-parser.cxx b/Framework/Utils/src/raw-parser.cxx index e345fc8c3bf77..e2b530056e955 100644 --- a/Framework/Utils/src/raw-parser.cxx +++ b/Framework/Utils/src/raw-parser.cxx @@ -16,6 +16,7 @@ #include "Framework/ConfigParamSpec.h" #include "DPLUtils/DPLRawParser.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include #include @@ -66,10 +67,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) } // print the DataHeader information only for the first part or if we have high verbosity if (loglevel > 1 || dh->splitPayloadIndex == 0) { - rdhprintout << "DH: " - << dh->dataOrigin.as() << "/" - << dh->dataDescription.as() << "/" - << dh->subSpecification << " " + rdhprintout << fmt::format("DH: {}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification) << " " << " TF " << dh->tfCounter << " Run " << dh->runNumber << " |"; // at high verbosity print part number, otherwise only the total number of parts diff --git a/Framework/Utils/test/test_RootTreeWriterWorkflow.cxx b/Framework/Utils/test/test_RootTreeWriterWorkflow.cxx index 744497903fcb2..98b229b1195e3 100644 --- a/Framework/Utils/test/test_RootTreeWriterWorkflow.cxx +++ b/Framework/Utils/test/test_RootTreeWriterWorkflow.cxx @@ -23,6 +23,7 @@ #include "DPLUtils/RootTreeWriter.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "Headers/DataHeader.h" +#include "Headers/DataHeaderHelpers.h" #include "../../Core/test/TestClasses.h" #include "Framework/Logger.h" #include @@ -195,11 +196,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) auto preprocessor = [](ProcessingContext& ctx) { for (auto const& ref : InputRecordWalker(ctx.inputs())) { auto const* dh = DataRefUtils::getHeader(ref); - std::cout << "got data: " - << dh->dataOrigin.as() << "/" - << dh->dataDescription.as() << "/" - << dh->subSpecification << " " - << std::endl; + LOGP(INFO, "got data: {}/{}/{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification); } };