CMS 3D CMS Logo

utilities.cc
Go to the documentation of this file.
2 
3 #include <algorithm>
4 #include <fstream>
5 #include <regex>
6 #include <unordered_map>
7 #include <boost/iostreams/filter/gzip.hpp>
8 #include <boost/iostreams/filter/lzma.hpp>
9 #include <boost/iostreams/filtering_stream.hpp>
10 
11 #ifdef CMSSW_GIT_HASH
13 #endif
15 
16 namespace {
17 
18  l1t::demo::BoardData createBoardDataFromRows(const std::string& id,
19  const std::vector<size_t>& channels,
20  const std::vector<std::vector<l1t::demo::Frame>>& dataRows) {
21  l1t::demo::BoardData boardData(id);
22 
23  for (size_t i = 0; i < channels.size(); i++) {
24  std::vector<l1t::demo::Frame> channelData(dataRows.size());
25  for (size_t j = 0; j < dataRows.size(); j++)
26  channelData.at(j) = dataRows.at(j).at(i);
27  boardData.add(channels.at(i), channelData);
28  }
29 
30  return boardData;
31  }
32 
33  std::vector<std::string> searchAndTokenize(std::istream& file, const std::string& linePrefix) {
35 
36  while (getline(file, line)) {
37  // Strip leading spaces
38  size_t startIndex = line.find_first_not_of(" \t");
39  if (startIndex != std::string::npos)
40  line = line.substr(startIndex);
41 
42  if (line.empty())
43  continue;
44  if (line[0] == '#')
45  continue;
46 
47  if (line.rfind(linePrefix, 0) != std::string::npos) {
48  std::vector<std::string> tokens;
49 
50  // Split the line into tokens
51  const std::regex delimiterRegex("\\s+");
52  std::sregex_token_iterator it(line.begin() + linePrefix.size(), line.end(), delimiterRegex, -1);
53 
54  for (; it != std::sregex_token_iterator(); it++) {
55  const std::string token(it->str());
56  if (token.empty())
57  continue;
58  tokens.push_back(token);
59  }
60 
61  return tokens;
62  } else
63  throw std::logic_error("Found unexpected line found when searching for \"" + linePrefix + "\": \"" + line +
64  "\"");
65  }
66  throw std::logic_error("Couldn't find any line starting with \"" + linePrefix + "\"");
67  }
68 
69 } // namespace
70 
71 namespace l1t::demo {
72 
74  static const std::unordered_map<std::string, FileFormat> kFormatStringMap({{"EMP", FileFormat::EMPv1},
75  {"emp", FileFormat::EMPv1},
76  {"EMPv1", FileFormat::EMPv1},
77  {"EMPv2", FileFormat::EMPv2},
78  {"APx", FileFormat::APx},
79  {"apx", FileFormat::APx},
80  {"X2O", FileFormat::X2O},
81  {"x2O", FileFormat::X2O}});
82 
83  const auto it = kFormatStringMap.find(s);
84  if (it == kFormatStringMap.end())
85  throw std::runtime_error("Could not convert '" + s + "' to FileFormat enum value");
86 
87  return it->second;
88  }
89 
90  BoardData readAPxFile(std::istream&);
91 
92  BoardData readEMPFileV1(std::istream&);
93 
94  BoardData readEMPFileV2(std::istream&);
95 
96  BoardData readX2OFile(std::istream&);
97 
99  std::ifstream file(filePath, std::ios_base::in | std::ios_base::binary);
100 
101  if (not file.is_open())
102  throw std::runtime_error("Could not open file '" + filePath + "'");
103 
104  boost::iostreams::filtering_istream stream;
105  if (filePath.rfind(".gz") == filePath.length() - 3)
106  stream.push(boost::iostreams::gzip_decompressor());
107  else if (filePath.rfind(".xz") == filePath.length() - 3)
108  stream.push(boost::iostreams::lzma_decompressor());
109 
110  stream.push(file);
111 
112  return read(stream, format);
113  }
114 
115  BoardData read(std::istream& file, const FileFormat format) {
116  switch (format) {
117  case FileFormat::APx:
118  return readAPxFile(file);
119  case FileFormat::EMPv1:
120  return readEMPFileV1(file);
121  case FileFormat::EMPv2:
122  return readEMPFileV2(file);
123  case FileFormat::X2O:
124  return readX2OFile(file);
125  }
126 
127  std::ostringstream messageStream;
128  messageStream << "No read function registered for format " << format;
129  throw std::runtime_error(messageStream.str());
130  }
131 
132  BoardData readAPxFile(std::istream& file) {
134 
135  // Complain if file is empty
136  if (not std::getline(file, line))
137  throw std::runtime_error("Specified file is empty!");
138 
139  // If first line is sideband, skip it and move onto 2nd line
140  if (line.find("#Sideband") == 0) {
141  if (not std::getline(file, line))
142  throw std::runtime_error("APx file has incorrect format: Link labels and data missing!");
143  }
144 
145  // Parse link labels
146  if (line.find("#LinkLabel") != 0)
147  throw std::runtime_error(
148  "APx file has incorrect format: Link header does not start with '#LinkLabel' (line is '" + line + "')");
149 
150  std::vector<size_t> indices;
151  const std::regex delimiterRegex("\\s+");
152  std::sregex_token_iterator it(line.begin() + 10, line.end(), delimiterRegex, -1);
153  for (; it != std::sregex_token_iterator(); it++) {
154  const std::string token(it->str());
155  if (token.empty())
156  continue;
157 
158  if (token.find("LINK_") != 0)
159  throw std::runtime_error("Link column name '" + token + "' (does not start with 'LINK_')");
160  if (token.size() == 5)
161  throw std::runtime_error("Link column name '" + token + "' is too short");
162  if (not std::all_of(token.begin() + 5, token.end(), ::isdigit))
163  throw std::runtime_error("Link column name '" + token + "' does not end with a number");
164 
165  indices.push_back(std::stoul(token.substr(5)));
166  }
167 
168  // Check for '#BeginData' line
169  if (not std::getline(file, line))
170  throw std::runtime_error("APx file has incorrect format: Data missing!");
171  if (line != "#BeginData")
172  throw std::runtime_error("APx file has incorrect format: '#BeginData' line missing (found '" + line + "')");
173 
174  // Parse link data
175  std::vector<std::vector<l1t::demo::Frame>> dataRows;
176  while (std::getline(file, line)) {
177  it = std::sregex_token_iterator(line.begin(), line.end(), delimiterRegex, -1);
178  size_t count = 0;
179  for (; it != std::sregex_token_iterator(); it++, count++) {
180  const std::string token(it->str());
181 
182  if ((token.find("0x") != 0) or (not std::all_of(token.begin() + 2, token.end(), ::isxdigit)))
183  throw std::runtime_error("APx file has incorrect format: Data token '" + token +
184  "' is not hexadecimal number");
185 
186  if (count == 0) {
187  size_t rowIndex = std::stoul(token, nullptr, 16);
188  if (rowIndex != dataRows.size())
189  throw std::runtime_error("APx file has incorrect format: Expected data row " +
190  std::to_string(dataRows.size()) + ", but found row " + std::to_string(rowIndex));
191  dataRows.push_back(std::vector<l1t::demo::Frame>(indices.size()));
192  }
193  // Sideband info
194  else if ((count % 2) == 1) {
195  uint16_t sbValue = std::stoul(token, nullptr, 16);
196  dataRows.back().at((count - 1) / 2).valid = (sbValue & 0x1);
197  dataRows.back().at((count - 1) / 2).startOfPacket = ((sbValue >> 1) & 0x1);
198  dataRows.back().at((count - 1) / 2).endOfPacket = ((sbValue >> 3) & 0x1);
199  }
200  // Data word
201  else
202  dataRows.back().at((count - 1) / 2).data = ap_uint<64>(std::stoull(token, nullptr, 16));
203  }
204 
205  if (count != (2 * indices.size() + 1))
206  throw std::runtime_error("APx file has incorrect format: Line has incorrect number of tokens (expected " +
207  std::to_string(2 * indices.size() + 1) + ", found " + std::to_string(count) + "!");
208  }
209 
210  return createBoardDataFromRows("", indices, dataRows);
211  }
212 
213  BoardData readEMPFileV1(std::istream& file) {
214  // 1) Search for ID string
216  while (getline(file, line)) {
217  if (line.empty())
218  continue;
219  if (line[0] == '#')
220  continue;
221 
222  if (line.rfind("Board ", 0) != std::string::npos) {
223  id = line.substr(6);
224  break;
225  } else
226  throw std::logic_error("Found unexpected line found when searching for board ID: \"" + line + "\"");
227  }
228 
229  // 2) Search for column labels (i.e. list of channels/links)
230  searchAndTokenize(file, "Quad/Chan :");
231  const auto tokens = searchAndTokenize(file, "Link :");
232  std::vector<size_t> channels;
233  std::transform(tokens.begin(), tokens.end(), std::back_inserter(channels), [](const std::string& s) {
234  return std::stoull(s);
235  });
236 
237  // 3) Read the main data rows
238  const std::regex delimiterRegex("\\s+");
239  static const std::regex frameRegex("([01]s)?([01]v)([0-9a-fA-F]{16})");
240  std::vector<std::vector<Frame>> dataRows;
241  while (file.good() and getline(file, line)) {
242  if (line.empty() or line[0] == '#')
243  continue;
244 
245  std::ostringstream prefixStream;
246  prefixStream << "Frame ";
247  prefixStream << std::setw(4) << std::setfill('0') << dataRows.size();
248  prefixStream << " :";
249 
250  const std::string prefix(prefixStream.str());
251  if (line.rfind(prefix, 0) == std::string::npos)
252  throw std::logic_error("Found unexpected line found when searching for \"" + prefix + "\": \"" + line + "\"");
253 
254  std::vector<l1t::demo::Frame> row;
255  std::sregex_token_iterator it(line.begin() + prefix.size(), line.end(), delimiterRegex, -1);
256  for (; it != std::sregex_token_iterator(); it++) {
257  const std::string token(it->str());
258  if (token.empty())
259  continue;
260 
261  std::smatch what;
262  if (not std::regex_match(token, what, frameRegex))
263  throw std::logic_error("Token '" + token + "' doesn't match the valid format");
264 
266  // Import strobe if the strobe group is matched
267  if (what[1].matched) {
268  value.strobe = (what[1] == "1s");
269  }
270 
271  value.valid = (what[2] == "1v");
272  value.data = ap_uint<64>(std::stoull(what[3].str(), nullptr, 16));
273 
274  row.push_back(value);
275  }
276 
277  dataRows.push_back(row);
278  }
279 
280  return createBoardDataFromRows(id, channels, dataRows);
281  }
282 
283  BoardData readEMPFileV2(std::istream& file) {
284  // 1) Search for ID string
286  while (getline(file, line)) {
287  if (line.empty())
288  continue;
289  if (line[0] == '#')
290  continue;
291 
292  if (line.rfind("ID: ", 0) != std::string::npos) {
293  id = line.substr(4);
294  break;
295  } else
296  throw std::logic_error("Found unexpected line found when searching for board ID: \"" + line + "\"");
297  }
298 
299  // 2) Check that next line states metadata formatting
300  getline(file, line);
301  if (line.find("Metadata: (strobe,) start of orbit, start of packet, end of packet, valid") != 0)
302  throw std::logic_error("Expected metadata line following 'ID' line. Instead found:" + line);
303 
304  // 3) Search for column labels (i.e. list of channels/links)
305  const auto tokens = searchAndTokenize(file, "Link ");
306  std::vector<size_t> channels;
307  std::transform(tokens.begin(), tokens.end(), std::back_inserter(channels), [](const std::string& s) {
308  return std::stoull(s);
309  });
310 
311  // 4) Read the main data rows
312  const std::regex delimiterRegex("\\s\\s+");
313  static const std::regex frameRegex("([01])?([01])([01])([01])([01]) ([0-9a-fA-F]{16})");
314  std::vector<std::vector<Frame>> dataRows;
315  while (file.good() and getline(file, line)) {
316  if (line.empty() or line[0] == '#')
317  continue;
318 
319  std::ostringstream prefixStream;
320  prefixStream << "Frame ";
321  prefixStream << std::setw(4) << std::setfill('0') << dataRows.size();
322  prefixStream << " ";
323 
324  const std::string prefix(prefixStream.str());
325  if (line.rfind(prefix, 0) == std::string::npos)
326  throw std::logic_error("Found unexpected line found when searching for \"" + prefix + "\": \"" + line + "\"");
327 
328  std::vector<l1t::demo::Frame> row;
329  std::sregex_token_iterator it(line.begin() + prefix.size(), line.end(), delimiterRegex, -1);
330  for (; it != std::sregex_token_iterator(); it++) {
331  const std::string token(it->str());
332  if (token.empty())
333  continue;
334 
335  std::smatch what;
336  if (not std::regex_match(token, what, frameRegex))
337  throw std::logic_error("Token '" + token + "' doesn't match the valid format");
338 
340  // Import strobe if the strobe group is matched
341  if (what[1].matched) {
342  value.strobe = (what[1] == "1");
343  }
344 
345  value.startOfOrbit = (what[2] == "1");
346  value.startOfPacket = (what[3] == "1");
347  value.endOfPacket = (what[4] == "1");
348  value.valid = (what[5] == "1");
349  value.data = ap_uint<64>(std::stoull(what[6].str(), nullptr, 16));
350 
351  row.push_back(value);
352  }
353 
354  dataRows.push_back(row);
355  }
356 
357  return createBoardDataFromRows(id, channels, dataRows);
358  }
359 
360  BoardData readX2OFile(std::istream& file) {
361  throw std::runtime_error("Reading X2O file format not yet implemented. Will be done ASAP.");
362  }
363 
364  void writeAPxFile(const BoardData&, std::ostream&);
365 
366  void writeEMPFileV1(const BoardData&, std::ostream&);
367 
368  void writeEMPFileV2(const BoardData&, std::ostream&);
369 
370  void writeX2OFile(const BoardData&, std::ostream&);
371 
372  void write(const BoardData& data, const std::string& filePath, const FileFormat format) {
373  // Open file
374 #ifdef CMSSW_GIT_HASH
375  edm::LogInfo("L1TDemonstratorTools")
376 #else
377  std::cout
378 #endif
379  << "Writing board data (" << std::distance(data.begin(), data.end()) << " channels, "
380  << data.begin()->second.size() << " frames) to file '" << filePath << "' (format: " << format << ")"
381  << std::endl;
382 
383  std::ofstream file(filePath, std::ios_base::out | std::ios_base::binary);
384 
385  if (not file.is_open())
386  throw std::runtime_error("Could not open file '" + filePath + "'");
387 
388  boost::iostreams::filtering_ostream stream;
389  if (filePath.rfind(".gz") == filePath.length() - 3)
390  stream.push(boost::iostreams::gzip_compressor());
391  else if (filePath.rfind(".xz") == filePath.length() - 3)
392  stream.push(boost::iostreams::lzma_compressor());
393  stream.push(file);
394  write(data, stream, format);
395  }
396 
397  void write(const BoardData& data, std::ostream& file, const FileFormat format) {
398  // Check that number of frames is same for every channel
399  const auto firstChannel = data.begin();
400 
401  for (const auto& channel : data) {
402  const auto i = channel.first;
403  const auto channelData = channel.second;
404  if (channelData.size() != firstChannel->second.size())
405  throw std::runtime_error("Cannot write board data to file - channels do not all have the same length (" +
406  std::to_string(channelData.size()) + " words on channel " + std::to_string(i) +
407  ", but " + std::to_string(firstChannel->second.size()) + " words on channel " +
408  std::to_string(firstChannel->first) + ")");
409  }
410 
411  // Call relevant write function
412  switch (format) {
413  case FileFormat::APx:
415  return;
416  case FileFormat::EMPv1:
418  return;
419  case FileFormat::EMPv2:
421  return;
422  case FileFormat::X2O:
424  return;
425  }
426  }
427 
428  void writeAPxFile(const BoardData& data, std::ostream& file) {
429  // Note: APx sideband encoding
430  // Short-term, simulation only:
431  // 0 -> Valid
432  // 1 -> EOF
433  // Planned (from ~ May 2021)
434  // 0 -> Valid
435  // 1 -> SOF (Start Of Frame)
436  // 2 -> FFO (First Frame of Orbit)
437  // 3 -> EOF (End Of Frame)
438  // 4 -> FERR (Frame Error)
439  // 5 -> RSV1
440  // 6 -> RSV2
441  // 7 -> RSV3
442 
443  file << std::setfill('0');
444  file << "#Sideband ON" << std::endl;
445 
446  // Channel header
447  file << "#LinkLabel";
448  for (const auto& channel : data) {
449  const auto i = channel.first;
450  file << " LINK_" << std::setw(2) << i << " ";
451  }
452  file << std::endl;
453 
454  file << "#BeginData" << std::endl;
455 
456  // Frames
457  file << std::hex;
458  const auto firstChannel = data.begin();
459  for (size_t i = 0; i < firstChannel->second.size(); i++) {
460  file << "0x" << std::setw(4) << i;
461  for (const auto& channel : data) {
462  //const auto j = channel.first;
463  const auto channelData = channel.second;
464  uint16_t sideband = channelData.at(i).valid;
465  sideband |= channelData.at(i).startOfPacket << 1;
466  sideband |= channelData.at(i).endOfPacket << 3;
467  file << " 0x" << std::setw(2) << sideband;
468  file << " 0x" << std::setw(16) << uint64_t(channelData.at(i).data);
469  }
470  file << std::endl;
471  }
472  }
473 
474  void writeEMPFileV1(const BoardData& data, std::ostream& file) {
475  file << std::setfill('0');
476 
477  // Board name/id
478  file << "Board CMSSW" << std::endl;
479 
480  // Quad/chan header
481  file << " Quad/Chan :";
482  for (const auto& channel : data) {
483  const auto i = channel.first;
484  file << " q" << std::setw(2) << i / 4 << 'c' << std::setw(1) << i % 4 << " ";
485  }
486  file << std::endl;
487 
488  // Link header
489  file << " Link :";
490  for (const auto& channel : data) {
491  const auto i = channel.first;
492  file << " " << std::setw(3) << i << " ";
493  }
494  file << std::endl;
495 
496  // Frames
497  const auto firstChannel = data.begin();
498  for (size_t i = 0; i < firstChannel->second.size(); i++) {
499  file << "Frame " << std::setw(4) << i << " :";
500  for (const auto& channel : data) {
501  //const auto j = channel.first;
502  const auto channelData = channel.second;
503  file << " ";
504  //TODO: Add strobe if zero anywhere on channel
505  file << " ";
506  file << std::setw(1) << channelData.at(i).valid << "v" << std::setw(16) << std::hex
507  << uint64_t(channelData.at(i).data);
508  }
509  file << std::endl << std::dec;
510  }
511  }
512 
513  void writeEMPFileV2(const BoardData& data, std::ostream& file) {
514  file << std::setfill('0');
515 
516  // Board name/id
517  file << "ID: " << data.name() << std::endl;
518  file << "Metadata: (strobe,) start of orbit, start of packet, end of packet, valid" << std::endl;
519  file << std::endl;
520 
521  // Link header
522  file << " Link ";
523  std::map<size_t, bool> strobedLinkMap;
524  for (const auto& channel : data) {
525  const auto i = channel.first;
526  strobedLinkMap[i] =
527  std::any_of(channel.second.begin(), channel.second.end(), [](const Frame& x) { return not x.strobe; });
528  if (strobedLinkMap.at(i))
529  file << " ";
530  file << " " << std::setw(3) << i << " ";
531  }
532  file << std::endl;
533 
534  // Frames
535  const auto firstChannel = data.begin();
536  for (size_t i = 0; i < firstChannel->second.size(); i++) {
537  file << "Frame " << std::setw(4) << i << " ";
538  for (const auto& channel : data) {
539  //const auto j = channel.first;
540  const auto channelData = channel.second;
541  file << " ";
542  if (strobedLinkMap.at(channel.first))
543  file << std::setw(1) << channelData.at(i).strobe;
544  file << std::setw(1) << channelData.at(i).startOfOrbit << channelData.at(i).startOfPacket
545  << channelData.at(i).endOfPacket << channelData.at(i).valid;
546  file << " " << std::setw(16) << std::hex << uint64_t(channelData.at(i).data);
547  }
548  file << std::endl << std::dec;
549  }
550  }
551 
552  void writeX2OFile(const BoardData& data, std::ostream& file) {
553  throw std::runtime_error("Writing X2O file format not yet implemented. Will be done ASAP.");
554  }
555 
556 } // namespace l1t::demo
BoardData readEMPFileV1(std::istream &)
Definition: utilities.cc:213
void writeEMPFileV1(const BoardData &, std::ostream &)
Definition: utilities.cc:474
FileFormat parseFileFormat(const std::string &)
Definition: utilities.cc:73
void writeX2OFile(const BoardData &, std::ostream &)
Definition: utilities.cc:552
uint32_t T const *__restrict__ uint32_t const *__restrict__ int32_t int Histo::index_type cudaStream_t stream
static std::string to_string(const XMLCh *ch)
void write(const BoardData &, const std::string &filePath, const FileFormat)
Definition: utilities.cc:372
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
BoardData readEMPFileV2(std::istream &)
Definition: utilities.cc:283
BoardData readX2OFile(std::istream &)
Definition: utilities.cc:360
void writeEMPFileV2(const BoardData &, std::ostream &)
Definition: utilities.cc:513
Definition: value.py:1
Log< level::Info, false > LogInfo
unsigned long long uint64_t
Definition: Time.h:13
void writeAPxFile(const BoardData &, std::ostream &)
Definition: utilities.cc:428
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:80
BoardData read(const std::string &filePath, const FileFormat)
Definition: utilities.cc:98
float x
Class representing information that&#39;s stored in the input or output buffers on a phase-2 board...
Definition: BoardData.h:13
#define str(s)
BoardData readAPxFile(std::istream &)
Definition: utilities.cc:132
unsigned transform(const HcalDetId &id, unsigned transformCode)