rate_control.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <exceptions/exceptions.h>
  15. #include <tests/tools/perfdhcp/rate_control.h>
  16. namespace isc {
  17. namespace perfdhcp {
  18. using namespace boost::posix_time;
  19. RateControl::RateControl()
  20. : send_due_(currentTime()), last_sent_(currentTime()),
  21. aggressivity_(1), rate_(0), late_sent_(false) {
  22. }
  23. RateControl::RateControl(const int rate, const int aggressivity)
  24. : send_due_(currentTime()), last_sent_(currentTime()),
  25. aggressivity_(aggressivity), rate_(rate), late_sent_(false) {
  26. if (aggressivity < 1) {
  27. isc_throw(isc::BadValue, "invalid value of aggressivity "
  28. << aggressivity << ", expected value is greater than 0");
  29. }
  30. }
  31. uint64_t
  32. RateControl::getOutboundMessageCount() {
  33. // We need calculate the due time for sending next set of messages.
  34. updateSendDue();
  35. // Get current time. If we are behind due time, we have to calculate
  36. // how many messages to send to catch up with the rate.
  37. ptime now = currentTime();
  38. if (now >= send_due_) {
  39. // Reset number of exchanges.
  40. uint64_t due_exchanges = 0;
  41. // If rate is specified from the command line we have to
  42. // synchornize with it.
  43. if (getRate() != 0) {
  44. time_period period(send_due_, now);
  45. time_duration duration = period.length();
  46. // due_factor indicates the number of seconds that
  47. // sending next chunk of packets will take.
  48. double due_factor = duration.fractional_seconds() /
  49. time_duration::ticks_per_second();
  50. due_factor += duration.total_seconds();
  51. // Multiplying due_factor by expected rate gives the number
  52. // of exchanges to be initiated.
  53. due_exchanges = static_cast<uint64_t>(due_factor * getRate());
  54. // We want to make sure that at least one packet goes out.
  55. if (due_exchanges == 0) {
  56. due_exchanges = 1;
  57. }
  58. // We should not exceed aggressivity as it could have been
  59. // restricted from command line.
  60. if (due_exchanges > getAggressivity()) {
  61. due_exchanges = getAggressivity();
  62. }
  63. } else {
  64. // Rate is not specified so we rely on aggressivity
  65. // which is the number of packets to be sent in
  66. // one chunk.
  67. due_exchanges = getAggressivity();
  68. }
  69. return (due_exchanges);
  70. }
  71. return (0);
  72. }
  73. boost::posix_time::ptime
  74. RateControl::currentTime() {
  75. return (microsec_clock::universal_time());
  76. }
  77. void
  78. RateControl::updateSendDue() {
  79. // There is no sense to update due time if the current due time is in the
  80. // future. The due time is calculated as a duration between the moment
  81. // when the last message of the given type was sent and the time when
  82. // next one is supposed to be sent based on a given rate. The former value
  83. // will not change until we send the next message, which we don't do
  84. // until we reach the due time.
  85. if (send_due_ > currentTime()) {
  86. return;
  87. }
  88. // This is initialized in the class constructor, so if it is not initialized
  89. // it is a programmatic error.
  90. if (last_sent_.is_not_a_date_time()) {
  91. isc_throw(isc::Unexpected, "timestamp of the last sent packet not"
  92. " initialized");
  93. }
  94. // If rate was not specified we will wait just one clock tick to
  95. // send next packet. This simulates best effort conditions.
  96. long duration = 1;
  97. if (getRate() != 0) {
  98. // We use number of ticks instead of nanoseconds because
  99. // nanosecond resolution may not be available on some
  100. // machines. Number of ticks guarantees the highest possible
  101. // timer resolution.
  102. duration = time_duration::ticks_per_second() / getRate();
  103. }
  104. // Calculate due time to initiate next chunk of exchanges.
  105. send_due_ = last_sent_ + time_duration(0, 0, 0, duration);
  106. if (send_due_ > currentTime()) {
  107. late_sent_ = true;
  108. } else {
  109. late_sent_ = false;
  110. }
  111. }
  112. void
  113. RateControl::setRelativeDue(const int offset) {
  114. send_due_ = offset > 0 ?
  115. currentTime() + seconds(abs(offset)) :
  116. currentTime() - seconds(abs(offset));
  117. }
  118. void
  119. RateControl::updateSendTime() {
  120. last_sent_ = currentTime();
  121. }
  122. } // namespace perfdhcp
  123. } // namespace isc