Commit 13cb26e1 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[3181] Added a RateControl class omitted in the previous commit.

parent 3c33b14c
// Copyright (C) 2013 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.
#include <exceptions/exceptions.h>
#include <tests/tools/perfdhcp/rate_control.h>
namespace isc {
namespace perfdhcp {
using namespace boost::posix_time;
RateControl::RateControl()
: send_due_(currentTime()), last_sent_(currentTime()),
aggressivity_(1), rate_(0), late_sent_(false) {
}
RateControl::RateControl(const int rate, const int aggressivity)
: send_due_(currentTime()), last_sent_(currentTime()),
aggressivity_(aggressivity), rate_(rate), late_sent_(false) {
if (aggressivity < 1) {
isc_throw(isc::BadValue, "invalid value of aggressivity "
<< aggressivity << ", expected value is greater than 0");
}
}
uint64_t
RateControl::getOutboundMessageCount() {
// We need calculate the due time for sending next set of messages.
updateSendDue();
// Get current time. If we are behind due time, we have to calculate
// how many messages to send to catch up with the rate.
ptime now = currentTime();
if (now >= send_due_) {
// Reset number of exchanges.
uint64_t due_exchanges = 0;
// If rate is specified from the command line we have to
// synchornize with it.
if (getRate() != 0) {
time_period period(send_due_, now);
time_duration duration = period.length();
// due_factor indicates the number of seconds that
// sending next chunk of packets will take.
double due_factor = duration.fractional_seconds() /
time_duration::ticks_per_second();
due_factor += duration.total_seconds();
// Multiplying due_factor by expected rate gives the number
// of exchanges to be initiated.
due_exchanges = static_cast<uint64_t>(due_factor * getRate());
// We want to make sure that at least one packet goes out.
if (due_exchanges == 0) {
due_exchanges = 1;
}
// We should not exceed aggressivity as it could have been
// restricted from command line.
if (due_exchanges > getAggressivity()) {
due_exchanges = getAggressivity();
}
} else {
// Rate is not specified so we rely on aggressivity
// which is the number of packets to be sent in
// one chunk.
due_exchanges = getAggressivity();
}
return (due_exchanges);
}
return (0);
}
boost::posix_time::ptime
RateControl::currentTime() {
return (microsec_clock::universal_time());
}
void
RateControl::updateSendDue() {
// There is no sense to update due time if the current due time is in the
// future. The due time is calculated as a duration between the moment
// when the last message of the given type was sent and the time when
// next one is supposed to be sent based on a given rate. The former value
// will not change until we send the next message, which we don't do
// until we reach the due time.
if (send_due_ > currentTime()) {
return;
}
// This is initialized in the class constructor, so if it is not initialized
// it is a programmatic error.
if (last_sent_.is_not_a_date_time()) {
isc_throw(isc::Unexpected, "timestamp of the last sent packet not"
" initialized");
}
// If rate was not specified we will wait just one clock tick to
// send next packet. This simulates best effort conditions.
long duration = 1;
if (getRate() != 0) {
// We use number of ticks instead of nanoseconds because
// nanosecond resolution may not be available on some
// machines. Number of ticks guarantees the highest possible
// timer resolution.
duration = time_duration::ticks_per_second() / getRate();
}
// Calculate due time to initiate next chunk of exchanges.
send_due_ = last_sent_ + time_duration(0, 0, 0, duration);
if (send_due_ > currentTime()) {
late_sent_ = true;
} else {
late_sent_ = false;
}
}
void
RateControl::setRelativeDue(const int offset) {
send_due_ = offset > 0 ?
currentTime() + seconds(abs(offset)) :
currentTime() - seconds(abs(offset));
}
void
RateControl::updateSendTime() {
last_sent_ = currentTime();
}
} // namespace perfdhcp
} // namespace isc
// Copyright (C) 2013 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.
#ifndef RATE_CONTROL_H
#define RATE_CONTROL_H
#include <boost/date_time/posix_time/posix_time.hpp>
namespace isc {
namespace perfdhcp {
/// \brief A message sending rate control class for perfdhcp.
///
/// This class provides the means to control the rate at which messages
/// of the specific type are sent by perfdhcp. Each message type,
/// for which the desired rate can be specified, has a corresponding
/// \c RateControl object. So, the perfdhcp is using up to three objects
/// of this type in the same time, to control the rate of the following
/// messages being sent:
/// - Discover(DHCPv4) or Solicit (DHCPv6)
/// - Renew (DHCPv6) or Request (DHCPv4) to renew leases.
/// - Release
///
/// The purpose of the RateControl class is to track the due time for
/// sending next message (or bunch of messages) to keep outbound rate
/// of particular messages on the desired level. The due time is calculated
/// using the desired rate value and the timestamp when the last message of
/// the particular type has been sent. That puts the responsibility on the
/// \c TestControl class to invoke the \c RateControl::updateSendDue, every
/// time the message is sent.
///
/// The \c RateControl object returns the number of messages to be sent at
/// the time. Typically the number returned is 0, if perfdhcp shouldn't send
/// any messages yet, or 1 (sometimes more) if the send due time has been
/// reached.
class RateControl {
public:
/// \brief Default constructor.
RateControl();
/// \brief Constructor which sets desired rate and aggressivity.
///
/// \param rate A desired rate.
/// \param aggressivity A desired aggressivity.
RateControl(const int rate, const int aggressivity);
/// \brief Returns the value of aggressivity.
int getAggressivity() const {
return (aggressivity_);
}
/// \brief Returns current due time to send next message.
boost::posix_time::ptime getDue() const {
return (send_due_);
}
/// \brief Returns number of messages to be sent "now".
///
/// This function calculates how many masseges of the given type should
/// be sent immediately when the call to the function returns, to catch
/// up with the desired message rate.
///
/// The value returned depends on the due time calculated with the
/// \c RateControl::updateSendDue function and the current time. If
/// the due time has been hit, the non-zero number of messages is returned.
/// If the due time hasn't been hit, the number returned is 0.
///
/// \return A number of messages to be sent immediately.
uint64_t getOutboundMessageCount();
/// \brief Returns the rate.
int getRate() const {
return (rate_);
}
/// \brief Returns the value of the late send flag.
///
/// The flag returned by this function indicates whether the new due time
/// calculated by the \c RateControl::updateSendDue has been in the past.
/// This value is used by the \c TestControl object to increment the counter
/// of the late sent messages in the \c StatsMgr.
bool isLateSent() const {
return (late_sent_);
}
/// \brief Sets the value of aggressivity.
///
/// \param aggressivity A new value of aggressivity.
void setAggressivity(const int aggressivity) {
aggressivity_ = aggressivity;
}
/// \brief Sets the new rate.
///
/// \param A new value of rate.
void setRate(const int rate) {
rate_ = rate;
}
/// \brief Sets the value of the due time.
///
/// This function is intended for unit testing. It manipulates the value of
/// the due time. The parameter passed to this function specifies the
/// (positive or negative) number of seconds relative to current time.
///
/// \param A number of seconds relative to current time which constitutes
/// the new due time.
void setRelativeDue(const int offset);
/// \brief Sets the timestamp of the last sent message to current time.
void updateSendTime();
protected:
/// \brief Convenience function returning current time.
///
/// \return current time.
static boost::posix_time::ptime currentTime();
/// \brief Calculates the send due.
///
/// This function calculates the send due timestamp using the current time
/// and desired rate. The due timestamp is calculated as a sum of the
/// timestamp when the last message was sent and the reciprocal of the rate
/// in micro or nanoseconds (depending on the timer resolution). If the rate
/// is not specified, the duration between two consecutive sends is one
/// timer tick.
void updateSendDue();
/// \brief Holds a timestamp when the next message should be sent.
boost::posix_time::ptime send_due_;
/// \brief Holds a timestamp when the last message was sent.
boost::posix_time::ptime last_sent_;
/// \brief Holds an aggressivity value.
int aggressivity_;
/// \brief Holds a desired rate value.
int rate_;
/// \brief A flag which indicates that the calculated due time is in the
/// past.
bool late_sent_;
};
}
}
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment