LCOV - code coverage report
Current view: top level - tpglibs/src - AVXPipeline.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 98.0 % 50 49
Test Date: 2026-10-11 15:05:20 Functions: 100.0 % 3 3

            Line data    Source code
       1              : /**
       2              :  * @file AVXPipeline.cpp
       3              :  *
       4              :  * @copyright This is part of the DUNE DAQ Software Suite, copyright 2020.
       5              :  * Licensing/copyright details are in the COPYING file that you should have
       6              :  * received with this code.
       7              :  */
       8              : #include "tpglibs/AVXPipeline.hpp"
       9              : 
      10              : namespace tpglibs {
      11              : 
      12              : __m256i
      13          780 : AVXPipeline::save_state(const __m256i& processed_signal)
      14              : {
      15          780 :   __m256i active = _mm256_cmpgt_epi16(processed_signal, _mm256_setzero_si256());
      16          780 :   __m256i inactive = _mm256_cmpeq_epi16(processed_signal, _mm256_setzero_si256());
      17          780 :   __m256i was_inactive = _mm256_cmpeq_epi16(m_samples_over_threshold, _mm256_setzero_si256());
      18              : 
      19              :   // If it was *not* inactive and is now inactive, then it must be a new TP.
      20          780 :   __m256i new_tps = _mm256_andnot_si256(was_inactive, inactive);
      21              : 
      22              :   // Get the potentially saturated integral and overflown integral.
      23          780 :   __m256i adc_integral_sat = _mm256_adds_epu16(m_adc_integral_lo, processed_signal);
      24          780 :   m_adc_integral_lo = _mm256_add_epi16(m_adc_integral_lo, processed_signal);
      25              : 
      26              :   // If it is saturated, then increment the hi. The overflown integral already "reset".
      27          780 :   __m256i is_saturated = _mm256_cmpeq_epi16(adc_integral_sat, m_max_value_register);
      28              :   // If lo and sat are the same, then it is *not* saturated and happened to exactly sum to 0xFFFF.
      29          780 :   __m256i exact = _mm256_cmpeq_epi16(m_adc_integral_lo, adc_integral_sat);
      30              :   // So, (!exact) & is_saturated == [truly saturated].
      31          780 :   is_saturated = _mm256_andnot_si256(exact, is_saturated);
      32              : 
      33          780 :   __m256i to_add = _mm256_and_si256(m_ones_register, is_saturated);
      34          780 :   m_adc_integral_hi = _mm256_adds_epu16(m_adc_integral_hi, to_add);
      35              : 
      36          780 :   __m256i above_peak = _mm256_cmpgt_epi16(processed_signal, m_adc_peak);
      37              : 
      38          780 :   m_adc_peak = _mm256_max_epi16(m_adc_peak, processed_signal);
      39          780 :   m_samples_to_peak = _mm256_blendv_epi8(m_samples_to_peak, m_samples_over_threshold, above_peak);
      40              : 
      41          780 :   __m256i time_add = _mm256_blendv_epi8(_mm256_setzero_si256(), m_ones_register, active);
      42          780 :   m_samples_over_threshold = _mm256_adds_epi16(m_samples_over_threshold, time_add);
      43              : 
      44          780 :   return new_tps;
      45              : }
      46              : 
      47              : bool
      48          780 : AVXPipeline::check_for_tps(const __m256i& tp_mask)
      49              : {
      50              :   // tp_mask & 0xFFFF = 0 -> tp_mask == 0.
      51              :   // True => tp_mask is all zeros and has no TPs.
      52              :   // Negate!
      53          780 :   return !_mm256_testz_si256(tp_mask, _mm256_set1_epi16(-1));
      54              : }
      55              : 
      56              : std::vector<dunedaq::trgdataformats::TriggerPrimitive>
      57          147 : AVXPipeline::generate_tps(const __m256i& tp_mask)
      58              : {
      59              :   // Mask everything that's relevant.
      60          147 :   __m256i samples_over_threshold = _mm256_blendv_epi8(_mm256_setzero_si256(), m_samples_over_threshold, tp_mask);
      61          147 :   __m256i adc_integral_lo = _mm256_blendv_epi8(_mm256_setzero_si256(), m_adc_integral_lo, tp_mask);
      62          147 :   __m256i adc_integral_hi = _mm256_blendv_epi8(_mm256_setzero_si256(), m_adc_integral_hi, tp_mask);
      63          147 :   __m256i adc_peak = _mm256_blendv_epi8(_mm256_setzero_si256(), m_adc_peak, tp_mask);
      64          147 :   __m256i samples_to_peak = _mm256_blendv_epi8(_mm256_setzero_si256(), m_samples_to_peak, tp_mask);
      65              : 
      66              :   // Convert to uint16_t.
      67          147 :   uint16_t tp_sot[16], tp_integral_lo[16], tp_integral_hi[16], tp_adc_peak[16], tp_samples_to_peak[16];
      68          147 :   _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_sot), samples_over_threshold);
      69          147 :   _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_integral_lo), adc_integral_lo);
      70          147 :   _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_integral_hi), adc_integral_hi);
      71          147 :   _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_adc_peak), adc_peak);
      72          147 :   _mm256_storeu_si256(reinterpret_cast<__m256i*>(tp_samples_to_peak), samples_to_peak);
      73              : 
      74          147 :   std::vector<dunedaq::trgdataformats::TriggerPrimitive> tps;
      75         2499 :   for (int i = 0; i < 16; i++) {
      76         2352 :     if (tp_sot[i] < m_sot_minima[m_plane_numbers[i]])
      77          368 :       continue; // Don't track short TPs.
      78         1984 :     dunedaq::trgdataformats::TriggerPrimitive tp;
      79         1984 :     tp.adc_integral = uint32_t(tp_integral_lo[i]) + (uint32_t(tp_integral_hi[i]) << 16);
      80         1984 :     tp.adc_peak = tp_adc_peak[i];
      81         1984 :     tp.channel = m_channels[i];
      82         1984 :     tp.samples_to_peak = tp_samples_to_peak[i];
      83         1984 :     tp.samples_over_threshold = tp_sot[i];
      84              : 
      85              :     // time_start is handled at the next level up, since it is aware of the true and relative times.
      86         1984 :     tps.push_back(tp);
      87              :   }
      88              : 
      89              :   // Reset the channels that generated tps.
      90          147 :   m_samples_over_threshold = _mm256_blendv_epi8(m_samples_over_threshold, _mm256_setzero_si256(), tp_mask);
      91          147 :   m_adc_integral_lo = _mm256_blendv_epi8(m_adc_integral_lo, _mm256_setzero_si256(), tp_mask);
      92          147 :   m_adc_integral_hi = _mm256_blendv_epi8(m_adc_integral_hi, _mm256_setzero_si256(), tp_mask);
      93          147 :   m_adc_peak = _mm256_blendv_epi8(m_adc_peak, _mm256_setzero_si256(), tp_mask);
      94          147 :   m_samples_to_peak = _mm256_blendv_epi8(m_samples_to_peak, _mm256_setzero_si256(), tp_mask);
      95              : 
      96              :   // Finalize.
      97          147 :   return tps;
      98            0 : }
      99              : 
     100              : } // namespace tpglibs
        

Generated by: LCOV version 2.0-1