Bug Summary

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