1 /* 2 * Copyright 2016 The Android Open Source Project 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 #ifndef UTILITY_MONOTONIC_COUNTER_H 18 #define UTILITY_MONOTONIC_COUNTER_H 19 20 #include <stdint.h> 21 22 /** 23 * Maintain a 64-bit monotonic counter. 24 * Can be used to track a 32-bit counter that wraps or gets reset. 25 * 26 * Note that this is not atomic and has no interior locks. 27 * A caller will need to provide their own exterior locking 28 * if they need to use it from multiple threads. 29 */ 30 class MonotonicCounter { 31 32 public: 33 MonotonicCounter() = default; 34 virtual ~MonotonicCounter() = default; 35 36 /** 37 * @return current value of the counter 38 */ get()39 int64_t get() const { 40 return mCounter64; 41 } 42 43 /** 44 * Advance the current value to match the counter. 45 * 46 * Note that it will take several million years for the 64-bit 47 * counters to wrap around. 48 * So we do not use __builtin_sub_overflow. 49 * We want to know if overflow happens because of a bug. 50 */ catchUpTo(int64_t counter)51 void catchUpTo(int64_t counter) { 52 if ((counter - mCounter64) > 0) { 53 mCounter64 = counter; 54 } 55 } 56 57 /** 58 * Advance the counter if delta is positive. 59 * @return current value of the counter 60 */ increment(int64_t delta)61 int64_t increment(int64_t delta) { 62 if (delta > 0) { 63 mCounter64 += delta; 64 } 65 return mCounter64; 66 } 67 68 /** 69 * Advance the 64-bit counter if (current32 - previousCurrent32) > 0. 70 * This can be used to convert a 32-bit counter that may be wrapping into 71 * a monotonic 64-bit counter. 72 * 73 * This counter32 should NOT be allowed to advance by more than 0x7FFFFFFF between calls. 74 * Think of the wrapping counter like a sine wave. If the frequency of the signal 75 * is more than half the sampling rate (Nyquist rate) then you cannot measure it properly. 76 * If the counter wraps around every 24 hours then we should measure it with a period 77 * of less than 12 hours. 78 * 79 * @return current value of the 64-bit counter 80 */ update32(int32_t counter32)81 int64_t update32(int32_t counter32) { 82 int32_t delta; 83 __builtin_sub_overflow(counter32, mCounter32, &delta); 84 // protect against the mCounter64 going backwards 85 if (delta > 0) { 86 mCounter64 += delta; 87 mCounter32 = counter32; 88 } 89 return mCounter64; 90 } 91 92 /** 93 * Reset the stored value of the 32-bit counter. 94 * This is used if your counter32 has been reset to zero. 95 */ reset32()96 void reset32() { 97 mCounter32 = 0; 98 } 99 100 /** 101 * Round 64-bit counter up to a multiple of the period. 102 * 103 * @param period might be, for example, a buffer capacity 104 */ roundUp64(int32_t period)105 void roundUp64(int32_t period) { 106 if (period > 0) { 107 int64_t numPeriods = (mCounter64 + period - 1) / period; 108 mCounter64 = numPeriods * period; 109 } 110 } 111 112 private: 113 int64_t mCounter64 = 0; 114 int32_t mCounter32 = 0; 115 }; 116 117 #endif //UTILITY_MONOTONIC_COUNTER_H 118