correct HTB rtable/HZ calculations
The HTB implementation in libnl uses units of microseconds in a number of places where it seems TC is expecting time in units of ticks, which causes actual rates much higher than requested. Additionally, libnl uses USER_HZ for calculating buffer and cbuffer sizes, which can result in much larger buffers than necessary on systems with high resolution timers. Note that the TBF qdisc uses microseconds incorrectly in two spots as well, I fixed this but did not test.
This commit is contained in:
parent
9bb30a5e80
commit
970f5d0221
5 changed files with 30 additions and 17 deletions
|
@ -56,6 +56,7 @@ extern long nl_prob2int(const char *);
|
|||
|
||||
/* time translations */
|
||||
extern int nl_get_user_hz(void);
|
||||
extern int nl_get_psched_hz(void);
|
||||
extern uint32_t nl_us2ticks(uint32_t);
|
||||
extern uint32_t nl_ticks2us(uint32_t);
|
||||
extern int nl_str2msec(const char *, uint64_t *);
|
||||
|
|
|
@ -86,9 +86,9 @@ static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
|
|||
htb->ch_prio = opts.prio;
|
||||
rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
|
||||
rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
|
||||
htb->ch_rbuffer = rtnl_tc_calc_bufsize(opts.buffer,
|
||||
htb->ch_rbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
|
||||
opts.rate.rate);
|
||||
htb->ch_cbuffer = rtnl_tc_calc_bufsize(opts.cbuffer,
|
||||
htb->ch_cbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.cbuffer),
|
||||
opts.ceil.rate);
|
||||
htb->ch_quantum = opts.quantum;
|
||||
htb->ch_level = opts.level;
|
||||
|
@ -242,16 +242,16 @@ static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
|
|||
if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
|
||||
buffer = htb->ch_rbuffer;
|
||||
else
|
||||
buffer = opts.rate.rate / nl_get_user_hz() + mtu; /* XXX */
|
||||
buffer = opts.rate.rate / nl_get_psched_hz() + mtu; /* XXX */
|
||||
|
||||
opts.buffer = rtnl_tc_calc_txtime(buffer, opts.rate.rate);
|
||||
opts.buffer = nl_us2ticks(rtnl_tc_calc_txtime(buffer, opts.rate.rate));
|
||||
|
||||
if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
|
||||
cbuffer = htb->ch_cbuffer;
|
||||
else
|
||||
cbuffer = opts.ceil.rate / nl_get_user_hz() + mtu; /* XXX */
|
||||
cbuffer = opts.ceil.rate / nl_get_psched_hz() + mtu; /* XXX */
|
||||
|
||||
opts.cbuffer = rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate);
|
||||
opts.cbuffer = nl_us2ticks(rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate));
|
||||
|
||||
if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
|
||||
opts.quantum = htb->ch_quantum;
|
||||
|
|
|
@ -290,7 +290,7 @@ void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
|
|||
tbf->qt_rate.rs_rate = rate;
|
||||
tbf->qt_rate_bucket = bucket;
|
||||
tbf->qt_rate.rs_cell_log = cell_log;
|
||||
tbf->qt_rate_txtime = rtnl_tc_calc_txtime(bucket, rate);
|
||||
tbf->qt_rate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
|
||||
tbf->qt_mask |= TBF_ATTR_RATE;
|
||||
}
|
||||
|
||||
|
@ -372,7 +372,7 @@ int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
|
|||
tbf->qt_peakrate.rs_rate = rate;
|
||||
tbf->qt_peakrate_bucket = bucket;
|
||||
tbf->qt_peakrate.rs_cell_log = cell_log;
|
||||
tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate);
|
||||
tbf->qt_peakrate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
|
||||
|
||||
tbf->qt_mask |= TBF_ATTR_PEAKRATE;
|
||||
|
||||
|
|
|
@ -710,7 +710,7 @@ int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec,
|
|||
|
||||
for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
|
||||
size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype);
|
||||
dst[i] = rtnl_tc_calc_txtime(size, spec->rs_rate);
|
||||
dst[i] = nl_us2ticks(rtnl_tc_calc_txtime(size, spec->rs_rate));
|
||||
}
|
||||
|
||||
spec->rs_cell_align = -1;
|
||||
|
|
28
lib/utils.c
28
lib/utils.c
|
@ -359,12 +359,13 @@ long nl_prob2int(const char *str)
|
|||
* @{
|
||||
*/
|
||||
|
||||
#ifdef USER_HZ
|
||||
static uint32_t user_hz = USER_HZ;
|
||||
#else
|
||||
static uint32_t user_hz = 100;
|
||||
#ifndef USER_HZ
|
||||
#define USER_HZ 100
|
||||
#endif
|
||||
|
||||
static uint32_t user_hz = USER_HZ;
|
||||
static uint32_t psched_hz = USER_HZ;
|
||||
|
||||
static double ticks_per_usec = 1.0f;
|
||||
|
||||
/* Retrieves the configured HZ and ticks/us value in the kernel.
|
||||
|
@ -394,6 +395,8 @@ static void __init get_psched_settings(void)
|
|||
if (!got_hz)
|
||||
user_hz = sysconf(_SC_CLK_TCK);
|
||||
|
||||
psched_hz = user_hz;
|
||||
|
||||
if (getenv("TICKS_PER_USEC")) {
|
||||
double t = strtod(getenv("TICKS_PER_USEC"), NULL);
|
||||
ticks_per_usec = t;
|
||||
|
@ -408,14 +411,16 @@ static void __init get_psched_settings(void)
|
|||
strncpy(name, "/proc/net/psched", sizeof(name) - 1);
|
||||
|
||||
if ((fd = fopen(name, "r"))) {
|
||||
uint32_t ns_per_usec, ns_per_tick;
|
||||
/* the file contains 4 hexadecimals, but we just use
|
||||
the first two of them */
|
||||
fscanf(fd, "%08x %08x", &ns_per_usec, &ns_per_tick);
|
||||
uint32_t ns_per_usec, ns_per_tick, nom, denom;
|
||||
|
||||
fscanf(fd, "%08x %08x %08x %08x",
|
||||
&ns_per_usec, &ns_per_tick, &nom, &denom);
|
||||
|
||||
ticks_per_usec = (double) ns_per_usec /
|
||||
(double) ns_per_tick;
|
||||
|
||||
if (nom == 1000000)
|
||||
psched_hz = denom;
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
|
@ -431,6 +436,13 @@ int nl_get_user_hz(void)
|
|||
return user_hz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of packet scheduler HZ
|
||||
*/
|
||||
int nl_get_psched_hz(void)
|
||||
{
|
||||
return psched_hz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert micro seconds to ticks
|
||||
|
|
Loading…
Add table
Reference in a new issue