rate_control.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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 "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. if (rate_ < 0) {
  31. isc_throw(isc::BadValue, "invalid value of rate " << rate
  32. << ", expected non-negative value");
  33. }
  34. }
  35. uint64_t
  36. RateControl::getOutboundMessageCount() {
  37. // We need calculate the due time for sending next set of messages.
  38. updateSendDue();
  39. // Get current time. If we are behind due time, we have to calculate
  40. // how many messages to send to catch up with the rate.
  41. ptime now = currentTime();
  42. if (now >= send_due_) {
  43. // Reset number of exchanges.
  44. uint64_t due_exchanges = 0;
  45. // If rate is specified from the command line we have to
  46. // synchornize with it.
  47. if (getRate() != 0) {
  48. time_period period(send_due_, now);
  49. time_duration duration = period.length();
  50. // due_factor indicates the number of seconds that
  51. // sending next chunk of packets will take.
  52. double due_factor = duration.fractional_seconds() /
  53. time_duration::ticks_per_second();
  54. due_factor += duration.total_seconds();
  55. // Multiplying due_factor by expected rate gives the number
  56. // of exchanges to be initiated.
  57. due_exchanges = static_cast<uint64_t>(due_factor * getRate());
  58. // We want to make sure that at least one packet goes out.
  59. if (due_exchanges == 0) {
  60. due_exchanges = 1;
  61. }
  62. // We should not exceed aggressivity as it could have been
  63. // restricted from command line.
  64. if (due_exchanges > getAggressivity()) {
  65. due_exchanges = getAggressivity();
  66. }
  67. } else {
  68. // Rate is not specified so we rely on aggressivity
  69. // which is the number of packets to be sent in
  70. // one chunk.
  71. due_exchanges = getAggressivity();
  72. }
  73. return (due_exchanges);
  74. }
  75. return (0);
  76. }
  77. boost::posix_time::ptime
  78. RateControl::currentTime() {
  79. return (microsec_clock::universal_time());
  80. }
  81. void
  82. RateControl::updateSendDue() {
  83. // There is no sense to update due time if the current due time is in the
  84. // future. The due time is calculated as a duration between the moment
  85. // when the last message of the given type was sent and the time when
  86. // next one is supposed to be sent based on a given rate. The former value
  87. // will not change until we send the next message, which we don't do
  88. // until we reach the due time.
  89. if (send_due_ > currentTime()) {
  90. return;
  91. }
  92. // This is initialized in the class constructor, so if it is not initialized
  93. // it is a programmatic error.
  94. if (last_sent_.is_not_a_date_time()) {
  95. isc_throw(isc::Unexpected, "timestamp of the last sent packet not"
  96. " initialized");
  97. }
  98. // If rate was not specified we will wait just one clock tick to
  99. // send next packet. This simulates best effort conditions.
  100. long duration = 1;
  101. if (getRate() != 0) {
  102. // We use number of ticks instead of nanoseconds because
  103. // nanosecond resolution may not be available on some
  104. // machines. Number of ticks guarantees the highest possible
  105. // timer resolution.
  106. duration = time_duration::ticks_per_second() / getRate();
  107. }
  108. // Calculate due time to initiate next chunk of exchanges.
  109. send_due_ = last_sent_ + time_duration(0, 0, 0, duration);
  110. if (send_due_ > currentTime()) {
  111. late_sent_ = true;
  112. } else {
  113. late_sent_ = false;
  114. }
  115. }
  116. void
  117. RateControl::setAggressivity(const int aggressivity) {
  118. if (aggressivity < 1) {
  119. isc_throw(isc::BadValue, "invalid value of aggressivity "
  120. << aggressivity << ", expected value is greater than 0");
  121. }
  122. aggressivity_ = aggressivity;
  123. }
  124. void
  125. RateControl::setRate(const int rate) {
  126. if (rate < 0) {
  127. isc_throw(isc::BadValue, "invalid value of rate " << rate
  128. << ", expected non-negative value");
  129. }
  130. rate_ = rate;
  131. }
  132. void
  133. RateControl::setRelativeDue(const int offset) {
  134. send_due_ = offset > 0 ?
  135. currentTime() + seconds(abs(offset)) :
  136. currentTime() - seconds(abs(offset));
  137. }
  138. void
  139. RateControl::updateSendTime() {
  140. last_sent_ = currentTime();
  141. }
  142. } // namespace perfdhcp
  143. } // namespace isc