Bug Summary

File:libraries/DAQ/HDEVIO.cc
Location:line 100, column 2
Description:Value stored to 'left' is never read

Annotated Source Code

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#include <stdlib.h>
9#include <string.h>
10
11#include "HDEVIO.h"
12
13//---------------------------------
14// HDEVIO (Constructor)
15//---------------------------------
16HDEVIO::HDEVIO(string filename):filename(filename)
17{
18 // These must be initialized in case we return early
19 // so they aren't deleted in the destructor if they
20 // were never allocated.
21 fbuff = NULL__null;
22 buff = NULL__null;
23
24 is_open = false;
25 ifs.open(filename.c_str());
26 if(!ifs.is_open()){
27 ClearErrorMessage();
28 err_mess << "Unable to open EVIO file: " << filename;
29 return;
30 }
31
32 fbuff_size = 10000000; // 40MB input buffer
33 fbuff = new uint32_t[fbuff_size];;
34 fnext = fbuff;
35 fbuff_end = fbuff;
36 fbuff_len = 0;
37 _gcount = 0;
38
39 buff_limit = 5000000; // Don't allow us to allocate more than 5M words for read buffer
40 buff_size = 1024; // initialize with 4kB buffer
41 buff_len = 0;
42 buff = new uint32_t[buff_size];
43 next = buff; // needed so initial calculation of left is 0
44 last_event_pos = 0;
45 last_event_len = 0;
46 err_code = HDEVIO_OK;
47
48 Nblocks = 0;
49 Nevents = 0;
50 Nerrors = 0;
51 Nbad_blocks = 0;
52 Nbad_events = 0;
53
54 event_type_mask = 0xFFFF; // default to accepting all types
55 is_mapped = false;
56
57 NB_next_pos = 0;
58
59 ifs.seekg(0, ios_base::end);
60 total_size_bytes = ifs.tellg();
61 ifs.seekg(0, ios_base::beg);
62
63 is_open = true;
64}
65
66//---------------------------------
67// ~HDEVIO (Destructor)
68//---------------------------------
69HDEVIO::~HDEVIO()
70{
71 if(ifs.is_open()) ifs.close();
72 if(buff ) delete[] buff;
73 if(fbuff) delete[] fbuff;
74}
75
76//---------------------------------
77// buff_read
78//---------------------------------
79void HDEVIO::buff_read(char* s, streamsize nwords)
80{
81 /// Read n bytes into the specified buffer.
82 /// This will read from the file if needed, or simply copy
83 /// the bytes from the existing fbuff. It is purposely meant
84 /// as a drop-in replacement for ifstream::read so that we
85 /// can make actual reads from the file in larger chunks and
86 /// avoid backwards seeks on the actual file. This is needed
87 /// because the Lustre filesystem is optimized for large data
88 /// reads but smaller reads with backwards seeks tend to cripple
89 /// its performance. The main difference between this and
90 /// ifstream::read is that this does not return an istream&
91 /// reference.
92
93 // Number of words left in fbuff
94 uint64_t left = ((uint64_t)fbuff_end - (uint64_t)fnext)/sizeof(uint32_t);
95
96 // First, copy what's already in fbuff
97 uint64_t Ncopied = nwords<(int64_t)left ? (uint64_t)nwords:left;
98 _gcount = Ncopied*sizeof(uint32_t);
99 if(_gcount>0) memcpy((char*)s, (char*)fnext, _gcount);
100 left -= Ncopied;
Value stored to 'left' is never read
101 fnext += Ncopied;
102 s += _gcount; // advance pointer to user buff in case we need to write more
103
104 // If needed, read in another chunk from the file.
105 // Try and keep last 8 words so if a seekg is called to back
106 // us up that amount, we don't have to call seekg on the file.
107 if( (int64_t)Ncopied < nwords ){
108
109 // Initialize to start of buffer
110 uint32_t *myfbuff = fbuff;
111 uint32_t myfbuff_size = fbuff_size;
112 fbuff_len = 0;
113
114 // If at least 8 words exist in fbuff, then copy last
115 // 8 words into front of fbuff.
116 if( fbuff_len >= 8 ){
117 memcpy((char*)fbuff, (char*)&fbuff[fbuff_len-8], 8*sizeof(uint32_t));
118 myfbuff = &fbuff[8];
119 myfbuff_size -= 8;
120 fbuff_len += 8;
121 }
122
123 // Read in chunk from file
124 ifs.read((char*)myfbuff, myfbuff_size*sizeof(uint32_t));
125 fbuff_len += (uint64_t)(ifs.gcount()/sizeof(uint32_t));
126 fnext = myfbuff;
127 fbuff_end = &fbuff[fbuff_len];
128
129 // Copy remainder of request
130 uint64_t myleft = ((uint64_t)fbuff_end - (uint64_t)fnext)/sizeof(uint32_t);
131
132 uint64_t mynwords = nwords - Ncopied;
133 uint64_t myNcopied = mynwords<myleft ? mynwords:myleft;
134 uint64_t mygcount = myNcopied*sizeof(uint32_t);
135 if(mygcount>0) memcpy((char*)s, (char*)fnext, mygcount);
136 fnext += myNcopied;
137 _gcount += myNcopied*sizeof(uint32_t);
138 }
139}
140
141//---------------------------------
142// buff_seekg
143//---------------------------------
144void HDEVIO::buff_seekg (streamoff off, ios_base::seekdir way)
145{
146 // Convert offset from bytes to words
147 int64_t off_words = (int64_t)off/(int64_t)sizeof(uint32_t);
148
149 // find current position relative to start of buffer in words
150 int64_t fpos = (int64_t)((uint64_t)fnext - (uint64_t)fbuff)/sizeof(uint32_t);
151
152 // Seek depending on what user has requested
153 if( way == ios_base::cur ){
154
155 // Add requested offset
156 fpos += off_words; // desired position relative to start of fbuff
157
158 if(fpos>=0 && fpos<(int64_t)fbuff_len){
159 // Request is to a point inside current buffer
160 fnext = &fbuff[fpos];
161 _gcount = 0;
162 }else if(fpos<0){
163 // Seek point is outside of buffer. Move file pointer
164 // and indicate buffer is now empty so next buff_read()
165 // call will force a read.
166
167 // Current file position should be just after end of fbuff
168 // Subtract fbuff_len to move it back to start of fbuff.
169 // fpos is position relative to start of fbuff.
170 off = (streamoff)fpos - (streamoff)fbuff_len; // offset relative to actual current file position
171
172 ifs.seekg(off);
173
174 // Set fbuff parameters to indicate no valid data
175 fnext = fbuff;
176 fbuff_end = fbuff;
177 fbuff_len = 0;
178 _gcount = 0;
179
180 }
181
182 }else{
183 _DBG_cout<<"libraries/DAQ/HDEVIO.cc"<<":"<<183<<
" "
<<"buff_seekg called with something other than ios_base::cur is unsupported!" << endl;
184 exit(-1);
185 }
186}
187
188//---------------------------------
189// ReadBlock
190//---------------------------------
191bool HDEVIO::ReadBlock(void)
192{
193 /// Read in the next EVIO block. Return true if successful
194 /// and false otherwise.
195
196 err_code = HDEVIO_OK;
197 next = NULL__null;
198
199 buff_read((char*)buff, 8);
200 uint32_t valid_words = buff_gcount()/sizeof(uint32_t);
201 if(valid_words != 8){
202 SetErrorMessage("Could not read in 8 word EVIO block header!");
203 err_code = HDEVIO_FILE_TRUNCATED;
204 Nerrors++;
205 return false;
206 }
207
208 // Check endianess
209 if(buff[7]!=0xc0da0100 && buff[7]!=0x0001dac0){
210 ClearErrorMessage();
211 err_mess << "Magic word not valid!: " << HexStr(buff[7]) << endl;
212 err_code = HDEVIO_BAD_BLOCK_HEADER;
213 Nerrors++;
214 Nbad_blocks++;
215 return false;
216 }
217 swap_needed = (buff[7]==0x0001dac0);
218
219 // Swap header (if needed)
220 if(swap_needed) swap_block(buff, 8, buff);
221
222 // Re-allocate buffer if needed so we can read in entire block
223 uint32_t block_length = buff[0];
224 if(buff_size < block_length){
225 if(block_length > buff_limit){
226 ClearErrorMessage();
227 err_mess << "ERROR: EVIO block length greater than allocation limit (" << block_length <<" > " << block_length << " words)" << endl;
228 err_code = HDEVIO_BLOCKSIZE_GREATER_THAN_LIMIT;
229 Nerrors++;
230 return false;
231 }
232 if(buff) delete[] buff;
233 buff_size = block_length;
234 buff = new uint32_t[buff_size];
235 if(buff == NULL__null){
236 ClearErrorMessage();
237 err_mess << "ERROR: unable to allocate " << block_length <<" words" << endl;
238 err_code = HDEVIO_MEMORY_ALLOCATION_ERROR;
239 return false;
240 }
241
242 // Re-read in the block header
243 buff_seekg(-8*sizeof(uint32_t), ifs.cur);
244 buff_read((char*)buff, 8);
245 if(swap_needed) swap_block(buff, 8, buff);
246 }
247
248 if(block_length == 8){
249 // block_length =8 indicates end of file.
250 SetErrorMessage("end of file");
251 err_code = HDEVIO_EOF;
252 return false;
253 }
254
255 // Read payload of block
256 buff_read((char*)&buff[8], (block_length-8));
257 valid_words = 8 + buff_gcount()/sizeof(uint32_t);
258 if(valid_words < block_length){
259 ClearErrorMessage();
260 err_mess << "Error reading in EVIO entire block! (block number: " << buff[1] << ")" << endl;
261 err_mess << "valid_words="<<valid_words << " block_length=" << block_length;
262 err_code = HDEVIO_FILE_TRUNCATED;
263 Nerrors++;
264 return false;
265 }
266
267 // Set pointers
268 buff_len = valid_words;
269 buff_end = &buff[valid_words];
270 next = &buff[8];
271 bh = (BLOCKHEADER_t*)buff;
272
273 Nblocks++;
274 return true;
275}
276
277//---------------------------------
278// read
279//---------------------------------
280bool HDEVIO::read(uint32_t *user_buff, uint32_t user_buff_len, bool allow_swap)
281{
282 /// Read the next EVIO event into the user supplied buffer.
283 /// Return true if successful and false otherwise. Details of
284 /// the error will be in err_mess.
285
286 // If only certain event types are requested then
287 // defer to the sparse reader
288 if(event_type_mask != 0xFFFF){
289 return readSparse(user_buff, user_buff_len, allow_swap);
290 }
291
292 err_code = HDEVIO_OK;
293
294 // calculate remaining valid words in buffer
295 uint32_t left = buff_len - (uint32_t)(((unsigned long)next - (unsigned long)buff)/sizeof(uint32_t));
296
297 // Read in another event block if necessary
298 if(left < 1 || next==NULL__null){
299 bool isgood = ReadBlock();
300 if(!isgood) return false;
301 left = buff_len - 8;
302 }
303
304 if(next == NULL__null){
305 SetErrorMessage("No valid events in buffer");
306 err_code = HDEVIO_NO_EVENTS_IN_BUFFER;
307 return false;
308 }
309
310 // Check if next event will fit into user supplied buffer
311 uint32_t event_len = next[0];
312 if(swap_needed) swap_block(&event_len, 1, &event_len);
313 event_len++; // include length word for EVIO bank
314 last_event_len = event_len;
315
316 // Check that event isn't claiming to be larger than EVIO block
317 if( event_len > left ){
318 ClearErrorMessage();
319 err_mess << "WARNING: EVIO bank indicates a bigger size than block header (" << event_len << " > " << left << ")";
320 next = &buff[buff_len]; // setup so subsequent call will read in another block
321 err_code = HDEVIO_EVENT_BIGGER_THAN_BLOCK;
322 Nerrors++;
323 Nbad_blocks++;
324 return false;
325 }
326
327 // Check if user buffer is big enough to hold this
328 if(event_len > user_buff_len){
329 ClearErrorMessage();
330 err_mess << "user buffer too small for event (" << user_buff_len << " < " << event_len << ")";
331 err_code = HDEVIO_USER_BUFFER_TOO_SMALL;
332 return false;
333 }
334
335 // Copy entire event into user buffer, swapping if needed during copy
336 bool isgood = true;
337 if(swap_needed && allow_swap){
338 uint32_t Nswapped = swap_bank(user_buff, next, event_len);
339 isgood = (Nswapped == event_len);
340 }else{
341 memcpy(user_buff, next, event_len*sizeof(uint32_t));
342 }
343
344 // Advance next pointer to next EVIO event or past end of buffer.
345 next = &next[event_len];
346
347 if(isgood) Nevents++;
348
349 return isgood;
350}
351
352//---------------------------------
353// readSparse
354//---------------------------------
355bool HDEVIO::readSparse(uint32_t *user_buff, uint32_t user_buff_len, bool allow_swap)
356{
357 /// This is an alternative to the read(...) method above that
358 /// is used when the user has specified that only certain
359 /// event types are desired. This really only makes sense
360 /// for EPICS and SYNC events. This method does not use the
361 /// fbuff system and instead reads directly from the file
362 /// after seeking to the desired location determined from
363 /// a previously generated map.
364
365 err_code = HDEVIO_OK;
366 ClearErrorMessage();
367
368 // Make sure we've mapped this file
369 if(!is_mapped) MapBlocks();
370
371 // Loop over all events of all blocks looking for the next
372 // event matching the currently set type mask.
373 for(; sparse_block_iter!=evio_blocks.end(); sparse_block_iter++, sparse_event_idx = 0){
374
375 // Filter out blocks of the wrong type
376 EVIOBlockRecord &br = *sparse_block_iter;
377 uint32_t type = (1 << br.block_type);
378
379 for(; sparse_event_idx < br.evio_events.size(); sparse_event_idx++){
380 EVIOEventRecord &er = sparse_block_iter->evio_events[sparse_event_idx];
381
382 uint32_t etype = (1 << er.event_type);
383 if( etype & event_type_mask ) break;
384 }
385 if(sparse_event_idx >= br.evio_events.size()) continue;
386
387 EVIOEventRecord &er = sparse_block_iter->evio_events[sparse_event_idx];
388
389 uint32_t event_len = er.event_len;
390 last_event_len = event_len;
391
392 // Check if user buffer is big enough to hold block
393 if( event_len > user_buff_len ){
394 ClearErrorMessage();
395 err_mess << "user buffer too small for event (" << user_buff_len << " < " << event_len << ")";
396 err_code = HDEVIO_USER_BUFFER_TOO_SMALL;
397 return false;
398 }
399
400 // At this point we're committed to reading this event so go
401 // ahead and increment pointer to next event so no matter
402 // what happens below, we don't try reading it again.
403 sparse_event_idx++;
404
405 // Set file pointer to start of EVIO event (NOT block header!)
406 last_event_pos = er.pos;
407 ifs.seekg(last_event_pos, ios_base::beg);
408
409 // Read data directly into user buffer
410 ifs.read((char*)user_buff, event_len*sizeof(uint32_t));
411
412 // Swap entire bank if needed
413 swap_needed = br.swap_needed; // set flag in HDEVIO
414 bool isgood = true;
415 if(br.swap_needed && allow_swap){
416 uint32_t Nswapped = swap_bank(user_buff, user_buff, event_len);
417 isgood = (Nswapped == event_len);
418 }
419
420 // Double check that event length matches EVIO block header
421 // but only if we either don't need to swap or need to and
422 // were allowed to (otherwise, the test will almost certainly
423 // fail!)
424 if( (!br.swap_needed) || (br.swap_needed && allow_swap) ){
425 if( (user_buff[0]+1) != event_len ){
426 ClearErrorMessage();
427 err_mess << "WARNING: EVIO bank indicates a different size than block header (" << event_len << " != " << (user_buff[0]+1) << ")";
428 err_code = HDEVIO_EVENT_BIGGER_THAN_BLOCK;
429 Nerrors++;
430 Nbad_blocks++;
431 return false;
432 }
433 }
434
435 if(isgood) Nevents++;
436
437 return isgood;
438 }
439
440 // If we got here then we did not find an event of interest
441 // above. Report that there are no more events in the file.
442 SetErrorMessage("No more events");
443 err_code = HDEVIO_EOF;
444 return false; // isgood=false
445}
446
447//---------------------------------
448// readNoFileBuff
449//---------------------------------
450bool HDEVIO::readNoFileBuff(uint32_t *user_buff, uint32_t user_buff_len, bool allow_swap)
451{
452 /// This is an alternative to the read(...) method above that
453 /// does not use a large primary file buffer. A single EVIO
454 /// header is read in at a time and the events within the block
455 /// mapped just like when using readSparse. The difference is
456 /// that here, only a single block is mapped at a time rather
457 /// than trying to map the entire file before starting. This
458 /// gives a faster start up. This may be quicker for most
459 /// desktop filesystems but may be slower for Lustre file systems
460 /// that are configured for large volume data transfers and show
461 /// perfomance degredation with small reads.
462
463 err_code = HDEVIO_OK;
464 ClearErrorMessage();
465
466 // Check if we need to read in a block header using the
467 // current file position
468 EVIOBlockRecord &br = NB_block_record;
469 if(br.evio_events.empty()){
470
471 // read EVIO block header
472 BLOCKHEADER_t bh;
473 ifs.seekg( NB_next_pos, ios_base::beg);
474 ifs.read((char*)&bh, sizeof(bh));
475 if(!ifs.good()){
476 err_code = HDEVIO_FILE_TRUNCATED;
477 return false;
478 }
479
480 // Check if we need to byte swap and simultaneously
481 // verify header is good by checking magic word
482 bool swap_needed = false;
483 if(bh.magic==0x0001dac0){
484 swap_needed = true;
485 }else{
486 if(bh.magic!=0xc0da0100){
487 err_mess.str() = "Bad magic word";
488 err_code = HDEVIO_BAD_BLOCK_HEADER;
489 return false;
490 }
491 }
492
493 if(swap_needed)swap_block((uint32_t*)&bh, sizeof(bh)>>2, (uint32_t*)&bh);
494
495 Nblocks++;
496 streampos pos = ifs.tellg() - (streampos)sizeof(bh);
497
498 if( (uint64_t)(pos+(streampos)bh.length) > total_size_bytes ){
499 err_mess << "EVIO block extends past end of file!";
500 err_code = HDEVIO_FILE_TRUNCATED;
501 return false;
502 }
503
504 br.pos = pos;
505 br.block_len = bh.length;
506 br.swap_needed = swap_needed;
507 br.first_event = 0;
508 br.last_event = 0;
509
510 MapEvents(bh, br);
511
512 NB_next_pos = pos + (streampos)(bh.length<<2);
513 }
514
515 // Check if we did not find an event of interest above.
516 // If not, report that there are no more events in the file.
517 if(br.evio_events.empty() || !ifs.good()){
518 SetErrorMessage("No more events");
519 err_code = HDEVIO_EOF;
520 return false; // isgood=false
521 }
522
523 // Grab next event record
524 EVIOEventRecord &er = br.evio_events.front();
525
526 uint32_t event_len = er.event_len;
527 last_event_len = event_len;
528
529 // Check if user buffer is big enough to hold block
530 if( event_len > user_buff_len ){
531 ClearErrorMessage();
532 err_mess << "user buffer too small for event (" << user_buff_len << " < " << event_len << ")";
533 err_code = HDEVIO_USER_BUFFER_TOO_SMALL;
534 return false;
535 }
536
537 // Set file pointer to start of EVIO event (NOT block header!)
538 last_event_pos = er.pos;
539 ifs.seekg(last_event_pos, ios_base::beg);
540
541 // Read data directly into user buffer
542 ifs.read((char*)user_buff, event_len*sizeof(uint32_t));
543 if(!ifs.good()){
544 SetErrorMessage("No more events");
545 err_code = HDEVIO_EOF;
546 return false; // isgood=false
547 }
548
549 // Remove EVIO Event record, effectively advancing to
550 // next event for the next time we're called
551 br.evio_events.erase(NB_block_record.evio_events.begin());
552
553 // Swap entire bank if needed
554 swap_needed = br.swap_needed; // set flag in HDEVIO
555 bool isgood = true;
556 if(br.swap_needed && allow_swap){
557 uint32_t Nswapped = swap_bank(user_buff, user_buff, event_len);
558 isgood = (Nswapped == event_len);
559 }
560
561 // Double check that event length matches EVIO block header
562 // but only if we either don't need to swap or need to and
563 // were allowed to (otherwise, the test will almost certainly
564 // fail!)
565 if( (!br.swap_needed) || (br.swap_needed && allow_swap) ){
566 if( (user_buff[0]+1) != event_len ){
567 ClearErrorMessage();
568 err_mess << "WARNING: EVIO bank indicates a different size than block header (" << event_len << " != " << (user_buff[0]+1) << ")";
569 err_code = HDEVIO_EVENT_BIGGER_THAN_BLOCK;
570 Nerrors++;
571 Nbad_blocks++;
572 return false;
573 }
574 }
575
576 if(isgood) Nevents++;
577
578 return isgood;
579}
580
581//------------------------
582// rewind
583//------------------------
584void HDEVIO::rewind(void)
585{
586 /// This can be used whe reading from a file to
587 /// reset the file pointer and other position holders
588 /// to the begining of the file. This is done when
589 /// the "LOOP_FOREVER" option is used in the event source
590 /// to continuously re-read a file, essesntially making
591 /// it an infinite stream of events that can be used for
592 /// testing.
593
594 ifs.seekg(0, ios_base::beg);
595 ifs.clear();
596
597 sparse_block_iter = evio_blocks.begin();
598 sparse_event_idx = 0;
599
600 NB_block_record.evio_events.clear();
601 NB_next_pos = 0;
602
603 ClearErrorMessage();
604 err_code = HDEVIO_OK;
605}
606
607//------------------------
608// SetEventMask
609//------------------------
610uint32_t HDEVIO::SetEventMask(uint32_t mask)
611{
612 uint32_t prev_mask = event_type_mask;
613 event_type_mask = mask;
614
615 return prev_mask;
616}
617
618//------------------------
619// SetEventMask
620//------------------------
621uint32_t HDEVIO::SetEventMask(string types_str)
622{
623 uint32_t prev_mask = event_type_mask;
624
625 event_type_mask = 0;
626 if(types_str.find("BOR" ) != string::npos) event_type_mask |= (1<<kBT_BOR);
627 if(types_str.find("EPICS" ) != string::npos) event_type_mask |= (1<<kBT_EPICS);
628 if(types_str.find("PHYSICS") != string::npos) event_type_mask |= (1<<kBT_PHYSICS);
629
630 return prev_mask;
631}
632
633//------------------------
634// AddToEventMask
635//------------------------
636uint32_t HDEVIO::AddToEventMask(string type_str)
637{
638 return 0;
639}
640
641//------------------------
642// GetEVIOBlockRecords
643//------------------------
644vector<HDEVIO::EVIOBlockRecord>& HDEVIO::GetEVIOBlockRecords(void)
645{
646 if(!is_mapped) MapBlocks();
647
648 return evio_blocks;
649}
650
651//------------------------
652// MapBlocks
653//------------------------
654void HDEVIO::MapBlocks(bool print_ticker)
655{
656 if(!is_open){
657 err_mess.str() = "File is not open";
658 err_code = HDEVIO_FILE_NOT_OPEN;
659 return;
660 }
661
662 // Remember current file pos so we can restore it.
663 streampos start_pos = ifs.tellg();
664
665 if(print_ticker) cout << "Mapping EVIO file ..." << endl;
666
667 // Rewind to beginning of file and loop over all blocks
668 ifs.seekg(0, ios_base::beg);
669 BLOCKHEADER_t bh;
670 uint64_t Nblocks = 0;
671 while(ifs.good()){
672 ifs.read((char*)&bh, sizeof(bh));
673 if(!ifs.good()) break;
674
675 // Check if we need to byte swap and simultaneously
676 // verify header is good by checking magic word
677 bool swap_needed = false;
678 if(bh.magic==0x0001dac0){
679 swap_needed = true;
680 }else{
681 if(bh.magic!=0xc0da0100){
682 err_mess.str() = "Bad magic word";
683 err_code = HDEVIO_BAD_BLOCK_HEADER;
684 break;
685 }
686 }
687
688 if(swap_needed)swap_block((uint32_t*)&bh, sizeof(bh)>>2, (uint32_t*)&bh);
689
690 Nblocks++;
691 streampos block_len_bytes = (bh.length<<2)-sizeof(bh); // <<2 is for *4
692 streampos pos = ifs.tellg() - (streampos)sizeof(bh);
693
694 EVIOBlockRecord br;
695 br.pos = pos;
696 br.block_len = bh.length;
697 br.swap_needed = swap_needed;
698 br.first_event = 0;
699 br.last_event = 0;
700
701 // Categorize this block
702 uint32_t tag = bh.header>>16;
703 uint32_t M = bh.header&0xFF;
704
705 switch(tag){
706 case 0xFFD0: br.block_type = kBT_SYNC; break;
707 case 0xFFD1: br.block_type = kBT_PRESTART; break;
708 case 0xFFD2: br.block_type = kBT_GO; break;
709 case 0xFFD3: br.block_type = kBT_PAUSE; break;
710 case 0xFFD4: br.block_type = kBT_END; break;
711 case 0x0060: br.block_type = kBT_EPICS; break;
712 case 0x0070: br.block_type = kBT_BOR; break;
713 case 0xFF50:
714 case 0xFF51:
715 case 0xFF70:
716 br.block_type = kBT_PHYSICS;
717 br.first_event = bh.physics.first_event_lo;
718 br.first_event += ((uint64_t)bh.physics.first_event_hi)<<32;
719 br.last_event = br.first_event + (uint64_t)M - 1;
720 break;
721 default:
722 _DBG_cout<<"libraries/DAQ/HDEVIO.cc"<<":"<<722<<
" "
<< "Uknown tag: " << hex << tag << dec << endl;
723 }
724
725 // Scan through and map all events within this block
726 MapEvents(bh, br);
727
728 // Add block to list
729 evio_blocks.push_back(br);
730
731 // Update ticker
732 if(print_ticker){
733 if((Nblocks%500) == 0){
734 uint64_t total_MB = total_size_bytes>>20;
735 uint64_t read_MB = ifs.tellg()>>20;
736 if(Nblocks==0) cout << endl;
737 cout << Nblocks << " blocks scanned (" << read_MB << "/" << total_MB << " MB " << (100*read_MB/total_MB) << "%) \r";
738 cout.flush();
739 }
740 }
741
742 // Advance file pointer to start of next EVIO block header
743 ifs.seekg(block_len_bytes, ios_base::cur);
744 }
745
746 if(print_ticker) cout << endl;
747
748 // Setup iterators for sparse reading
749 sparse_block_iter = evio_blocks.begin();
750 sparse_event_idx = 0;
751
752 // Restore file pos and set flag that file has been mapped
753 ifs.clear();
754 ifs.seekg(start_pos, ios_base::beg);
755 is_mapped = true;
756}
757
758//---------------------------------
759// MapEvents
760//---------------------------------
761void HDEVIO::MapEvents(BLOCKHEADER_t &bh, EVIOBlockRecord &br)
762{
763 /// This is called if the EVIO block header indicates that
764 /// it contains more than one top-level event. The position
765 /// and event length of the first top-level event are passed
766 /// in as starting parameters.
767
768 // Record stream position upon entry so we can restore it at end
769 streampos start_pos = ifs.tellg();
770
771 // Calculate stream position of EVIO event
772 streampos pos = start_pos -(streampos)sizeof(BLOCKHEADER_t) + (streampos)(8<<2); // (8<<2) is 8 word EVIO block header times 4bytes/word
773 ifs.seekg(pos, ios_base::beg);
774
775 EVENTHEADER_t myeh;
776 for(uint32_t i=0; i<bh.eventcnt; i++){
777
778 // For the first iteration through this loop,
779 // we use the event header that has already been
780 // read in as part of the block header.
781 EVENTHEADER_t *eh = (EVENTHEADER_t*)&bh.event_len;
782 if(i!=0){
783 // Read in first few words of event
784 eh = &myeh;
785 ifs.read((char*)eh, sizeof(EVENTHEADER_t));
786 if(!ifs.good()) break;
787 if(br.swap_needed)swap_block((uint32_t*)eh, sizeof(EVENTHEADER_t)>>2, (uint32_t*)eh);
788 }else{
789 ifs.seekg(sizeof(EVENTHEADER_t), ios_base::cur);
790 }
791
792 EVIOEventRecord er;
793 er.pos = pos;
794 er.event_len = eh->event_len + 1; // +1 to include length word
795 er.event_type = kBT_UNKNOWN;
796 er.first_event = 0;
797 er.last_event = 0;
798
799 uint32_t tag = eh->header>>16;
800 uint32_t M = eh->header&0xFF;
801
802 switch(tag){
803 case 0xFFD0: er.event_type = kBT_SYNC; break;
804 case 0xFFD1: er.event_type = kBT_PRESTART; break;
805 case 0xFFD2: er.event_type = kBT_GO; break;
806 case 0xFFD3: er.event_type = kBT_PAUSE; break;
807 case 0xFFD4: er.event_type = kBT_END; break;
808 case 0x0060: er.event_type = kBT_EPICS; break;
809 case 0x0070: er.event_type = kBT_BOR; break;
810 case 0xFF50:
811 case 0xFF51:
812 case 0xFF70:
813 er.event_type = kBT_PHYSICS;
814 er.first_event = eh->physics.first_event_lo;
815 er.first_event += ((uint64_t)eh->physics.first_event_hi)<<32;
816 er.last_event = er.first_event + (uint64_t)M - 1;
817 if(er.first_event < br.first_event) br.first_event = er.first_event;
818 if(er.last_event > br.last_event ) br.last_event = er.last_event;
819 break;
820 default:
821 _DBG_cout<<"libraries/DAQ/HDEVIO.cc"<<":"<<821<<
" "
<< "Uknown tag: " << hex << tag << dec << endl;
822 }
823
824 br.evio_events.push_back(er);
825
826 // Move file position to start of next event
827 streampos delta = (streampos)((eh->event_len+1)<<2) - (streampos)sizeof(EVENTHEADER_t);
828 ifs.seekg(delta, ios_base::cur);
829 pos += (streampos)((eh->event_len+1)<<2);
830 }
831
832 ifs.seekg(start_pos, ios_base::beg);
833}
834
835//---------------------------------
836// swap_bank
837//---------------------------------
838uint32_t HDEVIO::swap_bank(uint32_t *outbuff, uint32_t *inbuff, uint32_t len)
839{
840 /// Swap an EVIO bank. If the bank contains data, it is automatically
841 /// swapped according to it's type. If the bank is a container of other
842 /// containers, then this repeatedly calls the swapper methods for the
843 /// appropriate container type (bank, tagsegment, segment). This means
844 /// that this method will be recursive in the cases where it is a bank
845 /// of banks.
846
847 if(len < 2){
848 SetErrorMessage("Attempt to swap bank with len<2");
849 err_code = HDEVIO_BANK_TRUNCATED;
850 Nerrors++;
851 Nbad_events++;
852 return 0;
853 }
854
855 // Swap length and header words
856 swap_block(inbuff, 2, outbuff);
857 uint32_t bank_len = outbuff[0];
858 if((bank_len+1) > len){
859 ClearErrorMessage();
860 err_mess << "WARNING: Bank length word exceeds valid words in buffer (" << bank_len+1 << " > " << len << ")";
861 err_code = HDEVIO_BANK_TRUNCATED;
862 Nerrors++;
863 Nbad_events++;
864 return 0;
865 }
866
867 uint32_t type = (outbuff[1]>>8) & 0xFF;
868 uint32_t Nwords = bank_len - 1;
869 uint32_t Nswapped = 2;
870 switch(type){
871 case 0x0a: // 64 bit unsigned int
872 case 0x08: // 64 bit double
873 case 0x09: // 64 bit signed int
874 swap_block((uint64_t*)&inbuff[2], Nwords/2, (uint64_t*)&outbuff[2]);
875 Nswapped += Nwords;
876 break;
877 case 0x01: // 32 bit unsigned int
878 case 0x02: // 32 bit float
879 case 0x0b: // 32 bit signed int
880 swap_block(&inbuff[2], Nwords, &outbuff[2]);
881 Nswapped += Nwords;
882 break;
883 case 0x05: // 16 bit unsigned int
884 case 0x04: // 16 bit signed int
885 swap_block((uint16_t*)&inbuff[2], Nwords*2, (uint16_t*)&outbuff[2]);
886 Nswapped += Nwords;
887 break;
888 case 0x00: // 32 bit unknown (not swapped)
889 case 0x07: // 8 bit unsigned int
890 case 0x06: // 8 bit signed int
891 memcpy((uint8_t*)&outbuff[2], (uint8_t*)&inbuff[2], Nwords*sizeof(uint32_t));
892 Nswapped += Nwords;
893 break;
894 case 0x0c:
895 while(Nswapped < (Nwords+2)){
896 uint32_t N = swap_tagsegment(&outbuff[Nswapped], &inbuff[Nswapped], (Nwords+2)-Nswapped);
897 if(N == 0) return Nswapped;
898 Nswapped += N;
899 }
900 break;
901 case 0x0d:
902 case 0x20:
903 while(Nswapped < (Nwords+2)){
904 uint32_t N = swap_segment(&outbuff[Nswapped], &inbuff[Nswapped], (Nwords+2)-Nswapped);
905 if(N == 0) return Nswapped;
906 Nswapped += N;
907 }
908 break;
909 case 0x0e:
910 case 0x10:
911 while(Nswapped < (Nwords+2)){
912 uint32_t N = swap_bank(&outbuff[Nswapped], &inbuff[Nswapped], (Nwords+2)-Nswapped);
913 if(N == 0) return Nswapped;
914 Nswapped += N;
915 }
916 break;
917 default:
918 ClearErrorMessage();
919 err_mess << "WARNING: unknown bank type (0x" << hex << type << dec << ")";
920 err_code = HDEVIO_UNKNOWN_BANK_TYPE;
921 Nerrors++;
922 Nbad_events++;
923 return 0;
924 break;
925 }
926
927 return Nswapped;
928}
929
930//---------------------------------
931// swap_tagsegment
932//---------------------------------
933uint32_t HDEVIO::swap_tagsegment(uint32_t *outbuff, uint32_t *inbuff, uint32_t len)
934{
935 /// Swap an EVIO tagsegment.
936
937 if(len < 1){
938 SetErrorMessage("Attempt to swap segment with len<1");
939 err_code = HDEVIO_BANK_TRUNCATED;
940 Nerrors++;
941 Nbad_events++;
942 return 0;
943 }
944
945 // Swap header/length word
946 swap_block(inbuff, 1, outbuff);
947 uint32_t bank_len = outbuff[0] & 0xFFFF;
948 if((bank_len) > len){
949 ClearErrorMessage();
950 err_mess << "Segment length word exceeds valid words in buffer (" << bank_len << " > " << len << ")";
951 err_code = HDEVIO_BANK_TRUNCATED;
952 Nerrors++;
953 Nbad_events++;
954 return 0;
955 }
956
957 uint32_t type = (outbuff[0]>>16) & 0x0F;
958 uint32_t Nwords = bank_len;
959 uint32_t Nswapped = 1;
960 switch(type){
961 case 0x0a: // 64 bit unsigned int
962 case 0x08: // 64 bit double
963 case 0x09: // 64 bit signed int
964 swap_block((uint64_t*)&inbuff[1], Nwords/2, (uint64_t*)&outbuff[1]);
965 Nswapped += Nwords;
966 break;
967 case 0x01: // 32 bit unsigned int
968 case 0x02: // 32 bit float
969 case 0x0b: // 32 bit signed int
970 swap_block(&inbuff[1], Nwords, &outbuff[1]);
971 Nswapped += Nwords;
972 break;
973 case 0x05: // 16 bit unsigned int
974 case 0x04: // 16 bit signed int
975 swap_block((uint16_t*)&inbuff[1], Nwords*2, (uint16_t*)&outbuff[1]);
976 Nswapped += Nwords;
977 break;
978 case 0x00: // 32 bit unknown (not swapped)
979 case 0x07: // 8 bit unsigned int
980 case 0x06: // 8 bit signed int
981 memcpy((uint8_t*)&outbuff[1], (uint8_t*)&inbuff[1], Nwords*sizeof(uint32_t));
982 Nswapped += Nwords;
983 break;
984 }
985
986 return Nswapped;
987}
988
989//---------------------------------
990// swap_segment
991//---------------------------------
992uint32_t HDEVIO::swap_segment(uint32_t *outbuff, uint32_t *inbuff, uint32_t len)
993{
994 /// Swap an EVIO segment.
995
996 if(len < 1){
997 SetErrorMessage("Attempt to swap segment with len<1");
998 err_code = HDEVIO_BANK_TRUNCATED;
999 Nerrors++;
1000 Nbad_events++;
1001 return 0;
1002 }
1003
1004 // Swap header/length word
1005 swap_block(inbuff, 1, outbuff);
1006 uint32_t bank_len = outbuff[0] & 0xFFFF;
1007 if((bank_len) > len){
1008 ClearErrorMessage();
1009 err_mess << "Segment length word exceeds valid words in buffer (" << bank_len << " > " << len << ")";
1010 err_code = HDEVIO_BANK_TRUNCATED;
1011 Nerrors++;
1012 Nbad_events++;
1013 return 0;
1014 }
1015
1016 uint32_t type = (outbuff[0]>>16) & 0x3F;
1017 uint32_t Nwords = bank_len;
1018 uint32_t Nswapped = 1;
1019 switch(type){
1020 case 0x0a: // 64 bit unsigned int
1021 case 0x08: // 64 bit double
1022 case 0x09: // 64 bit signed int
1023 swap_block((uint64_t*)&inbuff[1], Nwords/2, (uint64_t*)&outbuff[1]);
1024 Nswapped += Nwords;
1025 break;
1026 case 0x01: // 32 bit unsigned int
1027 case 0x02: // 32 bit float
1028 case 0x0b: // 32 bit signed int
1029 swap_block(&inbuff[1], Nwords, &outbuff[1]);
1030 Nswapped += Nwords;
1031 break;
1032 case 0x05: // 16 bit unsigned int
1033 case 0x04: // 16 bit signed int
1034 swap_block((uint16_t*)&inbuff[1], Nwords*2, (uint16_t*)&outbuff[1]);
1035 Nswapped += Nwords;
1036 break;
1037 case 0x00: // 32 bit unknown (not swapped)
1038 case 0x07: // 8 bit unsigned int
1039 case 0x06: // 8 bit signed int
1040 memcpy((uint8_t*)&outbuff[1], (uint8_t*)&inbuff[1], Nwords*sizeof(uint32_t));
1041 Nswapped += Nwords;
1042 break;
1043 }
1044
1045 return Nswapped;
1046}
1047
1048//------------------------
1049// Print_fbuff
1050//------------------------
1051void HDEVIO::Print_fbuff(void)
1052{
1053 cout << endl;
1054 cout << " fbuff: " << hex << (uint64_t)fbuff << dec << endl;
1055 cout << " fnext: " << hex << (uint64_t)fnext << dec << endl;
1056 cout << " fbuff_end: " << hex << (uint64_t)fbuff_end << dec << endl;
1057 cout << " fbuff_size: " << fbuff_size << endl;
1058 cout << " fbuff_len: " << fbuff_len << endl;
1059 cout << " _gcount: " << _gcount << endl;
1060}
1061
1062//------------------------
1063// PrintEVIOBlockHeader
1064//------------------------
1065void HDEVIO::PrintEVIOBlockHeader(void)
1066{
1067
1068 cout << endl;
1069 cout << "EVIO Block Header:" << endl;
1070 cout << "------------------------" << endl;
1071 cout << " Block Length: " << HexStr(buff[0]) << " (" << buff[0] << " words = " << (buff[0]>>(10-2)) << " kB)" << endl;
1072 cout << " Block Number: " << HexStr(buff[1]) << endl;
1073 cout << "Header Length: " << HexStr(buff[2]) << " (should be 8)" << endl;
1074 cout << " Event Count: " << HexStr(buff[3]) << endl;
1075 cout << " Reserved 1: " << HexStr(buff[4]) << endl;
1076 cout << " Bit Info: " << HexStr(buff[5]>>8) << endl;
1077 cout << " Version: " << HexStr(buff[5]&0xFF) << endl;
1078 cout << " Reserved 3: " << HexStr(buff[6]) << endl;
1079 cout << " Magic word: " << HexStr(buff[7]) << (swap_needed ? " (after swapping)":"") << endl;
1080 cout << "Byte swapping is" << (swap_needed ? " ":" not ") << "needed" << endl;
1081}
1082
1083//------------------------
1084// PrintStats
1085//------------------------
1086void HDEVIO::PrintStats(void)
1087{
1088 cout << endl;
1089 cout << "EVIO Statistics for " << filename << " :" << endl;
1090 cout << "------------------------" << endl;
1091 cout << " Nblocks: " << Nblocks << endl;
1092 cout << " Nevents: " << Nevents << endl;
1093 cout << " Nerrors: " << Nerrors << endl;
1094 cout << "Nbad_blocks: " << Nbad_blocks << endl;
1095 cout << "Nbad_events: " << Nbad_events << endl;
1096 cout << endl;
1097}
1098
1099//------------------------
1100// PrintFileSummary
1101//------------------------
1102void HDEVIO::PrintFileSummary(void)
1103{
1104 if(!is_mapped) MapBlocks();
1105
1106 uint32_t Nsync = 0;
1107 uint32_t Nprestart = 0;
1108 uint32_t Ngo = 0;
1109 uint32_t Npause = 0;
1110 uint32_t Nend = 0;
1111 uint32_t Nepics = 0;
1112 uint32_t Nbor = 0;
1113 uint32_t Nphysics = 0;
1114
1115 uint64_t first_event = 0;
1116 uint64_t last_event = 0;
1117
1118 uint32_t map_size = evio_blocks.size()*sizeof(EVIOBlockRecord);
1119
1120 set<uint32_t> block_levels;
1121 set<uint32_t> events_in_block;
1122
1123 // Loop over all EVIO block records
1124 for(uint32_t i=0; i<evio_blocks.size(); i++){
1125 EVIOBlockRecord &br = evio_blocks[i];
1126 events_in_block.insert(br.evio_events.size());
1127 map_size += br.evio_events.size()*sizeof(EVIOEventRecord);
1128
1129 for(uint32_t j=0; j<br.evio_events.size(); j++){
1130 EVIOEventRecord &er = br.evio_events[j];
1131
1132 uint32_t block_level;
1133 switch(er.event_type){
1134 case kBT_SYNC: Nsync++; break;
1135 case kBT_PRESTART: Nprestart++; break;
1136 case kBT_GO: Ngo++; break;
1137 case kBT_PAUSE: Npause++; break;
1138 case kBT_END: Nend++; break;
1139 case kBT_EPICS: Nepics++; break;
1140 case kBT_BOR: Nbor++; break;
1141 case kBT_PHYSICS:
1142 block_level = (uint32_t)((er.last_event - er.first_event) + 1);
1143 block_levels.insert(block_level);
1144 Nphysics += block_level;
1145 if(er.first_event<first_event || first_event==0) first_event = er.first_event;
1146 if(er.last_event>last_event) last_event = er.last_event;
1147 break;
1148 default:
1149 break;
1150 }
1151
1152 //_DBG_ << "Block " << i << " event " << j << " " << er.last_event <<" - " << er.first_event << " = " << block_level << endl;
1153 }
1154 }
1155
1156 // form succint string of block levels
1157 stringstream ss;
1158 set<uint32_t>::iterator it = block_levels.begin();
1159 for(; it!=block_levels.end(); it++) ss << *it << ",";
1160 string sblock_levels = ss.str();
1161 if(!sblock_levels.empty()) sblock_levels.erase(sblock_levels.length()-1);
1162
1163 // form succint string of events per block
1164 ss.str("");
1165 it = events_in_block.begin();
1166 for(; it!=events_in_block.end(); it++){
1167 uint32_t val = *it;
1168 ss << val;
1169 if(++it==events_in_block.end()) break;
1170 if( *it == ++val ){
1171 ss << "-";
1172 for(it++; it!=events_in_block.end(); it++){
1173 if( *it != ++val ){
1174 ss << (val-1) << ",";
1175 it--;
1176 break;
1177 }
1178 }
1179 }else{
1180 ss << ",";
1181 }
1182 if( it==events_in_block.end() ) break;
1183 }
1184 string sevents_in_block = ss.str();
1185
1186 // Print results
1187 cout << endl;
1188 cout << "EVIO file size: " << (total_size_bytes>>20) << " MB" <<endl;
1189 cout << "EVIO block map size: " << (map_size>>10) << " kB" <<endl;
1190 cout << "first event: " << first_event << endl;
1191 cout << "last event: " << last_event << endl;
1192
1193 cout << endl;
1194 cout << " Nblocks = " << evio_blocks.size() << endl;
1195 cout << " block levels = " << sblock_levels << endl;
1196 cout << "events per block = " << sevents_in_block << endl;
1197 cout << " Nsync = " << Nsync << endl;
1198 cout << " Nprestart = " << Nprestart << endl;
1199 cout << " Ngo = " << Ngo << endl;
1200 cout << " Npause = " << Npause << endl;
1201 cout << " Nend = " << Nend << endl;
1202 cout << " Nepics = " << Nepics << endl;
1203 cout << " Nbor = " << Nbor << endl;
1204 cout << " Nphysics = " << Nphysics << endl;
1205 cout << endl;
1206}
1207
1208