Skip to content
Snippets Groups Projects

New and faster decoding versions

Merged Jeroen van Tilburg requested to merge dev-scifi-rawbankdecoder-noheaders-jvt into master

Requires MR!10 from SIMCOND.

Introduced new raw data format (v4 and v5). The new data format has no local headers for each SiPM anymore. This improves the decoding speed a lot. Also new is the partitioning (5 banks per quadrant instead of 1) and a global truncation header.

For backwards compatibility, the decoding can still decode the old data formats (v2 and v3). The difference between v4 and v5 is that in v5 the adjacent clusters (that are split by the FE) are merged back and that very wide clusters are recovered into many adjacent clusters. These extra operations are not done in v4, which makes it a little bit faster at the costs of a reduction in tracking performance (possible these extra operations can be done on the TELL40 in the future). The encoding works only for the v5 format. To run the v4 decoding on v5 data, a flag is introduced in FTRawBankDecoder (ForceVersion4).

At same time, the container format for the FTLiteClusters is changed from FastClusterContainer to MultiIndexedContainer.

Closes LHCBSCIFI-101.

@sesen @lohenry @rquaglia

Edited by Marco Cattaneo

Merge request reports

Loading
Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
43 FTNewRawBankDecoder::operator()(const LHCb::RawEvent& rawEvent) const
44 {
45 const auto& banks = rawEvent.banks(LHCb::RawBank::FTCluster);
46
47 // Simple loop over the banks to determine total number of clusters
48 // Bank size is half the number of clusters and includes headers
49 // No 0.4 scaling
50 // In the future, the #clusters should be encoded in raw bank.
51 FTLiteClusters clus;
52 int totSize = 0;
53 for ( const LHCb::RawBank* bank : banks) { totSize += bank->size();}
54 clus.reserve(totSize);
55
56 // Store partition points for quadrants for faster sorting
57 std::vector<int> partitionPoints;
58 partitionPoints.reserve(48); // 48 quadrants
  • In case you know you will need (upto) 48 values, either use std::array<int,48> (always 48) or boost::static_vector<int,48> (in case you sometimes need less than 48), both of which will avoid allocating memory on the heap.

  • Thanks! It's always 48 as far as I understood (3 stations, 4 layers, 4 quadrants). However, we want to fill it in order (using push_back then), so the boost solution looks much better.

    Edited by Louis Henry
  • Isn't there already header which defines eg NStations, NLayers and NQuadrants (to be 3,4 and 4 respectively)? In that case, I'd write this as std::array<int,NStations*NLayers*NQuadrants> -- and if not, I'd introduce those three constants first ;-)

    (note: these three constants should be qualified constexpr so that their product can be evaluated at compile-time)

  • OK I have implemented that! There is probably such a header but right now I have put that into FTRawBankParams.

  • Please register or sign in to reply
  • Gerhard Raven @graven started a thread on commit 0adcea1e
  • 128 short int c = *it;
    129 unsigned channel = ( c >> FTRawBank::cellShift ) & FTRawBank::cellMaximum;
    130 int fraction = ( c >> FTRawBank::fractionShift ) & FTRawBank::fractionMaximum;
    131 bool cSize = ( c >> FTRawBank::sizeShift ) & FTRawBank::sizeMaximum;
    132
    133 //not the last cluster
    134 if( !cSize && it<first+nClus-1 ){
    135 short int c2 = *(it+1);
    136 bool cSize2 = ( c2 >> FTRawBank::sizeShift ) & FTRawBank::sizeMaximum;
    137
    138 if( !cSize2 ){ //next cluster is not last fragment
    139 clus.emplace_back(LHCb::FTChannelID{ 0,0,uniqueQuarter,
    140 module, mat, sipm, channel },
    141 fraction, 4 );
    142
    143 if ( msgLevel( MSG::VERBOSE ) ) {
    • Putting if statements in a loop will not make it go faster. Please consider splitting things (duplicating!) into two loops: one which does the work, and one which just does the printout -- i.e. something like:

      
         const auto last  = bank->end<short int>();
         if (msgLevel(MSG::VERBOSE)) {
            auto first = bank->begin<short int>();
            while (first!=last) {
              // generate just the output
            }
         }
         auto first = bank->begin<short int>();
         while (first!=last) {
             // do the decoding without any verbose() output
         }
      }
      

      In case that generates to much 'duplicate code', then consider doing something along the lines of:

      
      enum class Verbose { True, False };
      
      FTLiteClusters
      FTNewRawBankDecoder::operator()(const LHCb::RawEvent& rawEvent) const {
         return msgLevel(MSG::VERBOSE) ? decode<Verbose::True>(rawEvent) : decode<Verbose::False>(rawEvent);
      }
      
      template <Verbose verbose>
      FTLiteClusters
      FTNewRawBankDecoder::decode( const LHCb::RawEvent& rawEvent) const {
      {
         // take current code in operator(), and replace 'msgLevel(MSG::VERBOSE)' with 'verbose==Verbose::True'
      }

      This will then generate two versions of decode, one 'slow' one with printout, and a 'fast' one without any printout, and do the check just once, and dispatch the relevant version.

    • That's probably the way to go (template coding rather than code duplication), bthanks a lot for the example! I will first go to a compiling/working version of the code though.

    • Please register or sign in to reply
  • Gerhard Raven @graven started a thread on commit 0adcea1e
  • 85 << " for source " << source << " size " << size << " bytes."
    86 << endmsg;
    87 throw GaudiException("Unsupported FT bank version",
    88 "FTNewRawBankDecoder",
    89 StatusCode::FAILURE);
    90 }
    91
    92 auto first = bank->begin<short int>();
    93 auto last = bank->end<short int>();
    94
    95 while( first != last ) {
    96 int sipmHeader = *first++;
    97 if ( first == last && sipmHeader == 0 ) continue; // padding at the end...
    98 unsigned modulesipm = sipmHeader >> FTRawBank::sipmShift ;
    99 unsigned module = modulesipm >> FTRawBank::sipmShift ;
    100 LHCb::FTChannelID chanModuleSiPM = m_ftReadoutTool->sipm(modulesipm);
    • Do you really need a separate tool to determine the channelID?

      One reason to have such a tool is if there are multiple implementation which you want to be able to interchange, and thus you need a well-defined interface (IFTReadoutTool in this case). But is there really more than one implementation necessary?

      Another reason would be if there would be another place where the same functionality is required, i.e. if the tool would be shared between algorithms. So the question then is, is that the case?

      If either of the two questions is yes, then there still remains the question on whether an interface which accepts a single unsigned, and returns an FTChannelID is optimal. For example, is it possible to return (a reference to) a (concrete) map (lookup table, ...) from modulesipm to (mat,sipm) which can be retrieved outside of the loop (and thus avoid a virtual function call inside the loop)

    • Leaving the two first questions to later, what do you have in mind? Another property of FTRawBankDecoder that point to an xml (probably linked to the DDDB) that makes the mapping FTChannelID -> (module/sipm/channelID), leaving only station/layer/quarter/mat to the logical operations we are performing?

    • What I have in mind is just to move the code currently in FTReadoutTool into this algorithm -- and if that takes another property here, then yes, that should be added. So what are the downsides of just doing that?

    • Please register or sign in to reply
  • Gerhard Raven @graven started a thread on commit 0adcea1e
  • 20 // Standard constructor, initializes variables
    21 //=============================================================================
    22 FTNewRawBankDecoder::FTNewRawBankDecoder( const std::string& name,
    23 ISvcLocator* pSvcLocator)
    24 : Transformer ( name , pSvcLocator,
    25 KeyValue{ "RawEventLocations",
    26 Gaudi::Functional::concat_alternatives( LHCb::RawEventLocation::Other,
    27 LHCb::RawEventLocation::Default )},
    28 KeyValue{ "OutputLocation", LHCb::FTLiteClusterLocation::Default } )
    29 { }
    30
    31 StatusCode FTNewRawBankDecoder::initialize()
    32 {
    33 StatusCode sc = Transformer::initialize();
    34 m_ftReadoutTool = tool<IFTReadoutTool>("FTReadoutTool",this);
    35 m_ftReadoutTool->initialize();
    • why must an instance of IFTReadoutTool be explicitly initialized? Can the implementation not figure this out itself?

    • I am unfamiliar with the Interface pattern, and its interplay with Gaudi. What would be the piece of code/framework that takes care of initialisation by itself? Thanks a lot for your helpful comments.

    • Looking at the contents of FTReadoutTool, I wonder why it is a separate tool, and not just substituted 'in situ' in this algorithm. What triggered me is the need for an initialize() method in the tool. That suggest that the code must be tied into the Gaudi state machine, and at that point, you have an algorithm, not a tool. Hence the questions below, which are aimed at figuring out what is really needed, and whether a tool is the right thing to implement this.

    • Please register or sign in to reply
  • Gerhard Raven @graven started a thread on commit 0adcea1e
  • 1 #ifndef FTNEWRAWBANKDECODER_H
    • I would avoid adjectives like 'New' instead class names, as it will look weird in a few years time (and what will you call the next version? FtNewerRawBankDecoder?)

      Instead, I'd put it in a namespace with a version number. And given that I think it would be good to put subsystem code in a dedicated namespace which is close to the package name, why not something like

      namespace LHCb { namespace FT { namespace DAQ {  
      
         namespace v2 {
      
         class RawBankDecoder : ...
      
         }
      
       } } }

      Ideally, all subsystems would adopt such a common namespace pattern... (and eg. Rich::DAQ does already exist ;-)

    • I did not know about the namespace pattern, that seems neat! Concerning the NewRawBankDecoder, this is temporary (and I mean, really temporary) because we don't know which version we want to use and I wanted to start working in parallel. As I still try to master the intricacies of GIT I did not want to use two branches.

    • Please register or sign in to reply
  • Jeroen van Tilburg
    Jeroen van Tilburg @jvantilb started a thread on commit b0136da6
  • 381 else{
    382 if( !cSize1 && it<last-1 && (getSipm(modulesipm) == getSipm(modulesipm2)))
    383 {
    385 384 make_clusters(firstChannel,c,c2);
    386 385 ++it;
    387 }//last edge found
    388 }//not the last cluster
    389
    390 else{ //last cluster, so nothing we can do
    391 make_cluster(source+modulesipm, fraction1, 4 );
    392 }//last cluster added
    393 }//end loop over clusters in one sipm
    394 }//end loop over rawbanks
    386 }
    387 else {//fragmented cluster, last edge found
    388 make_cluster(source+modulesipm, fraction1, 4 );
  • mentioned in merge request Rec!1072 (merged)

  • mentioned in merge request Boole!153 (merged)

  • Jeroen van Tilburg changed the description

    changed the description

  • added 1 commit

    • fc44900a - Simplify estimate for number of clusters from raw bank

    Compare with previous version

  • added 2 commits

    • 9e9058a3 - Size flag in cluster words is now also set for first cluster
    • 6042d5e2 - Move Lambda functions out of loop

    Compare with previous version

  • added 1 commit

    • 54bdfd8e - Split output from outer Tell40s in two banks and add 32b truncation header

    Compare with previous version

  • Jeroen van Tilburg changed the description

    changed the description

  • Edited by Software for LHCb
  • Marco Cattaneo
  • added 1 commit

    • cee5f374 - Fix typo in MultiIndexHitContainer

    Compare with previous version

  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Please register or sign in to reply
    Loading