1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
// 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 "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");
}
if (rate_ < 0) {
isc_throw(isc::BadValue, "invalid value of rate " << rate
<< ", expected non-negative value");
}
}
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::setAggressivity(const int aggressivity) {
if (aggressivity < 1) {
isc_throw(isc::BadValue, "invalid value of aggressivity "
<< aggressivity << ", expected value is greater than 0");
}
aggressivity_ = aggressivity;
}
void
RateControl::setRate(const int rate) {
if (rate < 0) {
isc_throw(isc::BadValue, "invalid value of rate " << rate
<< ", expected non-negative value");
}
rate_ = rate;
}
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
|