Yet more cleanup, and add meters to paths.

This commit is contained in:
Adam Ierymenko 2020-02-19 11:06:05 -08:00
parent 1affb6814c
commit 0589964f99
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
7 changed files with 51 additions and 61 deletions

View file

@ -116,11 +116,6 @@
*/ */
#define ZT_PATH_ALIVE_TIMEOUT ((ZT_PATH_KEEPALIVE_PERIOD * 2) + 5000) #define ZT_PATH_ALIVE_TIMEOUT ((ZT_PATH_KEEPALIVE_PERIOD * 2) + 5000)
/**
* Timeout for path active-ness (measured from last receive)
*/
#define ZT_PATH_ACTIVITY_TIMEOUT (ZT_PATH_KEEPALIVE_PERIOD + 5000)
/** /**
* Delay between full HELLO messages between peers * Delay between full HELLO messages between peers
*/ */

View file

@ -156,7 +156,7 @@ bool Identity::locallyValidate() const
return false; return false;
} }
void Identity::hashWithPrivate(uint8_t h[48]) const void Identity::hashWithPrivate(uint8_t h[ZT_IDENTITY_HASH_SIZE]) const
{ {
if (_hasPrivate) { if (_hasPrivate) {
switch (_type) { switch (_type) {

View file

@ -137,7 +137,7 @@ public:
* *
* @param h Buffer to store SHA384 hash * @param h Buffer to store SHA384 hash
*/ */
void hashWithPrivate(uint8_t h[48]) const; void hashWithPrivate(uint8_t h[ZT_IDENTITY_HASH_SIZE]) const;
/** /**
* Sign a message with this identity (private key required) * Sign a message with this identity (private key required)

View file

@ -25,9 +25,9 @@ namespace ZeroTier {
* Transfer rate and total transferred amount meter * Transfer rate and total transferred amount meter
* *
* @tparam TUNIT Unit of time in milliseconds (default: 1000 for one second) * @tparam TUNIT Unit of time in milliseconds (default: 1000 for one second)
* @tparam LSIZE Log size in units of time (default: 60 for one minute worth of data) * @tparam LSIZE Log size in units of time (default: 10 for 10s worth of data)
*/ */
template<int64_t TUNIT = 1000,unsigned long LSIZE = 60> template<int64_t TUNIT = 1000,unsigned long LSIZE = 10>
class Meter class Meter
{ {
public: public:
@ -36,58 +36,46 @@ public:
* *
* @param now Start time * @param now Start time
*/ */
ZT_ALWAYS_INLINE Meter(const int64_t now) noexcept : startTime(now) {} ZT_ALWAYS_INLINE Meter(const int64_t now) noexcept {}
/** /**
* Add a measurement * Add a measurement
* *
* @tparam I Type of 'count' (usually inferred)
* @param now Current time * @param now Current time
* @param count Count of items (usually bytes) * @param count Count of items (usually bytes)
*/ */
template<typename I> ZT_ALWAYS_INLINE void log(const int64_t now,uint64_t count) noexcept
ZT_ALWAYS_INLINE void log(const int64_t now,I count) noexcept
{ {
_total += (uint64_t)count;
// We log by choosing a log bucket based on the current time in units modulo // 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 // the log size and then if it's a new bucket setting it or otherwise adding
// to it. // to it.
const unsigned long bucket = ((unsigned int)((uint64_t)(now / TUNIT))) % LSIZE; const unsigned long bucket = ((unsigned long)(now / TUNIT)) % LSIZE;
if (_bucket.exchange(bucket) != bucket) if (_bucket.exchange(bucket) != bucket) {
_counts[bucket].store((uint64_t)count); _totalExclCounts.fetch_add(_counts[bucket].exchange(count));
else _counts[bucket].fetch_add((uint64_t)count); } else {
_counts[bucket].fetch_add(count);
}
} }
/** /**
* Get rate per TUNIT time * Get rate per TUNIT time
* *
* @param now Current time * @param now Current time
* @return Count per TUNIT time (rate) * @param rate Result parameter: rate in count/TUNIT
* @param total Total count for life of object
*/ */
ZT_ALWAYS_INLINE double rate(const int64_t now) const noexcept ZT_ALWAYS_INLINE void rate(double &rate,uint64_t &total) const noexcept
{ {
// Rate is computed by looking back at N buckets where N is the smaller of total = 0;
// the size of the log or the number of units since the start time. for(unsigned long i=0;i<LSIZE;++i)
const unsigned long lookback = std::min((unsigned long)((now - startTime) / TUNIT),LSIZE); total += _counts[i].load();
if (lookback == 0) rate = (double)total / (double)LSIZE;
return 0.0; total += _totalExclCounts.load();
unsigned long bi = ((unsigned int)((uint64_t)(now / TUNIT)));
double sum = 0.0;
for(unsigned long l=0;l<lookback;++l)
sum += (double)_counts[bi-- % LSIZE].load();
return sum / (double)lookback;
} }
/**
* @return Total count since meter was created
*/
ZT_ALWAYS_INLINE uint64_t total() const noexcept { return _total.load(); }
private: private:
const int64_t startTime;
std::atomic<uint64_t> _total;
std::atomic<uint64_t> _counts[LSIZE]; std::atomic<uint64_t> _counts[LSIZE];
std::atomic<uint64_t> _totalExclCounts;
std::atomic<unsigned long> _bucket; std::atomic<unsigned long> _bucket;
}; };

View file

@ -21,6 +21,7 @@ bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigne
{ {
if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) { if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) {
_lastOut = now; _lastOut = now;
_outMeter.log(now,len);
return true; return true;
} }
return false; return false;

View file

@ -14,6 +14,13 @@
#ifndef ZT_PATH_HPP #ifndef ZT_PATH_HPP
#define ZT_PATH_HPP #define ZT_PATH_HPP
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include "Mutex.hpp"
#include "Meter.hpp"
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
@ -21,12 +28,6 @@
#include <algorithm> #include <algorithm>
#include <set> #include <set>
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include "Mutex.hpp"
namespace ZeroTier { namespace ZeroTier {
class RuntimeEnvironment; class RuntimeEnvironment;
@ -69,30 +70,33 @@ public:
/** /**
* Explicitly update last sent time * Explicitly update last sent time
* *
* @param t Time of send * @param now Time of send
* @param bytes Bytes sent
*/ */
ZT_ALWAYS_INLINE void sent(const int64_t t) noexcept { _lastOut = t; } ZT_ALWAYS_INLINE void sent(const int64_t now,const unsigned int bytes) noexcept
{
_lastOut.store(now);
_outMeter.log(now,bytes);
}
/** /**
* Called when a packet is received from this remote path, regardless of content * Called when a packet is received from this remote path, regardless of content
* *
* @param t Time of receive * @param now Time of receive
* @param bytes Bytes received
*/ */
ZT_ALWAYS_INLINE void received(const int64_t t) noexcept { _lastIn = t; } ZT_ALWAYS_INLINE void received(const int64_t now,const unsigned int bytes) noexcept
{
_lastIn.store(now);
_inMeter.log(now,bytes);
}
/** /**
* Check path aliveness * Check path aliveness
* *
* @param now Current time * @param now Current time
*/ */
ZT_ALWAYS_INLINE bool alive(const int64_t now) const noexcept { return ((now - _lastIn) < ZT_PATH_ALIVE_TIMEOUT); } ZT_ALWAYS_INLINE bool alive(const int64_t now) const noexcept { return ((now - _lastIn.load()) < ZT_PATH_ALIVE_TIMEOUT); }
/**
* Check if path is considered active
*
* @param now Current time
*/
ZT_ALWAYS_INLINE bool active(const int64_t now) const noexcept { return ((now - _lastIn) < ZT_PATH_ACTIVITY_TIMEOUT); }
/** /**
* @return Physical address * @return Physical address
@ -107,18 +111,20 @@ public:
/** /**
* @return Last time we received anything * @return Last time we received anything
*/ */
ZT_ALWAYS_INLINE int64_t lastIn() const noexcept { return _lastIn; } ZT_ALWAYS_INLINE int64_t lastIn() const noexcept { return _lastIn.load(); }
/** /**
* @return Last time we sent something * @return Last time we sent something
*/ */
ZT_ALWAYS_INLINE int64_t lastOut() const noexcept { return _lastOut; } ZT_ALWAYS_INLINE int64_t lastOut() const noexcept { return _lastOut.load(); }
private: private:
int64_t _localSocket; int64_t _localSocket;
int64_t _lastIn; std::atomic<int64_t> _lastIn;
int64_t _lastOut; std::atomic<int64_t> _lastOut;
InetAddress _addr; InetAddress _addr;
Meter<> _inMeter;
Meter<> _outMeter;
// These fields belong to Defragmenter but are kept in Path for performance // These fields belong to Defragmenter but are kept in Path for performance
// as it's much faster this way than having Defragmenter maintain another // as it's much faster this way than having Defragmenter maintain another

View file

@ -224,7 +224,7 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
uint64_t *k = nullptr; uint64_t *k = nullptr;
SharedPtr<Path> *p = nullptr; SharedPtr<Path> *p = nullptr;
while (i.next(k,p)) { while (i.next(k,p)) {
if (p->references() <= 1) if ((p->references() <= 1)&&(!(*p)->alive(now)))
_paths.erase(*k); _paths.erase(*k);
} }
} }