Project
Loading...
Searching...
No Matches
DCSConfigSpec.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
15
16#include <memory>
17#include <cassert>
18#include <chrono>
19#include <bitset>
20#include <fstream>
21#include <sstream>
22#include <string>
23#include <string_view>
24#include <filesystem>
25#include <unordered_map>
26#include <vector>
27
28#include "TFile.h"
29
31#include "Framework/Task.h"
32#include "Framework/Logger.h"
37#include "CCDB/CcdbObjectInfo.h"
38#include "CCDB/CcdbApi.h"
40
43#include "TPCBase/FEEConfig.h"
44#include "TPCBase/FECInfo.h"
45
47
48namespace fs = std::filesystem;
49using namespace o2::utils;
50using namespace o2::framework;
53
54namespace o2::tpc
55{
56
57const std::unordered_map<CDBType, o2::header::DataDescription> CDBDescMap{
59};
60
62{
63 public:
64 struct TagInfo {
65 TagInfo(int t, std::string_view c)
66 {
67 tag = t;
68 comment = c.data();
69 }
70
71 int tag;
72 std::string comment;
73 };
74 using TagInfos = std::vector<TagInfo>;
75
76 DCSConfigDevice() = default;
77
78 void init(o2::framework::InitContext& ic) final;
79
81
82 void writeRootFile(int tag);
83
85 {
86 LOGP(info, "endOfStream");
87 }
88
89 void stop() final
90 {
91 LOGP(info, "stop");
92 }
93
94 static TagInfos readTagInfos(gsl::span<const char> configBuff);
95
96 private:
97 struct membuf : std::streambuf {
98 membuf(char* base, std::ptrdiff_t n)
99 {
100 this->setg(base, base, base + n);
101 }
102 };
103
105 static constexpr std::string_view CalDetNames = "ITfraction,ITexpLambda,ThresholdMap,Pedestals,CMkValues";
106 static constexpr int NCalDets = 5;
107
108 static constexpr std::string_view CRUConfigName = "CRUdata";
109 static constexpr std::string_view TagInfoName = "TagInfo";
110 static constexpr std::string_view RunInfoFileName = "TPCRunInfo.txt";
111 static constexpr int NLinksTotal = 2 * FECInfo::FECsTotal;
112
113 CDBStorage mCDBStorage;
114 o2::ccdb::CcdbApi mCCDBApi;
115 FEEConfig mFEEConfig;
116 std::unordered_map<std::string, std::vector<char>> mDataBuffer;
117 std::unordered_map<std::string, long> mDataBufferTimes;
118 std::bitset<NCalDets> mFEEPadDataReceived;
119 bool mCRUConfigReceived = false;
120 bool mDumpToRootFile = false;
121 bool mDumpToTextFiles = false;
122 bool mReadFromRootFile = false;
123 bool mDontWriteRunInfo = false;
124
125 void updateRunInfo(gsl::span<const char> configBuff);
126 void fillFEEPad(std::string_view configFileName, gsl::span<const char> configBuff, bool update);
127 void fillCRUConfig(gsl::span<const char> configBuff, bool update);
128 void dumpToTextFile(std::string_view configFileName, gsl::span<const char> configBuff, std::string_view tagNames);
129 bool loadFEEConfig(int tag);
130 void updateTags(DataAllocator& output);
131 void updateCCDB(DataAllocator& output, const TagInfo& tagInfo);
132};
133
135{
136 mDumpToTextFiles = ic.options().get<bool>("dump-to-text-files");
137 mDumpToRootFile = ic.options().get<bool>("dump-to-root-file");
138 mReadFromRootFile = ic.options().get<bool>("read-from-root-file");
139 mDontWriteRunInfo = ic.options().get<bool>("dont-write-run-info");
140
141 const auto calDetNamesVec = Str::tokenize(CalDetNames.data(), ',');
142 assert(NCalDets == calDetNamesVec.size());
143
144 for (const auto& name : calDetNamesVec) {
145 mFEEConfig.padMaps[name.data()].setName(name.data());
146 }
147
149 // set default meta data
150 mCDBStorage.setResponsible("Jens Wiechula (jens.wiechula@cern.ch)");
152}
153
155{
156 auto configBuff = pc.inputs().get<gsl::span<char>>("inputConfig");
157 auto configFileName = pc.inputs().get<std::string>("inputConfigFileName");
158 const auto creation = pc.services().get<o2::framework::TimingInfo>().creation;
159 LOG(info) << "received input file " << configFileName << " of size " << configBuff.size();
160
161 // either we receive a run info file or an update of a FEE config tag
162 if (configFileName == RunInfoFileName) {
163 updateRunInfo(configBuff);
164 } else { // update tag
165 std::string objName = fs::path(configFileName).stem().c_str();
166 objName = objName.substr(3, objName.size());
167 // first buffer all the datao
168 auto& dataVec = mDataBuffer[objName];
169 auto& objTime = mDataBufferTimes[objName];
170 if (dataVec.size()) {
171 LOGP(warning, "Another object with name {} was already received before: {}, now: {}, old object will be overwritten", objName, objTime, creation);
172 dataVec.clear();
173 }
174 dataVec.insert(dataVec.begin(), configBuff.begin(), configBuff.end());
175 objTime = creation;
176
177 if (objName == TagInfoName) {
178 updateTags(pc.outputs());
179 }
180 }
181}
182
183void DCSConfigDevice::updateRunInfo(gsl::span<const char> configBuff)
184{
185 const std::string line(configBuff.data(), configBuff.size());
186 const auto data = Str::tokenize(line, ',');
187 const std::string_view runInfoConf("Run number;SOX;Tag number;Run type");
188 if (data.size() != 4) {
189 LOGP(error, "{} has wrong format: {}, expected: {}, not writing RunInformation to CCDB", RunInfoFileName, line, runInfoConf);
190 return;
191 }
192 const auto tagString = data[2];
193 //
194 // retrieve ETag from FEEConfig to set up Redirect
195 const auto headers = mCCDBApi.retrieveHeaders(CDBTypeMap.at(CDBType::ConfigFEE), {}, std::stol(tagString));
196
197 std::map<std::string, std::string> md;
198 md[o2::base::NameConf::CCDBRunTag.data()] = data[0];
199 md["RunType"] = data[3];
201 if (headers.find("ETag") != headers.end()) {
202 auto etag = headers.at("ETag");
203 etag.erase(std::remove(etag.begin(), etag.end(), '"'), etag.end());
204 md["Redirect"] = fmt::format("/{}/{}/{}", CDBTypeMap.at(CDBType::ConfigFEE), tagString, etag);
205 } else {
206 LOGP(error, "No ETag found for Tag {}, not setting Redirect in RunInfo", tagString);
207 }
208
209 const long startValRCT = std::stol(data[1]);
210 const long endValRCT = startValRCT + 48l * 60l * 60l * 1000l;
211 if (!mDontWriteRunInfo) {
212 o2::ccdb::CcdbObjectInfo w(CDBTypeMap.at(CDBType::ConfigRunInfo), "", "", md, startValRCT, endValRCT);
213 mCCDBApi.storeAsBinaryFile(nullptr, 0, "ignored", "", CDBTypeMap.at(CDBType::ConfigRunInfo), md, startValRCT, endValRCT);
214 if (!mCCDBApi.isSnapshotMode()) {
216 }
217 }
218
219 std::string mdInfo = "[";
220 for (const auto& [key, val] : md) {
221 mdInfo += fmt::format("{} = {}, ", key, val);
222 }
223 mdInfo += "]";
224 LOGP(info, "Updated {} with {} for validity range {}, {}", CDBTypeMap.at(CDBType::ConfigRunInfo), mdInfo, startValRCT, endValRCT);
225}
226
227void DCSConfigDevice::updateCCDB(DataAllocator& output, const TagInfo& tagInfo)
228{
229 mCDBStorage.setReason(tagInfo.comment);
230 std::map<std::string, std::string> md = mCDBStorage.getMetaData();
232 o2::calibration::Utils::prepareCCDBobjectInfo(mFEEConfig, w, CDBTypeMap.at(CDBType::ConfigFEE), md, tagInfo.tag, tagInfo.tag + 1);
233
234 mFEEConfig.tag = FEEConfig::Tags(tagInfo.tag);
235 auto image = o2::ccdb::CcdbApi::createObjectImage(&mFEEConfig, &w);
236
237 LOGP(info, "Sending object {} / {} of size {} bytes, valid for {} : {} ", w.getPath(), w.getFileName(), image->size(), w.getStartValidityTimestamp(), w.getEndValidityTimestamp());
238 output.snapshot(Output{CDBPayload, CDBDescMap.at(CDBType::ConfigFEE), 0}, *image.get());
240
241 mFEEPadDataReceived.reset();
242 mCRUConfigReceived = false;
243
244 if (mDumpToRootFile) {
245 writeRootFile(tagInfo.tag);
246 }
247
248 mFEEConfig.clear();
249}
250
251void DCSConfigDevice::fillFEEPad(std::string_view configFileName, gsl::span<const char> configBuff, bool update)
252{
253 auto& calPad = mFEEConfig.padMaps[configFileName.data()];
254 int nLines = 0;
255 if (configFileName == "ITfraction") {
256 nLines = cru_calib_helpers::fillCalPad<0>(calPad, configBuff);
257 mFEEPadDataReceived.set(0);
258 } else if (configFileName == "ITexpLambda") {
259 nLines = cru_calib_helpers::fillCalPad<0>(calPad, configBuff);
260 mFEEPadDataReceived.set(1);
261 } else if (configFileName == "ThresholdMap") {
262 nLines = cru_calib_helpers::fillCalPad<2>(calPad, configBuff);
263 mFEEPadDataReceived.set(2);
264 } else if (configFileName == "Pedestals") {
265 nLines = cru_calib_helpers::fillCalPad<2>(calPad, configBuff);
266 mFEEPadDataReceived.set(3);
267 } else if (configFileName == "CMkValues") {
268 nLines = cru_calib_helpers::fillCalPad<0>(calPad, configBuff);
269 mFEEPadDataReceived.set(4);
270 }
271
272 if (!update && (nLines != NLinksTotal)) {
273 LOGP(error, "Full FEEConfig expected, but only {} / {} lines read for object {}", nLines, NLinksTotal, configFileName);
274 } else {
275 LOGP(info, "updating CalDet object {} for {} links", configFileName, nLines);
276 }
277}
278
279void DCSConfigDevice::fillCRUConfig(gsl::span<const char> configBuff, bool update)
280{
281 membuf sbuf((char*)configBuff.data(), configBuff.size());
282 std::istream in(&sbuf);
283 std::string line;
284
285 int nLines = 0;
286 while (std::getline(in, line)) {
287 const auto cru = std::stoi(line.substr(0, line.find_first_of(' ')));
288 if ((cru < 0) || (cru >= CRU::MaxCRU)) {
289 LOGP(error, "unexpected CRU number {} in line {}", cru, line);
290 continue;
291 }
292
293 const std::string cruData(line.substr(line.find_first_of(' ') + 1, line.size()));
294
295 auto& cruConfig = mFEEConfig.cruConfig[cru];
296 if (cruConfig.setValues(cruData)) {
297 ++nLines;
298 }
299 }
300
301 if (!update && (nLines != CRU::MaxCRU)) {
302 LOGP(error, "Full FEEConfig expected, but only {} / {} lines read for CRUConfig", nLines, (int)CRU::MaxCRU);
303 } else {
304 LOGP(info, "updating CRUConfig for {} crus", nLines);
305 }
306 mCRUConfigReceived = true;
307}
308
309void DCSConfigDevice::dumpToTextFile(std::string_view objName, gsl::span<const char> configBuff, std::string_view tagNames)
310{
311 const auto now = std::chrono::system_clock::now();
312 const long timeStart = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
313
314 const auto outputFileName = fmt::format("TPC{}.{}.{}.txt", objName, tagNames, timeStart);
315
316 std::ofstream outFile(outputFileName);
317 outFile.write(configBuff.data(), configBuff.size());
318 outFile.close();
319}
320
321void DCSConfigDevice::updateTags(DataAllocator& outputs)
322{
323 const auto tagInfos = readTagInfos(mDataBuffer.at(TagInfoName.data()));
324 std::string tagNames;
325
326 for (const auto& tagInfo : tagInfos) {
327 if (tagNames.size()) {
328 tagNames += "_";
329 }
330 tagNames += std::to_string(tagInfo.tag);
331 LOGP(info, "Updating TPC FEE config for tag {}", tagInfo.tag);
332 const auto update = loadFEEConfig(tagInfo.tag);
333
334 for (const auto& [objName, configBuff] : mDataBuffer) {
335 if (CalDetNames.find(objName) != std::string_view::npos) {
336 fillFEEPad(objName, configBuff, update);
337 } else if (objName == CRUConfigName) {
338 fillCRUConfig(configBuff, update);
339 }
340 }
341 if (!update && ((mFEEPadDataReceived.count() != NCalDets) || !mCRUConfigReceived)) {
342 std::string errorMessage;
343 if (mFEEPadDataReceived.count() != NCalDets) {
344 errorMessage = fmt::format("not all CalDet objects received: {} ({})", mFEEPadDataReceived.to_string(), CalDetNames);
345 }
346 if (!mCRUConfigReceived) {
347 if (errorMessage.size()) {
348 errorMessage += " and ";
349 }
350 errorMessage += "CRUConfig not reveived";
351 }
352
353 LOGP(error, "Full FEEConfig expected, but {}", errorMessage);
354 }
355 updateCCDB(outputs, tagInfo);
356 }
357
358 if (mDumpToTextFiles) {
359 for (const auto& [objName, configBuff] : mDataBuffer) {
360 dumpToTextFile(objName, configBuff, tagNames);
361 }
362 }
363
364 mDataBuffer.clear();
365}
366
368{
369 const auto now = std::chrono::system_clock::now();
370 const long timeStart = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
371 const auto outputFileName = fmt::format("TPCFEEConfig.{}.{}.root", tag, timeStart);
372 std::unique_ptr<TFile> outFile(TFile::Open(outputFileName.data(), "recreate"));
373 outFile->WriteObject(&mFEEConfig, "FEEConfig");
374}
375
377{
378
379 membuf sbuf((char*)configBuff.data(), configBuff.size());
380 std::istream in(&sbuf);
381 std::string line;
382
383 TagInfos infos;
384 while (std::getline(in, line)) {
385 const auto firstComma = line.find_first_of(',');
386 int tag = -1;
387 try {
388 tag = std::stoi(std::string(line.substr(0, firstComma)));
389 } catch (...) {
390 }
391 const std::string comment(line.substr(firstComma + 1, line.size()));
392 if ((tag < 0) || comment.empty()) {
393 LOGP(warning, "Ill formatted line in 'TPC{}.txt': {}, expecting <tag,comment>, skipping", TagInfoName, line);
394 continue;
395 }
396 if (tag == 0) {
397 LOGP(warning, "Tag '{}' not accepted, must be > 0, skipping", tag);
398 continue;
399 }
400 infos.emplace_back(tag, comment);
401 }
402
403 return infos;
404}
405
406bool DCSConfigDevice::loadFEEConfig(int tag)
407{
408 FEEConfig* feeConfig = nullptr;
409 if (mReadFromRootFile) {
410 // find last file of a tag in the local directory, assuming
411 std::vector<std::string> filenames;
412 for (const auto& entry : fs::directory_iterator("./")) {
413 const auto fileName = entry.path().filename().string();
414 // chek if root file and contains tag number
415 if (entry.is_regular_file() &&
416 fileName.find(".root") == (fileName.size() - 5) &&
417 fileName.find(fmt::format(".{}.", tag)) != std::string::npos) {
418 filenames.emplace_back(fileName);
419 }
420 }
421 if (filenames.size()) {
422 std::sort(filenames.begin(), filenames.end());
423 const auto& lastFile = filenames.back();
424 std::unique_ptr<TFile> inFile(TFile::Open(lastFile.data()));
425 if (inFile->IsOpen() && !inFile->IsZombie()) {
426 inFile->GetObject("FEEConfig", feeConfig);
427 }
428 if (feeConfig) {
429 LOGP(info, "Read FEEConfig from file {} for updating", lastFile);
430 }
431 }
432 } else {
433 std::map<std::string, std::string> headers;
434 feeConfig = mCCDBApi.retrieveFromTFileAny<FEEConfig>(CDBTypeMap.at(CDBType::ConfigFEE), std::map<std::string, std::string>(), tag, &headers);
435 if (feeConfig) {
436 LOGP(info, "Read FEEConfig from ccdb for updating: URL: {}, Validity: {} - {}, Last modfied: {}, ETag: {}", mCCDBApi.getURL(), headers["Valid-From"], headers["Valid-Until"], headers["Last-Modified"], headers["ETag"]);
437 }
438 }
439
440 if (!feeConfig) {
441 LOGP(warning, "Could not retrieve FEE config for tag {}, a new entry will be created, full config should be sent", tag);
442 mFEEConfig.clear();
443 return false;
444 }
445 mFEEConfig = *feeConfig;
446 if (mReadFromRootFile) {
447 delete feeConfig;
448 }
449 return true;
450}
451
453{
454
455 std::vector<OutputSpec> outputs;
458
459 return DataProcessorSpec{
460 "tpc-dcs-config",
461 Inputs{{"inputConfig", o2::header::gDataOriginTPC, "DCS_CONFIG_FILE", Lifetime::Sporadic},
462 {"inputConfigFileName", o2::header::gDataOriginTPC, "DCS_CONFIG_NAME", Lifetime::Sporadic}},
463 outputs,
464 AlgorithmSpec{adaptFromTask<DCSConfigDevice>()},
465 Options{
466 {"dump-to-text-files", VariantType::Bool, false, {"Optionally dump received data to text files"}},
467 {"dump-to-root-file", VariantType::Bool, false, {"Optionally write FEEConfig to root file"}},
468 {"read-from-root-file", VariantType::Bool, false, {"For testing purposes: read configuration from local root file instead of ccdb"}},
469 {"dont-write-run-info", VariantType::Bool, false, {"For testing purposes: skip writing RunInformation to ccdb"}},
470 }};
471}
472
473} // namespace o2::tpc
Simple interface to the CDB manager.
constexpr auto CDBWrapper
constexpr auto CDBPayload
DCS configuration processing.
Utils and constants for calibration and related workflows.
Frontend electronics configuration values.
void output(const std::map< std::string, ChannelStat > &channels)
Definition rawdump.cxx:197
Definition of the Names Generator class.
uint32_t c
Definition RawData.h:2
StringRef key
static constexpr std::string_view CCDBRunTag
Definition NameConf.h:69
static std::string getCCDBServer()
Definition NameConf.cxx:110
void init(std::string const &hosts)
Definition CcdbApi.cxx:165
std::string const & getURL() const
Definition CcdbApi.h:87
static std::unique_ptr< std::vector< char > > createObjectImage(const T *obj, CcdbObjectInfo *info=nullptr)
Definition CcdbApi.h:103
bool isSnapshotMode() const
Definition CcdbApi.h:93
std::enable_if<!std::is_base_of< o2::conf::ConfigurableParam, T >::value, T * >::type retrieveFromTFileAny(std::string const &path, std::map< std::string, std::string > const &metadata, long timestamp=-1, std::map< std::string, std::string > *headers=nullptr, std::string const &etag="", const std::string &createdNotAfter="", const std::string &createdNotBefore="") const
Definition CcdbApi.h:660
std::map< std::string, std::string > retrieveHeaders(std::string const &path, std::map< std::string, std::string > const &metadata, long timestamp=-1) const
Definition CcdbApi.cxx:1416
int storeAsBinaryFile(const char *buffer, size_t size, const std::string &fileName, const std::string &objectType, const std::string &path, const std::map< std::string, std::string > &metadata, long startValidityTimestamp, long endValidityTimestamp, std::vector< char >::size_type maxSize=0) const
Definition CcdbApi.cxx:351
static constexpr const char * AdjustableEOV
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
void setReason(std::string_view reason)
void setIntervention(CDBIntervention const intervention)
void setResponsible(std::string_view responsible)
const auto & getMetaData() const
@ MaxCRU
Definition CRU.h:31
std::vector< TagInfo > TagInfos
void init(o2::framework::InitContext &ic) final
void stop() final
This is invoked on stop.
void run(o2::framework::ProcessingContext &pc) final
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
static TagInfos readTagInfos(gsl::span< const char > configBuff)
static constexpr int FECsTotal
Definition FECInfo.h:29
GLdouble n
Definition glcorearb.h:1982
GLeglImageOES image
Definition glcorearb.h:4021
GLuint entry
Definition glcorearb.h:5735
GLuint const GLchar * name
Definition glcorearb.h:781
GLboolean * data
Definition glcorearb.h:298
GLuint GLfloat * val
Definition glcorearb.h:1582
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
int adjustOverriddenEOV(CcdbApi &api, const CcdbObjectInfo &infoNew)
set EOV of overriden objects to SOV-1 of overriding one if it is allowed
uint64_t now() noexcept
Definition Clock.h:69
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > Options
std::vector< InputSpec > Inputs
Global TPC definitions and constants.
Definition SimTraits.h:167
DataProcessorSpec getDCSConfigSpec()
create DCS processor
const std::unordered_map< CDBType, const std::string > CDBTypeMap
Storage name in CCDB for each calibration and parameter type.
Definition CDBTypes.h:94
@ FEEConfig
use fee config
const std::unordered_map< CDBType, o2::header::DataDescription > CDBDescMap
@ Automatic
Automatic upload.
@ ConfigFEE
FEE configuration map for each tag.
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
static void prepareCCDBobjectInfo(T &obj, o2::ccdb::CcdbObjectInfo &info, const std::string &path, const std::map< std::string, std::string > &md, long start, long end=-1)
Definition Utils.h:91
static constexpr o2::header::DataOrigin gDataOriginCDBWrapper
Definition Utils.h:44
static constexpr o2::header::DataOrigin gDataOriginCDBPayload
Definition Utils.h:43
TagInfo(int t, std::string_view c)
CalPadMapType padMaps
pad-wise configuration data
Definition FEEConfig.h:86
std::vector< CRUConfig > cruConfig
CRU configuration values.
Definition FEEConfig.h:87
Tags
Tag definitions for TPC/Config/FEE.
Definition FEEConfig.h:50
Tags tag
tag number
Definition FEEConfig.h:88
static std::vector< std::string > tokenize(const std::string &src, char delim, bool trimToken=true, bool skipEmpty=true)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"