Skip to content

Commit 93eab49

Browse files
GeorgeHahnblt
andauthored
Throttle fixes (#554)
* `Strings` are UTF-8 encoded and use 1 byte for ascii chars * Refill capacity based on elapsed time * Wait based on refill per tick * Clarify variable names, fix division by zero Signed-off-by: Brian L. Troutwine <brian.troutwine@datadoghq.com> * Changelog formatting * Add changelog entry --------- Signed-off-by: Brian L. Troutwine <brian.troutwine@datadoghq.com> Co-authored-by: Brian L. Troutwine <brian.troutwine@datadoghq.com>
1 parent 2251295 commit 93eab49

3 files changed

Lines changed: 25 additions & 20 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8-
## Added
8+
### Added
99
- Added target metrics support for Go expvars
1010

11+
### Fixed
12+
- Fixed throttle behavior for generators that run very quickly
13+
1114
## [0.14.0]
12-
## Added
15+
### Added
1316
- Added the ability to configure details about DogStatsD payload
14-
## Changed
17+
### Changed
1518
- Datadog logs generation now much faster, relying on an experimentally
1619
determined 'encoded size' rather than searching at runtime for the same.
1720
(PR #564).
@@ -21,30 +24,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2124
of some memory during the generation process. (PR #547)
2225

2326
## [0.13.1]
24-
## Added
27+
### Added
2528
- Introduced Proportional Set Size (PSS) memory measurement under the
2629
`pss_bytes` metric.
2730
- Convert `Block` to use `Bytes` type instead of `Vec<u8>`.
2831
- Introduce Datadog trace-agent payload support in JSON and MsgPack serialization.
2932

3033
## [0.13.0]
31-
## Added
34+
### Added
3235
- Introduced automatic throttling into generators to search for stable target load.
33-
## Fixed
36+
### Fixed
3437
- Use saturating addition in observer stats gathering routine
3538

3639
## [0.12.0]
37-
## Added
40+
### Added
3841
- Added the ability for lading to back-off load generation based on RSS limits.
3942
- Process tree generator contributed by @safchain
4043
- Fixed: OpenTelemetry message length calculation corrected for some messages.
4144
- **Breaking change:** Split UDS support between explict datagram and stream modules.
4245
- Fixed: Corrected mistakes in the DogStatsD payload implementation.
43-
## Changed
46+
### Changed
4447
- Adjusted the cardinality of DogStatsD keys, values and names downward.
4548
- **Breaking change:** Added support for DogStatsD payload.
4649
- **Breaking change:** Support for Kafka generator is removed.
47-
## Fixed
50+
### Fixed
4851
- Lading's UDS will now re-attempt to connect to a UDS socket, rather than
4952
erroring.
5053

src/payload/common.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ impl Generator<String> for AsciiString {
2727
R: rand::Rng + ?Sized,
2828
{
2929
let len: usize = rng.gen_range(1..self.max_length) as usize;
30-
let total_bytes = 4 * len; // max size of an `char` times length
31-
let mut s = String::with_capacity(total_bytes);
30+
let total_bytes = len;
31+
let mut s = String::new();
3232
s.reserve(total_bytes);
3333
s.extend(
3434
CHARSET

src/throttle.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub(crate) struct GenericThrottle<C>
8585
where
8686
C: Clock,
8787
{
88+
last_tick: u64,
8889
spare_capacity: u64,
8990
/// The maximum capacity of `Throttle` past which no more capacity will be
9091
/// added.
@@ -118,13 +119,12 @@ where
118119
// 'interval' happens once every second. If we allow for the tick of
119120
// Throttle to be one per microsecond that's 1x10^6 ticks per interval.
120121

121-
let refill_per_tick = u64::from(maximum_capacity.get()) / INTERVAL_TICKS;
122-
123-
// let rate_limiter = RateLimiter::direct(Quota::per_second(maximum_capacity));
124-
// let maximum_capacity = maximum_capacity.get();
125-
// let interval_actual_budget = maximum_capacity / 10;
122+
// We do not want a situation where refill never happens. If the maximum
123+
// capacity is less than INTERVAL_TICKS we set the floor at 1.
124+
let refill_per_tick = cmp::max(1, u64::from(maximum_capacity.get()) / INTERVAL_TICKS);
126125

127126
Self {
127+
last_tick: clock.ticks_elapsed(),
128128
maximum_capacity: u64::from(maximum_capacity.get()),
129129
refill_per_tick,
130130
requested_budget: 0,
@@ -206,9 +206,11 @@ where
206206
// called. Depending on how long ago this was we may have completely
207207
// filled up throttle capacity. Note we fill to the _projected_ budget
208208
// and not the maximum capacity.
209-
let ticks_since = self.clock.ticks_elapsed();
209+
let ticks_since_start = self.clock.ticks_elapsed();
210+
let ticks_since_last_wait = ticks_since_start.saturating_sub(self.last_tick);
211+
self.last_tick = ticks_since_start;
210212
let refilled_capacity: u64 = cmp::min(
211-
ticks_since
213+
ticks_since_last_wait
212214
.saturating_mul(self.refill_per_tick)
213215
.saturating_add(self.spare_capacity),
214216
self.projected_budget,
@@ -221,7 +223,7 @@ where
221223
// budget for those 'missing' intervals, although that would be
222224
// interesting to do maybe.
223225

224-
let current_interval = ticks_since / INTERVAL_TICKS;
226+
let current_interval = ticks_since_start / INTERVAL_TICKS;
225227
if current_interval == self.interval {
226228
// Intentionally blank. There is nothing to do in the event we are
227229
// in the same interval, with regard to budgets.
@@ -264,7 +266,7 @@ where
264266
// need to pass before capacity is sufficient, force the client to
265267
// wait that amount of time.
266268
self.spare_capacity = 0;
267-
let slop = capacity_request - refilled_capacity;
269+
let slop = (capacity_request - refilled_capacity) / self.refill_per_tick;
268270
self.clock.wait(slop).await;
269271
}
270272
Ok(())

0 commit comments

Comments
 (0)