]>
Commit | Line | Data |
---|---|---|
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 | |
15 | #define QEMU_RATELIMIT_H | |
16 | ||
17 | typedef struct { | |
18 | int64_t slice_start_time; | |
19 | int64_t slice_end_time; | |
20 | uint64_t slice_quota; | |
21 | uint64_t slice_ns; | |
22 | uint64_t dispatched; | |
23 | } RateLimit; | |
24 | ||
25 | /** Calculate and return delay for next request in ns | |
26 | * | |
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 | |
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 | */ | |
36 | static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n) | |
37 | { | |
38 | int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); | |
39 | double delay_slices; | |
40 | ||
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; | |
48 | limit->dispatched = 0; | |
49 | } | |
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. */ | |
55 | return 0; | |
56 | } | |
57 | ||
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; | |
61 | limit->slice_end_time = limit->slice_start_time + | |
62 | (uint64_t)(delay_slices * limit->slice_ns); | |
63 | return limit->slice_end_time - now; | |
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; | |
70 | limit->slice_quota = MAX(((double)speed * slice_ns) / 1000000000ULL, 1); | |
71 | } | |
72 | ||
73 | #endif |