Kea  1.5.0
bin/perfdhcp/stats_mgr.h
Go to the documentation of this file.
1 // Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef STATS_MGR_H
8 #define STATS_MGR_H
9 
10 #include <dhcp/pkt4.h>
11 #include <dhcp/pkt6.h>
12 #include <exceptions/exceptions.h>
13 
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>
22 
23 #include <iostream>
24 #include <map>
25 #include <queue>
26 
27 
28 namespace isc {
29 namespace perfdhcp {
30 
47 template <class T = dhcp::Pkt4>
48 class StatsMgr : public boost::noncopyable {
49 public:
50 
57  class CustomCounter {
58  public:
65  CustomCounter(const std::string& name) :
66  counter_(0),
67  name_(name) { };
68 
71  ++counter_;
72  return (*this);
73  }
74 
76  const CustomCounter& operator++(int) {
77  CustomCounter& this_counter(*this);
78  operator++();
79  return (this_counter);
80  }
81 
82  const CustomCounter& operator+=(int val) {
83  counter_ += val;
84  return (*this);
85  }
86 
92  uint64_t getValue() const { return(counter_); }
93 
99  const std::string& getName() const { return(name_); }
100  private:
106  CustomCounter() { };
107 
108  uint64_t counter_;
109  std::string name_;
110  };
111 
112  typedef typename boost::shared_ptr<CustomCounter> CustomCounterPtr;
113 
123  };
124 
133  public:
134 
145  static uint32_t hashTransid(const boost::shared_ptr<T>& packet) {
146  if (!packet) {
147  isc_throw(BadValue, "Packet is null");
148  }
149  return(packet->getTransid() & 1023);
150  }
151 
220  typedef boost::multi_index_container<
221  // Container holds shared_ptr<Pkt4> or shared_ptr<Pkt6> objects.
222  boost::shared_ptr<T>,
223  // List container indexes.
224  boost::multi_index::indexed_by<
225  // Sequenced index provides the way to use this container
226  // in the same way as std::list.
227  boost::multi_index::sequenced<>,
228  // The other index keeps products of transaction id.
229  // Elements with the same hash value are grouped together
230  // into buckets and transactions are ordered from the
231  // oldest to latest within a bucket.
232  boost::multi_index::ordered_non_unique<
233  // Specify hash function to get the product of
234  // transaction id. This product is obtained by calling
235  // hashTransid() function.
236  boost::multi_index::global_fun<
237  // Hashing function takes shared_ptr<Pkt4> or
238  // shared_ptr<Pkt6> as argument.
239  const boost::shared_ptr<T>&,
240  // ... and returns uint32 value.
241  uint32_t,
242  // ... and here is a reference to it.
244  >
245  >
246  >
248 
250  typedef typename PktList::iterator PktListIterator;
252  typedef typename PktList::template nth_index<1>::type
255  typedef typename PktListTransidHashIndex::const_iterator
258  typedef typename std::queue<PktListTransidHashIterator>
260 
269  ExchangeStats(const ExchangeType xchg_type,
270  const double drop_time,
271  const bool archive_enabled,
272  const boost::posix_time::ptime boot_time)
273  : xchg_type_(xchg_type),
274  sent_packets_(),
275  rcvd_packets_(),
276  archived_packets_(),
277  archive_enabled_(archive_enabled),
278  drop_time_(drop_time),
279  min_delay_(std::numeric_limits<double>::max()),
280  max_delay_(0.),
281  sum_delay_(0.),
282  sum_delay_squared_(0.),
283  orphans_(0),
284  collected_(0),
285  unordered_lookup_size_sum_(0),
286  unordered_lookups_(0),
287  ordered_lookups_(0),
288  sent_packets_num_(0),
289  rcvd_packets_num_(0),
290  boot_time_(boot_time)
291  {
292  next_sent_ = sent_packets_.begin();
293  }
294 
301  void appendSent(const boost::shared_ptr<T>& packet) {
302  if (!packet) {
303  isc_throw(BadValue, "Packet is null");
304  }
305  ++sent_packets_num_;
306  sent_packets_.template get<0>().push_back(packet);
307  }
308 
315  void appendRcvd(const boost::shared_ptr<T>& packet) {
316  if (!packet) {
317  isc_throw(BadValue, "Packet is null");
318  }
319  rcvd_packets_.push_back(packet);
320  }
321 
331  void updateDelays(const boost::shared_ptr<T>& sent_packet,
332  const boost::shared_ptr<T>& rcvd_packet) {
333  if (!sent_packet) {
334  isc_throw(BadValue, "Sent packet is null");
335  }
336  if (!rcvd_packet) {
337  isc_throw(BadValue, "Received packet is null");
338  }
339 
340  boost::posix_time::ptime sent_time = sent_packet->getTimestamp();
341  boost::posix_time::ptime rcvd_time = rcvd_packet->getTimestamp();
342 
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");
348  }
349  boost::posix_time::time_period period(sent_time, rcvd_time);
350  // We don't bother calculating deltas in nanoseconds. It is much
351  // more convenient to use seconds instead because we are going to
352  // sum them up.
353  double delta =
354  static_cast<double>(period.length().total_nanoseconds()) / 1e9;
355 
356  if (delta < 0) {
357  isc_throw(Unexpected, "Sent packet's timestamp must not be "
358  "greater than received packet's timestamp");
359  }
360 
361  // Record the minimum delay between sent and received packets.
362  if (delta < min_delay_) {
363  min_delay_ = delta;
364  }
365  // Record the maximum delay between sent and received packets.
366  if (delta > max_delay_) {
367  max_delay_ = delta;
368  }
369  // Update delay sum and square sum. That will be used to calculate
370  // mean delays.
371  sum_delay_ += delta;
372  sum_delay_squared_ += delta * delta;
373  }
374 
390  boost::shared_ptr<T>
391  matchPackets(const boost::shared_ptr<T>& rcvd_packet) {
392  using namespace boost::posix_time;
393 
394  if (!rcvd_packet) {
395  isc_throw(BadValue, "Received packet is null");
396  }
397 
398  if (sent_packets_.size() == 0) {
399  // List of sent packets is empty so there is no sense
400  // to continue looking fo the packet. It also means
401  // that the received packet we got has no corresponding
402  // sent packet so orphans counter has to be updated.
403  ++orphans_;
404  return(boost::shared_ptr<T>());
405  } else if (next_sent_ == sent_packets_.end()) {
406  // Even if there are still many unmatched packets on the
407  // list we might hit the end of it because of unordered
408  // lookups. The next logical step is to reset iterator.
409  next_sent_ = sent_packets_.begin();
410  }
411 
412  // With this variable we will be signalling success or failure
413  // to find the packet.
414  bool packet_found = false;
415  // Most likely responses are sent from the server in the same
416  // order as client's requests to the server. We are caching
417  // next sent packet and first try to match it with the next
418  // incoming packet. We are successful if there is no
419  // packet drop or out of order packets sent. This is actually
420  // the fastest way to look for packets.
421  if ((*next_sent_)->getTransid() == rcvd_packet->getTransid()) {
422  ++ordered_lookups_;
423  packet_found = true;
424  } else {
425  // If we are here, it means that we were unable to match the
426  // next incoming packet with next sent packet so we need to
427  // take a little more expensive approach to look packets using
428  // alternative index (transaction id & 1023).
429  PktListTransidHashIndex& idx = sent_packets_.template get<1>();
430  // Packets are grouped using transaction id masked with value
431  // of 1023. For instance, packets with transaction id equal to
432  // 1, 1024 ... will belong to the same group (a.k.a. bucket).
433  // When using alternative index we don't find the packet but
434  // bucket of packets and we need to iterate through the bucket
435  // to find the one that has desired transaction id.
436  std::pair<PktListTransidHashIterator,PktListTransidHashIterator> p =
437  idx.equal_range(hashTransid(rcvd_packet));
438  // We want to keep statistics of unordered lookups to make
439  // sure that there is a right balance between number of
440  // unordered lookups and ordered lookups. If number of unordered
441  // lookups is high it may mean that many packets are lost or
442  // sent out of order.
443  ++unordered_lookups_;
444  // We also want to keep the mean value of the bucket. The lower
445  // bucket size the better. If bucket sizes appear to big we
446  // might want to increase number of buckets.
447  unordered_lookup_size_sum_ += std::distance(p.first, p.second);
448  bool non_expired_found = false;
449  // Removal can be done only after the loop
450  PktListRemovalQueue to_remove;
451  for (PktListTransidHashIterator it = p.first; it != p.second;
452  ++it) {
453  // If transaction id is matching, we found the original
454  // packet sent to the server. Therefore, we reset the
455  // 'next sent' pointer to point to this location. We
456  // also indicate that the matching packet is found.
457  // Even though the packet has been found, we continue
458  // iterating over the bucket to remove all those packets
459  // that are timed out.
460  if (!packet_found && ((*it)->getTransid() == rcvd_packet->getTransid())) {
461  packet_found = true;
462  next_sent_ = sent_packets_.template project<0>(it);
463  }
464 
465  if (!non_expired_found) {
466  // Check if the packet should be removed due to timeout.
467  // This includes the packet matching the received one.
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_)) {
477  // Push the iterator on the removal queue.
478  to_remove.push(it);
479 
480  } else {
481  // We found first non-expired transaction. All other
482  // transactions within this bucket are considered
483  // non-expired because packets are held in the
484  // order of addition within the bucket.
485  non_expired_found = true;
486  }
487  }
488  }
489 
490  // If we found the packet and all expired transactions,
491  // there is nothing more to do.
492  if (non_expired_found && packet_found) {
493  break;
494  }
495  }
496 
497  // Deal with the removal queue.
498  while (!to_remove.empty()) {
499  PktListTransidHashIterator it = to_remove.front();
500  to_remove.pop();
501  // If timed out packet is not the one matching server response,
502  // we simply remove it and keep the pointer to the 'next sent'
503  // packet as it was. If the timed out packet appears to be the
504  // one that is matching the server response, we still want to
505  // remove it, but we need to update the 'next sent' pointer to
506  // point to a valid location.
507  if (sent_packets_.template project<0>(it) != next_sent_) {
508  eraseSent(sent_packets_.template project<0>(it));
509  } else {
510  next_sent_ = eraseSent(sent_packets_.template project<0>(it));
511  // We removed the matching packet because of the timeout. It
512  // means that there is no match anymore.
513  packet_found = false;
514  }
515  ++collected_;
516  }
517  }
518 
519  if (!packet_found) {
520  // If we are here, it means that both ordered lookup and
521  // unordered lookup failed. Searched packet is not on the list.
522  ++orphans_;
523  return(boost::shared_ptr<T>());
524  }
525 
526  // Packet is matched so we count it. We don't count unmatched packets
527  // as they are counted as orphans with a separate counter.
528  ++rcvd_packets_num_;
529  boost::shared_ptr<T> sent_packet(*next_sent_);
530  // If packet was found, we assume it will be never searched
531  // again. We want to delete this packet from the list to
532  // improve performance of future searches.
533  next_sent_ = eraseSent(next_sent_);
534  return(sent_packet);
535  }
536 
542  double getMinDelay() const { return(min_delay_); }
543 
549  double getMaxDelay() const { return(max_delay_); }
550 
560  double getAvgDelay() const {
561  if (rcvd_packets_num_ == 0) {
562  isc_throw(InvalidOperation, "no packets received");
563  }
564  return(sum_delay_ / rcvd_packets_num_);
565  }
566 
577  double getStdDevDelay() const {
578  if (rcvd_packets_num_ == 0) {
579  isc_throw(InvalidOperation, "no packets received");
580  }
581  return(sqrt(sum_delay_squared_ / rcvd_packets_num_ -
582  getAvgDelay() * getAvgDelay()));
583  }
584 
592  uint64_t getOrphans() const { return(orphans_); }
593 
603  uint64_t getCollectedNum() const { return(collected_); }
604 
615  if (unordered_lookups_ == 0) {
616  isc_throw(InvalidOperation, "no unordered lookups");
617  }
618  return(static_cast<double>(unordered_lookup_size_sum_) /
619  static_cast<double>(unordered_lookups_));
620  }
621 
630  uint64_t getUnorderedLookups() const { return(unordered_lookups_); }
631 
641  uint64_t getOrderedLookups() const { return(ordered_lookups_); }
642 
648  uint64_t getSentPacketsNum() const { return(sent_packets_num_); }
649 
655  uint64_t getRcvdPacketsNum() const { return(rcvd_packets_num_); }
656 
662  uint64_t getDroppedPacketsNum() const {
663  uint64_t drops = 0;
665  drops = getSentPacketsNum() - getRcvdPacketsNum();
666  }
667  return(drops);
668  }
669 
683  void printMainStats() const {
684  using namespace std;
685  cout << "sent packets: " << getSentPacketsNum() << endl
686  << "received packets: " << getRcvdPacketsNum() << endl
687  << "drops: " << getDroppedPacketsNum() << endl;
688  // << "orphans: " << getOrphans() << endl;
689  }
690 
698  void printRTTStats() const {
699  using namespace std;
700  try {
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
705  << "std deviation: " << getStdDevDelay() * 1e3 << " ms"
706  << endl
707  << "collected packets: " << getCollectedNum() << endl;
708  } catch (const Exception&) {
709  cout << "Delay summary unavailable! No packets received." << endl;
710  }
711  }
712 
724  // If archive mode is disabled there is no sense to proceed
725  // because we don't have packets and their timestamps.
726  if (!archive_enabled_) {
728  "packets archive mode is disabled");
729  }
730  if (rcvd_packets_num_ == 0) {
731  std::cout << "Unavailable! No packets received." << std::endl;
732  }
733  // We will be using boost::posix_time extensively here
734  using namespace boost::posix_time;
735 
736  // Iterate through all received packets.
737  for (PktListIterator it = rcvd_packets_.begin();
738  it != rcvd_packets_.end();
739  ++it) {
740  boost::shared_ptr<T> rcvd_packet = *it;
742  archived_packets_.template get<1>();
743  std::pair<PktListTransidHashIterator,
745  idx.equal_range(hashTransid(rcvd_packet));
746  for (PktListTransidHashIterator it_archived = p.first;
747  it_archived != p.second;
748  ++it_archived) {
749  if ((*it_archived)->getTransid() ==
750  rcvd_packet->getTransid()) {
751  boost::shared_ptr<T> sent_packet = *it_archived;
752  // Get sent and received packet times.
753  ptime sent_time = sent_packet->getTimestamp();
754  ptime rcvd_time = rcvd_packet->getTimestamp();
755  // All sent and received packets should have timestamps
756  // set but if there is a bug somewhere and packet does
757  // not have timestamp we want to catch this here.
758  if (sent_time.is_not_a_date_time() ||
759  rcvd_time.is_not_a_date_time()) {
761  "packet time is not set");
762  }
763  // Calculate durations of packets from beginning of epoch.
764  time_period sent_period(boot_time_, sent_time);
765  time_period rcvd_period(boot_time_, rcvd_time);
766  // Print timestamps for sent and received packet.
767  std::cout << "sent / received: "
768  << to_iso_string(sent_period.length())
769  << " / "
770  << to_iso_string(rcvd_period.length())
771  << std::endl;
772  break;
773  }
774  }
775  }
776  }
777 
778  private:
779 
784  ExchangeStats();
785 
793  PktListIterator eraseSent(const PktListIterator it) {
794  if (archive_enabled_) {
795  // We don't want to keep list of all sent packets
796  // because it will affect packet lookup performance.
797  // If packet is matched with received packet we
798  // move it to list of archived packets. List of
799  // archived packets may be used for diagnostics
800  // when test is completed.
801  archived_packets_.push_back(*it);
802  }
803  // get<0>() template returns sequential index to
804  // container.
805  return(sent_packets_.template get<0>().erase(it));
806  }
807 
808  ExchangeType xchg_type_;
809  PktList sent_packets_;
810 
814  PktListIterator next_sent_;
815 
816  PktList rcvd_packets_;
817 
821  PktList archived_packets_;
822 
834  bool archive_enabled_;
835 
838  double drop_time_;
839 
840  double min_delay_;
841  double max_delay_;
843  double sum_delay_;
845  double sum_delay_squared_;
847 
849  uint64_t orphans_;
850 
851  uint64_t collected_;
852 
858  uint64_t unordered_lookup_size_sum_;
859 
860  uint64_t unordered_lookups_;
861  uint64_t ordered_lookups_;
863 
865  uint64_t sent_packets_num_;
866  uint64_t rcvd_packets_num_;
867  boost::posix_time::ptime boot_time_;
868  };
869 
871  typedef boost::shared_ptr<ExchangeStats> ExchangeStatsPtr;
873  typedef typename std::map<ExchangeType, ExchangeStatsPtr> ExchangesMap;
875  typedef typename ExchangesMap::const_iterator ExchangesMapIterator;
877  typedef typename std::map<std::string, CustomCounterPtr> CustomCountersMap;
879  typedef typename CustomCountersMap::const_iterator CustomCountersMapIterator;
880 
894  StatsMgr(const bool archive_enabled = false) :
895  exchanges_(),
896  archive_enabled_(archive_enabled),
897  boot_time_(boost::posix_time::microsec_clock::universal_time()) {
898  }
899 
910  void addExchangeStats(const ExchangeType xchg_type,
911  const double drop_time = -1) {
912  if (exchanges_.find(xchg_type) != exchanges_.end()) {
913  isc_throw(BadValue, "Exchange of specified type already added.");
914  }
915  exchanges_[xchg_type] =
916  ExchangeStatsPtr(new ExchangeStats(xchg_type,
917  drop_time,
918  archive_enabled_,
919  boot_time_));
920  }
921 
932  bool hasExchangeStats(const ExchangeType xchg_type) const {
933  return (exchanges_.find(xchg_type) != exchanges_.end());
934  }
935 
943  void addCustomCounter(const std::string& short_name,
944  const std::string& long_name) {
945  if (custom_counters_.find(short_name) != custom_counters_.end()) {
947  "Custom counter " << short_name << " already added.");
948  }
949  custom_counters_[short_name] =
950  CustomCounterPtr(new CustomCounter(long_name));
951  }
952 
955  // \return true, if packet drops occurred.
956  bool droppedPackets() const {
957  for (ExchangesMapIterator it = exchanges_.begin();
958  it != exchanges_.end();
959  ++it) {
960  if (it->second->getDroppedPacketsNum() > 0) {
961  return (true);
962  }
963  }
964  return (false);
965  }
966 
974  CustomCounterPtr getCounter(const std::string& counter_key) {
975  CustomCountersMapIterator it = custom_counters_.find(counter_key);
976  if (it == custom_counters_.end()) {
978  "Custom counter " << counter_key << "does not exist");
979  }
980  return(it->second);
981  }
982 
990  const CustomCounter& incrementCounter(const std::string& counter_key,
991  const uint64_t value = 1) {
992  CustomCounterPtr counter = getCounter(counter_key);
993  *counter += value;
994  return (*counter);
995  }
996 
1007  void passSentPacket(const ExchangeType xchg_type,
1008  const boost::shared_ptr<T>& packet) {
1009  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1010  xchg_stats->appendSent(packet);
1011  }
1012 
1026  boost::shared_ptr<T>
1027  passRcvdPacket(const ExchangeType xchg_type,
1028  const boost::shared_ptr<T>& packet) {
1029  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1030  boost::shared_ptr<T> sent_packet
1031  = xchg_stats->matchPackets(packet);
1032 
1033  if (sent_packet) {
1034  xchg_stats->updateDelays(sent_packet, packet);
1035  if (archive_enabled_) {
1036  xchg_stats->appendRcvd(packet);
1037  }
1038  }
1039  return(sent_packet);
1040  }
1041 
1050  double getMinDelay(const ExchangeType xchg_type) const {
1051  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1052  return(xchg_stats->getMinDelay());
1053  }
1054 
1063  double getMaxDelay(const ExchangeType xchg_type) const {
1064  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1065  return(xchg_stats->getMaxDelay());
1066  }
1067 
1074  double getAvgDelay(const ExchangeType xchg_type) const {
1075  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1076  return(xchg_stats->getAvgDelay());
1077  }
1078 
1085  double getStdDevDelay(const ExchangeType xchg_type) const {
1086  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1087  return(xchg_stats->getStdDevDelay());
1088  }
1089 
1098  uint64_t getOrphans(const ExchangeType xchg_type) const {
1099  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1100  return(xchg_stats->getOrphans());
1101  }
1102 
1112  double getAvgUnorderedLookupSetSize(const ExchangeType xchg_type) const {
1113  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1114  return(xchg_stats->getAvgUnorderedLookupSetSize());
1115  }
1116 
1127  uint64_t getUnorderedLookups(const ExchangeType xchg_type) const {
1128  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1129  return(xchg_stats->getUnorderedLookups());
1130  }
1131 
1143  uint64_t getOrderedLookups(const ExchangeType xchg_type) const {
1144  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1145  return(xchg_stats->getOrderedLookups());
1146  }
1147 
1156  uint64_t getSentPacketsNum(const ExchangeType xchg_type) const {
1157  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1158  return(xchg_stats->getSentPacketsNum());
1159  }
1160 
1169  uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const {
1170  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1171  return(xchg_stats->getRcvdPacketsNum());
1172  }
1173 
1182  uint64_t getDroppedPacketsNum(const ExchangeType xchg_type) const {
1183  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1184  return(xchg_stats->getDroppedPacketsNum());
1185  }
1186 
1197  uint64_t getCollectedNum(const ExchangeType xchg_type) const {
1198  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
1199  return(xchg_stats->getCollectedNum());
1200  }
1201 
1202 
1210  boost::posix_time::time_period getTestPeriod() const {
1211  using namespace boost::posix_time;
1212  time_period test_period(boot_time_,
1213  microsec_clock::universal_time());
1214  return test_period;
1215  }
1216 
1224  static std::string exchangeToString(ExchangeType xchg_type) {
1225  switch(xchg_type) {
1226  case XCHG_DO:
1227  return("DISCOVER-OFFER");
1228  case XCHG_RA:
1229  return("REQUEST-ACK");
1230  case XCHG_RNA:
1231  return("REQUEST-ACK (renewal)");
1232  case XCHG_SA:
1233  return("SOLICIT-ADVERTISE");
1234  case XCHG_RR:
1235  return("REQUEST-REPLY");
1236  case XCHG_RN:
1237  return("RENEW-REPLY");
1238  case XCHG_RL:
1239  return("RELEASE-REPLY");
1240  default:
1241  return("Unknown exchange type");
1242  }
1243  }
1244 
1258  void printStats() const {
1259  if (exchanges_.empty()) {
1261  "no exchange type added for tracking");
1262  }
1263  for (ExchangesMapIterator it = exchanges_.begin();
1264  it != exchanges_.end();
1265  ++it) {
1266  ExchangeStatsPtr xchg_stats = it->second;
1267  std::cout << "***Statistics for: " << exchangeToString(it->first)
1268  << "***" << std::endl;
1269  xchg_stats->printMainStats();
1270  std::cout << std::endl;
1271  xchg_stats->printRTTStats();
1272  std::cout << std::endl;
1273  }
1274  }
1275 
1281  void printIntermediateStats() const {
1282  std::ostringstream stream_sent;
1283  std::ostringstream stream_rcvd;
1284  std::ostringstream stream_drops;
1285  std::string sep("");
1286  for (ExchangesMapIterator it = exchanges_.begin();
1287  it != exchanges_.end(); ++it) {
1288 
1289  if (it != exchanges_.begin()) {
1290  sep = "/";
1291  }
1292  stream_sent << sep << it->second->getSentPacketsNum();
1293  stream_rcvd << sep << it->second->getRcvdPacketsNum();
1294  stream_drops << sep << it->second->getDroppedPacketsNum();
1295  }
1296  std::cout << "sent: " << stream_sent.str()
1297  << "; received: " << stream_rcvd.str()
1298  << "; drops: " << stream_drops.str()
1299  << std::endl;
1300  }
1301 
1313  void printTimestamps() const {
1314  if (exchanges_.empty()) {
1316  "no exchange type added for tracking");
1317  }
1318  for (ExchangesMapIterator it = exchanges_.begin();
1319  it != exchanges_.end();
1320  ++it) {
1321  ExchangeStatsPtr xchg_stats = it->second;
1322  std::cout << "***Timestamps for packets: "
1323  << exchangeToString(it->first)
1324  << "***" << std::endl;
1325  xchg_stats->printTimestamps();
1326  std::cout << std::endl;
1327  }
1328  }
1329 
1336  void printCustomCounters() const {
1337  if (custom_counters_.empty()) {
1338  isc_throw(isc::InvalidOperation, "no custom counters specified");
1339  }
1340  for (CustomCountersMapIterator it = custom_counters_.begin();
1341  it != custom_counters_.end();
1342  ++it) {
1343  CustomCounterPtr counter = it->second;
1344  std::cout << counter->getName() << ": " << counter->getValue()
1345  << std::endl;
1346  }
1347  }
1348 
1349 private:
1350 
1358  ExchangeStatsPtr getExchangeStats(const ExchangeType xchg_type) const {
1359  ExchangesMapIterator it = exchanges_.find(xchg_type);
1360  if (it == exchanges_.end()) {
1361  isc_throw(BadValue, "Packets exchange not specified");
1362  }
1363  ExchangeStatsPtr xchg_stats = it->second;
1364  return(xchg_stats);
1365  }
1366 
1367  ExchangesMap exchanges_;
1368  CustomCountersMap custom_counters_;
1369 
1378  bool archive_enabled_;
1379 
1380  boost::posix_time::ptime boot_time_;
1381 };
1382 
1383 } // namespace perfdhcp
1384 } // namespace isc
1385 
1386 #endif // STATS_MGR_H
void passSentPacket(const ExchangeType xchg_type, const boost::shared_ptr< T > &packet)
Adds new packet to the sent packets list.
uint64_t getRcvdPacketsNum() const
Return total number of received packets.
boost::shared_ptr< T > matchPackets(const boost::shared_ptr< T > &rcvd_packet)
Match received packet with the corresponding sent packet.
void printTimestamps() const
Print timestamps of all packets.
bool droppedPackets() const
Check if any packet drops occurred.
const CustomCounter & incrementCounter(const std::string &counter_key, const uint64_t value=1)
Increment specified counter.
double getMaxDelay() const
Return maximum delay between sent and received packet.
uint64_t getUnorderedLookups() const
Return number of unordered sent packets lookups.
static uint32_t hashTransid(const boost::shared_ptr< T > &packet)
Hash transaction id of the packet.
CustomCounter(const std::string &name)
Constructor.
std::queue< PktListTransidHashIterator > PktListRemovalQueue
Packet list iterator queue for removal.
ExchangeType
DHCP packet exchange types.
boost::posix_time::time_period getTestPeriod() const
Get time period since the start of test.
const CustomCounter & operator+=(int val)
uint64_t getOrderedLookups(const ExchangeType xchg_type) const
Return number of ordered sent packets lookups.
uint64_t getUnorderedLookups(const ExchangeType xchg_type) const
Return number of unordered sent packets lookups.
double getAvgDelay() const
Return average packet delay.
uint64_t getCollectedNum() const
Return number of garbage collected packets.
boost::shared_ptr< CustomCounter > CustomCounterPtr
static std::string exchangeToString(ExchangeType xchg_type)
Return name of the exchange.
PktListTransidHashIndex::const_iterator PktListTransidHashIterator
Packet list iterator to access packets using transaction id hash.
uint64_t getValue() const
Return counter value.
void appendRcvd(const boost::shared_ptr< T > &packet)
Add new packet to list of received packets.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
uint64_t getCollectedNum(const ExchangeType xchg_type) const
Return number of garbage collected packets.
double getStdDevDelay() const
Return standard deviation of packet delay.
bool hasExchangeStats(const ExchangeType xchg_type) const
Check if the exchange type has been specified.
void printIntermediateStats() const
Print intermediate statistics.
A generic exception that is thrown when an unexpected error condition occurs.
uint64_t getSentPacketsNum(const ExchangeType xchg_type) const
Return total number of sent packets.
uint64_t getOrderedLookups() const
Return number of ordered sent packets lookups.
void printRTTStats() const
Print round trip time packets statistics.
uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const
Return total number of received packets.
double getAvgUnorderedLookupSetSize() const
Return average unordered lookup set size.
double getMaxDelay(const ExchangeType xchg_type) const
Return maximum delay between sent and received packet.
CustomCountersMap::const_iterator CustomCountersMapIterator
Iterator for CustomCountersMap.
double getMinDelay(const ExchangeType xchg_type) const
Return minimum delay between sent and received packet.
void printTimestamps()
Print timestamps for sent and received packets.
std::map< std::string, CustomCounterPtr > CustomCountersMap
Map containing custom counters.
ExchangeStats(const ExchangeType xchg_type, const double drop_time, const bool archive_enabled, const boost::posix_time::ptime boot_time)
Constructor.
This is a base class for exceptions thrown from the DNS library module.
const CustomCounter & operator++()
Increment operator.
Defines the logger used by the top-level component of kea-dhcp-ddns.
void printMainStats() const
Print main statistics for packet exchange.
void printCustomCounters() const
Print names and values of custom counters.
void printStats() const
Print statistics counters for all exchange types.
A generic exception that is thrown if a function is called in a prohibited way.
ExchangesMap::const_iterator ExchangesMapIterator
Iterator pointing to ExchangesMap.
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).
double getMinDelay() const
Return minimum delay between sent and received packet.
PktList::template nth_index< 1 >::type PktListTransidHashIndex
Packet list index to search packets using transaction id hash.
uint64_t getOrphans(const ExchangeType xchg_type) const
Return number of orphan packets.
double getAvgDelay(const ExchangeType xchg_type) const
Return average packet delay.
void addExchangeStats(const ExchangeType xchg_type, const double drop_time=-1)
Specify new exchange type.
CustomCounterPtr getCounter(const std::string &counter_key)
Return specified counter.
void updateDelays(const boost::shared_ptr< T > &sent_packet, const boost::shared_ptr< T > &rcvd_packet)
Update delay counters.
uint64_t getDroppedPacketsNum(const ExchangeType xchg_type) const
Return total number of dropped 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.
const std::string & getName() const
Return counter name.
PktList::iterator PktListIterator
Packet list iterator for sequential access to elements.
const CustomCounter & operator++(int)
Increment operator.
boost::shared_ptr< ExchangeStats > ExchangeStatsPtr
Pointer to ExchangeStats.
void appendSent(const boost::shared_ptr< T > &packet)
Add new packet to list of sent packets.
double getStdDevDelay(const ExchangeType xchg_type) const
Return standard deviation of packet delay.
uint64_t getSentPacketsNum() const
Return total number of sent packets.
double getAvgUnorderedLookupSetSize(const ExchangeType xchg_type) const
Return average unordered lookup set size.
void addCustomCounter(const std::string &short_name, const std::string &long_name)
Add named custom uint64 counter.
uint64_t getOrphans() const
Return number of orphan packets.
std::map< ExchangeType, ExchangeStatsPtr > ExchangesMap
Map containing all specified exchange types.
uint64_t getDroppedPacketsNum() const
Return number of dropped packets.
StatsMgr(const bool archive_enabled=false)
Constructor.