stats_mgr.h 55.4 KB
Newer Older
 Marcin Siodelski committed Jul 10, 2012 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE.  Mukund Sivaraman committed Oct 25, 2012 15 16 #ifndef STATS_MGR_H #define STATS_MGR_H  Marcin Siodelski committed Jul 10, 2012 17   Marcin Siodelski committed Jul 11, 2012 18 #include  Marcin Siodelski committed Jul 10, 2012 19 20 21 22 23 #include #include #include #include  Marcin Siodelski committed Jul 12, 2012 24 #include  Marcin Siodelski committed Jul 10, 2012 25 #include  Marcin Siodelski committed Jul 12, 2012 26 #include  Marcin Siodelski committed Jul 25, 2012 27 #include  Marcin Siodelski committed Jul 10, 2012 28 #include  Marcin Siodelski committed Jul 10, 2012 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49  #include namespace isc { namespace perfdhcp { /// \brief Statistics Manager /// /// This class template is a storage for various performance statistics /// collected during performance tests execution with perfdhcp tool. /// /// Statistics Manager holds lists of sent and received packets and /// groups them into exchanges. For example: DHCPDISCOVER message and /// corresponding DHCPOFFER messages belong to one exchange, DHCPREQUEST /// and corresponding DHCPACK message belong to another exchange etc. /// In order to update statistics for a particular exchange type, client /// class passes sent and received packets. Internally, Statistics Manager /// tries to match transaction id of received packet with sent packet /// stored on the list of sent packets. When packets are matched the /// round trip time can be calculated. ///  Marcin Siodelski committed Aug 21, 2012 50 51 /// \param T class representing DHCPv4 or DHCPv6 packet. template  Marcin Siodelski committed Jul 10, 2012 52 53 54 class StatsMgr : public boost::noncopyable { public:  Marcin Siodelski committed Jul 19, 2012 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75  /// \brief Custom Counter /// /// This class represents custom statistics counters. Client class /// may create unlimited number of counters. Such counters are /// being stored in map in Statistics Manager and access using /// unique string key. class CustomCounter { public: /// \brief Constructor. /// /// This constructor sets counter name. This name is used in /// log file to report value of each counter. /// /// \param name name of the counter used in log file. CustomCounter(const std::string& name) : counter_(0), name_(name) { }; /// \brief Increment operator. const CustomCounter& operator++() { ++counter_;  Marcin Siodelski committed Sep 13, 2012 76  return (*this);  Marcin Siodelski committed Jul 19, 2012 77 78 79 80 81 82  } /// \brief Increment operator. const CustomCounter& operator++(int) { CustomCounter& this_counter(*this); operator++();  Marcin Siodelski committed Sep 13, 2012 83 84 85 86  return (this_counter); } const CustomCounter& operator+=(int val) {  Marcin Siodelski committed Sep 21, 2012 87  counter_ += val;  Marcin Siodelski committed Sep 13, 2012 88  return (*this);  Marcin Siodelski committed Jul 19, 2012 89 90 91 92 93 94 95  } /// \brief Return counter value. /// /// Method returns counter value. /// /// \return counter value.  Marcin Siodelski committed Aug 07, 2012 96  uint64_t getValue() const { return(counter_); }  Marcin Siodelski committed Jul 19, 2012 97 98 99 100 101 102  /// \brief Return counter name. /// /// Method returns counter name. /// /// \return counter name.  Marcin Siodelski committed Aug 07, 2012 103  const std::string& getName() const { return(name_); }  Marcin Siodelski committed Jul 19, 2012 104 105 106  private: /// \brief Default constructor. ///  Jeremy C. Reed committed Mar 06, 2013 107  /// Default constructor is private because we don't want client  Marcin Siodelski committed Jul 19, 2012 108 109 110 111  /// class to call it because we want client class to specify /// counter's name. CustomCounter() { };  Marcin Siodelski committed Jul 30, 2012 112  uint64_t counter_; ///< Counter's value.  Marcin Siodelski committed Jul 25, 2012 113  std::string name_; ///< Counter's name.  Marcin Siodelski committed Jul 19, 2012 114 115 116 117  }; typedef typename boost::shared_ptr CustomCounterPtr;  Marcin Siodelski committed Jul 10, 2012 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135  /// DHCP packet exchange types. enum ExchangeType { XCHG_DO, ///< DHCPv4 DISCOVER-OFFER XCHG_RA, ///< DHCPv4 REQUEST-ACK XCHG_SA, ///< DHCPv6 SOLICIT-ADVERTISE XCHG_RR ///< DHCPv6 REQUEST-REPLY }; /// \brief Exchange Statistics. /// /// This class collects statistics for exchanges. Parent class /// may define number of different packet exchanges like: /// DHCPv4 DISCOVER-OFFER, DHCPv6 SOLICIT-ADVERTISE etc. Performance /// statistics will be collected for each of those separately in /// corresponding instance of ExchangeStats. class ExchangeStats { public:  Marcin Siodelski committed Jul 23, 2012 136 137 138 139 140 141 142 143 144 145  /// \brief Hash transaction id of the packet. /// /// Function hashes transaction id of the packet. Hashing is /// non-unique. Many packets may have the same hash value and thus /// they belong to the same packet buckets. Packet buckets are /// used for unordered packets search with multi index container. /// /// \param packet packet which transaction id is to be hashed. /// \throw isc::BadValue if packet is null. /// \return transaction id hash.  Marcin Siodelski committed Aug 21, 2012 146  static uint32_t hashTransid(const boost::shared_ptr& packet) {  Marcin Siodelski committed Jul 23, 2012 147 148 149  if (!packet) { isc_throw(BadValue, "Packet is null"); }  Marcin Siodelski committed Jul 30, 2012 150  return(packet->getTransid() & 1023);  Marcin Siodelski committed Jul 12, 2012 151 152  }  Marcin Siodelski committed Jul 10, 2012 153 154 155 156  /// \brief List of packets (sent or received). /// /// List of packets based on multi index container allows efficient /// search of packets based on their sequence (order in which they  157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220  /// were inserted) as well as based on their hashed transaction id. /// The first index (sequenced) provides the way to use container /// as a regular list (including iterators, removal of elements from /// the middle of the collection etc.). This index is meant to be used /// more frequently than the latter one and it is based on the /// assumption that responses from the DHCP server are received in /// order. In this case, when next packet is received it can be /// matched with next packet on the list of sent packets. This /// prevents intensive searches on the list of sent packets every /// time new packet arrives. In many cases however packets can be /// dropped by the server or may be sent out of order and we still /// want to have ability to search packets using transaction id. /// The second index can be used for this purpose. This index is /// hashing transaction ids using custom function \ref hashTransid. /// Note that other possibility would be to simply specify index /// that uses transaction id directly (instead of hashing with /// \ref hashTransid). In this case however we have chosen to use /// hashing function because it shortens the index size to just /// 1023 values maximum. Search operation on this index generally /// returns the range of packets that have the same transaction id /// hash assigned but most often these ranges will be short so further /// search within a range to find a packet with pacrticular transaction /// id will not be intensive. /// /// Example 1: Add elements to the list /// \code /// PktList packets_collection(); /// boost::shared_ptr pkt1(new Pkt4(...)); /// boost::shared_ptr pkt2(new Pkt4(...)); /// // Add new packet to the container, it will be available through /// // both indexes /// packets_collection.push_back(pkt1); /// // Here is another way to add packet to the container. The result /// // is exactly the same as previously. /// packets_collection.template get<0>().push_back(pkt2); /// \endcode /// /// Example 2: Access elements through sequencial index /// \code /// PktList packets_collection(); /// ... # Add elements to the container /// for (PktListIterator it = packets_collection.begin(); /// it != packets_collection.end(); /// ++it) { /// boost::shared_ptr pkt = *it; /// # Do something with packet; /// } /// \endcode /// /// Example 3: Access elements through hashed index /// \code /// // Get the instance of the second search index. /// PktListTransidHashIndex& idx = sent_packets_.template get<1>(); /// // Get the range (bucket) of packets sharing the same transaction /// // id hash. /// std::pair p = /// idx.equal_range(hashTransid(rcvd_packet)); /// // Iterate through the returned bucket. /// for (PktListTransidHashIterator it = p.first; it != p.second; /// ++it) { /// boost::shared_ptr pkt = *it; /// ... # Do something with the packet (e.g. check transaction id) /// } /// \endcode  Marcin Siodelski committed Jul 10, 2012 221  typedef boost::multi_index_container<  Marcin Siodelski committed Sep 04, 2012 222  // Container holds shared_ptr or shared_ptr objects.  Marcin Siodelski committed Aug 21, 2012 223  boost::shared_ptr,  Marcin Siodelski committed Sep 04, 2012 224  // List container indexes.  Marcin Siodelski committed Jul 10, 2012 225  boost::multi_index::indexed_by<  Marcin Siodelski committed Sep 04, 2012 226 227  // Sequenced index provides the way to use this container // in the same way as std::list.  Marcin Siodelski committed Jul 10, 2012 228  boost::multi_index::sequenced<>,  Marcin Siodelski committed Sep 04, 2012 229  // The other index keeps products of transaction id.  Marcin Siodelski committed Jul 12, 2012 230  boost::multi_index::hashed_non_unique<  Marcin Siodelski committed Sep 04, 2012 231 232 233 234 235 236 237 238 239 240 241 242  // Specify hash function to get the product of // transaction id. This product is obtained by calling // hashTransid() function. boost::multi_index::global_fun< // Hashing function takes shared_ptr or // shared_ptr as argument. const boost::shared_ptr&, // ... and returns uint32 value. uint32_t, // ... and here is a reference to it. &ExchangeStats::hashTransid >  Marcin Siodelski committed Jul 10, 2012 243 244 245 246 247  > > > PktList; /// Packet list iterator for sequencial access to elements.  Marcin Siodelski committed Aug 21, 2012 248  typedef typename PktList::iterator PktListIterator;  Marcin Siodelski committed Jul 25, 2012 249  /// Packet list index to search packets using transaction id hash.  Marcin Siodelski committed Jul 10, 2012 250  typedef typename PktList::template nth_index<1>::type  Marcin Siodelski committed Jul 25, 2012 251 252 253 254  PktListTransidHashIndex; /// Packet list iterator to access packets using transaction id hash. typedef typename PktListTransidHashIndex::const_iterator PktListTransidHashIterator;  Marcin Siodelski committed Jul 10, 2012 255 256 257 258  /// \brief Constructor /// /// \param xchg_type exchange type  Marcin Siodelski committed Sep 21, 2012 259 260  /// \param drop_time maximum time elapsed before packet is /// assumed dropped. Negative value disables it.  Marcin Siodelski committed Aug 07, 2012 261 262  /// \param archive_enabled if true packets archive mode is enabled. /// In this mode all packets are stored throughout the test execution.  Marcin Siodelski committed Sep 13, 2012 263 264  ExchangeStats(const ExchangeType xchg_type, const double drop_time,  Thomas Markwalder committed Mar 21, 2013 265 266  const bool archive_enabled, const boost::posix_time::ptime boot_time)  Marcin Siodelski committed Jul 11, 2012 267  : xchg_type_(xchg_type),  Marcin Siodelski committed Sep 13, 2012 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282  sent_packets_(), rcvd_packets_(), archived_packets_(), archive_enabled_(archive_enabled), drop_time_(drop_time), min_delay_(std::numeric_limits::max()), max_delay_(0.), sum_delay_(0.), sum_delay_squared_(0.), orphans_(0), collected_(0), unordered_lookup_size_sum_(0), unordered_lookups_(0), ordered_lookups_(0), sent_packets_num_(0),  Thomas Markwalder committed Mar 21, 2013 283 284  rcvd_packets_num_(0), boot_time_(boot_time)  Marcin Siodelski committed Aug 16, 2012 285  {  Marcin Siodelski committed Jul 30, 2012 286  next_sent_ = sent_packets_.begin();  Marcin Siodelski committed Jul 10, 2012 287 288 289 290 291 292  } /// \brief Add new packet to list of sent packets. /// /// Method adds new packet to list of sent packets. ///  Marcin Siodelski committed Jul 12, 2012 293  /// \param packet packet object to be added.  Marcin Siodelski committed Jul 23, 2012 294  /// \throw isc::BadValue if packet is null.  Marcin Siodelski committed Aug 21, 2012 295  void appendSent(const boost::shared_ptr& packet) {  Marcin Siodelski committed Jul 23, 2012 296 297 298  if (!packet) { isc_throw(BadValue, "Packet is null"); }  299  ++sent_packets_num_;  Marcin Siodelski committed Jul 10, 2012 300 301 302  sent_packets_.template get<0>().push_back(packet); }  Marcin Siodelski committed Jul 12, 2012 303 304 305 306 307  /// \brief Add new packet to list of received packets. /// /// Method adds new packet to list of received packets. /// /// \param packet packet object to be added.  Marcin Siodelski committed Jul 23, 2012 308  /// \throw isc::BadValue if packet is null.  Marcin Siodelski committed Aug 21, 2012 309  void appendRcvd(const boost::shared_ptr& packet) {  Marcin Siodelski committed Jul 23, 2012 310 311 312  if (!packet) { isc_throw(BadValue, "Packet is null"); }  Marcin Siodelski committed Jul 25, 2012 313  rcvd_packets_.push_back(packet);  Marcin Siodelski committed Jul 12, 2012 314 315  }  316 317 318 319 320 321 322  /// \brief Update delay counters. /// /// Method updates delay counters based on timestamps of /// sent and received packets. /// /// \param sent_packet sent packet /// \param rcvd_packet received packet  Marcin Siodelski committed Jul 23, 2012 323  /// \throw isc::BadValue if sent or received packet is null.  324  /// \throw isc::Unexpected if failed to calculate timestamps  Marcin Siodelski committed Aug 21, 2012 325 326  void updateDelays(const boost::shared_ptr& sent_packet, const boost::shared_ptr& rcvd_packet) {  Marcin Siodelski committed Jul 23, 2012 327 328 329 330 331 332 333  if (!sent_packet) { isc_throw(BadValue, "Sent packet is null"); } if (!rcvd_packet) { isc_throw(BadValue, "Received packet is null"); }  334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365  boost::posix_time::ptime sent_time = sent_packet->getTimestamp(); boost::posix_time::ptime rcvd_time = rcvd_packet->getTimestamp(); if (sent_time.is_not_a_date_time() || rcvd_time.is_not_a_date_time()) { isc_throw(Unexpected, "Timestamp must be set for sent and " "received packet to measure RTT"); } boost::posix_time::time_period period(sent_time, rcvd_time); // We don't bother calculating deltas in nanoseconds. It is much // more convenient to use seconds instead because we are going to // sum them up. double delta = static_cast(period.length().total_nanoseconds()) / 1e9; if (delta < 0) { isc_throw(Unexpected, "Sent packet's timestamp must not be " "greater than received packet's timestamp"); } // Record the minimum delay between sent and received packets. if (delta < min_delay_) { min_delay_ = delta; } // Record the maximum delay between sent and received packets. if (delta > max_delay_) { max_delay_ = delta; } // Update delay sum and square sum. That will be used to calculate // mean delays. sum_delay_ += delta;  Marcin Siodelski committed Jul 30, 2012 366  sum_delay_squared_ += delta * delta;  367 368  }  Marcin Siodelski committed Aug 07, 2012 369  /// \brief Match received packet with the corresponding sent packet.  Marcin Siodelski committed Jul 10, 2012 370 371 372 373 374 375 376 377 378 379  /// /// Method finds packet with specified transaction id on the list /// of sent packets. It is used to match received packet with /// corresponding sent packet. /// Since packets from the server most often come in the same order /// as they were sent by client, this method will first check if /// next sent packet matches. If it doesn't, function will search /// the packet using indexing by transaction id. This reduces /// packet search time significantly. ///  Marcin Siodelski committed Jul 23, 2012 380  /// \param rcvd_packet received packet to be matched with sent packet.  Marcin Siodelski committed Jul 23, 2012 381  /// \throw isc::BadValue if received packet is null.  Marcin Siodelski committed Jul 11, 2012 382 383  /// \return packet having specified transaction or NULL if packet /// not found  Marcin Siodelski committed Aug 21, 2012 384 385  boost::shared_ptr matchPackets(const boost::shared_ptr& rcvd_packet) {  Marcin Siodelski committed Sep 13, 2012 386 387  using namespace boost::posix_time;  Marcin Siodelski committed Jul 23, 2012 388 389 390 391  if (!rcvd_packet) { isc_throw(BadValue, "Received packet is null"); }  Marcin Siodelski committed Jul 10, 2012 392  if (sent_packets_.size() == 0) {  393 394 395 396  // List of sent packets is empty so there is no sense // to continue looking fo the packet. It also means // that the received packet we got has no corresponding // sent packet so orphans counter has to be updated.  Marcin Siodelski committed Jul 11, 2012 397  ++orphans_;  Marcin Siodelski committed Aug 21, 2012 398  return(boost::shared_ptr());  Marcin Siodelski committed Jul 30, 2012 399  } else if (next_sent_ == sent_packets_.end()) {  400 401  // Even if there are still many unmatched packets on the // list we might hit the end of it because of unordered  Marcin Siodelski committed Jul 30, 2012 402 403  // lookups. The next logical step is to reset iterator. next_sent_ = sent_packets_.begin();  Marcin Siodelski committed Jul 10, 2012 404 405  }  406 407  // With this variable we will be signalling success or failure // to find the packet.  Marcin Siodelski committed Jul 10, 2012 408  bool packet_found = false;  409 410  // Most likely responses are sent from the server in the same // order as client's requests to the server. We are caching  Marcin Siodelski committed Jul 19, 2012 411  // next sent packet and first try to match it with the next  412 413 414  // incoming packet. We are successful if there is no // packet drop or out of order packets sent. This is actually // the fastest way to look for packets.  Marcin Siodelski committed Jul 30, 2012 415  if ((*next_sent_)->getTransid() == rcvd_packet->getTransid()) {  Marcin Siodelski committed Jul 12, 2012 416  ++ordered_lookups_;  Marcin Siodelski committed Jul 10, 2012 417 418  packet_found = true; } else {  419 420 421 422  // If we are here, it means that we were unable to match the // next incoming packet with next sent packet so we need to // take a little more expensive approach to look packets using // alternative index (transaction id & 1023).  Marcin Siodelski committed Jul 25, 2012 423  PktListTransidHashIndex& idx = sent_packets_.template get<1>();  Marcin Siodelski committed Jul 19, 2012 424  // Packets are grouped using trasaction id masked with value  425 426 427  // of 1023. For instance, packets with transaction id equal to // 1, 1024 ... will belong to the same group (a.k.a. bucket). // When using alternative index we don't find the packet but  Marcin Siodelski committed Jul 19, 2012 428  // bucket of packets and we need to iterate through the bucket  429  // to find the one that has desired transaction id.  Marcin Siodelski committed Jul 25, 2012 430  std::pair p =  Marcin Siodelski committed Jul 23, 2012 431  idx.equal_range(hashTransid(rcvd_packet));  432  // We want to keep statistics of unordered lookups to make  Marcin Siodelski committed Jul 19, 2012 433  // sure that there is a right balance between number of  434 435 436  // unordered lookups and ordered lookups. If number of unordered // lookups is high it may mean that many packets are lost or // sent out of order.  Marcin Siodelski committed Jul 12, 2012 437  ++unordered_lookups_;  438 439 440  // We also want to keep the mean value of the bucket. The lower // bucket size the better. If bucket sizes appear to big we // might want to increase number of buckets.  Marcin Siodelski committed Jul 12, 2012 441  unordered_lookup_size_sum_ += std::distance(p.first, p.second);  Marcin Siodelski committed Jul 25, 2012 442  for (PktListTransidHashIterator it = p.first; it != p.second;  Marcin Siodelski committed Jul 12, 2012 443  ++it) {  Marcin Siodelski committed Jul 23, 2012 444  if ((*it)->getTransid() == rcvd_packet->getTransid()) {  Marcin Siodelski committed Jul 12, 2012 445  packet_found = true;  Marcin Siodelski committed Jul 30, 2012 446  next_sent_ =  Marcin Siodelski committed Jul 12, 2012 447 448 449  sent_packets_.template project<0>(it); break; }  Marcin Siodelski committed Sep 13, 2012 450 451 452 453 454 455 456 457 458 459 460 461 462 463  ptime now = microsec_clock::universal_time(); ptime packet_time = (*it)->getTimestamp(); time_period packet_period(packet_time, now); if (!packet_period.is_null()) { double period_fractional = packet_period.length().total_seconds() + (static_cast(packet_period.length().fractional_seconds()) / packet_period.length().ticks_per_second()); if (drop_time_ > 0 && (period_fractional > drop_time_)) { eraseSent(sent_packets_.template project<0>(it)); ++collected_; } }  Marcin Siodelski committed Jul 10, 2012 464 465 466 467  } } if (!packet_found) {  468 469  // If we are here, it means that both ordered lookup and // unordered lookup failed. Searched packet is not on the list.  Marcin Siodelski committed Jul 11, 2012 470  ++orphans_;  Marcin Siodelski committed Aug 21, 2012 471  return(boost::shared_ptr());  Marcin Siodelski committed Jul 10, 2012 472 473  }  Marcin Siodelski committed Aug 07, 2012 474 475  // Packet is matched so we count it. We don't count unmatched packets // as they are counted as orphans with a separate counter.  Marcin Siodelski committed Jul 30, 2012 476  ++rcvd_packets_num_;  Marcin Siodelski committed Aug 21, 2012 477  boost::shared_ptr sent_packet(*next_sent_);  478 479 480  // If packet was found, we assume it will be never searched // again. We want to delete this packet from the list to // improve performance of future searches.  Marcin Siodelski committed Jul 30, 2012 481  next_sent_ = eraseSent(next_sent_);  Marcin Siodelski committed Jul 30, 2012 482  return(sent_packet);  Marcin Siodelski committed Jul 10, 2012 483 484  }  Marcin Siodelski committed Jul 10, 2012 485 486 487 488 489  /// \brief Return minumum delay between sent and received packet. /// /// Method returns minimum delay between sent and received packet. /// /// \return minimum delay between packets.  Marcin Siodelski committed Jul 30, 2012 490  double getMinDelay() const { return(min_delay_); }  Marcin Siodelski committed Jul 10, 2012 491 492 493 494 495 496  /// \brief Return maxmimum delay between sent and received packet. /// /// Method returns maximum delay between sent and received packet. /// /// \return maximum delay between packets.  Marcin Siodelski committed Jul 30, 2012 497  double getMaxDelay() const { return(max_delay_); }  Marcin Siodelski committed Jul 10, 2012 498   Jeremy C. Reed committed Mar 06, 2013 499  /// \brief Return average packet delay.  Marcin Siodelski committed Jul 10, 2012 500  ///  Marcin Siodelski committed Jul 25, 2012 501 502 503  /// Method returns average packet delay. If no packets have been /// received for this exchange avg delay can't be calculated and /// thus method throws exception.  Marcin Siodelski committed Jul 10, 2012 504  ///  Marcin Siodelski committed Jul 25, 2012 505 506 507 508  /// \throw isc::InvalidOperation if no packets for this exchange /// have been received yet. /// \return average packet delay. double getAvgDelay() const {  Marcin Siodelski committed Jul 30, 2012 509  if (rcvd_packets_num_ == 0) {  Marcin Siodelski committed Jul 25, 2012 510 511  isc_throw(InvalidOperation, "no packets received"); }  Marcin Siodelski committed Jul 30, 2012 512  return(sum_delay_ / rcvd_packets_num_);  Marcin Siodelski committed Jul 25, 2012 513  }  Marcin Siodelski committed Jul 10, 2012 514   Marcin Siodelski committed Jul 25, 2012 515  /// \brief Return standard deviation of packet delay.  Marcin Siodelski committed Jul 10, 2012 516  ///  Marcin Siodelski committed Jul 25, 2012 517 518 519 520  /// Method returns standard deviation of packet delay. If no /// packets have been received for this exchange, the standard /// deviation can't be calculated and thus method throws /// exception.  Marcin Siodelski committed Jul 10, 2012 521  ///  Marcin Siodelski committed Jul 25, 2012 522 523 524 525 526 527 528  /// \throw isc::InvalidOperation if number of received packets /// for the exchange is equal to zero. /// \return standard deviation of packet delay. double getStdDevDelay() const { if (rcvd_packets_num_ == 0) { isc_throw(InvalidOperation, "no packets received"); }  Marcin Siodelski committed Jul 30, 2012 529 530  return(sqrt(sum_delay_squared_ / rcvd_packets_num_ - getAvgDelay() * getAvgDelay()));  Marcin Siodelski committed Jul 25, 2012 531  }  Marcin Siodelski committed Jul 11, 2012 532 533 534 535 536 537 538 539  /// \brief Return number of orphant packets. /// /// Method returns number of received packets that had no matching /// sent packet. It is possible that such packet was late or not /// for us. /// /// \return number of orphant received packets.  Marcin Siodelski committed Jul 30, 2012 540  uint64_t getOrphans() const { return(orphans_); }  Marcin Siodelski committed Jul 12, 2012 541   Marcin Siodelski committed Sep 13, 2012 542 543 544 545 546 547 548 549 550 551 552  /// \brief Return number of garbage collected packets. /// /// Method returns number of garbage collected timed out /// packets. Packet is assumed timed out when duration /// between sending it to server and receiving server's /// response is greater than value specified with -d /// command line argument. /// /// \return number of garbage collected packets. uint64_t getCollectedNum() const { return(collected_); }  Marcin Siodelski committed Jul 12, 2012 553 554 555  /// \brief Return average unordered lookup set size. /// /// Method returns average unordered lookup set size.  Marcin Siodelski committed Aug 07, 2012 556  /// This value changes every time \ref ExchangeStats::matchPackets  Marcin Siodelski committed Jul 23, 2012 557  /// function performs unordered packet lookup.  Marcin Siodelski committed Jul 12, 2012 558  ///  Marcin Siodelski committed Jul 25, 2012 559 560  /// \throw isc::InvalidOperation if there have been no unordered /// lookups yet.  Marcin Siodelski committed Jul 12, 2012 561 562  /// \return average unordered lookup set size. double getAvgUnorderedLookupSetSize() const {  563  if (unordered_lookups_ == 0) {  Marcin Siodelski committed Jul 25, 2012 564  isc_throw(InvalidOperation, "no unordered lookups");  565  }  Marcin Siodelski committed Jul 30, 2012 566 567  return(static_cast(unordered_lookup_size_sum_) / static_cast(unordered_lookups_));  Marcin Siodelski committed Jul 12, 2012 568 569 570 571 572 573 574 575 576 577  } /// \brief Return number of unordered sent packets lookups /// /// Method returns number of unordered sent packet lookups. /// Unordered lookup is used when received packet was sent /// out of order by server - transaction id of received /// packet does not match transaction id of next sent packet. /// /// \return number of unordered lookups.  Marcin Siodelski committed Jul 30, 2012 578  uint64_t getUnorderedLookups() const { return(unordered_lookups_); }  Marcin Siodelski committed Jul 12, 2012 579 580 581 582 583 584 585 586 587 588  /// \brief Return number of ordered sent packets lookups /// /// Method returns number of ordered sent packet lookups. /// Ordered lookup is used when packets are received in the /// same order as they were sent to the server. /// If packets are skipped or received out of order, lookup /// function will use unordered lookup (with hash table). /// /// \return number of ordered lookups.  Marcin Siodelski committed Jul 30, 2012 589  uint64_t getOrderedLookups() const { return(ordered_lookups_); }  590 591 592 593 594 595  /// \brief Return total number of sent packets /// /// Method returns total number of sent packets. /// /// \return number of sent packets.  Marcin Siodelski committed Jul 30, 2012 596  uint64_t getSentPacketsNum() const { return(sent_packets_num_); }  597 598 599 600 601 602  /// \brief Return total number of received packets /// /// Method returns total number of received packets. /// /// \return number of received packets.  Marcin Siodelski committed Jul 30, 2012 603  uint64_t getRcvdPacketsNum() const { return(rcvd_packets_num_); }  604   Marcin Siodelski committed Aug 21, 2012 605 606 607 608 609 610 611 612 613 614 615 616 617  /// \brief Return number of dropped packets. /// /// Method returns number of dropped packets. /// /// \return number of dropped packets. uint64_t getDroppedPacketsNum() const { uint64_t drops = 0; if (getSentPacketsNum() > getRcvdPacketsNum()) { drops = getSentPacketsNum() - getRcvdPacketsNum(); } return(drops); }  Marcin Siodelski committed Jul 30, 2012 618 619 620 621 622 623 624 625 626  /// \brief Print main statistics for packet exchange. /// /// Method prints main statistics for particular exchange. /// Statistics includes: number of sent and received packets, /// number of dropped packets and number of orphans. void printMainStats() const { using namespace std; cout << "sent packets: " << getSentPacketsNum() << endl << "received packets: " << getRcvdPacketsNum() << endl  Marcin Siodelski committed Aug 21, 2012 627  << "drops: " << getDroppedPacketsNum() << endl  Marcin Siodelski committed Jul 30, 2012 628 629 630 631 632 633 634 635 636 637 638 639  << "orphans: " << getOrphans() << endl; } /// \brief Print round trip time packets statistics. /// /// Method prints round trip time packets statistics. Statistics /// includes minimum packet delay, maximum packet delay, average /// packet delay and standard deviation of delays. Packet delay /// is a duration between sending a packet to server and receiving /// response from server. void printRTTStats() const { using namespace std;  Marcin Siodelski committed Jul 30, 2012 640 641 642 643 644 645  try { cout << fixed << setprecision(3) << "min delay: " << getMinDelay() * 1e3 << " ms" << endl << "avg delay: " << getAvgDelay() * 1e3 << " ms" << endl << "max delay: " << getMaxDelay() * 1e3 << " ms" << endl << "std deviation: " << getStdDevDelay() * 1e3 << " ms"  Marcin Siodelski committed Sep 13, 2012 646 647  << endl << "collected packets: " << getCollectedNum() << endl;  Marcin Siodelski committed Jul 30, 2012 648  } catch (const Exception& e) {  Marcin Siodelski committed Sep 13, 2012 649  cout << "Delay summary unavailable! No packets received." << endl;  Marcin Siodelski committed Jul 30, 2012 650  }  Marcin Siodelski committed Jul 30, 2012 651 652  }  Marcin Siodelski committed Jul 25, 2012 653 654 655  //// \brief Print timestamps for sent and received packets. /// /// Method prints timestamps for all sent and received packets for  Marcin Siodelski committed Jul 30, 2012 656 657 658 659  /// packet exchange. In order to run this method the packets /// archiving mode has to be enabled during object constructions. /// Otherwise sent packets are not stored during tests execution /// and this method has no ability to get and print their timestamps.  Marcin Siodelski committed Jul 25, 2012 660  ///  Marcin Siodelski committed Jul 30, 2012 661 662  /// \throw isc::InvalidOperation if found packet with no timestamp or /// if packets archive mode is disabled.  Marcin Siodelski committed Jul 25, 2012 663  void printTimestamps() {  Marcin Siodelski committed Jul 30, 2012 664 665 666 667 668 669 670 671 672  // If archive mode is disabled there is no sense to proceed // because we don't have packets and their timestamps. if (!archive_enabled_) { isc_throw(isc::InvalidOperation, "packets archive mode is disabled"); } if (rcvd_packets_num_ == 0) { std::cout << "Unavailable! No packets received." << std::endl; }  Jeremy C. Reed committed Mar 08, 2013 673  // We will be using boost::posix_time extensively here  Marcin Siodelski committed Jul 30, 2012 674 675  using namespace boost::posix_time;  Marcin Siodelski committed Jul 25, 2012 676 677 678 679  // Iterate through all received packets. for (PktListIterator it = rcvd_packets_.begin(); it != rcvd_packets_.end(); ++it) {  Marcin Siodelski committed Aug 21, 2012 680  boost::shared_ptr rcvd_packet = *it;  681 682 683 684 685 686 687  PktListTransidHashIndex& idx = archived_packets_.template get<1>(); std::pair p = idx.equal_range(hashTransid(rcvd_packet)); for (PktListTransidHashIterator it_archived = p.first; it_archived != p.second;  Marcin Siodelski committed Sep 13, 2012 688  ++it_archived) {  689 690  if ((*it_archived)->getTransid() == rcvd_packet->getTransid()) {  Marcin Siodelski committed Aug 21, 2012 691  boost::shared_ptr sent_packet = *it_archived;  692 693 694 695 696 697 698 699  // Get sent and received packet times. ptime sent_time = sent_packet->getTimestamp(); ptime rcvd_time = rcvd_packet->getTimestamp(); // All sent and received packets should have timestamps // set but if there is a bug somewhere and packet does // not have timestamp we want to catch this here. if (sent_time.is_not_a_date_time() || rcvd_time.is_not_a_date_time()) {  Marcin Siodelski committed Jul 30, 2012 700 701  isc_throw(InvalidOperation, "packet time is not set");  702 703  } // Calculate durations of packets from beginning of epoch.  Thomas Markwalder committed Mar 21, 2013 704 705  time_period sent_period(boot_time_, sent_time); time_period rcvd_period(boot_time_, rcvd_time);  706 707 708 709 710 711 712  // Print timestamps for sent and received packet. std::cout << "sent / received: " << to_iso_string(sent_period.length()) << " / " << to_iso_string(rcvd_period.length()) << std::endl; break;  Marcin Siodelski committed Jul 25, 2012 713 714 715 716 717  } } } }  Marcin Siodelski committed Jul 10, 2012 718 719 720 721  private: /// \brief Private default constructor. ///  Marcin Siodelski committed Jul 10, 2012 722  /// Default constructor is private because we want the client  Jeremy C. Reed committed Apr 09, 2013 723  /// class to specify exchange type explicitly.  Marcin Siodelski committed Jul 10, 2012 724 725  ExchangeStats();  726 727 728 729 730 731 732 733  /// \brief Erase packet from the list of sent packets. /// /// Method erases packet from the list of sent packets. /// /// \param it iterator pointing to packet to be erased. /// \return iterator pointing to packet following erased /// packet or sent_packets_.end() if packet not found. PktListIterator eraseSent(const PktListIterator it) {  Marcin Siodelski committed Jul 30, 2012 734 735 736 737 738 739 740 741 742  if (archive_enabled_) { // We don't want to keep list of all sent packets // because it will affect packet lookup performance. // If packet is matched with received packet we // move it to list of archived packets. List of // archived packets may be used for diagnostics // when test is completed. archived_packets_.push_back(*it); }  743 744  // get<0>() template returns sequencial index to // container.  Marcin Siodelski committed Jul 30, 2012 745  return(sent_packets_.template get<0>().erase(it));  746 747  }  Marcin Siodelski committed Jul 10, 2012 748 749 750 751 752 753  ExchangeType xchg_type_; ///< Packet exchange type. PktList sent_packets_; ///< List of sent packets. /// Iterator pointing to the packet on sent list which will most /// likely match next received packet. This is based on the /// assumption that server responds in order to incoming packets.  Marcin Siodelski committed Jul 30, 2012 754  PktListIterator next_sent_;  Marcin Siodelski committed Jul 10, 2012 755 756 757  PktList rcvd_packets_; ///< List of received packets.  Marcin Siodelski committed Jul 25, 2012 758 759 760 761 762  /// List of archived packets. All sent packets that have /// been matched with received packet are moved to this /// list for diagnostics purposes. PktList archived_packets_;  Marcin Siodelski committed Jul 30, 2012 763 764 765 766 767 768 769 770 771 772 773 774 775  /// Indicates all packets have to be preserved after matching. /// By default this is disabled which means that when received /// packet is matched with sent packet both are deleted. This /// is important when test is executed for extended period of /// time and high memory usage might be the issue. /// When timestamps listing is specified from the command line /// (using diagnostics selector), all packets have to be preserved /// so as the printing method may read their timestamps and /// print it to user. In such usage model it will be rare to /// run test for extended period of time so it should be fine /// to keep all packets archived throughout the test. bool archive_enabled_;  Marcin Siodelski committed Sep 13, 2012 776 777 778 779  /// Maxmimum time elapsed between sending and receiving packet /// before packet is assumed dropped. double drop_time_;  Marcin Siodelski committed Jul 10, 2012 780 781 782 783 784 785  double min_delay_; ///< Minimum delay between sent ///< and received packets. double max_delay_; ///< Maximum delay between sent ///< and received packets. double sum_delay_; ///< Sum of delays between sent ///< and received packets.  Marcin Siodelski committed Jul 30, 2012 786  double sum_delay_squared_; ///< Squared sum of delays between  Marcin Siodelski committed Jul 10, 2012 787  ///< sent and recived packets.  Marcin Siodelski committed Jul 11, 2012 788   Marcin Siodelski committed Jul 30, 2012 789  uint64_t orphans_; ///< Number of orphant received packets.  Marcin Siodelski committed Jul 12, 2012 790   Marcin Siodelski committed Sep 13, 2012 791 792  uint64_t collected_; ///< Number of garbage collected packets.  Marcin Siodelski committed Jul 12, 2012 793 794 795 796 797  /// Sum of unordered lookup sets. Needed to calculate mean size of /// lookup set. It is desired that number of unordered lookups is /// minimal for performance reasons. Tracking number of lookups and /// mean size of the lookup set should give idea of packets serach /// complexity.  Marcin Siodelski committed Jul 30, 2012 798  uint64_t unordered_lookup_size_sum_;  Marcin Siodelski committed Jul 12, 2012 799   Marcin Siodelski committed Jul 30, 2012 800  uint64_t unordered_lookups_; ///< Number of unordered sent packets  Marcin Siodelski committed Jul 12, 2012 801  ///< lookups.  Marcin Siodelski committed Jul 30, 2012 802  uint64_t ordered_lookups_; ///< Number of ordered sent packets  Marcin Siodelski committed Jul 12, 2012 803 804  ///< lookups.  Marcin Siodelski committed Jul 30, 2012 805 806  uint64_t sent_packets_num_; ///< Total number of sent packets. uint64_t rcvd_packets_num_; ///< Total number of received packets.  Thomas Markwalder committed Mar 21, 2013 807  boost::posix_time::ptime boot_time_; ///< Time when test is started.  Marcin Siodelski committed Jul 10, 2012 808 809 810 811 812 813 814  }; /// Pointer to ExchangeStats. typedef boost::shared_ptr ExchangeStatsPtr; /// Map containing all specified exchange types. typedef typename std::map ExchangesMap; /// Iterator poiting to \ref ExchangesMap  Marcin Siodelski committed Jul 11, 2012 815  typedef typename ExchangesMap::const_iterator ExchangesMapIterator;  Marcin Siodelski committed Jul 19, 2012 816 817 818  /// Map containing custom counters. typedef typename std::map CustomCountersMap; /// Iterator for \ref CustomCountersMap.  Marcin Siodelski committed Jul 20, 2012 819  typedef typename CustomCountersMap::const_iterator CustomCountersMapIterator;  Marcin Siodelski committed Jul 19, 2012 820   Marcin Siodelski committed Aug 07, 2012 821  /// \brief Constructor.  Marcin Siodelski committed Jul 30, 2012 822 823 824 825 826 827 828 829 830 831 832 833  /// /// This constructor by default disables packets archiving mode. /// In this mode all packets from the list of sent packets are /// moved to list of archived packets once they have been matched /// with received packets. This is required if it has been selected /// from the command line to print timestamps for all packets after /// the test. If this is not selected archiving should be disabled /// for performance reasons and to avoid waste of memory for storing /// large list of archived packets. /// /// \param archive_enabled true indicates that packets /// archive mode is enabled.  Marcin Siodelski committed Aug 07, 2012 834  StatsMgr(const bool archive_enabled = false) :  Marcin Siodelski committed Jul 30, 2012 835  exchanges_(),  Marcin Siodelski committed Aug 21, 2012 836 837  archive_enabled_(archive_enabled), boot_time_(boost::posix_time::microsec_clock::universal_time()) {  Marcin Siodelski committed Jul 19, 2012 838  }  Marcin Siodelski committed Jul 10, 2012 839 840 841 842 843 844 845 846  /// \brief Specify new exchange type. /// /// This method creates new \ref ExchangeStats object that will /// collect statistics data from packets exchange of the specified /// type. /// /// \param xchg_type exchange type.  Marcin Siodelski committed Sep 21, 2012 847 848  /// \param drop_time maximum time elapsed before packet is /// assumed dropped. Negative value disables it.  Marcin Siodelski committed Jul 10, 2012 849  /// \throw isc::BadValue if exchange of specified type exists.  Marcin Siodelski committed Sep 13, 2012 850 851  void addExchangeStats(const ExchangeType xchg_type, const double drop_time = -1) {  Marcin Siodelski committed Jul 10, 2012 852 853 854  if (exchanges_.find(xchg_type) != exchanges_.end()) { isc_throw(BadValue, "Exchange of specified type already added."); }  Marcin Siodelski committed Jul 30, 2012 855  exchanges_[xchg_type] =  Marcin Siodelski committed Sep 13, 2012 856 857  ExchangeStatsPtr(new ExchangeStats(xchg_type, drop_time,  Thomas Markwalder committed Mar 21, 2013 858 859  archive_enabled_, boot_time_));  Marcin Siodelski committed Jul 10, 2012 860 861  }  Marcin Siodelski committed Jul 19, 2012 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878  /// \brief Add named custom uint64 counter. /// /// Method creates new named counter and stores in counter's map under /// key specified here as short_name. /// /// \param short_name key to use to access counter in the map. /// \param long_name name of the counter presented in the log file. void addCustomCounter(const std::string& short_name, const std::string& long_name) { if (custom_counters_.find(short_name) != custom_counters_.end()) { isc_throw(BadValue, "Custom counter " << short_name << " already added."); } custom_counters_[short_name] = CustomCounterPtr(new CustomCounter(long_name)); }  Marcin Siodelski committed Sep 13, 2012 879 880 881 882 883 884 885 886 887 888 889 890 891 892  /// \brief Check if any packet drops occured. /// // \return true, if packet drops occured. bool droppedPackets() const { for (ExchangesMapIterator it = exchanges_.begin(); it != exchanges_.end(); ++it) { if (it->second->getDroppedPacketsNum() > 0) { return (true); } } return (false); }  Marcin Siodelski committed Jul 19, 2012 893 894 895 896 897  /// \brief Return specified counter. /// /// Method returns specified counter. /// /// \param counter_key key poiting to the counter in the counters map.  Marcin Siodelski committed Jul 30, 2012 898  /// The short counter name has to be used to access counter.  Marcin Siodelski committed Jul 19, 2012 899 900 901 902 903 904 905  /// \return pointer to specified counter object. CustomCounterPtr getCounter(const std::string& counter_key) { CustomCountersMapIterator it = custom_counters_.find(counter_key); if (it == custom_counters_.end()) { isc_throw(BadValue, "Custom counter " << counter_key << "does not exist"); }  Marcin Siodelski committed Jul 30, 2012 906  return(it->second);  Marcin Siodelski committed Jul 19, 2012 907 908 909 910  } /// \brief Increment specified counter. ///  Jeremy C. Reed committed Apr 09, 2013 911  /// Increment counter value by one.  Marcin Siodelski committed Jul 19, 2012 912  ///  Marcin Siodelski committed Sep 13, 2012 913  /// \param counter_key key poiting to the counter in the counters map.  Marcin Siodelski committed Sep 21, 2012 914  /// \param value value to increment counter by.  Marcin Siodelski committed Jul 19, 2012 915  /// \return pointer to specified counter after incrementation.  Marcin Siodelski committed Sep 13, 2012 916 917  const CustomCounter& incrementCounter(const std::string& counter_key, const uint64_t value = 1) {  Marcin Siodelski committed Jul 19, 2012 918  CustomCounterPtr counter = getCounter(counter_key);  Marcin Siodelski committed Sep 13, 2012 919 920  *counter += value; return (*counter);  Marcin Siodelski committed Jul 19, 2012 921 922  }  Marcin Siodelski committed Jul 10, 2012 923 924 925 926 927 928 929 930  /// \brief Adds new packet to the sent packets list. /// /// Method adds new packet to the sent packets list. /// Packets are added to the list sequentially and /// most often read sequentially. /// /// \param xchg_type exchange type. /// \param packet packet to be added to the list  Marcin Siodelski committed Jul 23, 2012 931 932  /// \throw isc::BadValue if invalid exchange type specified or /// packet is null.  Marcin Siodelski committed Jul 10, 2012 933  void passSentPacket(const ExchangeType xchg_type,  Marcin Siodelski committed Aug 21, 2012 934  const boost::shared_ptr& packet) {  Marcin Siodelski committed Jul 11, 2012 935 936  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type); xchg_stats->appendSent(packet);  Marcin Siodelski committed Jul 10, 2012 937 938 939 940 941 942 943 944 945 946 947  } /// \brief Add new received packet and match with sent packet. /// /// Method adds new packet to the list of received packets. It /// also searches for corresponding packet on the list of sent /// packets. When packets are matched the statistics counters /// are updated accordingly for the particular exchange type. /// /// \param xchg_type exchange type. /// \param packet received packet  Marcin Siodelski committed Jul 23, 2012 948 949  /// \throw isc::BadValue if invalid exchange type specified /// or packet is null.  Marcin Siodelski committed Jul 10, 2012 950 951  /// \throw isc::Unexpected if corresponding packet was not /// found on the list of sent packets.  Marcin Siodelski committed Aug 21, 2012 952 953 954  boost::shared_ptr passRcvdPacket(const ExchangeType xchg_type, const boost::shared_ptr& packet) {  Marcin Siodelski committed Jul 11, 2012 955  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Aug 21, 2012 956  boost::shared_ptr sent_packet  Marcin Siodelski committed Aug 07, 2012 957  = xchg_stats->matchPackets(packet);  Marcin Siodelski committed Jul 11, 2012 958 959 960  if (sent_packet) { xchg_stats->updateDelays(sent_packet, packet);  Marcin Siodelski committed Jul 30, 2012 961 962 963  if (archive_enabled_) { xchg_stats->appendRcvd(packet); }  Marcin Siodelski committed Jul 11, 2012 964  }  Marcin Siodelski committed Aug 21, 2012 965  return(sent_packet);  Marcin Siodelski committed Jul 11, 2012 966 967  }  968 969 970 971 972 973 974 975 976 977  /// \brief Return minumum delay between sent and received packet. /// /// Method returns minimum delay between sent and received packet /// for specified exchange type. /// /// \param xchg_type exchange type. /// \throw isc::BadValue if invalid exchange type specified. /// \return minimum delay between packets. double getMinDelay(const ExchangeType xchg_type) const { ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 978  return(xchg_stats->getMinDelay());  979 980 981 982 983 984 985 986 987 988 989 990  } /// \brief Return maxmimum delay between sent and received packet. /// /// Method returns maximum delay between sent and received packet /// for specified exchange type. /// /// \param xchg_type exchange type. /// \throw isc::BadValue if invalid exchange type specified. /// \return maximum delay between packets. double getMaxDelay(const ExchangeType xchg_type) const { ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 991  return(xchg_stats->getMaxDelay());  992 993  }  Jeremy C. Reed committed Mar 06, 2013 994  /// \brief Return average packet delay.  995  ///  Marcin Siodelski committed Jul 25, 2012 996 997  /// Method returns average packet delay for specified /// exchange type.  998  ///  Marcin Siodelski committed Jul 25, 2012 999 1000  /// \return average packet delay. double getAvgDelay(const ExchangeType xchg_type) const {  1001  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 1002  return(xchg_stats->getAvgDelay());  1003 1004  }  Marcin Siodelski committed Jul 25, 2012 1005  /// \brief Return standard deviation of packet delay.  1006  ///  Marcin Siodelski committed Jul 25, 2012 1007 1008  /// Method returns standard deviation of packet delay /// for specified exchange type.  1009  ///  Marcin Siodelski committed Jul 25, 2012 1010 1011  /// \return standard deviation of packet delay. double getStdDevDelay(const ExchangeType xchg_type) const {  1012  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 1013  return(xchg_stats->getStdDevDelay());  1014 1015  }  Marcin Siodelski committed Jul 11, 2012 1016 1017 1018 1019 1020 1021 1022 1023  /// \brief Return number of orphant packets. /// /// Method returns number of orphant packets for specified /// exchange type. /// /// \param xchg_type exchange type. /// \throw isc::BadValue if invalid exchange type specified. /// \return number of orphant packets so far.  Marcin Siodelski committed Jul 30, 2012 1024  uint64_t getOrphans(const ExchangeType xchg_type) const {  Marcin Siodelski committed Jul 11, 2012 1025  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 1026  return(xchg_stats->getOrphans());  Marcin Siodelski committed Jul 11, 2012 1027  }  Marcin Siodelski committed Jul 12, 2012 1028 1029 1030 1031  /// \brief Return average unordered lookup set size. /// /// Method returns average unordered lookup set size.  Marcin Siodelski committed Aug 07, 2012 1032  /// This value changes every time \ref ExchangeStats::matchPackets  Marcin Siodelski committed Jul 23, 2012 1033  /// function performs unordered packet lookup.  Marcin Siodelski committed Jul 12, 2012 1034 1035  /// /// \param xchg_type exchange type.  1036  /// \throw isc::BadValue if invalid exchange type specified.  Marcin Siodelski committed Jul 12, 2012 1037 1038 1039  /// \return average unordered lookup set size. double getAvgUnorderedLookupSetSize(const ExchangeType xchg_type) const { ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 1040  return(xchg_stats->getAvgUnorderedLookupSetSize());  Marcin Siodelski committed Jul 12, 2012 1041 1042 1043 1044 1045 1046 1047 1048 1049  } /// \brief Return number of unordered sent packets lookups /// /// Method returns number of unordered sent packet lookups. /// Unordered lookup is used when received packet was sent /// out of order by server - transaction id of received /// packet does not match transaction id of next sent packet. ///  1050 1051  /// \param xchg_type exchange type. /// \throw isc::BadValue if invalid exchange type specified.  Marcin Siodelski committed Jul 12, 2012 1052  /// \return number of unordered lookups.  Marcin Siodelski committed Jul 30, 2012 1053  uint64_t getUnorderedLookups(const ExchangeType xchg_type) const {  Marcin Siodelski committed Jul 12, 2012 1054  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 1055  return(xchg_stats->getUnorderedLookups());  Marcin Siodelski committed Jul 12, 2012 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065  } /// \brief Return number of ordered sent packets lookups /// /// Method returns number of ordered sent packet lookups. /// Ordered lookup is used when packets are received in the /// same order as they were sent to the server. /// If packets are skipped or received out of order, lookup /// function will use unordered lookup (with hash table). ///  1066 1067  /// \param xchg_type exchange type. /// \throw isc::BadValue if invalid exchange type specified.  Marcin Siodelski committed Jul 12, 2012 1068  /// \return number of ordered lookups.  Marcin Siodelski committed Jul 30, 2012 1069  uint64_t getOrderedLookups(const ExchangeType xchg_type) const {  Marcin Siodelski committed Jul 12, 2012 1070  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 1071  return(xchg_stats->getOrderedLookups());  Marcin Siodelski committed Jul 12, 2012 1072 1073  }  1074 1075 1076 1077 1078 1079 1080 1081  /// \brief Return total number of sent packets /// /// Method returns total number of sent packets for specified /// exchange type. /// /// \param xchg_type exchange type. /// \throw isc::BadValue if invalid exchange type specified. /// \return number of sent packets.  Marcin Siodelski committed Jul 30, 2012 1082  uint64_t getSentPacketsNum(const ExchangeType xchg_type) const {  1083  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 1084  return(xchg_stats->getSentPacketsNum());  1085  }  Marcin Siodelski committed Jul 11, 2012 1086   1087 1088 1089 1090 1091 1092 1093 1094  /// \brief Return total number of received packets /// /// Method returns total number of received packets for specified /// exchange type. /// /// \param xchg_type exchange type. /// \throw isc::BadValue if invalid exchange type specified. /// \return number of received packets.  Marcin Siodelski committed Jul 30, 2012 1095  uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const {  1096  ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);  Marcin Siodelski committed Jul 30, 2012 1097  return(xchg_stats->getRcvdPacketsNum());  1098  }  Marcin Siodelski committed Jul 19, 2012 1099   Marcin Siodelski committed Aug 21, 2012 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112  /// \brief Return total number of dropped packets. /// /// Method returns total number of dropped packets for specified /// exchange type. /// /// \param xchg_type exchange type. /// \throw isc::BadValue if invalid exchange type specified. /// \return number of dropped packets. uint64_t getDroppedPacketsNum(const ExchangeType xchg_type) const { ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type); return(xchg_stats->getDroppedPacketsNum()); }  Marcin Siodelski committed Sep 13, 2012 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128  /// \brief Return number of garbage collected packets. /// /// Method returns number of garbage collected timed out /// packets. Packet is assumed timed out when duration /// between sending it to server and receiving server's /// response is greater than value specified with -d /// command line argument. /// /// \throw isc::BadValue if invalid exchange type specified. /// \return number of garbage collected packets. uint64_t getCollectedNum(const ExchangeType xchg_type) const { ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type); return(xchg_stats->getCollectedNum()); }  Marcin Siodelski committed Aug 21, 2012 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142  /// \brief Get time period since the start of test. /// /// Calculate dna return period since the test start. This /// can be specifically helpful when calculating packet /// exchange rates. /// /// \return test period so far. boost::posix_time::time_period getTestPeriod() const { using namespace boost::posix_time; time_period test_period(boot_time_, microsec_clock::universal_time()); return test_period; }  Marcin Siodelski committed Jul 25, 2012 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152  /// \brief Return name of the exchange. /// /// Method returns name of the specified exchange type. /// This function is mainly for logging purposes. /// /// \param xchg_type exchange type. /// \return string representing name of the exchange. std::string exchangeToString(ExchangeType xchg_type) const { switch(xchg_type) { case XCHG_DO:  Marcin Siodelski committed Jul 30, 2012 1153  return("DISCOVER-OFFER");  Marcin Siodelski committed Jul 25, 2012 1154  case XCHG_RA:  Marcin Siodelski committed Jul 30, 2012 1155  return("REQUEST-ACK");  Marcin Siodelski committed Jul 25, 2012 1156  case XCHG_SA:  Marcin Siodelski committed Jul 30, 2012 1157  return("SOLICIT-ADVERTISE");  Marcin Siodelski committed Jul 25, 2012 1158  case XCHG_RR:  Marcin Siodelski committed Jul 30, 2012 1159  return("REQUEST-REPLY");  Marcin Siodelski committed Jul 25, 2012 1160  default:  Marcin Siodelski committed Jul 30, 2012 1161  return("Unknown exchange type");  Marcin Siodelski committed Jul 25, 2012 1162 1163 1164  } }  Marcin Siodelski committed Jul 30, 2012 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174  /// \brief Print statistics counters for all exchange types. /// /// Method prints statistics for all exchange types. /// Statistics includes: /// - number of sent and received packets /// - number of dropped packets and number of orphans /// - minimum packets delay, /// - average packets delay, /// - maximum packets delay, /// - standard deviation of packets delay.  Marcin Siodelski committed Jul 30, 2012 1175 1176 1177  /// /// \throw isc::InvalidOperation if no exchange type added to /// track statistics.  Marcin Siodelski committed Jul 30, 2012 1178  void printStats() const {  Marcin Siodelski committed Jul 30, 2012 1179 1180 1181 1182  if (exchanges_.size() == 0) { isc_throw(isc::InvalidOperation, "no exchange type added for tracking"); }  Marcin Siodelski committed Jul 25, 2012 1183 1184 1185 1186  for (ExchangesMapIterator it = exchanges_.begin(); it != exchanges_.end(); ++it) { ExchangeStatsPtr xchg_stats = it->second;  Marcin Siodelski committed Jul 30, 2012 1187 1188 1189 1190 1191 1192  std::cout << "***Statistics for: " << exchangeToString(it->first) << "***" << std::endl; xchg_stats->printMainStats(); std::cout << std::endl; xchg_stats->printRTTStats(); std::cout << std::endl;  Marcin Siodelski committed Jul 25, 2012 1193 1194 1195  } }  Marcin Siodelski committed Aug 24, 2012 1196 1197 1198 1199 1200 1201  /// \brief Print intermediate statistics. /// /// Method prints intermediate statistics for all exchanges. /// Statistics includes sent, received and dropped packets /// counters. void printIntermediateStats() const {  Marcin Siodelski committed Sep 04, 2012 1202 1203 1204  std::ostringstream stream_sent; std::ostringstream stream_rcvd; std::ostringstream stream_drops;  Marcin Siodelski committed Aug 24, 2012 1205 1206  std::string sep(""); for (ExchangesMapIterator it = exchanges_.begin();  Marcin Siodelski committed Sep 04, 2012 1207  it != exchanges_.end(); ++it) {  Marcin Siodelski committed Aug 24, 2012 1208 1209 1210 1211 1212 1213 1214 1215  if (it != exchanges_.begin()) { sep = "/"; } stream_sent << sep << it->second->getSentPacketsNum(); stream_rcvd << sep << it->second->getRcvdPacketsNum(); stream_drops << sep << it->second->getDroppedPacketsNum(); }  Marcin Siodelski committed Sep 13, 2012 1216  std::cout << "sent: " << stream_sent.str()  Marcin Siodelski committed Aug 24, 2012 1217 1218 1219 1220 1221  << "; received: " << stream_rcvd.str() << "; drops: " << stream_drops.str() << std::endl; }  Marcin Siodelski committed Jul 25, 2012 1222 1223 1224 1225 1226 1227  /// \brief Print timestamps of all packets. /// /// Method prints timestamps of all sent and received /// packets for all defined exchange types. /// /// \throw isc::InvalidOperation if one of the packets has  Marcin Siodelski committed Jul 30, 2012 1228 1229 1230 1231 1232  /// no timestamp value set or if packets archive mode is /// disabled. /// /// \throw isc::InvalidOperation if no exchange type added to /// track statistics or packets archive mode is disabled.  Marcin Siodelski committed Jul 25, 2012 1233  void printTimestamps() const {  Marcin Siodelski committed Jul 30, 2012 1234 1235 1236 1237  if (exchanges_.size() == 0) { isc_throw(isc::InvalidOperation, "no exchange type added for tracking"); }  Marcin Siodelski committed Jul 25, 2012 1238 1239 1240 1241  for (ExchangesMapIterator it = exchanges_.begin(); it != exchanges_.end(); ++it) { ExchangeStatsPtr xchg_stats = it->second;  Marcin Siodelski committed Jul 30, 2012 1242 1243 1244  std::cout << "***Timestamps for packets: " << exchangeToString(it->first) << "***" << std::endl;  Marcin Siodelski committed Jul 25, 2012 1245  xchg_stats->printTimestamps();  Marcin Siodelski committed Jul 30, 2012 1246  std::cout << std::endl;  Marcin Siodelski committed Jul 25, 2012 1247 1248 1249 1250 1251 1252 1253  } } /// \brief Print names and values of custom counters. /// /// Method prints names and values of custom counters. Custom counters /// are defined by client class for tracking different statistics.  Marcin Siodelski committed Jul 30, 2012 1254 1255  /// /// \throw isc::InvalidOperation if no custom counters added for tracking.  Marcin Siodelski committed Jul 25, 2012 1256  void printCustomCounters() const {  Marcin Siodelski committed Jul 30, 2012 1257 1258  if (custom_counters_.size() == 0) { isc_throw(isc::InvalidOperation, "no custom counters specified");  Marcin Siodelski committed Jul 25, 2012 1259 1260 1261 1262 1263  } for (CustomCountersMapIterator it = custom_counters_.begin(); it != custom_counters_.end(); ++it) { CustomCounterPtr counter = it->second;  Marcin Siodelski committed Jul 30, 2012 1264 1265  std::cout << counter->getName() << ": " << counter->getValue() << std::endl;  Marcin Siodelski committed Jul 25, 2012 1266 1267 1268  } }  1269 private:  Marcin Siodelski committed Jul 30, 2012 1270   Marcin Siodelski committed Jul 11, 2012 1271 1272 1273 1274 1275 1276 1277 1278  /// \brief Return exchange stats object for given exchange type /// /// Method returns exchange stats object for given exchange type. /// /// \param xchg_type exchange type.