14#include <boost/noncopyable.hpp>
15#include <boost/shared_ptr.hpp>
16#include <boost/multi_index_container.hpp>
17#include <boost/multi_index/ordered_index.hpp>
18#include <boost/multi_index/sequenced_index.hpp>
19#include <boost/multi_index/global_fun.hpp>
20#include <boost/multi_index/mem_fun.hpp>
21#include <boost/date_time/posix_time/posix_time.hpp>
47template <
class T = dhcp::Pkt4>
79 return (this_counter);
92 uint64_t
getValue()
const {
return(counter_); }
99 const std::string&
getName()
const {
return(name_); }
149 return(packet->getTransid() & 1023);
220 typedef boost::multi_index_container<
222 boost::shared_ptr<T>,
224 boost::multi_index::indexed_by<
227 boost::multi_index::sequenced<>,
232 boost::multi_index::ordered_non_unique<
236 boost::multi_index::global_fun<
239 const boost::shared_ptr<T>&,
252 typedef typename PktList::template nth_index<1>::type
255 typedef typename PktListTransidHashIndex::const_iterator
258 typedef typename std::queue<PktListTransidHashIterator>
270 const double drop_time,
271 const bool archive_enabled,
272 const boost::posix_time::ptime boot_time)
273 : xchg_type_(xchg_type),
277 archive_enabled_(archive_enabled),
278 drop_time_(drop_time),
279 min_delay_(std::numeric_limits<double>::max()),
282 sum_delay_squared_(0.),
285 unordered_lookup_size_sum_(0),
286 unordered_lookups_(0),
288 sent_packets_num_(0),
289 rcvd_packets_num_(0),
290 boot_time_(boot_time)
292 next_sent_ = sent_packets_.begin();
306 sent_packets_.template get<0>().push_back(packet);
319 rcvd_packets_.push_back(packet);
332 const boost::shared_ptr<T>& rcvd_packet) {
340 boost::posix_time::ptime sent_time = sent_packet->getTimestamp();
341 boost::posix_time::ptime rcvd_time = rcvd_packet->getTimestamp();
343 if (sent_time.is_not_a_date_time() ||
344 rcvd_time.is_not_a_date_time()) {
346 "Timestamp must be set for sent and "
347 "received packet to measure RTT");
349 boost::posix_time::time_period period(sent_time, rcvd_time);
354 static_cast<double>(period.length().total_nanoseconds()) / 1e9;
358 "greater than received packet's timestamp");
362 if (delta < min_delay_) {
366 if (delta > max_delay_) {
372 sum_delay_squared_ += delta * delta;
392 using namespace boost::posix_time;
398 if (sent_packets_.size() == 0) {
404 return(boost::shared_ptr<T>());
405 }
else if (next_sent_ == sent_packets_.end()) {
409 next_sent_ = sent_packets_.begin();
414 bool packet_found =
false;
421 if ((*next_sent_)->getTransid() == rcvd_packet->getTransid()) {
436 std::pair<PktListTransidHashIterator,PktListTransidHashIterator> p =
443 ++unordered_lookups_;
447 unordered_lookup_size_sum_ += std::distance(p.first, p.second);
448 bool non_expired_found =
false;
460 if (!packet_found && ((*it)->getTransid() == rcvd_packet->getTransid())) {
462 next_sent_ = sent_packets_.template project<0>(it);
465 if (!non_expired_found) {
468 ptime now = microsec_clock::universal_time();
469 ptime packet_time = (*it)->getTimestamp();
470 time_period packet_period(packet_time, now);
471 if (!packet_period.is_null()) {
472 double period_fractional =
473 packet_period.length().total_seconds() +
474 (
static_cast<double>(packet_period.length().fractional_seconds())
475 / packet_period.length().ticks_per_second());
476 if (drop_time_ > 0 && (period_fractional > drop_time_)) {
485 non_expired_found =
true;
492 if (non_expired_found && packet_found) {
498 while (!to_remove.empty()) {
507 if (sent_packets_.template project<0>(it) != next_sent_) {
508 eraseSent(sent_packets_.template project<0>(it));
510 next_sent_ = eraseSent(sent_packets_.template project<0>(it));
513 packet_found =
false;
523 return(boost::shared_ptr<T>());
529 boost::shared_ptr<T> sent_packet(*next_sent_);
533 next_sent_ = eraseSent(next_sent_);
561 if (rcvd_packets_num_ == 0) {
564 return(sum_delay_ / rcvd_packets_num_);
578 if (rcvd_packets_num_ == 0) {
581 return(sqrt(sum_delay_squared_ / rcvd_packets_num_ -
615 if (unordered_lookups_ == 0) {
618 return(
static_cast<double>(unordered_lookup_size_sum_) /
619 static_cast<double>(unordered_lookups_));
701 cout << fixed << setprecision(3)
702 <<
"min delay: " <<
getMinDelay() * 1e3 <<
" ms" << endl
703 <<
"avg delay: " <<
getAvgDelay() * 1e3 <<
" ms" << endl
704 <<
"max delay: " <<
getMaxDelay() * 1e3 <<
" ms" << endl
709 cout <<
"Delay summary unavailable! No packets received." << endl;
726 if (!archive_enabled_) {
728 "packets archive mode is disabled");
730 if (rcvd_packets_num_ == 0) {
731 std::cout <<
"Unavailable! No packets received." << std::endl;
734 using namespace boost::posix_time;
738 it != rcvd_packets_.end();
740 boost::shared_ptr<T> rcvd_packet = *it;
742 archived_packets_.template get<1>();
747 it_archived != p.second;
749 if ((*it_archived)->getTransid() ==
750 rcvd_packet->getTransid()) {
751 boost::shared_ptr<T> sent_packet = *it_archived;
753 ptime sent_time = sent_packet->getTimestamp();
754 ptime rcvd_time = rcvd_packet->getTimestamp();
758 if (sent_time.is_not_a_date_time() ||
759 rcvd_time.is_not_a_date_time()) {
761 "packet time is not set");
764 time_period sent_period(boot_time_, sent_time);
765 time_period rcvd_period(boot_time_, rcvd_time);
767 std::cout <<
"sent / received: "
768 << to_iso_string(sent_period.length())
770 << to_iso_string(rcvd_period.length())
794 if (archive_enabled_) {
801 archived_packets_.push_back(*it);
805 return(sent_packets_.template get<0>().erase(it));
834 bool archive_enabled_;
846 double sum_delay_squared_;
858 uint64_t unordered_lookup_size_sum_;
860 uint64_t unordered_lookups_;
862 uint64_t ordered_lookups_;
865 uint64_t sent_packets_num_;
866 uint64_t rcvd_packets_num_;
867 boost::posix_time::ptime boot_time_;
873 typedef typename std::map<ExchangeType, ExchangeStatsPtr>
ExchangesMap;
896 archive_enabled_(archive_enabled),
897 boot_time_(
boost::posix_time::microsec_clock::universal_time()) {
911 const double drop_time = -1) {
912 if (exchanges_.find(xchg_type) != exchanges_.end()) {
915 exchanges_[xchg_type] =
933 return (exchanges_.find(xchg_type) != exchanges_.end());
944 const std::string& long_name) {
945 if (custom_counters_.find(short_name) != custom_counters_.end()) {
947 "Custom counter " << short_name <<
" already added.");
949 custom_counters_[short_name] =
958 it != exchanges_.end();
960 if (it->second->getDroppedPacketsNum() > 0) {
976 if (it == custom_counters_.end()) {
978 "Custom counter " << counter_key <<
"does not exist");
991 const uint64_t value = 1) {
1008 const boost::shared_ptr<T>& packet) {
1010 xchg_stats->appendSent(packet);
1026 boost::shared_ptr<T>
1028 const boost::shared_ptr<T>& packet) {
1030 boost::shared_ptr<T> sent_packet
1031 = xchg_stats->matchPackets(packet);
1034 xchg_stats->updateDelays(sent_packet, packet);
1035 if (archive_enabled_) {
1036 xchg_stats->appendRcvd(packet);
1039 return(sent_packet);
1052 return(xchg_stats->getMinDelay());
1065 return(xchg_stats->getMaxDelay());
1076 return(xchg_stats->getAvgDelay());
1087 return(xchg_stats->getStdDevDelay());
1100 return(xchg_stats->getOrphans());
1114 return(xchg_stats->getAvgUnorderedLookupSetSize());
1129 return(xchg_stats->getUnorderedLookups());
1145 return(xchg_stats->getOrderedLookups());
1158 return(xchg_stats->getSentPacketsNum());
1171 return(xchg_stats->getRcvdPacketsNum());
1184 return(xchg_stats->getDroppedPacketsNum());
1199 return(xchg_stats->getCollectedNum());
1211 using namespace boost::posix_time;
1212 time_period test_period(boot_time_,
1213 microsec_clock::universal_time());
1227 return(
"DISCOVER-OFFER");
1229 return(
"REQUEST-ACK");
1231 return(
"REQUEST-ACK (renewal)");
1233 return(
"SOLICIT-ADVERTISE");
1235 return(
"REQUEST-REPLY");
1237 return(
"RENEW-REPLY");
1239 return(
"RELEASE-REPLY");
1241 return(
"Unknown exchange type");
1259 if (exchanges_.empty()) {
1261 "no exchange type added for tracking");
1264 it != exchanges_.end();
1268 <<
"***" << std::endl;
1269 xchg_stats->printMainStats();
1270 std::cout << std::endl;
1271 xchg_stats->printRTTStats();
1272 std::cout << std::endl;
1282 std::ostringstream stream_sent;
1283 std::ostringstream stream_rcvd;
1284 std::ostringstream stream_drops;
1285 std::string sep(
"");
1287 it != exchanges_.end(); ++it) {
1289 if (it != exchanges_.begin()) {
1292 stream_sent << sep << it->second->getSentPacketsNum();
1293 stream_rcvd << sep << it->second->getRcvdPacketsNum();
1294 stream_drops << sep << it->second->getDroppedPacketsNum();
1296 std::cout <<
"sent: " << stream_sent.str()
1297 <<
"; received: " << stream_rcvd.str()
1298 <<
"; drops: " << stream_drops.str()
1314 if (exchanges_.empty()) {
1316 "no exchange type added for tracking");
1319 it != exchanges_.end();
1322 std::cout <<
"***Timestamps for packets: "
1324 <<
"***" << std::endl;
1325 xchg_stats->printTimestamps();
1326 std::cout << std::endl;
1337 if (custom_counters_.empty()) {
1341 it != custom_counters_.end();
1344 std::cout << counter->getName() <<
": " << counter->getValue()
1360 if (it == exchanges_.end()) {
1378 bool archive_enabled_;
1380 boost::posix_time::ptime boot_time_;
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown when an unexpected error condition occurs.
const CustomCounter & operator++()
Increment operator.
const std::string & getName() const
Return counter name.
uint64_t getValue() const
Return counter value.
CustomCounter(const std::string &name)
Constructor.
const CustomCounter & operator+=(int val)
const CustomCounter & operator++(int)
Increment operator.
void updateDelays(const boost::shared_ptr< T > &sent_packet, const boost::shared_ptr< T > &rcvd_packet)
Update delay counters.
uint64_t getSentPacketsNum() const
Return total number of sent packets.
PktList::template nth_index< 1 >::type PktListTransidHashIndex
Packet list index to search packets using transaction id hash.
PktListTransidHashIndex::const_iterator PktListTransidHashIterator
Packet list iterator to access packets using transaction id hash.
ExchangeStats(const ExchangeType xchg_type, const double drop_time, const bool archive_enabled, const boost::posix_time::ptime boot_time)
Constructor.
double getStdDevDelay() const
Return standard deviation of packet delay.
uint64_t getOrphans() const
Return number of orphan packets.
std::queue< PktListTransidHashIterator > PktListRemovalQueue
Packet list iterator queue for removal.
uint64_t getUnorderedLookups() const
Return number of unordered sent packets lookups.
void appendRcvd(const boost::shared_ptr< T > &packet)
Add new packet to list of received packets.
double getMaxDelay() const
Return maximum delay between sent and received packet.
uint64_t getRcvdPacketsNum() const
Return total number of received packets.
uint64_t getDroppedPacketsNum() const
Return number of dropped packets.
void printRTTStats() const
Print round trip time packets statistics.
uint64_t getCollectedNum() const
Return number of garbage collected packets.
void appendSent(const boost::shared_ptr< T > &packet)
Add new packet to list of sent packets.
double getMinDelay() const
Return minimum delay between sent and received packet.
double getAvgUnorderedLookupSetSize() const
Return average unordered lookup set size.
boost::multi_index_container< boost::shared_ptr< T >, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::ordered_non_unique< boost::multi_index::global_fun< const boost::shared_ptr< T > &, uint32_t, &ExchangeStats::hashTransid > > > > PktList
List of packets (sent or received).
boost::shared_ptr< T > matchPackets(const boost::shared_ptr< T > &rcvd_packet)
Match received packet with the corresponding sent packet.
static uint32_t hashTransid(const boost::shared_ptr< T > &packet)
Hash transaction id of the packet.
uint64_t getOrderedLookups() const
Return number of ordered sent packets lookups.
void printMainStats() const
Print main statistics for packet exchange.
double getAvgDelay() const
Return average packet delay.
void printTimestamps()
Print timestamps for sent and received packets.
PktList::iterator PktListIterator
Packet list iterator for sequential access to elements.
uint64_t getDroppedPacketsNum(const ExchangeType xchg_type) const
Return total number of dropped packets.
uint64_t getUnorderedLookups(const ExchangeType xchg_type) const
Return number of unordered sent packets lookups.
void printStats() const
Print statistics counters for all exchange types.
uint64_t getOrderedLookups(const ExchangeType xchg_type) const
Return number of ordered sent packets lookups.
double getAvgDelay(const ExchangeType xchg_type) const
Return average packet delay.
void passSentPacket(const ExchangeType xchg_type, const boost::shared_ptr< T > &packet)
Adds new packet to the sent packets list.
const CustomCounter & incrementCounter(const std::string &counter_key, const uint64_t value=1)
Increment specified counter.
bool hasExchangeStats(const ExchangeType xchg_type) const
Check if the exchange type has been specified.
std::map< ExchangeType, ExchangeStatsPtr > ExchangesMap
Map containing all specified exchange types.
void printIntermediateStats() const
Print intermediate statistics.
uint64_t getCollectedNum(const ExchangeType xchg_type) const
Return number of garbage collected packets.
double getMinDelay(const ExchangeType xchg_type) const
Return minimum delay between sent and received packet.
StatsMgr(const bool archive_enabled=false)
Constructor.
uint64_t getSentPacketsNum(const ExchangeType xchg_type) const
Return total number of sent packets.
std::map< std::string, CustomCounterPtr > CustomCountersMap
Map containing custom counters.
bool droppedPackets() const
Check if any packet drops occurred.
void addExchangeStats(const ExchangeType xchg_type, const double drop_time=-1)
Specify new exchange type.
boost::shared_ptr< ExchangeStats > ExchangeStatsPtr
Pointer to ExchangeStats.
static std::string exchangeToString(ExchangeType xchg_type)
Return name of the exchange.
uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const
Return total number of received packets.
boost::shared_ptr< T > passRcvdPacket(const ExchangeType xchg_type, const boost::shared_ptr< T > &packet)
Add new received packet and match with sent packet.
CustomCountersMap::const_iterator CustomCountersMapIterator
Iterator for CustomCountersMap.
void addCustomCounter(const std::string &short_name, const std::string &long_name)
Add named custom uint64 counter.
ExchangeType
DHCP packet exchange types.
@ XCHG_SA
DHCPv6 SOLICIT-ADVERTISE.
@ XCHG_RNA
DHCPv4 REQUEST-ACK (renewal)
@ XCHG_RA
DHCPv4 REQUEST-ACK.
@ XCHG_RL
DHCPv6 RELEASE-REPLY.
@ XCHG_RR
DHCPv6 REQUEST-REPLY.
@ XCHG_RN
DHCPv6 RENEW-REPLY.
@ XCHG_DO
DHCPv4 DISCOVER-OFFER.
double getMaxDelay(const ExchangeType xchg_type) const
Return maximum delay between sent and received packet.
void printTimestamps() const
Print timestamps of all packets.
CustomCounterPtr getCounter(const std::string &counter_key)
Return specified counter.
void printCustomCounters() const
Print names and values of custom counters.
double getStdDevDelay(const ExchangeType xchg_type) const
Return standard deviation of packet delay.
boost::posix_time::time_period getTestPeriod() const
Get time period since the start of test.
uint64_t getOrphans(const ExchangeType xchg_type) const
Return number of orphan packets.
double getAvgUnorderedLookupSetSize(const ExchangeType xchg_type) const
Return average unordered lookup set size.
ExchangesMap::const_iterator ExchangesMapIterator
Iterator pointing to ExchangesMap.
boost::shared_ptr< CustomCounter > CustomCounterPtr
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Defines the logger used by the top-level component of kea-dhcp-ddns.