diff options
Diffstat (limited to 'VNFs/DPPD-PROX/token_time.h')
-rw-r--r-- | VNFs/DPPD-PROX/token_time.h | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/VNFs/DPPD-PROX/token_time.h b/VNFs/DPPD-PROX/token_time.h new file mode 100644 index 00000000..e59647ad --- /dev/null +++ b/VNFs/DPPD-PROX/token_time.h @@ -0,0 +1,165 @@ +/* +// Copyright (c) 2010-2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#ifndef _TOKEN_TIME_H_ +#define _TOKEN_TIME_H_ + +#include <rte_cycles.h> +#include <math.h> + +#include "prox_assert.h" + +struct token_time_cfg { + uint64_t bpp; + uint64_t period; + uint64_t bytes_max; +}; + +struct token_time { + uint64_t tsc_last; + uint64_t tsc_last_bytes; + uint64_t bytes_now; + struct token_time_cfg cfg; +}; + +/* Convert a given fractional bytes per period into bpp with as + minimal loss of accuracy. */ +static struct token_time_cfg token_time_cfg_create(double frac, uint64_t period, uint64_t bytes_max) +{ + struct token_time_cfg ret; + + /* Since period is expressed in units of cycles and it is in + most cases set to 1 second (which means its value is <= + 3*10^9) and 2^64/10^9 > 6148914691 > 2^32). This means that + at most, period and frac will be doubled 32 times by the + following algorithm. Hence, the total error introduced by + the chosen values for bpp and period will be between 0 and + 1/2^33. Note that since there are more operations that + can't overflow, the actual accuracy will probably be + lower. */ + + /* The reason to limit period by UINT64_MAX/(uint64_t)frac is + that at run-time, the token_time_update function will + multiply a number that is <= period with bpp. In addition, + the token_time_tsc_until function will multiply at most + bytes_max with period so make sure that can't overflow. */ + + while (period < UINT64_MAX/2 && frac != floor(frac) && + (frac < 2.0f || period < UINT64_MAX/4/(uint64_t)frac) && + (bytes_max == UINT64_MAX || period < UINT64_MAX/2/bytes_max)) { + period *= 2; + frac *= 2; + } + + ret.bpp = floor(frac + 0.5); + ret.period = period; + ret.bytes_max = bytes_max; + + return ret; +} + +static void token_time_update(struct token_time *tt, uint64_t tsc) +{ + uint64_t new_bytes; + uint64_t t_diff = tsc - tt->tsc_last; + + /* Since the rate is expressed in tt->bpp, i.e. bytes per + period, counters can only be incremented/decremented + accurately every period cycles. */ + + /* If the last update was more than a period ago, the update + can be performed accurately. */ + if (t_diff > tt->cfg.period) { + /* First add remaining tokens in the last period that + was added partially. */ + new_bytes = tt->cfg.bpp - tt->tsc_last_bytes; + tt->tsc_last_bytes = 0; + tt->bytes_now += new_bytes; + t_diff -= tt->cfg.period; + tt->tsc_last += tt->cfg.period; + + /* If now it turns out that more periods have elapsed, + add the bytes for those periods directly. */ + if (t_diff > tt->cfg.period) { + uint64_t periods = t_diff/tt->cfg.period; + + tt->bytes_now += periods * tt->cfg.bpp; + t_diff -= tt->cfg.period * periods; + tt->tsc_last += tt->cfg.period * periods; + } + } + + /* At this point, t_diff will be guaranteed to be less + than tt->cfg.period. */ + new_bytes = t_diff * tt->cfg.bpp/tt->cfg.period - tt->tsc_last_bytes; + tt->tsc_last_bytes += new_bytes; + tt->bytes_now += new_bytes; + if (tt->bytes_now > tt->cfg.bytes_max) + tt->bytes_now = tt->cfg.bytes_max; +} + +static void token_time_set_bpp(struct token_time *tt, uint64_t bpp) +{ + tt->cfg.bpp = bpp; +} + +static void token_time_init(struct token_time *tt, const struct token_time_cfg *cfg) +{ + tt->cfg = *cfg; +} + +static void token_time_reset(struct token_time *tt, uint64_t tsc, uint64_t bytes_now) +{ + tt->tsc_last = tsc; + tt->bytes_now = bytes_now; + tt->tsc_last_bytes = 0; +} + +static void token_time_reset_full(struct token_time *tt, uint64_t tsc) +{ + token_time_reset(tt, tsc, tt->cfg.bytes_max); +} + +static int token_time_take(struct token_time *tt, uint64_t bytes) +{ + if (bytes > tt->bytes_now) + return -1; + tt->bytes_now -= bytes; + return 0; +} + +static void token_time_take_clamp(struct token_time *tt, uint64_t bytes) +{ + if (bytes > tt->bytes_now) + tt->bytes_now = 0; + else + tt->bytes_now -= bytes; +} + +static uint64_t token_time_tsc_until(const struct token_time *tt, uint64_t bytes) +{ + if (tt->bytes_now >= bytes) + return 0; + + return (bytes - tt->bytes_now) * tt->cfg.period / tt->cfg.bpp; +} + +static uint64_t token_time_tsc_until_full(const struct token_time *tt) +{ + return token_time_tsc_until(tt, tt->cfg.bytes_max); +} + +#endif /* _TOKEN_TIME_H_ */ |