Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HDEVIO.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: HDEVIO.cc
4 // Created: Wed Dec 10 07:22:00 EST 2014
5 // Creator: davidl (on Darwin harriet 13.4.0 i386)
6 //
7 
8 // n.b. the async_filebuf code does not currently compile
9 // on Mac OSX so we disable it's use here when compiling
10 // on that pltform.
11 #ifndef __APPLE__
12 #define USE_ASYNC_FILEBUF 1
13 #endif // __APPLE__
14 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <libgen.h>
18 #include <unistd.h>
19 #include <cinttypes>
20 using namespace std;
21 
22 #include "HDEVIO.h"
23 
24 #if USE_ASYNC_FILEBUF
25 #include <async_filebuf.h>
26 #endif
27 
28 //---------------------------------
29 // HDEVIO (Constructor)
30 //---------------------------------
31 HDEVIO::HDEVIO(string fname, bool read_map_file, int verbose):filename(fname),VERBOSE(verbose)
32 {
33  // These must be initialized in case we return early
34  // so they aren't deleted in the destructor if they
35  // were never allocated.
36  fbuff = NULL;
37  buff = NULL;
38 
39  is_open = false;
40 #ifndef USE_ASYNC_FILEBUF
41  ifs.open(filename.c_str());
42  if(!ifs.is_open()){
44  err_mess << "Unable to open EVIO file: " << filename;
45  return;
46  }
47 
48  fbuff_size = 10000000; // 40MB input buffer
49  fbuff = new uint32_t[fbuff_size];;
50  fnext = fbuff;
51  fbuff_end = fbuff;
52  fbuff_len = 0;
53  _gcount = 0;
54 #else
55  // Use custom async_filebuf to buffer file input to save io bandwidth
56  // because of the read-ahead-then-back-up access pattern of evio input.
57  ifs.open("/dev/null");
58  async_filebuf* sb = new async_filebuf(30000000, 4, 1);
59  sb->open(filename, std::ios::in);
60  ifs.std::ios::rdbuf(sb);
61  if (! ifs.is_open()) {
63  err_mess << "Unable to open EVIO file: " << filename;
64  return;
65  }
66 #endif
67 
68  buff_limit = 5000000; // Don't allow us to allocate more than 5M words for read buffer
69  buff_size = 1024; // initialize with 4kB buffer
70  buff_len = 0;
71  buff = new uint32_t[buff_size];
72  next = buff; // needed so initial calculation of left is 0
73  last_event_pos = 0;
74  last_event_len = 0;
76 
77  Nblocks = 0;
78  Nevents = 0;
79  Nerrors = 0;
80  Nbad_blocks = 0;
81  Nbad_events = 0;
82 
83  event_type_mask = 0xFFFF; // default to accepting all types
84  is_mapped = false;
85 
86  NB_next_pos = 0;
87 
88  if(read_map_file) ReadFileMap(); // check if a map file exists and read it if it does
89 
90  IGNORE_EMPTY_BOR = false;
91  SKIP_EVENT_MAPPING = false;
92 
93  ifs.seekg(0, ios_base::end);
94  total_size_bytes = ifs.tellg();
95  ifs.seekg(0, ios_base::beg);
96 
97  is_open = true;
98 }
99 
100 //---------------------------------
101 // ~HDEVIO (Destructor)
102 //---------------------------------
104 {
105 #ifdef USE_ASYNC_FILEBUF
106  delete ifs.std::ios::rdbuf();
107  ifs.std::ios::rdbuf(ifs.rdbuf());
108 #endif
109  if(ifs.is_open()) ifs.close();
110  if(buff ) delete[] buff;
111  if(fbuff) delete[] fbuff;
112 }
113 
114 //---------------------------------
115 // buff_read
116 //---------------------------------
117 void HDEVIO::buff_read(char* s, streamsize nwords)
118 {
119  /// Read n bytes into the specified buffer.
120  /// This will read from the file if needed, or simply copy
121  /// the bytes from the existing fbuff. It is purposely meant
122  /// as a drop-in replacement for ifstream::read so that we
123  /// can make actual reads from the file in larger chunks and
124  /// avoid backwards seeks on the actual file. This is needed
125  /// because the Lustre filesystem is optimized for large data
126  /// reads but smaller reads with backwards seeks tend to cripple
127  /// its performance. The main difference between this and
128  /// ifstream::read is that this does not return an istream&
129  /// reference.
130 
131 #if USE_ASYNC_FILEBUF
132  ifs.read(s, nwords);
133  _gcount = ifs.gcount();
134  return;
135 #endif
136 
137  // Number of words left in fbuff
138  uint64_t left = ((uint64_t)fbuff_end - (uint64_t)fnext)/sizeof(uint32_t);
139 
140  // First, copy what's already in fbuff
141  uint64_t Ncopied = nwords<(int64_t)left ? (uint64_t)nwords:left;
142  _gcount = Ncopied*sizeof(uint32_t);
143  if(_gcount>0) memcpy((char*)s, (char*)fnext, _gcount);
144  //left -= Ncopied; // this is true, but not used later on
145  fnext += Ncopied;
146  s += _gcount; // advance pointer to user buff in case we need to write more
147 
148  // If needed, read in another chunk from the file.
149  // Try and keep last 8 words so if a seekg is called to back
150  // us up that amount, we don't have to call seekg on the file.
151  if( (int64_t)Ncopied < nwords ){
152 
153  // Initialize to start of buffer
154  uint32_t *myfbuff = fbuff;
155  uint32_t myfbuff_size = fbuff_size;
156  fbuff_len = 0;
157 
158  // If at least 8 words exist in fbuff, then copy last
159  // 8 words into front of fbuff.
160  if( fbuff_len >= 8 ){
161  memcpy((char*)fbuff, (char*)&fbuff[fbuff_len-8], 8*sizeof(uint32_t));
162  myfbuff = &fbuff[8];
163  myfbuff_size -= 8;
164  fbuff_len += 8;
165  }
166 
167  // Read in chunk from file
168  ifs.read((char*)myfbuff, myfbuff_size*sizeof(uint32_t));
169  fbuff_len += (uint64_t)(ifs.gcount()/sizeof(uint32_t));
170  fnext = myfbuff;
172 
173  // Copy remainder of request
174  uint64_t myleft = ((uint64_t)fbuff_end - (uint64_t)fnext)/sizeof(uint32_t);
175 
176  uint64_t mynwords = nwords - Ncopied;
177  uint64_t myNcopied = mynwords<myleft ? mynwords:myleft;
178  uint64_t mygcount = myNcopied*sizeof(uint32_t);
179  if(mygcount>0) memcpy((char*)s, (char*)fnext, mygcount);
180  fnext += myNcopied;
181  _gcount += myNcopied*sizeof(uint32_t);
182  }
183 }
184 
185 //---------------------------------
186 // buff_seekg
187 //---------------------------------
188 void HDEVIO::buff_seekg (streamoff off, ios_base::seekdir way)
189 {
190 #if USE_ASYNC_FILEBUF
191  ifs.seekg(off, way);
192  return;
193 #endif
194 
195  // Convert offset from bytes to words
196  int64_t off_words = (int64_t)off/(int64_t)sizeof(uint32_t);
197 
198  // find current position relative to start of buffer in words
199  int64_t fpos = (int64_t)((uint64_t)fnext - (uint64_t)fbuff)/sizeof(uint32_t);
200 
201  // Seek depending on what user has requested
202  if( way == ios_base::cur ){
203 
204  // Add requested offset
205  fpos += off_words; // desired position relative to start of fbuff
206 
207  if(fpos>=0 && fpos<(int64_t)fbuff_len){
208  // Request is to a point inside current buffer
209  fnext = &fbuff[fpos];
210  _gcount = 0;
211  }else if(fpos<0){
212  // Seek point is outside of buffer. Move file pointer
213  // and indicate buffer is now empty so next buff_read()
214  // call will force a read.
215 
216  // Current file position should be just after end of fbuff
217  // Subtract fbuff_len to move it back to start of fbuff.
218  // fpos is position relative to start of fbuff.
219  off = (streamoff)fpos - (streamoff)fbuff_len; // offset relative to actual current file position
220 
221  ifs.seekg(off);
222 
223  // Set fbuff parameters to indicate no valid data
224  fnext = fbuff;
225  fbuff_end = fbuff;
226  fbuff_len = 0;
227  _gcount = 0;
228 
229  }
230 
231  }else{
232  _DBG_<<"buff_seekg called with something other than ios_base::cur is unsupported!" << endl;
233  exit(-1);
234  }
235 }
236 
237 //---------------------------------
238 // ReadBlock
239 //---------------------------------
241 {
242  /// Read in the next EVIO block. Return true if successful
243  /// and false otherwise.
244 
246  next = NULL;
247 
248  buff_read((char*)buff, 8);
249  uint32_t valid_words = buff_gcount()/sizeof(uint32_t);
250  if(valid_words != 8){
251  SetErrorMessage("Could not read in 8 word EVIO block header!");
253  Nerrors++;
254  return false;
255  }
256 
257  // Check endianess
258  if(buff[7]!=0xc0da0100 && buff[7]!=0x0001dac0){
260  err_mess << "Magic word not valid!: " << HexStr(buff[7]) << endl;
262  Nerrors++;
263  Nbad_blocks++;
264  return false;
265  }
266  swap_needed = (buff[7]==0x0001dac0);
267 
268  // Swap header (if needed)
269  if(swap_needed) swap_block(buff, 8, buff);
270 
271  // Re-allocate buffer if needed so we can read in entire block
272  uint32_t block_length = buff[0];
273  if(buff_size < block_length){
274  if(block_length > buff_limit){
276  err_mess << "ERROR: EVIO block length greater than allocation limit (" << block_length <<" > " << block_length << " words)" << endl;
278  Nerrors++;
279  return false;
280  }
281  if(buff) delete[] buff;
282  buff_size = block_length;
283  buff = new uint32_t[buff_size];
284  if(buff == NULL){
286  err_mess << "ERROR: unable to allocate " << block_length <<" words" << endl;
288  return false;
289  }
290 
291  // Re-read in the block header
292  buff_seekg(-8*sizeof(uint32_t), ifs.cur);
293  buff_read((char*)buff, 8);
294  if(swap_needed) swap_block(buff, 8, buff);
295  }
296 
297  if(block_length == 8){
298  // block_length =8 indicates end of file.
299  SetErrorMessage("end of file");
301  return false;
302  }
303 
304  // Read payload of block
305  buff_read((char*)&buff[8], (block_length-8));
306  valid_words = 8 + buff_gcount()/sizeof(uint32_t);
307  if(valid_words < block_length){
309  err_mess << "Error reading in EVIO entire block! (block number: " << buff[1] << ")" << endl;
310  err_mess << "valid_words="<<valid_words << " block_length=" << block_length;
312  Nerrors++;
313  return false;
314  }
315 
316  // Set pointers
317  buff_len = valid_words;
318  buff_end = &buff[valid_words];
319  next = &buff[8];
320  bh = (BLOCKHEADER_t*)buff;
321 
322  Nblocks++;
323  return true;
324 }
325 
326 //---------------------------------
327 // read
328 //---------------------------------
329 bool HDEVIO::read(uint32_t *user_buff, uint32_t user_buff_len, bool allow_swap)
330 {
331  /// Read the next EVIO event into the user supplied buffer.
332  /// Return true if successful and false otherwise. Details of
333  /// the error will be in err_mess.
334 
335  // If only certain event types are requested then
336  // defer to the sparse reader
337  if(event_type_mask != 0xFFFF){
338  return readSparse(user_buff, user_buff_len, allow_swap);
339  }
340 
342 
343  // calculate remaining valid words in buffer
344  uint32_t left = buff_len - (uint32_t)(((unsigned long)next - (unsigned long)buff)/sizeof(uint32_t));
345 
346  // Read in another event block if necessary
347  if(left < 1 || next==NULL){
348  bool isgood = ReadBlock();
349  if(!isgood) return false;
350  left = buff_len - 8;
351  }
352 
353  if(next == NULL){
354  SetErrorMessage("No valid events in buffer");
356  return false;
357  }
358 
359  // Check if next event will fit into user supplied buffer
360  uint32_t event_len = next[0];
361  if(swap_needed) swap_block(&event_len, 1, &event_len);
362  event_len++; // include length word for EVIO bank
363  last_event_len = event_len;
364 
365  // Check that event isn't claiming to be larger than EVIO block
366  if( event_len > left ){
368  err_mess << "WARNING: EVIO bank indicates a bigger size than block header (" << event_len << " > " << left << ")";
369  next = &buff[buff_len]; // setup so subsequent call will read in another block
371  Nerrors++;
372  Nbad_blocks++;
373  return false;
374  }
375 
376  // Check if user buffer is big enough to hold this
377  if(event_len > user_buff_len){
379  err_mess << "user buffer too small for event (" << user_buff_len << " < " << event_len << ")";
381  return false;
382  }
383 
384  // Copy entire event into user buffer, swapping if needed during copy
385  bool isgood = true;
386  if(swap_needed && allow_swap){
387  uint32_t Nswapped = swap_bank(user_buff, next, event_len);
388  isgood = (Nswapped == event_len);
389  }else{
390  memcpy(user_buff, next, event_len*sizeof(uint32_t));
391  }
392 
393  // Advance next pointer to next EVIO event or past end of buffer.
394  next = &next[event_len];
395 
396  if(isgood) Nevents++;
397 
398  return isgood;
399 }
400 
401 //---------------------------------
402 // readSparse
403 //---------------------------------
404 bool HDEVIO::readSparse(uint32_t *user_buff, uint32_t user_buff_len, bool allow_swap)
405 {
406  /// This is an alternative to the read(...) method above that
407  /// is used when the user has specified that only certain
408  /// event types are desired. This really only makes sense
409  /// for EPICS and SYNC events. This method does not use the
410  /// fbuff system and instead reads directly from the file
411  /// after seeking to the desired location determined from
412  /// a previously generated map.
413 
416 
417  // Make sure we've mapped this file
418  if(!is_mapped) MapBlocks();
419 
420  // Loop over all events of all blocks looking for the next
421  // event matching the currently set type mask.
423 
424  // Filter out blocks of the wrong type
426  // uint32_t type = (1 << br.block_type);
427 
428  for(; sparse_event_idx < br.evio_events.size(); sparse_event_idx++){
430 
431  uint32_t etype = (1 << er.event_type);
432  if( etype & event_type_mask ) break;
433  }
434  if(sparse_event_idx >= br.evio_events.size()) continue;
435 
437 
438  uint32_t event_len = er.event_len;
439  last_event_len = event_len;
440 
441  // Check if user buffer is big enough to hold block
442  if( event_len > user_buff_len ){
444  err_mess << "user buffer too small for event (" << user_buff_len << " < " << event_len << ")";
446  return false;
447  }
448 
449  // At this point we're committed to reading this event so go
450  // ahead and increment pointer to next event so no matter
451  // what happens below, we don't try reading it again.
452  sparse_event_idx++;
453 
454  // Set file pointer to start of EVIO event (NOT block header!)
455  last_event_pos = er.pos;
456  ifs.seekg(last_event_pos, ios_base::beg);
457 
458  // Read data directly into user buffer
459  ifs.read((char*)user_buff, event_len*sizeof(uint32_t));
460 
461  // Swap entire bank if needed
462  swap_needed = br.swap_needed; // set flag in HDEVIO
463  bool isgood = true;
464  if(br.swap_needed && allow_swap){
465  uint32_t Nswapped = swap_bank(user_buff, user_buff, event_len);
466  isgood = (Nswapped == event_len);
467  }
468 
469  // Double check that event length matches EVIO block header
470  // but only if we either don't need to swap or need to and
471  // were allowed to (otherwise, the test will almost certainly
472  // fail!)
473  if( (!br.swap_needed) || (br.swap_needed && allow_swap) ){
474  if( (user_buff[0]+1) != event_len ){
476  err_mess << "WARNING: EVIO bank indicates a different size than block header (" << event_len << " != " << (user_buff[0]+1) << ")";
478  Nerrors++;
479  Nbad_blocks++;
480  return false;
481  }
482  }
483 
484  if(isgood) Nevents++;
485 
486  return isgood;
487  }
488 
489  // If we got here then we did not find an event of interest
490  // above. Report that there are no more events in the file.
491  SetErrorMessage("No more events");
493  return false; // isgood=false
494 }
495 
496 //---------------------------------
497 // readNoFileBuff
498 //---------------------------------
499 bool HDEVIO::readNoFileBuff(uint32_t *user_buff, uint32_t user_buff_len, bool allow_swap)
500 {
501  /// This is an alternative to the read(...) method above that
502  /// does not use a large primary file buffer. A single EVIO
503  /// header is read in at a time and the events within the block
504  /// mapped just like when using readSparse. The difference is
505  /// that here, only a single block is mapped at a time rather
506  /// than trying to map the entire file before starting. This
507  /// gives a faster start up. This may be quicker for most
508  /// desktop filesystems but may be slower for Lustre file systems
509  /// that are configured for large volume data transfers and show
510  /// perfomance degredation with small reads.
511 
514 
515  // Check if we need to read in a block header using the
516  // current file position
518  if(br.evio_events.empty()){
519 
520  // Check if we are at end of file
521  uint64_t words_left_in_file = (total_size_bytes-NB_next_pos)/4;
522  if( words_left_in_file == 8 ){ // (if <8 then let read below fail and return HDEVIO_FILE_TRUNCATED)
523  SetErrorMessage("No more events");
525  return false;
526  }
527 
528  // read EVIO block header
530  ifs.seekg( NB_next_pos, ios_base::beg);
531  ifs.clear();
532  ifs.read((char*)&bh, sizeof(bh));
533  if(!ifs.good()){
534  err_mess << "Error reading EVIO block header (truncated?)"<<endl;
535  err_mess << "words_left_in_file (before read): " << words_left_in_file << endl;
536  err_mess << "total_size_bytes: " << total_size_bytes << " tellg: " << ifs.tellg();
538  return false;
539  }
540 
541  // Check if we need to byte swap and simultaneously
542  // verify header is good by checking magic word
543  bool swap_needed = false;
544  if(bh.magic==0x0001dac0){
545  swap_needed = true;
546  }else{
547  if(bh.magic!=0xc0da0100){
548  err_mess.str("Bad magic word");
550  return false;
551  }
552  }
553 
554  if(swap_needed)swap_block((uint32_t*)&bh, sizeof(bh)>>2, (uint32_t*)&bh);
555 
556  Nblocks++;
557  streampos pos = ifs.tellg() - (streampos)sizeof(bh);
558 
559  if( (uint64_t)(pos+(streampos)bh.length) > total_size_bytes ){
560  err_mess << "EVIO block extends past end of file!";
562  return false;
563  }
564 
565  br.pos = pos;
566  br.block_len = bh.length;
568  br.first_event = 0;
569  br.last_event = 0;
570 
571  MapEvents(bh, br);
572 
573  NB_next_pos = pos + (streampos)(bh.length<<2);
574  }
575 
576  // Check if we did not find an event of interest above.
577  // If not, report that there are no more events in the file.
578  if(br.evio_events.empty() || !ifs.good()){
579  SetErrorMessage("No more events");
581  return false; // isgood=false
582  }
583 
584  // Grab next event record
585  EVIOEventRecord &er = br.evio_events.front();
586 
587  uint32_t event_len = er.event_len;
588  last_event_len = event_len;
589 
590  // Check if user buffer is big enough to hold block
591  if( event_len > user_buff_len ){
593  err_mess << "user buffer too small for event (" << user_buff_len << " < " << event_len << ")";
595  return false;
596  }
597 
598  // Set file pointer to start of EVIO event (NOT block header!)
599  last_event_pos = er.pos;
600  ifs.seekg(last_event_pos, ios_base::beg);
601 
602  // Read data directly into user buffer
603  ifs.read((char*)user_buff, event_len*sizeof(uint32_t));
604  if(!ifs.good()){
605  uint64_t bytes_to_read = (uint64_t)(event_len*sizeof(uint32_t));
606  if( (bytes_to_read + (uint64_t)last_event_pos) > total_size_bytes ){
607  auto words_left_in_file = total_size_bytes - last_event_pos;
608  err_mess << "Error reading EVIO event (truncated?)"<<endl;
609  err_mess << "words_left_in_file (before read): " << words_left_in_file << endl;
610  err_mess << " bytes tried to read : " << bytes_to_read << endl;
611  err_mess << " total_size_bytes: " << total_size_bytes << " tellg: " << ifs.tellg();
613  }else{
614  SetErrorMessage("No more events");
616  }
617  return false; // isgood=false
618  }
619 
620  // Remove EVIO Event record, effectively advancing to
621  // next event for the next time we're called
622  br.evio_events.erase(NB_block_record.evio_events.begin());
623 
624  // Swap entire bank if needed
625  swap_needed = br.swap_needed; // set flag in HDEVIO
626  bool isgood = true;
627  if(br.swap_needed && allow_swap){
628  uint32_t Nswapped = swap_bank(user_buff, user_buff, event_len);
629  isgood = (Nswapped == event_len);
630  }
631 
632  // Double check that event length matches EVIO block header
633  // but only if we either don't need to swap or need to and
634  // were allowed to (otherwise, the test will almost certainly
635  // fail!)
636  if( (!br.swap_needed) || (br.swap_needed && allow_swap) ){
637  if( (user_buff[0]+1) != event_len ){
639  err_mess << "WARNING: EVIO bank indicates a different size than block header (" << event_len << " != " << (user_buff[0]+1) << ")";
641  Nerrors++;
642  Nbad_blocks++;
643  return false;
644  }
645  }
646 
647  if(isgood) Nevents++;
648 
649  return isgood;
650 }
651 
652 //------------------------
653 // rewind
654 //------------------------
655 void HDEVIO::rewind(void)
656 {
657  /// This can be used whe reading from a file to
658  /// reset the file pointer and other position holders
659  /// to the begining of the file. This is done when
660  /// the "LOOP_FOREVER" option is used in the event source
661  /// to continuously re-read a file, essesntially making
662  /// it an infinite stream of events that can be used for
663  /// testing.
664 
665  ifs.seekg(0, ios_base::beg);
666  ifs.clear();
667 
668  sparse_block_iter = evio_blocks.begin();
669  sparse_event_idx = 0;
670 
672  NB_next_pos = 0;
673 
676 }
677 
678 //------------------------
679 // GetNWordsLeftInFile
680 //------------------------
682 {
683  return (total_size_bytes-NB_next_pos)/4;
684 }
685 
686 //------------------------
687 // SetEventMask
688 //------------------------
689 uint32_t HDEVIO::SetEventMask(uint32_t mask)
690 {
691  uint32_t prev_mask = event_type_mask;
692  event_type_mask = mask;
693 
694  return prev_mask;
695 }
696 
697 //------------------------
698 // SetEventMask
699 //------------------------
700 uint32_t HDEVIO::SetEventMask(string types_str)
701 {
702  uint32_t prev_mask = event_type_mask;
703 
704  event_type_mask = 0;
705  if(types_str.find("BOR" ) != string::npos) event_type_mask |= (1<<kBT_BOR);
706  if(types_str.find("EPICS" ) != string::npos) event_type_mask |= (1<<kBT_EPICS);
707  if(types_str.find("PHYSICS") != string::npos) event_type_mask |= (1<<kBT_PHYSICS);
708 
709  return prev_mask;
710 }
711 
712 //------------------------
713 // AddToEventMask
714 //------------------------
715 uint32_t HDEVIO::AddToEventMask(string type_str)
716 {
717  return 0;
718 }
719 
720 //------------------------
721 // GetEVIOBlockRecords
722 //------------------------
723 vector<HDEVIO::EVIOBlockRecord>& HDEVIO::GetEVIOBlockRecords(void)
724 {
725  if(!is_mapped) MapBlocks();
726 
727  return evio_blocks;
728 }
729 
730 //------------------------
731 // MapBlocks
732 //------------------------
733 void HDEVIO::MapBlocks(bool print_ticker)
734 {
735  if(!is_open){
736  err_mess.str("File is not open");
738  return;
739  }
740 
741  // Remember current file pos so we can restore it.
742  streampos start_pos = ifs.tellg();
743 
744  if(print_ticker) cout << "Mapping EVIO file ..." << endl;
745 
746  // Rewind to beginning of file and loop over all blocks
747  ifs.seekg(0, ios_base::beg);
749  uint64_t Nblocks = 0;
750  while(ifs.good()){
751  ifs.read((char*)&bh, sizeof(bh));
752  if(!ifs.good()) break;
753 
754  // Check if we need to byte swap and simultaneously
755  // verify header is good by checking magic word
756  bool swap_needed = false;
757  if(bh.magic==0x0001dac0){
758  swap_needed = true;
759  }else{
760  if(bh.magic!=0xc0da0100){
761  err_mess.str("Bad magic word");
763  EVIOBlockRecord br;
764  br.pos = ifs.tellg() - (streampos)sizeof(bh);
765  br.block_type = kBT_UNKNOWN;
766  evio_blocks.push_back(br);
767  break;
768  }
769  }
770 
771  if(swap_needed)swap_block((uint32_t*)&bh, sizeof(bh)>>2, (uint32_t*)&bh);
772 
773  Nblocks++;
774  streampos block_len_bytes = (bh.length<<2)-sizeof(bh); // <<2 is for *4
775  streampos pos = ifs.tellg() - (streampos)sizeof(bh);
776 
777  EVIOBlockRecord br;
778  br.pos = pos;
779  br.block_len = bh.length;
781  br.first_event = 0;
782  br.last_event = 0;
783 
784  // Categorize this block
785  uint32_t tag = bh.header>>16;
786  uint32_t M = bh.header&0xFF;
787 
788  switch(tag){
789  case 0xFFD0: br.block_type = kBT_SYNC; break;
790  case 0xFFD1: br.block_type = kBT_PRESTART; break;
791  case 0xFFD2: br.block_type = kBT_GO; break;
792  case 0xFFD3: br.block_type = kBT_PAUSE; break;
793  case 0xFFD4: br.block_type = kBT_END; break;
794  case 0x0060: br.block_type = kBT_EPICS; break;
795  case 0x0070: br.block_type = kBT_BOR; break;
796  case 0xFF50:
797  case 0xFF51:
798  case 0xFF70:
799  br.block_type = kBT_PHYSICS;
801  br.first_event += ((uint64_t)bh.physics.first_event_hi)<<32;
802  br.last_event = br.first_event + (uint64_t)M - 1;
803  break;
804  default:
805  br.block_type = kBT_UNKNOWN;
806  _DBG_ << "Uknown tag: " << hex << tag << dec << endl;
807  }
808 
809  // Scan through and map all events within this block
810  if( !SKIP_EVENT_MAPPING ) MapEvents(bh, br);
811 
812  // Add block to list
813  evio_blocks.push_back(br);
814 
815  // Update ticker
816  if(print_ticker){
817  if((Nblocks%500) == 0){
818  uint64_t total_MB = total_size_bytes>>20;
819  uint64_t read_MB = ifs.tellg()>>20;
820  if(Nblocks==0) cout << endl;
821  cout << Nblocks << " blocks scanned (" << read_MB << "/" << total_MB << " MB " << (100*read_MB/total_MB) << "%) \r";
822  cout.flush();
823  }
824  }
825 
826  // Advance file pointer to start of next EVIO block header
827  ifs.seekg(block_len_bytes, ios_base::cur);
828  }
829 
830  if(print_ticker) cout << endl;
831 
832  // Setup iterators for sparse reading
833  sparse_block_iter = evio_blocks.begin();
834  sparse_event_idx = 0;
835 
836  // Restore file pos and set flag that file has been mapped
837  ifs.clear();
838  ifs.seekg(start_pos, ios_base::beg);
839  is_mapped = true;
840 }
841 
842 //---------------------------------
843 // MapEvents
844 //---------------------------------
846 {
847  /// This is called if the EVIO block header indicates that
848  /// it contains more than one top-level event. The position
849  /// and event length of the first top-level event are passed
850  /// in as starting parameters.
851 
852  // Record stream position upon entry so we can restore it at end
853  streampos start_pos = ifs.tellg();
854 
855  // Calculate stream position of EVIO event
856  streampos pos = start_pos -(streampos)sizeof(BLOCKHEADER_t) + (streampos)(8<<2); // (8<<2) is 8 word EVIO block header times 4bytes/word
857  ifs.seekg(pos, ios_base::beg);
858 
859  EVENTHEADER_t myeh;
860  for(uint32_t i=0; i<bh.eventcnt; i++){
861 
862  // For the first iteration through this loop,
863  // we use the event header that has already been
864  // read in as part of the block header.
866  if(i!=0){
867  // Read in first few words of event
868  eh = &myeh;
869  ifs.read((char*)eh, sizeof(EVENTHEADER_t));
870  if(!ifs.good()) break;
871  if(br.swap_needed)swap_block((uint32_t*)eh, sizeof(EVENTHEADER_t)>>2, (uint32_t*)eh);
872  }else{
873  ifs.seekg(sizeof(EVENTHEADER_t), ios_base::cur);
874  }
875 
876  if (eh->event_len < 2) {
877  // Before disabling this warning (or hiding it behind a VERBOSE flag)
878  // you should ask yourself the question, "Is this something that we
879  // should simply be ignoring, garbage bytes in the input evio file?"
880  std::cout << "HDEVIO::MapEvents warning - " << "Attempt to swap bank with len<2 (len="<<eh->event_len<<" header="<<hex<<eh->header<<dec<<" pos=" << pos << " tellg=" << ifs.tellg() << " i=" << i << ")" << std::endl;
881 
882  // Reference run 20495: Seems ROL is putting BOR bank header, but
883  // the bank has no data in it. For this case we can go forward, but
884  // this is really a problem for production data. Detect this and warn
885  // user.
886  if(eh->event_len==1 && (eh->header&0xFFFF00FF)==0x00700001){
887  _DBG__;
888  _DBG_ << "WARNING: This looks like an empty BOR event. BOR configuration" << endl;
889  _DBG_ << " data will not be available and it is unlikely you will" << endl;
890  _DBG_ << " be able to do anything beyond the digihit level. " << endl;
891  _DBG__;
892 
893  if(IGNORE_EMPTY_BOR){
894  EVIOEventRecord er;
895  er.pos = pos;
896  er.event_len = eh->event_len + 1; // +1 to include length word
897  er.event_type = kBT_UNKNOWN;
898  er.first_event = 0;
899  er.last_event = 0;
900  br.evio_events.push_back(er);
901  }else{
902  _DBG_ << " The program will (probably) stop now." << endl;
903  _DBG_ << " To avoid stopping, re-run with EVIO:IGNORE_EMPTY_BOR=1 ." << endl; }
904  }
905 
906  Nbad_events++;
907  Nerrors++;
908  // --i; // This caused an infinite loop when reading hd_rawdata_020058_000.evio DL
909  streampos delta = (streampos)((eh->event_len+1)<<2) -
910  (streampos)sizeof(EVENTHEADER_t);
911  ifs.seekg(delta, ios_base::cur);
912  pos += (streampos)((eh->event_len+1)<<2);
913  continue;
914  }
915 
916  EVIOEventRecord er;
917  er.pos = pos;
918  er.event_len = eh->event_len + 1; // +1 to include length word
919  er.event_header= eh->header;
920  er.event_type = kBT_UNKNOWN;
921  er.first_event = 0;
922  er.last_event = 0;
923 
924  uint32_t tag = eh->header>>16;
925  uint32_t M = eh->header&0xFF;
926 
927  switch(tag){
928  case 0xFFD0: er.event_type = kBT_SYNC; break;
929  case 0xFFD1: er.event_type = kBT_PRESTART; break;
930  case 0xFFD2: er.event_type = kBT_GO; break;
931  case 0xFFD3: er.event_type = kBT_PAUSE; break;
932  case 0xFFD4: er.event_type = kBT_END; break;
933  case 0x0060: er.event_type = kBT_EPICS; break;
934  case 0x0070: er.event_type = kBT_BOR; break;
935  case 0xFF50:
936  case 0xFF51:
937  case 0xFF70:
938  er.event_type = kBT_PHYSICS;
940  er.first_event += ((uint64_t)eh->physics.first_event_hi)<<32;
941  er.last_event = er.first_event + (uint64_t)M - 1;
942  if(er.first_event < br.first_event) br.first_event = er.first_event;
943  if(er.last_event > br.last_event ) br.last_event = er.last_event;
944  break;
945  case 0xFF32: er.event_type = kBT_BOR; break; // CDAQ
946  case 0xFF33: // CDAQ
947  M = eh->cdaqphysics.roc1_bank_header&0xFF;
948  er.event_type = kBT_PHYSICS;
950  er.last_event = er.first_event + (uint64_t)M - 1;
951  if(er.first_event < br.first_event) br.first_event = er.first_event;
952  if(er.last_event > br.last_event ) br.last_event = er.last_event;
953  break;
954  default:
955  if(VERBOSE>1) _DBG_ << "Uknown tag: " << hex << tag << dec << endl;
956  }
957 
958  br.evio_events.push_back(er);
959 
960  // Move file position to start of next event
961  streampos delta = (streampos)((eh->event_len+1)<<2) - (streampos)sizeof(EVENTHEADER_t);
962  ifs.seekg(delta, ios_base::cur);
963  pos += (streampos)((eh->event_len+1)<<2);
964  }
965 
966  ifs.clear();
967  ifs.seekg(start_pos, ios_base::beg);
968 }
969 
970 //---------------------------------
971 // swap_bank
972 //---------------------------------
973 uint32_t HDEVIO::swap_bank(uint32_t *outbuff, uint32_t *inbuff, uint32_t len)
974 {
975  /// Swap an EVIO bank. If the bank contains data, it is automatically
976  /// swapped according to it's type. If the bank is a container of other
977  /// containers, then this repeatedly calls the swapper methods for the
978  /// appropriate container type (bank, tagsegment, segment). This means
979  /// that this method will be recursive in the cases where it is a bank
980  /// of banks.
981 
982  if(len < 2){
983  SetErrorMessage("Attempt to swap bank with len<2");
985  Nerrors++;
986  Nbad_events++;
987  return 0;
988  }
989 
990  // Swap length and header words
991  swap_block(inbuff, 2, outbuff);
992  uint32_t bank_len = outbuff[0];
993  if((bank_len+1) > len){
995  err_mess << "WARNING: Bank length word exceeds valid words in buffer (" << bank_len+1 << " > " << len << ")";
997  Nerrors++;
998  Nbad_events++;
999  return 0;
1000  }
1001 
1002  uint32_t type = (outbuff[1]>>8) & 0xFF;
1003  uint32_t Nwords = bank_len - 1;
1004  uint32_t Nswapped = 2;
1005  switch(type){
1006  case 0x0a: // 64 bit unsigned int
1007  case 0x08: // 64 bit double
1008  case 0x09: // 64 bit signed int
1009  swap_block((uint64_t*)&inbuff[2], Nwords/2, (uint64_t*)&outbuff[2]);
1010  Nswapped += Nwords;
1011  break;
1012  case 0x01: // 32 bit unsigned int
1013  case 0x02: // 32 bit float
1014  case 0x0b: // 32 bit signed int
1015  swap_block(&inbuff[2], Nwords, &outbuff[2]);
1016  Nswapped += Nwords;
1017  break;
1018  case 0x05: // 16 bit unsigned int
1019  case 0x04: // 16 bit signed int
1020  swap_block((uint16_t*)&inbuff[2], Nwords*2, (uint16_t*)&outbuff[2]);
1021  Nswapped += Nwords;
1022  break;
1023  case 0x00: // 32 bit unknown (not swapped)
1024  case 0x07: // 8 bit unsigned int
1025  case 0x06: // 8 bit signed int
1026  if( inbuff!=outbuff ) memcpy((uint8_t*)&outbuff[2], (uint8_t*)&inbuff[2], Nwords*sizeof(uint32_t));
1027  Nswapped += Nwords;
1028  break;
1029  case 0x0c:
1030  while(Nswapped < (Nwords+2)){
1031  uint32_t N = swap_tagsegment(&outbuff[Nswapped], &inbuff[Nswapped], (Nwords+2)-Nswapped);
1032  if(N == 0) return Nswapped;
1033  Nswapped += N;
1034  }
1035  break;
1036  case 0x0d:
1037  case 0x20:
1038  while(Nswapped < (Nwords+2)){
1039  uint32_t N = swap_segment(&outbuff[Nswapped], &inbuff[Nswapped], (Nwords+2)-Nswapped);
1040  if(N == 0) return Nswapped;
1041  Nswapped += N;
1042  }
1043  break;
1044  case 0x0e:
1045  case 0x10:
1046  while(Nswapped < (Nwords+2)){
1047  uint32_t N = swap_bank(&outbuff[Nswapped], &inbuff[Nswapped], (Nwords+2)-Nswapped);
1048  if(N == 0) return Nswapped;
1049  Nswapped += N;
1050  }
1051  break;
1052  default:
1054  err_mess << "WARNING: unknown bank type (0x" << hex << type << dec << ")";
1056  Nerrors++;
1057  Nbad_events++;
1058  return 0;
1059  break;
1060  }
1061 
1062  return Nswapped;
1063 }
1064 
1065 //---------------------------------
1066 // swap_tagsegment
1067 //---------------------------------
1068 uint32_t HDEVIO::swap_tagsegment(uint32_t *outbuff, uint32_t *inbuff, uint32_t len)
1069 {
1070  /// Swap an EVIO tagsegment.
1071 
1072  if(len < 1){
1073  SetErrorMessage("Attempt to swap segment with len<1");
1075  Nerrors++;
1076  Nbad_events++;
1077  return 0;
1078  }
1079 
1080  // Swap header/length word
1081  swap_block(inbuff, 1, outbuff);
1082  uint32_t bank_len = outbuff[0] & 0xFFFF;
1083  if((bank_len) > len){
1085  err_mess << "Segment length word exceeds valid words in buffer (" << bank_len << " > " << len << ")";
1087  Nerrors++;
1088  Nbad_events++;
1089  return 0;
1090  }
1091 
1092  uint32_t type = (outbuff[0]>>16) & 0x0F;
1093  uint32_t Nwords = bank_len;
1094  uint32_t Nswapped = 1;
1095  switch(type){
1096  case 0x0a: // 64 bit unsigned int
1097  case 0x08: // 64 bit double
1098  case 0x09: // 64 bit signed int
1099  swap_block((uint64_t*)&inbuff[1], Nwords/2, (uint64_t*)&outbuff[1]);
1100  Nswapped += Nwords;
1101  break;
1102  case 0x01: // 32 bit unsigned int
1103  case 0x02: // 32 bit float
1104  case 0x0b: // 32 bit signed int
1105  swap_block(&inbuff[1], Nwords, &outbuff[1]);
1106  Nswapped += Nwords;
1107  break;
1108  case 0x05: // 16 bit unsigned int
1109  case 0x04: // 16 bit signed int
1110  swap_block((uint16_t*)&inbuff[1], Nwords*2, (uint16_t*)&outbuff[1]);
1111  Nswapped += Nwords;
1112  break;
1113  case 0x00: // 32 bit unknown (not swapped)
1114  case 0x07: // 8 bit unsigned int
1115  case 0x06: // 8 bit signed int
1116  memcpy((uint8_t*)&outbuff[1], (uint8_t*)&inbuff[1], Nwords*sizeof(uint32_t));
1117  Nswapped += Nwords;
1118  break;
1119  }
1120 
1121  return Nswapped;
1122 }
1123 
1124 //---------------------------------
1125 // swap_segment
1126 //---------------------------------
1127 uint32_t HDEVIO::swap_segment(uint32_t *outbuff, uint32_t *inbuff, uint32_t len)
1128 {
1129  /// Swap an EVIO segment.
1130 
1131  if(len < 1){
1132  SetErrorMessage("Attempt to swap segment with len<1");
1134  Nerrors++;
1135  Nbad_events++;
1136  return 0;
1137  }
1138 
1139  // Swap header/length word
1140  swap_block(inbuff, 1, outbuff);
1141  uint32_t bank_len = outbuff[0] & 0xFFFF;
1142  if((bank_len) > len){
1144  err_mess << "Segment length word exceeds valid words in buffer (" << bank_len << " > " << len << ")";
1146  Nerrors++;
1147  Nbad_events++;
1148  return 0;
1149  }
1150 
1151  uint32_t type = (outbuff[0]>>16) & 0x3F;
1152  uint32_t Nwords = bank_len;
1153  uint32_t Nswapped = 1;
1154  switch(type){
1155  case 0x0a: // 64 bit unsigned int
1156  case 0x08: // 64 bit double
1157  case 0x09: // 64 bit signed int
1158  swap_block((uint64_t*)&inbuff[1], Nwords/2, (uint64_t*)&outbuff[1]);
1159  Nswapped += Nwords;
1160  break;
1161  case 0x01: // 32 bit unsigned int
1162  case 0x02: // 32 bit float
1163  case 0x0b: // 32 bit signed int
1164  swap_block(&inbuff[1], Nwords, &outbuff[1]);
1165  Nswapped += Nwords;
1166  break;
1167  case 0x05: // 16 bit unsigned int
1168  case 0x04: // 16 bit signed int
1169  swap_block((uint16_t*)&inbuff[1], Nwords*2, (uint16_t*)&outbuff[1]);
1170  Nswapped += Nwords;
1171  break;
1172  case 0x00: // 32 bit unknown (not swapped)
1173  case 0x07: // 8 bit unsigned int
1174  case 0x06: // 8 bit signed int
1175  if( inbuff!=outbuff ) memcpy((uint8_t*)&outbuff[1], (uint8_t*)&inbuff[1], Nwords*sizeof(uint32_t));
1176  Nswapped += Nwords;
1177  break;
1178  }
1179 
1180  return Nswapped;
1181 }
1182 
1183 //------------------------
1184 // Print_fbuff
1185 //------------------------
1187 {
1188  cout << endl;
1189  cout << " fbuff: " << hex << (uint64_t)fbuff << dec << endl;
1190  cout << " fnext: " << hex << (uint64_t)fnext << dec << endl;
1191  cout << " fbuff_end: " << hex << (uint64_t)fbuff_end << dec << endl;
1192  cout << " fbuff_size: " << fbuff_size << endl;
1193  cout << " fbuff_len: " << fbuff_len << endl;
1194  cout << " _gcount: " << _gcount << endl;
1195 }
1196 
1197 //------------------------
1198 // PrintEVIOBlockHeader
1199 //------------------------
1201 {
1202 
1203  cout << endl;
1204  cout << "EVIO Block Header:" << endl;
1205  cout << "------------------------" << endl;
1206  cout << " Block Length: " << HexStr(buff[0]) << " (" << buff[0] << " words = " << (buff[0]>>(10-2)) << " kB)" << endl;
1207  cout << " Block Number: " << HexStr(buff[1]) << endl;
1208  cout << "Header Length: " << HexStr(buff[2]) << " (should be 8)" << endl;
1209  cout << " Event Count: " << HexStr(buff[3]) << endl;
1210  cout << " Reserved 1: " << HexStr(buff[4]) << endl;
1211  cout << " Bit Info: " << HexStr(buff[5]>>8) << endl;
1212  cout << " Version: " << HexStr(buff[5]&0xFF) << endl;
1213  cout << " Reserved 3: " << HexStr(buff[6]) << endl;
1214  cout << " Magic word: " << HexStr(buff[7]) << (swap_needed ? " (after swapping)":"") << endl;
1215  cout << "Byte swapping is" << (swap_needed ? " ":" not ") << "needed" << endl;
1216 }
1217 
1218 //------------------------
1219 // PrintStats
1220 //------------------------
1222 {
1223  uint64_t Nblocks = this->Nblocks;
1224  uint64_t Nevents = this->Nevents;
1225 
1226  if(is_mapped){
1227  Nblocks = evio_blocks.size();
1228  Nevents = 0;
1229  for(auto b : evio_blocks) Nevents += b.evio_events.size();
1230  }
1231 
1232  cout << endl;
1233  cout << "EVIO Statistics for " << filename << " :" << endl;
1234  cout << "------------------------" << endl;
1235  cout << " Nblocks: " << Nblocks << endl;
1236  cout << " Nevents: " << Nevents << endl;
1237  cout << " Nerrors: " << Nerrors << endl;
1238  cout << "Nbad_blocks: " << Nbad_blocks << endl;
1239  cout << "Nbad_events: " << Nbad_events << endl;
1240  cout << endl;
1241 }
1242 
1243 //------------------------
1244 // PrintFileSummary
1245 //------------------------
1247 {
1248  if(!is_mapped) MapBlocks();
1249 
1250  uint32_t Nsync = 0;
1251  uint32_t Nprestart = 0;
1252  uint32_t Ngo = 0;
1253  uint32_t Npause = 0;
1254  uint32_t Nend = 0;
1255  uint32_t Nepics = 0;
1256  uint32_t Nbor = 0;
1257  uint32_t Nphysics = 0;
1258  uint32_t Nunknown = 0;
1259  uint32_t Nblockunknown = 0;
1260 
1261  uint64_t first_event = 0;
1262  uint64_t last_event = 0;
1263 
1264  uint32_t map_size = evio_blocks.size()*sizeof(EVIOBlockRecord);
1265 
1266  set<uint32_t> block_levels;
1267  set<uint32_t> events_in_block;
1268 
1269  // Loop over all EVIO block records
1270  for(uint32_t i=0; i<evio_blocks.size(); i++){
1271  EVIOBlockRecord &br = evio_blocks[i];
1272  events_in_block.insert(br.evio_events.size());
1273  map_size += br.evio_events.size()*sizeof(EVIOEventRecord);
1274 
1275  uint32_t Nunknown_prev = Nunknown;
1276  for(uint32_t j=0; j<br.evio_events.size(); j++){
1277  EVIOEventRecord &er = br.evio_events[j];
1278 
1279  uint32_t block_level;
1280  switch(er.event_type){
1281  case kBT_UNKNOWN: Nunknown++; break;
1282  case kBT_SYNC: Nsync++; break;
1283  case kBT_PRESTART: Nprestart++; break;
1284  case kBT_GO: Ngo++; break;
1285  case kBT_PAUSE: Npause++; break;
1286  case kBT_END: Nend++; break;
1287  case kBT_EPICS: Nepics++; break;
1288  case kBT_BOR: Nbor++; break;
1289  case kBT_PHYSICS:
1290  block_level = (uint32_t)((er.last_event - er.first_event) + 1);
1291  block_levels.insert(block_level);
1292  Nphysics += block_level;
1293  if(er.first_event<first_event || first_event==0) first_event = er.first_event;
1294  if(er.last_event>last_event) last_event = er.last_event;
1295  break;
1296  default:
1297  break;
1298  }
1299 
1300  //_DBG_ << "Block " << i << " event " << j << " " << er.last_event <<" - " << er.first_event << " = " << block_level << endl;
1301  }
1302 
1303  if( (Nunknown-Nunknown_prev) > 0 ) Nblockunknown++;
1304  }
1305 
1306  // form succint string of block levels
1307  stringstream ss;
1308  set<uint32_t>::iterator it = block_levels.begin();
1309  for(; it!=block_levels.end(); it++) ss << *it << ",";
1310  string sblock_levels = ss.str();
1311  if(!sblock_levels.empty()) sblock_levels.erase(sblock_levels.length()-1);
1312 
1313  // form succint string of events per block
1314  ss.str("");
1315  it = events_in_block.begin();
1316  for(; it!=events_in_block.end(); it++){
1317  uint32_t val = *it;
1318  ss << val;
1319  if(++it==events_in_block.end()) break;
1320  if( *it == ++val ){
1321  ss << "-";
1322  for(it++; it!=events_in_block.end(); it++){
1323  if( *it != ++val ){
1324  ss << (val-1) << ",";
1325  it--;
1326  break;
1327  }
1328  }
1329  }else{
1330  ss << ",";
1331  }
1332  if( it==events_in_block.end() ) break;
1333  }
1334  string sevents_in_block = ss.str();
1335 
1336  // Print results
1337  PrintStats();
1338  cout << "EVIO file size: " << (total_size_bytes>>20) << " MB" <<endl;
1339  cout << "EVIO block map size: " << (map_size>>10) << " kB" <<endl;
1340  cout << "first event: " << first_event << endl;
1341  cout << "last event: " << last_event << endl;
1342 
1343  cout << endl;
1344  cout << " block levels = " << sblock_levels << endl;
1345  cout << " events per block = " << sevents_in_block << endl;
1346  cout << " Nsync = " << Nsync << endl;
1347  cout << " Nprestart = " << Nprestart << endl;
1348  cout << " Ngo = " << Ngo << endl;
1349  cout << " Npause = " << Npause << endl;
1350  cout << " Nend = " << Nend << endl;
1351  cout << " Nepics = " << Nepics << endl;
1352  cout << " Nbor = " << Nbor << endl;
1353  cout << " Nphysics = " << Nphysics << endl;
1354  cout << " Nunknown = " << Nunknown << endl;
1355  cout << " blocks with unknown tags = " << Nblockunknown << endl;
1356  cout << endl;
1357 }
1358 
1359 //------------------------
1360 // SaveFileMap
1361 //------------------------
1362 void HDEVIO::SaveFileMap(string fname)
1363 {
1364  // Make sure file has been mapped
1365  if(!is_mapped) MapBlocks();
1366 
1367  // Open output file
1368  if(fname=="") fname = filename + ".map";
1369  ofstream ofs(fname.c_str());
1370  if(!ofs.is_open()){
1371  cerr << "Unable to open \""<<fname<<"\" for writing!" << endl;
1372  return;
1373  }
1374 
1375  cout << "Writing EVIO file map to: " << fname << endl;
1376 
1377  char str[256];
1378  time_t t = time(NULL);
1379  struct tm *tmp = localtime(&t);
1380  strftime(str, 255, "%c", tmp);
1381 
1382  ofs << "#" << endl;
1383  ofs << "# HDEVIO block map for " << filename << endl;
1384  ofs << "#" << endl;
1385  ofs << "# generated " << str << endl;
1386  ofs << "#" << endl;
1387  ofs << "# " << endl;
1388  ofs << "swap_needed: " << swap_needed << endl;
1389  ofs << "--------- Start of block data --------" << endl;
1390  ofs << "# pos block_len first_evt last_evt block_type" << endl;
1391  ofs << "# + pos evt_len evt_header first_evt last_evt event_type" << endl;
1392 
1393  for(auto br : evio_blocks){
1394  char line[512];
1395  sprintf(line, "0x%08x 0x%06x %8" PRIu64 " %8" PRIu64 " %d", (uint32_t)br.pos, br.block_len, br.first_event, br.last_event, br.block_type);
1396  ofs << line << endl;
1397 
1398  for(auto er : br.evio_events){
1399  sprintf(line, "+ 0x%08x 0x%06x 0x%08x %8" PRIu64 " %8" PRIu64 " %d", (uint32_t)er.pos, er.event_len, er.event_header, er.first_event, er.last_event, er.event_type);
1400  ofs << line << endl;
1401  }
1402  }
1403  ofs << "# --- End of map ---" << endl;
1404  // Close output file
1405  ofs.close();
1406 
1407  cout << "Done" << endl;
1408 }
1409 
1410 //------------------------
1411 // ReadFileMap
1412 //------------------------
1413 void HDEVIO::ReadFileMap(string fname, bool warn_if_not_found)
1414 {
1415  // Open input file
1416  if(VERBOSE>4) cout << " Attempting to read EVIO map file \"" << fname << "\" for \"" << filename << "\"" << endl;
1417  if(fname=="") {
1418 
1419  // No map file name given. Form a list of potential ones
1420  // in the order they should be checked.
1421  string dname = ".";
1422  string bname = filename;
1423  auto pos = filename.find_last_of("/");
1424  if(pos != string::npos){
1425  dname = filename.substr(0, pos);
1426  bname = filename.substr(pos+1, filename.size()-pos);
1427  }
1428 
1429  vector<string> fnames;
1430  fnames.push_back(filename + ".map");
1431  fnames.push_back(dname + "/filemaps/" + bname + ".map");
1432  fnames.push_back(bname + ".map");
1433  fnames.push_back(filename + ".bmap");
1434  fnames.push_back(dname + "/filemaps/" + bname + ".bmap");
1435  fnames.push_back(bname + ".bmap");
1436 
1437  // Loop over possible names until we find one that is readable
1438  for(string f : fnames){
1439  if(VERBOSE>2) cout << "Checking for EVIO map file: " << f << " ...";
1440  if( access(f.c_str(), R_OK) != 0 ) {
1441  if(VERBOSE>2) cout << "no" << endl;
1442  continue;
1443  }
1444  if(VERBOSE>2)cout << "yes" << endl;
1445  fname = f;
1446  break;
1447  }
1448  }
1449 
1450  if(fname=="") return;
1451 
1452  // Open map file
1453  ifstream mifs(fname.c_str());
1454  if(!mifs.is_open()){
1455  if(warn_if_not_found) cerr << "Unable to open \""<<fname<<"\" for reading!" << endl;
1456  return;
1457  }
1458 
1459  // Check if file was closed cleanly
1460  string eof_string("# --- End of map ---");
1461  mifs.seekg(-eof_string.length()*2, mifs.end); // not guaranteed how many char's endl is
1462  bool closed_cleanly = false;
1463  string line;
1464  while(getline(mifs,line)){
1465  if(string(line).find(eof_string)!=string::npos) closed_cleanly = true;
1466  }
1467  if(!closed_cleanly){
1468  cerr << "Found map file \"" << fname << "\" but it wasn't closed cleanly. Ignoring." << endl;
1469  mifs.close();
1470  return;
1471  }
1472 
1473  // Reset file pointers to start of file
1474  mifs.clear();
1475  mifs.seekg(0);
1476 
1477  // Loop over header
1478  while(getline(mifs, line)){
1479 
1480  if(line.length() < 5 ) continue;
1481  if(line.find("#") == 0 ) continue;
1482  if(line.find("Start of block data") != string::npos) break;
1483  }
1484 
1485  // Loop over body
1486  EVIOBlockRecord br;
1487  bool first_block_found = false;
1488  string s;
1489  while(getline(mifs, s)){
1490  stringstream ss(s);
1491  if(ss.str().find(eof_string) != string::npos ) break; // end of map trailer
1492  if(ss.str().find("#") == 0 ) continue; // ignore all other comment lines
1493 
1494  if(ss.str().find("+") == 0 ){
1495  // EVIO Event Record
1496  string tmp;
1497  uint64_t tmp64;
1498  EVIOEventRecord er;
1499  ss >> tmp; // '+"
1500  ss << hex;
1501  ss >> tmp64; er.pos = tmp64; // operator>> won't stream directly to streampos
1502  ss >> er.event_len;
1503  ss >> er.event_header;
1504  ss << dec;
1505  ss >> er.first_event;
1506  ss >> er.last_event;
1507  ss >> tmp64; er.event_type = (BLOCKTYPE)tmp64; // operator>> won't stream directly to BLOCKTYPE
1508  br.evio_events.push_back(er);
1509  }else{
1510  // EVIO Block Record
1511  if(first_block_found){
1512  evio_blocks.push_back(br);
1513  }else{
1514  first_block_found = true;
1515  }
1516  br.evio_events.clear();
1517  uint64_t tmp64;
1518  ss << hex;
1519  ss >> tmp64; br.pos = tmp64; // operator>> won't stream directly to streampos
1520  ss >> br.block_len;
1521  ss << dec;
1522  ss >> br.first_event;
1523  ss >> br.last_event;
1524  ss >> tmp64; br.block_type = (BLOCKTYPE)tmp64; // operator>> won't stream directly to BLOCKTYPE
1525  }
1526  }
1527  if(!br.evio_events.empty()) evio_blocks.push_back(br);
1528 
1529  is_mapped = true;
1530  cout << "Read EVIO file map from: " << fname << endl;
1531 }
1532 
uint32_t first_event_lo
Definition: HDEVIO.h:95
uint32_t sparse_event_idx
Definition: HDEVIO.h:233
virtual ~HDEVIO()
Definition: HDEVIO.cc:103
vector< EVIOBlockRecord > evio_blocks
Definition: HDEVIO.h:229
PHYSICSHEADER_t physics
Definition: HDEVIO.h:124
BLOCKTYPE event_type
Definition: HDEVIO.h:150
async_filebuf * open(const std::string fname, std::ios::openmode mode)
Definition: async_filebuf.h:29
BLOCKHEADER_t * bh
Definition: HDEVIO.h:182
uint32_t err_code
Definition: HDEVIO.h:192
uint32_t eventcnt
Definition: HDEVIO.h:110
HDEVIO(string filename, bool read_map_file=true, int verbose=1)
Definition: HDEVIO.cc:31
void buff_seekg(streamoff off, ios_base::seekdir way)
Definition: HDEVIO.cc:188
char str[256]
ifstream ifs
Definition: HDEVIO.h:165
void MapEvents(BLOCKHEADER_t &bh, EVIOBlockRecord &br)
Definition: HDEVIO.cc:845
bool is_mapped
Definition: HDEVIO.h:227
PHYSICSHEADER_t physics
Definition: HDEVIO.h:138
streampos last_event_pos
Definition: HDEVIO.h:183
uint32_t AddToEventMask(string type_str)
Definition: HDEVIO.cc:715
uint32_t * fnext
Definition: HDEVIO.h:168
sprintf(text,"Post KinFit Cut")
TString filename
bool is_open
Definition: HDEVIO.h:166
bool SKIP_EVENT_MAPPING
Definition: HDEVIO.h:189
void buff_read(char *s, streamsize n)
Definition: HDEVIO.cc:117
string HexStr(uint32_t v)
Definition: HDEVIO.h:250
void Print_fbuff(void)
Definition: HDEVIO.cc:1186
uint64_t _gcount
Definition: HDEVIO.h:172
void PrintEVIOBlockHeader(void)
Definition: HDEVIO.cc:1200
uint32_t * fbuff_end
Definition: HDEVIO.h:169
void rewind(void)
Definition: HDEVIO.cc:655
uint64_t first_event
Definition: HDEVIO.h:159
int VERBOSE
Definition: HDEVIO.h:187
streampos NB_next_pos
Definition: HDEVIO.h:235
vector< EVIOEventRecord > evio_events
Definition: HDEVIO.h:158
vector< EVIOBlockRecord >::iterator sparse_block_iter
Definition: HDEVIO.h:232
bool readSparse(uint32_t *user_buff, uint32_t user_buff_len, bool allow_swap=true)
Definition: HDEVIO.cc:404
uint64_t first_event
Definition: HDEVIO.h:148
uint32_t swap_tagsegment(uint32_t *outbuff, uint32_t *inbuff, uint32_t len)
Definition: HDEVIO.cc:1068
TF1 * f
Definition: FitGains.C:21
uint32_t SetEventMask(uint32_t mask)
Definition: HDEVIO.cc:689
void SetErrorMessage(string mess)
Definition: HDEVIO.h:238
vector< EVIOBlockRecord > & GetEVIOBlockRecords(void)
Definition: HDEVIO.cc:723
uint32_t event_header
Definition: HDEVIO.h:147
bool read(uint32_t *user_buff, uint32_t user_buff_len, bool allow_swap=true)
Definition: HDEVIO.cc:329
stringstream err_mess
Definition: HDEVIO.h:191
uint32_t buff_len
Definition: HDEVIO.h:179
const bool VERBOSE
uint32_t * buff_end
Definition: HDEVIO.h:177
uint32_t event_type_mask
Definition: HDEVIO.h:225
uint32_t last_event_len
Definition: HDEVIO.h:184
CDAQPHYSICSHEADER_t cdaqphysics
Definition: HDEVIO.h:139
uint32_t * next
Definition: HDEVIO.h:176
void MapBlocks(bool print_ticker=true)
Definition: HDEVIO.cc:733
void ClearErrorMessage(void)
Definition: HDEVIO.h:237
void ReadFileMap(string fname="", bool warn_if_not_found=false)
Definition: HDEVIO.cc:1413
#define _DBG_
Definition: HDEVIO.h:12
string filename
Definition: HDEVIO.h:164
uint64_t Nblocks
Definition: HDEVIO.h:194
bool readNoFileBuff(uint32_t *user_buff, uint32_t user_buff_len, bool allow_swap=true)
Definition: HDEVIO.cc:499
void SaveFileMap(string fname="")
Definition: HDEVIO.cc:1362
streamsize buff_gcount() const
Definition: HDEVIO.h:242
uint64_t GetNWordsLeftInFile(void)
Definition: HDEVIO.cc:681
#define _DBG__
Definition: HDEVIO.h:13
void PrintFileSummary(void)
Definition: HDEVIO.cc:1246
void PrintStats(void)
Definition: HDEVIO.cc:1221
uint64_t fbuff_size
Definition: HDEVIO.h:170
uint64_t total_size_bytes
Definition: HDEVIO.h:228
uint64_t Nbad_blocks
Definition: HDEVIO.h:197
uint64_t Nbad_events
Definition: HDEVIO.h:198
BLOCKTYPE
Definition: HDEVIO.h:65
BLOCKTYPE block_type
Definition: HDEVIO.h:161
uint32_t event_len
Definition: HDEVIO.h:131
uint64_t fbuff_len
Definition: HDEVIO.h:171
uint32_t first_event_hi
Definition: HDEVIO.h:94
uint32_t buff_limit
Definition: HDEVIO.h:180
bool IGNORE_EMPTY_BOR
Definition: HDEVIO.h:188
EVIOBlockRecord NB_block_record
Definition: HDEVIO.h:234
uint32_t swap_bank(uint32_t *outbuff, uint32_t *inbuff, uint32_t len)
Definition: HDEVIO.cc:973
bool ReadBlock(void)
Definition: HDEVIO.cc:240
uint32_t * fbuff
Definition: HDEVIO.h:167
bool swap_needed
Definition: HDEVIO.h:181
uint64_t Nerrors
Definition: HDEVIO.h:196
uint32_t buff_size
Definition: HDEVIO.h:178
void swap_block(uint16_t *inbuff, uint16_t len, uint16_t *outbuff)
Definition: HDEVIO.h:283
uint64_t Nevents
Definition: HDEVIO.h:195
uint32_t swap_segment(uint32_t *outbuff, uint32_t *inbuff, uint32_t len)
Definition: HDEVIO.cc:1127
uint32_t * buff
Definition: HDEVIO.h:175
uint32_t event_len
Definition: HDEVIO.h:117