1818
1919#include " cachelib/allocator/BackgroundMoverStrategy.h"
2020#include " cachelib/allocator/CacheStats.h"
21- #include " cachelib/common/AtomicCounter.h"
2221#include " cachelib/common/PeriodicWorker.h"
2322
2423namespace facebook ::cachelib {
@@ -51,6 +50,7 @@ enum class MoverDir { Evict = 0, Promote };
5150template <typename CacheT>
5251class BackgroundMover : public PeriodicWorker {
5352 public:
53+ using ClassBgStatsType = std::map<MemoryDescriptorType,uint64_t >;
5454 using Cache = CacheT;
5555 // @param cache the cache interface
5656 // @param strategy the stragey class that defines how objects are
@@ -62,8 +62,9 @@ class BackgroundMover : public PeriodicWorker {
6262 ~BackgroundMover () override ;
6363
6464 BackgroundMoverStats getStats () const noexcept ;
65- std::map<TierId, std::map<PoolId, std::map<ClassId, uint64_t >>>
66- getClassStats () const noexcept ;
65+ ClassBgStatsType getClassStats () const noexcept {
66+ return movesPerClass_;
67+ }
6768
6869 void setAssignedMemory (std::vector<MemoryDescriptorType>&& assignedMemory);
6970
@@ -72,8 +73,27 @@ class BackgroundMover : public PeriodicWorker {
7273 static size_t workerId (TierId tid, PoolId pid, ClassId cid, size_t numWorkers);
7374
7475 private:
75- std::map<TierId, std::map<PoolId, std::map<ClassId, uint64_t >>>
76- movesPerClass_;
76+ ClassBgStatsType movesPerClass_;
77+
78+ struct TraversalStats {
79+ // record a traversal and its time taken
80+ void recordTraversalTime (uint64_t nsTaken);
81+
82+ uint64_t getAvgTraversalTimeNs (uint64_t numTraversals) const ;
83+ uint64_t getMinTraversalTimeNs () const { return minTraversalTimeNs_; }
84+ uint64_t getMaxTraversalTimeNs () const { return maxTraversalTimeNs_; }
85+ uint64_t getLastTraversalTimeNs () const { return lastTraversalTimeNs_; }
86+
87+ private:
88+ // time it took us the last time to traverse the cache.
89+ uint64_t lastTraversalTimeNs_{0 };
90+ uint64_t minTraversalTimeNs_{
91+ std::numeric_limits<uint64_t >::max ()};
92+ uint64_t maxTraversalTimeNs_{0 };
93+ uint64_t totalTraversalTimeNs_{0 };
94+ };
95+
96+ TraversalStats traversalStats_;
7797 // cache allocator's interface for evicting
7898 using Item = typename Cache::Item;
7999
@@ -89,9 +109,10 @@ class BackgroundMover : public PeriodicWorker {
89109 void work () override final ;
90110 void checkAndRun ();
91111
92- AtomicCounter numMovedItems_{0 };
93- AtomicCounter numTraversals_{0 };
94- AtomicCounter totalBytesMoved_{0 };
112+ uint64_t numMovedItems{0 };
113+ uint64_t numTraversals{0 };
114+ uint64_t totalClasses{0 };
115+ uint64_t totalBytesMoved{0 };
95116
96117 std::vector<MemoryDescriptorType> assignedMemory_;
97118 folly::DistributedMutex mutex_;
@@ -111,6 +132,20 @@ BackgroundMover<CacheT>::BackgroundMover(
111132 }
112133}
113134
135+ template <typename CacheT>
136+ void BackgroundMover<CacheT>::TraversalStats::recordTraversalTime(uint64_t nsTaken) {
137+ lastTraversalTimeNs_ = nsTaken;
138+ minTraversalTimeNs_ = std::min (minTraversalTimeNs_, nsTaken);
139+ maxTraversalTimeNs_ = std::max (maxTraversalTimeNs_, nsTaken);
140+ totalTraversalTimeNs_ += nsTaken;
141+ }
142+
143+ template <typename CacheT>
144+ uint64_t BackgroundMover<CacheT>::TraversalStats::getAvgTraversalTimeNs(
145+ uint64_t numTraversals) const {
146+ return numTraversals ? totalTraversalTimeNs_ / numTraversals : 0 ;
147+ }
148+
114149template <typename CacheT>
115150BackgroundMover<CacheT>::~BackgroundMover () {
116151 stop (std::chrono::seconds (0 ));
@@ -144,44 +179,56 @@ template <typename CacheT>
144179void BackgroundMover<CacheT>::checkAndRun() {
145180 auto assignedMemory = mutex_.lock_combine ([this ] { return assignedMemory_; });
146181
147- unsigned int moves = 0 ;
148- auto batches = strategy_->calculateBatchSizes (cache_, assignedMemory);
149-
150- for (size_t i = 0 ; i < batches.size (); i++) {
151- const auto [tid, pid, cid] = assignedMemory[i];
152- const auto batch = batches[i];
182+ while (true ) {
183+ unsigned int moves = 0 ;
184+ std::set<ClassId> classes{};
185+ auto batches = strategy_->calculateBatchSizes (cache_, assignedMemory);
186+
187+ const auto begin = util::getCurrentTimeNs ();
188+ for (size_t i = 0 ; i < batches.size (); i++) {
189+ const auto [tid, pid, cid] = assignedMemory[i];
190+ const auto batch = batches[i];
191+ if (!batch) {
192+ continue ;
193+ }
194+
195+ // try moving BATCH items from the class in order to reach free target
196+ auto moved = moverFunc (cache_, tid, pid, cid, batch);
197+ moves += moved;
198+ movesPerClass_[assignedMemory[i]] += moved;
199+ }
200+ auto end = util::getCurrentTimeNs ();
201+ if (moves > 0 ) {
202+ traversalStats_.recordTraversalTime (end > begin ? end - begin : 0 );
203+ numMovedItems += moves;
204+ numTraversals++;
205+ }
153206
154- if (batch == 0 ) {
155- continue ;
207+ // we didn't move any objects done with this run
208+ if (moves == 0 || shouldStopWork ()) {
209+ break ;
156210 }
157- const auto & mpStats = cache_.getPoolByTid (pid, tid).getStats ();
158- // try moving BATCH items from the class in order to reach free target
159- auto moved = moverFunc (cache_, tid, pid, cid, batch);
160- moves += moved;
161- movesPerClass_[tid][pid][cid] += moved;
162- totalBytesMoved_.add (moved * mpStats.acStats .at (cid).allocSize );
163211 }
164-
165- numTraversals_.inc ();
166- numMovedItems_.add (moves);
167212}
168213
169214template <typename CacheT>
170215BackgroundMoverStats BackgroundMover<CacheT>::getStats() const noexcept {
171216 BackgroundMoverStats stats;
172- stats.numMovedItems = numMovedItems_.get ();
173- stats.runCount = numTraversals_.get ();
174- stats.totalBytesMoved = totalBytesMoved_.get ();
217+ stats.numMovedItems = numMovedItems;
218+ stats.totalBytesMoved = totalBytesMoved;
219+ stats.totalClasses = totalClasses;
220+ auto runCount = getRunCount ();
221+ stats.runCount = runCount;
222+ stats.numTraversals = numTraversals;
223+ stats.avgItemsMoved = (double ) stats.numMovedItems / (double )runCount;
224+ stats.lastTraversalTimeNs = traversalStats_.getLastTraversalTimeNs ();
225+ stats.avgTraversalTimeNs = traversalStats_.getAvgTraversalTimeNs (numTraversals);
226+ stats.minTraversalTimeNs = traversalStats_.getMinTraversalTimeNs ();
227+ stats.maxTraversalTimeNs = traversalStats_.getMaxTraversalTimeNs ();
175228
176229 return stats;
177230}
178231
179- template <typename CacheT>
180- std::map<TierId, std::map<PoolId, std::map<ClassId, uint64_t >>>
181- BackgroundMover<CacheT>::getClassStats() const noexcept {
182- return movesPerClass_;
183- }
184-
185232template <typename CacheT>
186233size_t BackgroundMover<CacheT>::workerId(TierId tid,
187234 PoolId pid,
0 commit comments