1 | /* |
2 | * Copyright 2012-present Facebook, Inc. |
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 <chrono> |
20 | #include <cstdint> |
21 | #include <type_traits> |
22 | |
23 | namespace folly { |
24 | namespace detail { |
25 | |
26 | /* |
27 | * Helper function to compute the average, given a specified input type and |
28 | * return type. |
29 | */ |
30 | |
31 | // If the input is long double, divide using long double to avoid losing |
32 | // precision. |
33 | template <typename ReturnType> |
34 | ReturnType avgHelper(long double sum, uint64_t count) { |
35 | if (count == 0) { |
36 | return ReturnType(0); |
37 | } |
38 | const long double countf = count; |
39 | return static_cast<ReturnType>(sum / countf); |
40 | } |
41 | |
42 | // In all other cases divide using double precision. |
43 | // This should be relatively fast, and accurate enough for most use cases. |
44 | template <typename ReturnType, typename ValueType> |
45 | typename std::enable_if< |
46 | !std::is_same<typename std::remove_cv<ValueType>::type, long double>::value, |
47 | ReturnType>::type |
48 | avgHelper(ValueType sum, uint64_t count) { |
49 | if (count == 0) { |
50 | return ReturnType(0); |
51 | } |
52 | const double sumf = double(sum); |
53 | const double countf = double(count); |
54 | return static_cast<ReturnType>(sumf / countf); |
55 | } |
56 | |
57 | /* |
58 | * Helper function to compute the rate per Interval, |
59 | * given the specified count recorded over the elapsed time period. |
60 | */ |
61 | template < |
62 | typename ReturnType = double, |
63 | typename Duration = std::chrono::seconds, |
64 | typename Interval = Duration> |
65 | ReturnType rateHelper(ReturnType count, Duration elapsed) { |
66 | if (elapsed == Duration(0)) { |
67 | return 0; |
68 | } |
69 | |
70 | // Use std::chrono::duration_cast to convert between the native |
71 | // duration and the desired interval. However, convert the rates, |
72 | // rather than just converting the elapsed duration. Converting the |
73 | // elapsed time first may collapse it down to 0 if the elapsed interval |
74 | // is less than the desired interval, which will incorrectly result in |
75 | // an infinite rate. |
76 | typedef std::chrono::duration< |
77 | ReturnType, |
78 | std::ratio<Duration::period::den, Duration::period::num>> |
79 | NativeRate; |
80 | typedef std::chrono::duration< |
81 | ReturnType, |
82 | std::ratio<Interval::period::den, Interval::period::num>> |
83 | DesiredRate; |
84 | |
85 | NativeRate native(count / elapsed.count()); |
86 | DesiredRate desired = std::chrono::duration_cast<DesiredRate>(native); |
87 | return desired.count(); |
88 | } |
89 | |
90 | template <typename T> |
91 | struct Bucket { |
92 | public: |
93 | typedef T ValueType; |
94 | |
95 | Bucket() : sum(ValueType()), count(0) {} |
96 | |
97 | void clear() { |
98 | sum = ValueType(); |
99 | count = 0; |
100 | } |
101 | |
102 | void add(const ValueType& s, uint64_t c) { |
103 | // TODO: It would be nice to handle overflow here. |
104 | sum += s; |
105 | count += c; |
106 | } |
107 | |
108 | Bucket& operator+=(const Bucket& o) { |
109 | add(o.sum, o.count); |
110 | return *this; |
111 | } |
112 | |
113 | Bucket& operator-=(const Bucket& o) { |
114 | // TODO: It would be nice to handle overflow here. |
115 | sum -= o.sum; |
116 | count -= o.count; |
117 | return *this; |
118 | } |
119 | |
120 | template <typename ReturnType> |
121 | ReturnType avg() const { |
122 | return avgHelper<ReturnType>(sum, count); |
123 | } |
124 | |
125 | ValueType sum; |
126 | uint64_t count; |
127 | }; |
128 | } // namespace detail |
129 | } // namespace folly |
130 | |