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>
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
28namespace isc {
29namespace perfdhcp {
30
47template <class T = dhcp::Pkt4>
48class StatsMgr : public boost::noncopyable {
49public:
50
58 public:
65 CustomCounter(const std::string& name) :
66 counter_(0),
67 name_(name) { };
68
71 ++counter_;
72 return (*this);
73 }
74
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
122 XCHG_RL
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
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;
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>();
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
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_;
842 double max_delay_;
844 double sum_delay_;
846 double sum_delay_squared_;
848
849 uint64_t orphans_;
850
851 uint64_t collected_;
852
858 uint64_t unordered_lookup_size_sum_;
859
860 uint64_t unordered_lookups_;
862 uint64_t ordered_lookups_;
864
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>
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
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
1349private:
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
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.