Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:53:09

0001 // Author: Enrico Guiraud CERN 09/2020
0002 
0003 /*************************************************************************
0004  * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers.               *
0005  * All rights reserved.                                                  *
0006  *                                                                       *
0007  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0008  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0009  *************************************************************************/
0010 
0011 #ifndef ROOT_RDF_RTREECOLUMNREADER
0012 #define ROOT_RDF_RTREECOLUMNREADER
0013 
0014 #include "RColumnReaderBase.hxx"
0015 #include <ROOT/RVec.hxx>
0016 #include <Rtypes.h>  // Long64_t, R__CLING_PTRCHECK
0017 #include <TTreeReader.h>
0018 #include <TTreeReaderValue.h>
0019 #include <TTreeReaderArray.h>
0020 
0021 #include <memory>
0022 #include <string>
0023 
0024 namespace ROOT {
0025 namespace Internal {
0026 namespace RDF {
0027 
0028 /// RTreeColumnReader specialization for TTree values read via TTreeReaderValues
0029 template <typename T>
0030 class R__CLING_PTRCHECK(off) RTreeColumnReader final : public ROOT::Detail::RDF::RColumnReaderBase {
0031    std::unique_ptr<TTreeReaderValue<T>> fTreeValue;
0032 
0033    void *GetImpl(Long64_t) final { return fTreeValue->Get(); }
0034 public:
0035    /// Construct the RTreeColumnReader. Actual initialization is performed lazily by the Init method.
0036    RTreeColumnReader(TTreeReader &r, const std::string &colName)
0037       : fTreeValue(std::make_unique<TTreeReaderValue<T>>(r, colName.c_str()))
0038    {
0039    }
0040 
0041    /// The dtor resets the TTreeReaderValue object.
0042    //
0043    // Otherwise a race condition is present in which a TTreeReader
0044    // and its TTreeReader{Value,Array}s can be deleted concurrently:
0045    // - Thread #1) a task ends and pushes back processing slot
0046    // - Thread #2) a task starts and overwrites thread-local TTreeReaderValues
0047    // - Thread #1) first task deletes TTreeReader
0048    // See https://github.com/root-project/root/commit/26e8ace6e47de6794ac9ec770c3bbff9b7f2e945
0049    ~RTreeColumnReader() override { fTreeValue.reset(); }
0050 };
0051 
0052 /// RTreeColumnReader specialization for TTree values read via TTreeReaderArrays.
0053 ///
0054 /// TTreeReaderArrays are used whenever the RDF column type is RVec<T>.
0055 template <typename T>
0056 class R__CLING_PTRCHECK(off) RTreeColumnReader<RVec<T>> final : public ROOT::Detail::RDF::RColumnReaderBase {
0057    std::unique_ptr<TTreeReaderArray<T>> fTreeArray;
0058 
0059    /// Enumerator for the memory layout of the branch
0060    enum class EStorageType : char { kContiguous, kUnknown, kSparse };
0061 
0062    /// We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory layout.
0063    RVec<T> fRVec;
0064 
0065    /// Signal whether we ever checked that the branch we are reading with a TTreeReaderArray stores array elements
0066    /// in contiguous memory.
0067    EStorageType fStorageType = EStorageType::kUnknown;
0068    Long64_t fLastEntry = -1;
0069 
0070    /// Whether we already printed a warning about performing a copy of the TTreeReaderArray contents
0071    bool fCopyWarningPrinted = false;
0072 
0073    void *GetImpl(Long64_t entry) final
0074    {
0075       if (entry == fLastEntry)
0076          return &fRVec; // we already pointed our fRVec to the right address
0077 
0078       auto &readerArray = *fTreeArray;
0079       // We only use TTreeReaderArrays to read columns that users flagged as type `RVec`, so we need to check
0080       // that the branch stores the array as contiguous memory that we can actually wrap in an `RVec`.
0081       // Currently we need the first entry to have been loaded to perform the check
0082       // TODO Move check to constructor once ROOT-10823 is fixed and TTreeReaderArray itself exposes this information
0083       const auto readerArraySize = readerArray.GetSize();
0084       if (EStorageType::kUnknown == fStorageType && readerArraySize > 1) {
0085          // We can decide since the array is long enough
0086          fStorageType = EStorageType::kContiguous;
0087          for (auto i = 0u; i < readerArraySize - 1; ++i) {
0088             if ((char *)&readerArray[i + 1] - (char *)&readerArray[i] != sizeof(T)) {
0089                fStorageType = EStorageType::kSparse;
0090                break;
0091             }
0092          }
0093       }
0094 
0095       if (EStorageType::kContiguous == fStorageType ||
0096           (EStorageType::kUnknown == fStorageType && readerArray.GetSize() < 2)) {
0097          if (readerArraySize > 0) {
0098             // trigger loading of the contents of the TTreeReaderArray
0099             // the address of the first element in the reader array is not necessarily equal to
0100             // the address returned by the GetAddress method
0101             auto readerArrayAddr = &readerArray.At(0);
0102             RVec<T> rvec(readerArrayAddr, readerArraySize);
0103             swap(fRVec, rvec);
0104          } else {
0105             RVec<T> emptyVec{};
0106             swap(fRVec, emptyVec);
0107          }
0108       } else {
0109          // The storage is not contiguous or we don't know yet: we cannot but copy into the rvec
0110 #ifndef NDEBUG
0111          if (!fCopyWarningPrinted) {
0112             Warning("RTreeColumnReader::Get",
0113                     "Branch %s hangs from a non-split branch. A copy is being performed in order "
0114                     "to properly read the content.",
0115                     readerArray.GetBranchName());
0116             fCopyWarningPrinted = true;
0117          }
0118 #else
0119          (void)fCopyWarningPrinted;
0120 #endif
0121          if (readerArraySize > 0) {
0122             RVec<T> rvec(readerArray.begin(), readerArray.end());
0123             swap(fRVec, rvec);
0124          } else {
0125             RVec<T> emptyVec{};
0126             swap(fRVec, emptyVec);
0127          }
0128       }
0129       fLastEntry = entry;
0130       return &fRVec;
0131    }
0132 
0133 public:
0134    RTreeColumnReader(TTreeReader &r, const std::string &colName)
0135       : fTreeArray(std::make_unique<TTreeReaderArray<T>>(r, colName.c_str()))
0136    {
0137    }
0138 
0139    /// See the other class template specializations for an explanation.
0140    ~RTreeColumnReader() override { fTreeArray.reset(); }
0141 };
0142 
0143 /// RTreeColumnReader specialization for arrays of boolean values read via TTreeReaderArrays.
0144 ///
0145 /// TTreeReaderArray<bool> is used whenever the RDF column type is RVec<bool>.
0146 template <>
0147 class R__CLING_PTRCHECK(off) RTreeColumnReader<RVec<bool>> final : public ROOT::Detail::RDF::RColumnReaderBase {
0148 
0149    std::unique_ptr<TTreeReaderArray<bool>> fTreeArray;
0150 
0151    /// We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory layout
0152    RVec<bool> fRVec;
0153 
0154    // We always copy the contents of TTreeReaderArray<bool> into an RVec<bool> (never take a view into the memory
0155    // buffer) because the underlying memory buffer might be the one of a std::vector<bool>, which is not a contiguous
0156    // slab of bool values.
0157    // Note that this also penalizes the case in which the column type is actually bool[], but the possible performance
0158    // gains in this edge case is probably not worth the extra complication required to differentiate the two cases.
0159    void *GetImpl(Long64_t) final
0160    {
0161       auto &readerArray = *fTreeArray;
0162       const auto readerArraySize = readerArray.GetSize();
0163       if (readerArraySize > 0) {
0164          // always perform a copy
0165          RVec<bool> rvec(readerArray.begin(), readerArray.end());
0166          swap(fRVec, rvec);
0167       } else {
0168          RVec<bool> emptyVec{};
0169          swap(fRVec, emptyVec);
0170       }
0171       return &fRVec;
0172    }
0173 
0174 public:
0175    RTreeColumnReader(TTreeReader &r, const std::string &colName)
0176       : fTreeArray(std::make_unique<TTreeReaderArray<bool>>(r, colName.c_str()))
0177    {
0178    }
0179 
0180    /// See the other class template specializations for an explanation.
0181    ~RTreeColumnReader() override { fTreeArray.reset(); }
0182 };
0183 
0184 } // namespace RDF
0185 } // namespace Internal
0186 } // namespace ROOT
0187 
0188 #endif