]>
Commit | Line | Data |
---|---|---|
6ef228fc PB |
1 | /* |
2 | * Ratelimiting calculations | |
3 | * | |
4 | * Copyright IBM, Corp. 2011 | |
5 | * | |
6 | * Authors: | |
7 | * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> | |
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 | 16 | |
4951967d | 17 | #include "qemu/lockable.h" |
ec150c7e MA |
18 | #include "qemu/timer.h" |
19 | ||
6ef228fc | 20 | typedef struct { |
4951967d | 21 | QemuMutex lock; |
f14a39cc SS |
22 | int64_t slice_start_time; |
23 | int64_t slice_end_time; | |
6ef228fc PB |
24 | uint64_t slice_quota; |
25 | uint64_t slice_ns; | |
26 | uint64_t dispatched; | |
27 | } RateLimit; | |
28 | ||
f14a39cc SS |
29 | /** Calculate and return delay for next request in ns |
30 | * | |
f3e4ce4a EB |
31 | * Record that we sent @n data units (where @n matches the scale chosen |
32 | * during ratelimit_set_speed). If we may send more data units | |
f14a39cc SS |
33 | * in the current time slice, return 0 (i.e. no delay). Otherwise |
34 | * return the amount of time (in ns) until the start of the next time | |
35 | * slice that will permit sending the next chunk of data. | |
36 | * | |
37 | * Recording sent data units even after exceeding the quota is | |
38 | * permitted; the time slice will be extended accordingly. | |
39 | */ | |
6ef228fc PB |
40 | static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n) |
41 | { | |
bc72ad67 | 42 | int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); |
b7728f32 | 43 | double delay_slices; |
6ef228fc | 44 | |
4951967d | 45 | QEMU_LOCK_GUARD(&limit->lock); |
720507ed PB |
46 | if (!limit->slice_quota) { |
47 | /* Throttling disabled. */ | |
48 | return 0; | |
49 | } | |
50 | assert(limit->slice_ns); | |
f14a39cc SS |
51 | |
52 | if (limit->slice_end_time < now) { | |
53 | /* Previous, possibly extended, time slice finished; reset the | |
54 | * accounting. */ | |
55 | limit->slice_start_time = now; | |
56 | limit->slice_end_time = now + limit->slice_ns; | |
6ef228fc PB |
57 | limit->dispatched = 0; |
58 | } | |
f14a39cc SS |
59 | |
60 | limit->dispatched += n; | |
61 | if (limit->dispatched < limit->slice_quota) { | |
62 | /* We may send further data within the current time slice, no | |
63 | * need to delay the next request. */ | |
6ef228fc | 64 | return 0; |
6ef228fc | 65 | } |
f14a39cc | 66 | |
b7728f32 WB |
67 | /* Quota exceeded. Wait based on the excess amount and then start a new |
68 | * slice. */ | |
69 | delay_slices = (double)limit->dispatched / limit->slice_quota; | |
f14a39cc | 70 | limit->slice_end_time = limit->slice_start_time + |
b7728f32 | 71 | (uint64_t)(delay_slices * limit->slice_ns); |
f14a39cc | 72 | return limit->slice_end_time - now; |
6ef228fc PB |
73 | } |
74 | ||
4951967d PB |
75 | static inline void ratelimit_init(RateLimit *limit) |
76 | { | |
77 | qemu_mutex_init(&limit->lock); | |
78 | } | |
79 | ||
80 | static inline void ratelimit_destroy(RateLimit *limit) | |
81 | { | |
82 | qemu_mutex_destroy(&limit->lock); | |
83 | } | |
84 | ||
6ef228fc PB |
85 | static inline void ratelimit_set_speed(RateLimit *limit, uint64_t speed, |
86 | uint64_t slice_ns) | |
87 | { | |
4951967d | 88 | QEMU_LOCK_GUARD(&limit->lock); |
6ef228fc | 89 | limit->slice_ns = slice_ns; |
720507ed PB |
90 | if (speed == 0) { |
91 | limit->slice_quota = 0; | |
92 | } else { | |
93 | limit->slice_quota = MAX(((double)speed * slice_ns) / 1000000000ULL, 1); | |
94 | } | |
6ef228fc PB |
95 | } |
96 | ||
97 | #endif |