| 
 | 1 | +/*  | 
 | 2 | + * Copyright (c) Facebook, Inc. and its affiliates.  | 
 | 3 | + *  | 
 | 4 | + * Licensed under the Apache License, Version 2.0 (the "License");  | 
 | 5 | + * you may not use this file except in compliance with the License.  | 
 | 6 | + * You may obtain a copy of the License at  | 
 | 7 | + *  | 
 | 8 | + *     http://www.apache.org/licenses/LICENSE-2.0  | 
 | 9 | + *  | 
 | 10 | + * Unless required by applicable law or agreed to in writing, software  | 
 | 11 | + * distributed under the License is distributed on an "AS IS" BASIS,  | 
 | 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
 | 13 | + * See the License for the specific language governing permissions and  | 
 | 14 | + * limitations under the License.  | 
 | 15 | + */  | 
 | 16 | + | 
 | 17 | +#pragma once  | 
 | 18 | + | 
 | 19 | +#include <folly/Range.h>  | 
 | 20 | +#include <folly/logging/xlog.h>  | 
 | 21 | + | 
 | 22 | +#include "cachelib/common/Utils.h"  | 
 | 23 | + | 
 | 24 | +namespace facebook {  | 
 | 25 | +namespace cachelib {  | 
 | 26 | +namespace util {  | 
 | 27 | + | 
 | 28 | +class RollingStats {  | 
 | 29 | + public:  | 
 | 30 | +  // track latency by taking the value of duration directly.  | 
 | 31 | +  void trackValue(double value) {  | 
 | 32 | +    // This is a highly unlikely scenario where  | 
 | 33 | +    // cnt_ reaches numerical limits. Skip update  | 
 | 34 | +    // of the rolling average anymore.  | 
 | 35 | +    if (cnt_ == std::numeric_limits<uint64_t>::max()) {  | 
 | 36 | +      cnt_ = 0;  | 
 | 37 | +      return;  | 
 | 38 | +    }  | 
 | 39 | +    auto ratio = static_cast<double>(cnt_) / (cnt_ + 1);  | 
 | 40 | +    avg_ *= ratio;  | 
 | 41 | +    ++cnt_;  | 
 | 42 | +    avg_ += value / cnt_;  | 
 | 43 | +  }  | 
 | 44 | + | 
 | 45 | +  // Return the rolling average.  | 
 | 46 | +  double estimate() { return avg_; }  | 
 | 47 | + | 
 | 48 | + private:  | 
 | 49 | +  double avg_{0};  | 
 | 50 | +  uint64_t cnt_{0};  | 
 | 51 | +};  | 
 | 52 | + | 
 | 53 | +class RollingLatencyTracker {  | 
 | 54 | + public:  | 
 | 55 | +  explicit RollingLatencyTracker(RollingStats& stats)  | 
 | 56 | +      : stats_(&stats), begin_(std::chrono::steady_clock::now()) {}  | 
 | 57 | +  RollingLatencyTracker() {}  | 
 | 58 | +  ~RollingLatencyTracker() {  | 
 | 59 | +    if (stats_) {  | 
 | 60 | +      auto tp = std::chrono::steady_clock::now();  | 
 | 61 | +      auto diffNanos =  | 
 | 62 | +          std::chrono::duration_cast<std::chrono::nanoseconds>(tp - begin_)  | 
 | 63 | +              .count();  | 
 | 64 | +      stats_->trackValue(static_cast<double>(diffNanos));  | 
 | 65 | +    }  | 
 | 66 | +  }  | 
 | 67 | + | 
 | 68 | +  RollingLatencyTracker(const RollingLatencyTracker&) = delete;  | 
 | 69 | +  RollingLatencyTracker& operator=(const RollingLatencyTracker&) = delete;  | 
 | 70 | + | 
 | 71 | +  RollingLatencyTracker(RollingLatencyTracker&& rhs) noexcept  | 
 | 72 | +      : stats_(rhs.stats_), begin_(rhs.begin_) {  | 
 | 73 | +    rhs.stats_ = nullptr;  | 
 | 74 | +  }  | 
 | 75 | + | 
 | 76 | +  RollingLatencyTracker& operator=(RollingLatencyTracker&& rhs) noexcept {  | 
 | 77 | +    if (this != &rhs) {  | 
 | 78 | +      this->~RollingLatencyTracker();  | 
 | 79 | +      new (this) RollingLatencyTracker(std::move(rhs));  | 
 | 80 | +    }  | 
 | 81 | +    return *this;  | 
 | 82 | +  }  | 
 | 83 | + | 
 | 84 | + private:  | 
 | 85 | +  RollingStats* stats_{nullptr};  | 
 | 86 | +  std::chrono::time_point<std::chrono::steady_clock> begin_;  | 
 | 87 | +};  | 
 | 88 | +} // namespace util  | 
 | 89 | +} // namespace cachelib  | 
 | 90 | +} // namespace facebook  | 
0 commit comments