]>
Commit | Line | Data |
---|---|---|
6ef228fc PB |
1 | /* |
2 | * Ratelimiting calculations | |
3 | * | |
4 | * Copyright IBM, Corp. 2011 | |
5 | * | |
6 | * Authors: | |
7 | * Stefan Hajnoczi <[email protected]> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU LGPL, version 2 or later. | |
10 | * See the COPYING.LIB file in the top-level directory. | |
11 | * | |
12 | */ | |
13 | ||
14 | #ifndef QEMU_RATELIMIT_H | |
175de524 | 15 | #define QEMU_RATELIMIT_H |
6ef228fc PB |
16 | |
17 | typedef struct { | |
f14a39cc SS |
18 | int64_t slice_start_time; |
19 | int64_t slice_end_time; | |
6ef228fc PB |
20 | uint64_t slice_quota; |
21 | uint64_t slice_ns; | |
22 | uint64_t dispatched; | |
23 | } RateLimit; | |
24 | ||
f14a39cc SS |
25 | /** Calculate and return delay for next request in ns |
26 | * | |
f3e4ce4a EB |
27 | * Record that we sent @n data units (where @n matches the scale chosen |
28 | * during ratelimit_set_speed). If we may send more data units | |
f14a39cc SS |
29 | * in the current time slice, return 0 (i.e. no delay). Otherwise |
30 | * return the amount of time (in ns) until the start of the next time | |
31 | * slice that will permit sending the next chunk of data. | |
32 | * | |
33 | * Recording sent data units even after exceeding the quota is | |
34 | * permitted; the time slice will be extended accordingly. | |
35 | */ | |
6ef228fc PB |
36 | static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n) |
37 | { | |
bc72ad67 | 38 | int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); |
b7728f32 | 39 | double delay_slices; |
6ef228fc | 40 | |
f14a39cc SS |
41 | assert(limit->slice_quota && limit->slice_ns); |
42 | ||
43 | if (limit->slice_end_time < now) { | |
44 | /* Previous, possibly extended, time slice finished; reset the | |
45 | * accounting. */ | |
46 | limit->slice_start_time = now; | |
47 | limit->slice_end_time = now + limit->slice_ns; | |
6ef228fc PB |
48 | limit->dispatched = 0; |
49 | } | |
f14a39cc SS |
50 | |
51 | limit->dispatched += n; | |
52 | if (limit->dispatched < limit->slice_quota) { | |
53 | /* We may send further data within the current time slice, no | |
54 | * need to delay the next request. */ | |
6ef228fc | 55 | return 0; |
6ef228fc | 56 | } |
f14a39cc | 57 | |
b7728f32 WB |
58 | /* Quota exceeded. Wait based on the excess amount and then start a new |
59 | * slice. */ | |
60 | delay_slices = (double)limit->dispatched / limit->slice_quota; | |
f14a39cc | 61 | limit->slice_end_time = limit->slice_start_time + |
b7728f32 | 62 | (uint64_t)(delay_slices * limit->slice_ns); |
f14a39cc | 63 | return limit->slice_end_time - now; |
6ef228fc PB |
64 | } |
65 | ||
66 | static inline void ratelimit_set_speed(RateLimit *limit, uint64_t speed, | |
67 | uint64_t slice_ns) | |
68 | { | |
69 | limit->slice_ns = slice_ns; | |
f14a39cc | 70 | limit->slice_quota = MAX(((double)speed * slice_ns) / 1000000000ULL, 1); |
6ef228fc PB |
71 | } |
72 | ||
73 | #endif |