qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

ratelimit.h (2747B)


      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
     15 #define QEMU_RATELIMIT_H
     16 
     17 #include "qemu/lockable.h"
     18 #include "qemu/timer.h"
     19 
     20 typedef struct {
     21     QemuMutex lock;
     22     int64_t slice_start_time;
     23     int64_t slice_end_time;
     24     uint64_t slice_quota;
     25     uint64_t slice_ns;
     26     uint64_t dispatched;
     27 } RateLimit;
     28 
     29 /** Calculate and return delay for next request in ns
     30  *
     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
     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  */
     40 static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
     41 {
     42     int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
     43     double delay_slices;
     44 
     45     QEMU_LOCK_GUARD(&limit->lock);
     46     if (!limit->slice_quota) {
     47         /* Throttling disabled.  */
     48         return 0;
     49     }
     50     assert(limit->slice_ns);
     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;
     57         limit->dispatched = 0;
     58     }
     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. */
     64         return 0;
     65     }
     66 
     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;
     70     limit->slice_end_time = limit->slice_start_time +
     71         (uint64_t)(delay_slices * limit->slice_ns);
     72     return limit->slice_end_time - now;
     73 }
     74 
     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 
     85 static inline void ratelimit_set_speed(RateLimit *limit, uint64_t speed,
     86                                        uint64_t slice_ns)
     87 {
     88     QEMU_LOCK_GUARD(&limit->lock);
     89     limit->slice_ns = slice_ns;
     90     if (speed == 0) {
     91         limit->slice_quota = 0;
     92     } else {
     93         limit->slice_quota = MAX(((double)speed * slice_ns) / 1000000000ULL, 1);
     94     }
     95 }
     96 
     97 #endif