|
|
|||
Warning, file /include/root/ROOT/RClusterPool.hxx was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /// \file ROOT/RClusterPool.hxx 0002 /// \ingroup NTuple 0003 /// \author Jakob Blomer <jblomer@cern.ch> 0004 /// \date 2020-03-11 0005 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback 0006 /// is welcome! 0007 0008 /************************************************************************* 0009 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. * 0010 * All rights reserved. * 0011 * * 0012 * For the licensing terms see $ROOTSYS/LICENSE. * 0013 * For the list of contributors see $ROOTSYS/README/CREDITS. * 0014 *************************************************************************/ 0015 0016 #ifndef ROOT_RClusterPool 0017 #define ROOT_RClusterPool 0018 0019 #include <ROOT/RCluster.hxx> 0020 #include <ROOT/RNTupleMetrics.hxx> 0021 #include <ROOT/RNTupleTypes.hxx> 0022 0023 #include <condition_variable> 0024 #include <deque> 0025 #include <memory> 0026 #include <mutex> 0027 #include <future> 0028 #include <thread> 0029 #include <unordered_map> 0030 #include <vector> 0031 0032 namespace ROOT { 0033 namespace Internal { 0034 class RPageSource; 0035 } 0036 0037 namespace Internal { 0038 0039 // clang-format off 0040 /** 0041 \class ROOT::Internal::RClusterPool 0042 \ingroup NTuple 0043 \brief Managed a set of clusters containing compressed and packed pages 0044 0045 The cluster pool steers the preloading of (partial) clusters. There is a two-step pipeline: in a first step, 0046 compressed pages are read from clusters into a memory buffer. The second pipeline step decompresses the pages 0047 and pushes them into the page pool. The actual logic of reading and unzipping is implemented by the page source. 0048 The cluster pool only orchestrates the work queues for reading and unzipping. It uses one extra I/O thread for 0049 reading waits for data from storage and generates no CPU load. 0050 0051 The unzipping step of the pipeline therefore behaves differently depending on whether or not implicit multi-threading 0052 is turned on. If it is turned off, i.e. in a single-threaded environment, the cluster pool will only read the 0053 compressed pages and the page source has to uncompresses pages at a later point when data from the page is requested. 0054 */ 0055 // clang-format on 0056 class RClusterPool { 0057 private: 0058 /// Request to load a subset of the columns of a particular cluster. 0059 /// Work items come in groups and are executed by the page source. 0060 struct RReadItem { 0061 /// Items with different bunch ids are scheduled for different vector reads 0062 std::int64_t fBunchId = -1; 0063 std::promise<std::unique_ptr<RCluster>> fPromise; 0064 RCluster::RKey fClusterKey; 0065 }; 0066 0067 /// Clusters that are currently being processed by the pipeline. Every in-flight cluster has a corresponding 0068 /// read item. 0069 struct RInFlightCluster { 0070 std::future<std::unique_ptr<RCluster>> fFuture; 0071 RCluster::RKey fClusterKey; 0072 0073 bool operator ==(const RInFlightCluster &other) const { 0074 return (fClusterKey.fClusterId == other.fClusterKey.fClusterId) && 0075 (fClusterKey.fPhysicalColumnSet == other.fClusterKey.fPhysicalColumnSet); 0076 } 0077 bool operator !=(const RInFlightCluster &other) const { return !(*this == other); } 0078 /// First order by cluster id, then by number of columns, than by the column ids in fColumns 0079 bool operator <(const RInFlightCluster &other) const; 0080 }; 0081 0082 /// Performance counters that get registered in fMetrics 0083 struct RCounters { 0084 ROOT::Experimental::Detail::RNTupleAtomicCounter &fNCluster; 0085 }; 0086 std::unique_ptr<RCounters> fCounters; 0087 0088 /// Every cluster pool is responsible for exactly one page source that triggers loading of the clusters 0089 /// (GetCluster()) and is used for implementing the I/O and cluster memory allocation (PageSource::LoadClusters()). 0090 ROOT::Internal::RPageSource &fPageSource; 0091 /// The number of clusters that are being read in a single vector read. 0092 unsigned int fClusterBunchSize; 0093 /// Used as an ever-growing counter in GetCluster() to separate bunches of clusters from each other 0094 std::int64_t fBunchId = 0; 0095 /// The cache of active clusters and their successors 0096 std::unordered_map<ROOT::DescriptorId_t, std::unique_ptr<RCluster>> fPool; 0097 0098 /// Protects the shared state between the main thread and the I/O thread, namely the work queue and the in-flight 0099 /// clusters vector 0100 std::mutex fLockWorkQueue; 0101 /// The clusters that were handed off to the I/O thread 0102 std::vector<RInFlightCluster> fInFlightClusters; 0103 /// Signals a non-empty I/O work queue 0104 std::condition_variable fCvHasReadWork; 0105 /// The communication channel to the I/O thread 0106 std::deque<RReadItem> fReadQueue; 0107 0108 /// The I/O thread calls RPageSource::LoadClusters() asynchronously. The thread is mostly waiting for the 0109 /// data to arrive (blocked by the kernel) and therefore can safely run in addition to the application 0110 /// main threads. 0111 std::thread fThreadIo; 0112 0113 /// The cluster pool counters are observed by the page source 0114 ROOT::Experimental::Detail::RNTupleMetrics fMetrics; 0115 0116 /// The I/O thread routine, there is exactly one I/O thread in-flight for every cluster pool 0117 void ExecReadClusters(); 0118 /// Returns the given cluster from the pool, which needs to contain at least the columns `physicalColumns`. 0119 /// Executed at the end of GetCluster when all missing data pieces have been sent to the load queue. 0120 /// Ideally, the function returns without blocking if the cluster is already in the pool. 0121 RCluster *WaitFor(ROOT::DescriptorId_t clusterId, const RCluster::ColumnSet_t &physicalColumns); 0122 0123 public: 0124 static constexpr unsigned int kDefaultClusterBunchSize = 1; 0125 RClusterPool(ROOT::Internal::RPageSource &pageSource, unsigned int clusterBunchSize); 0126 explicit RClusterPool(ROOT::Internal::RPageSource &pageSource) : RClusterPool(pageSource, kDefaultClusterBunchSize) 0127 { 0128 } 0129 RClusterPool(const RClusterPool &other) = delete; 0130 RClusterPool &operator =(const RClusterPool &other) = delete; 0131 ~RClusterPool(); 0132 0133 /// Spawn the I/O background thread. No-op if already started. 0134 void StartBackgroundThread(); 0135 0136 /// Stop the I/O background thread. No-op if already stopped. Called by the destructor. 0137 void StopBackgroundThread(); 0138 0139 /// Returns the requested cluster either from the pool or, in case of a cache miss, lets the I/O thread load 0140 /// the cluster in the pool, blocks until done, and then returns it. Triggers along the way the background loading 0141 /// of the following fClusterBunchSize number of clusters. The returned cluster has at least all the pages of 0142 /// `physicalColumns` and possibly pages of other columns, too. If implicit multi-threading is turned on, the 0143 /// uncompressed pages of the returned cluster are already pushed into the page pool associated with the page source 0144 /// upon return. The cluster remains valid until the next call to GetCluster(). 0145 RCluster *GetCluster(ROOT::DescriptorId_t clusterId, const RCluster::ColumnSet_t &physicalColumns); 0146 0147 /// Used by the unit tests to drain the queue of clusters to be preloaded 0148 void WaitForInFlightClusters(); 0149 0150 ROOT::Experimental::Detail::RNTupleMetrics &GetMetrics() { return fMetrics; } 0151 }; // class RClusterPool 0152 0153 } // namespace Internal 0154 } // namespace ROOT 0155 0156 #endif
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|