File: | libraries/DAQ/HDEVIO.cc |
Location: | line 98, column 2 |
Description: | Value stored to 'left' is never read |
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 | //--------------------------------- |
16 | HDEVIO::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 | //--------------------------------- |
67 | HDEVIO::~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 | //--------------------------------- |
77 | void 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 | //--------------------------------- |
142 | void 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 | //--------------------------------- |
189 | bool 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 | //--------------------------------- |
278 | bool 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 | //--------------------------------- |
353 | bool 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 | //------------------------ |
428 | uint32_t HDEVIO::SetEventMask(uint32_t mask) |
429 | { |
430 | return 0; |
431 | } |
432 | |
433 | //------------------------ |
434 | // SetEventMask |
435 | //------------------------ |
436 | uint32_t HDEVIO::SetEventMask(string types_str) |
437 | { |
438 | return 0; |
439 | } |
440 | |
441 | //------------------------ |
442 | // AddToEventMask |
443 | //------------------------ |
444 | uint32_t HDEVIO::AddToEventMask(string type_str) |
445 | { |
446 | return 0; |
447 | } |
448 | |
449 | //------------------------ |
450 | // GetEVIOBlockRecords |
451 | //------------------------ |
452 | vector<HDEVIO::EVIOBlockRecord>& HDEVIO::GetEVIOBlockRecords(void) |
453 | { |
454 | if(!is_mapped) MapBlocks(); |
455 | |
456 | return evio_blocks; |
457 | } |
458 | |
459 | //------------------------ |
460 | // MapBlocks |
461 | //------------------------ |
462 | void 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 | //--------------------------------- |
562 | void 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 | //--------------------------------- |
639 | uint32_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 | //--------------------------------- |
734 | uint32_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 | //--------------------------------- |
793 | uint32_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 | //------------------------ |
852 | void 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 | //------------------------ |
866 | void 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 | //------------------------ |
887 | void 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 | //------------------------ |
903 | void 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 |