1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- /*
- * Copyright (c)2013-2020 ZeroTier, Inc.
- *
- * Use of this software is governed by the Business Source License included
- * in the LICENSE.TXT file in the project's root directory.
- *
- * Change Date: 2025-01-01
- *
- * On the date above, in accordance with the Business Source License, use
- * of this software will be governed by version 2.0 of the Apache License.
- */
- /****/
- #ifndef ZT_METER_HPP
- #define ZT_METER_HPP
- #include "Constants.hpp"
- #include "Mutex.hpp"
- #include <algorithm>
- namespace ZeroTier {
- /**
- * Transfer rate and total transferred amount meter
- *
- * This class is lock-free and thread-safe.
- *
- * This maintains a set of buckets numbered according to the current time
- * modulo TUNIT. Each bucket is incremented within that time window. When
- * the time moves on to a new bucket, its old contents are added to a
- * total accumulator and a new counter for that bucket starts.
- *
- * @tparam TUNIT Unit of time in milliseconds (default: 1000 for one second)
- * @tparam LSIZE Log size in units of time (default: 10 for 10s worth of data)
- */
- template<int64_t TUNIT = 1000, unsigned long LSIZE = 10>
- class Meter
- {
- public:
- /**
- * Create and initialize a new meter
- *
- * @param now Start time
- */
- ZT_INLINE Meter() noexcept :
- m_counts(),
- m_totalExclCounts(0),
- m_bucket(0)
- {}
- /**
- * Add a measurement
- *
- * @param now Current time
- * @param count Count of items (usually bytes)
- */
- ZT_INLINE void log(const int64_t now, uint64_t count) noexcept
- {
- // We log by choosing a log bucket based on the current time in units modulo
- // the log size and then if it's a new bucket setting it or otherwise adding
- // to it.
- const unsigned long bucket = ((unsigned long)(now / TUNIT)) % LSIZE;
- if (m_bucket.exchange(bucket) != bucket) {
- m_totalExclCounts.fetch_add(m_counts[bucket].exchange(count));
- } else {
- m_counts[bucket].fetch_add(count);
- }
- }
- /**
- * Get rate per TUNIT time
- *
- * @param now Current time
- * @param rate Result parameter: rate in count/TUNIT
- * @param total Total count for life of object
- */
- ZT_INLINE void rate(double &rate, uint64_t &total) const noexcept
- {
- total = 0;
- for (unsigned long i = 0;i < LSIZE;++i)
- total += m_counts[i].load();
- rate = (double) total / (double) LSIZE;
- total += m_totalExclCounts.load();
- }
- private:
- std::atomic<uint64_t> m_counts[LSIZE];
- std::atomic<uint64_t> m_totalExclCounts;
- std::atomic<unsigned long> m_bucket;
- };
- } // namespace ZeroTier
- #endif
|