Skip to contentSkip to conversation

: Time cleanups + nano-second clock resolution support

RFC In review Patrick McHardy 2 participants 11 messages Mar 4, 2007 – Mar 14, 2007

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover : Time cleanups + nano-second clock resolution support

This patchset consists of four parts:

- minor TBF time conversion fix

- consolidation of time calculations: consolidate commonly used expressions with the goal of making it easier to audit for integer overflows when increasing the internally used clock resolution.

- support for detecting the clock resolution used by the kernel and converting time values as necessary.

- finally, increase the internally used clock resolution to nano-seconds

These patches have been tested (well, TBF and HFSC) with both old kernels and patched kernels using nano-second resolution.

 tc/m_estimator.c  |    4 +--
 tc/m_police.c     |    2 -
 tc/q_cbq.c        |   15 +++++++------
 tc/q_hfsc.c       |   18 +++++++--------
 tc/q_htb.c        |    4 +--
 tc/q_netem.c      |   14 +++---------
 tc/q_tbf.c        |   22 +++++++++----------
 tc/tc_cbq.c       |    8 +++----
 tc/tc_core.c      |   61 ++++++++++++++++++++++++++++++++++++++----------------
 tc/tc_core.h      |   13 +++++++----
 tc/tc_estimator.c |    2 -
 tc/tc_red.c       |    2 -
 tc/tc_util.c      |   40 ++++++++++++++++++++++-------------
 tc/tc_util.h      |    7 +++---
 14 files changed, 125 insertions(+), 87 deletions(-)

Patrick McHardy:
[IPROUTE]: tbf: fix latency printing
[IPROUTE]: Use tc_calc_xmittime() where appropriate
[IPROUTE]: Introduce tc_calc_xmitsize and use where appropriate [IPROUTE]: Introduce TIME_UNITS_PER_SEC to represent internal clock resolution [IPROUTE]: Replace "usec" by "time" in function names
[IPROUTE]: Add sprint_ticks() function and use in CBQ
[IPROUTE]: Handle different kernel clock resolutions
[IPROUTE]: Increase internal clock resolution to nsec

#1 lore raw

RFC 1/8 : tbf: fix latency printing

[IPROUTE]: tbf: fix latency printing

The calculated latency is already in usecs, the additional tick2usec conversion breaks the calculation with jiffies or tsc clock source.

Example:

# tc qdisc add dev dummy0 root tbf latency 20ms burst 10k rate 50mbit
# tc qdisc show dev dummy0
qdisc tbf 8002: rate 50000Kbit burst 10Kb lat 15.4ms 

Fixed:

# tc qdisc show dev dummy0
qdisc tbf 8002: rate 50000Kbit burst 10Kb lat 20ms

---
commit b17ff630348093476b7679b421aba1797f3d6466
tree 95acccdac41e6eeeb0a9b270b43d8e0c747f2524
parent 40076f622e0aacb2b792d3ac1b5d12aa97c4da9c
author Patrick McHardy <[email protected]> Sat, 03 Mar 2007 19:31:16 +0100 committer Patrick McHardy <[email protected]> Sat, 03 Mar 2007 19:31:16 +0100

 tc/q_tbf.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
tc/q_tbf.c +1 -1
index b8251cb..b50519f 100644
@@ -251,7 +251,7 @@ static int tbf_print_opt(struct qdisc_ut
 		if (lat2 > latency)
 			latency = lat2;
 	}
-	fprintf(f, "lat %s ", sprint_usecs(tc_core_tick2usec(latency), b1));
+	fprintf(f, "lat %s ", sprint_usecs(latency, b1));
 
 	return 0;
 }
#2 lore raw

RFC 2/8 : Use tc_calc_xmittime() where appropriate

In reply to Patrick McHardy

[IPROUTE]: Use tc_calc_xmittime() where appropriate

Replace expressions of the form "tc_core_usec2tick(1000000 * size/rate)" by tc_calc_xmittime().

The CBQ case deserves an extra comment: when called with bnwd=rate, tc_cbq_calc_maxidle() behaves identical to tc_calc_xmittime():

unsigned tc_cbq_calc_maxidle(...)

{
	double g = 1.0 - 1.0/(1<<ewma_log);
	double xmt = (double)avpkt/bndw;

	maxidle = xmt*(1-g);
	if (bndw != rate && maxburst) {
		...
	}
	return tc_core_usec2tick(maxidle*(1<<ewma_log)*1000000);
}

which comes down to:

maxidle = xmt * (1 - g)

	= xmt * (1 - (1.0 - 1.0/(1 << ewma_log))
	= xmt * (1.0/(1 << ewma_log))

so:

maxidle * (1 << ewma_log) * 1000000

	= xmt * (1.0/(1 << ewma_log)) * (1 << ewma_log) * 1000000
	= xmt * 1000000
	= avpkt/bndw * 1000000

Which means tc_core_usec2tick(maxidle*(1<<ewma_log)*1000000) is identical to tc_calc_xmittime(bndw, avpkt). Use it directly since its a lot easier to understand its limits.

---
commit a367af8046d31e986740aac45677c8fe8910c293
tree 056436a16da372e602f43259609e54bb3e7dce16
parent b17ff630348093476b7679b421aba1797f3d6466
author Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:47 +0100 committer Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:47 +0100

 tc/q_cbq.c   |    2 +-
 tc/tc_core.c |    2 +-
 tc/tc_red.c  |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
tc/q_cbq.c +1 -1
index bc7e8ba..0000a56 100644
@@ -147,7 +147,7 @@ static int cbq_parse_opt(struct qdisc_ut
 	if (ewma_log < 0)
 		ewma_log = TC_CBQ_DEF_EWMA;
 	lss.ewma_log = ewma_log;
-	lss.maxidle = tc_cbq_calc_maxidle(r.rate, r.rate, avpkt, lss.ewma_log, 0);
+	lss.maxidle = tc_calc_xmittime(r.rate, avpkt);
 	lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
 	lss.avpkt = avpkt;
 
tc/tc_core.c +1 -1
index 10c375e..90a097d 100644
@@ -76,7 +76,7 @@ int tc_calc_rtable(unsigned bps, __u32 *
 			sz += overhead;
 		if (sz < mpu)
 			sz = mpu;
-		rtab[i] = tc_core_usec2tick(1000000*((double)sz/bps));
+		rtab[i] = tc_calc_xmittime(bps, sz);
 	}
 	return cell_log;
 }
tc/tc_red.c +1 -1
index 385e7af..8f9bde0 100644
@@ -71,7 +71,7 @@ int tc_red_eval_ewma(unsigned qmin, unsi
 
 int tc_red_eval_idle_damping(int Wlog, unsigned avpkt, unsigned bps, __u8 *sbuf)
 {
-	double xmit_time = tc_core_usec2tick(1000000*(double)avpkt/bps);
+	double xmit_time = tc_calc_xmittime(bps, avpkt);
 	double lW = -log(1.0 - 1.0/(1<<Wlog))/xmit_time;
 	double maxtime = 31/lW;
 	int clog;
#3 lore raw

RFC 3/8 : Introduce tc_calc_xmitsize and use where appropriate

In reply to Patrick McHardy

[IPROUTE]: Introduce tc_calc_xmitsize and use where appropriate

Add tc_calc_xmitsize() as complement to tc_calc_xmittime(), which calculates the size that can be transmitted at a given rate during a given time.

Replace all expressions of the form "size = rate*tc_core_tick2usec(time))/1000000" by tc_calc_xmitsize() calls.

---
commit 8b41013e2abb8eb6d3c960911d2ce137b40ccd50
tree 85068a3019ad77563ae82b9277bd13f3a6de19ba
parent a367af8046d31e986740aac45677c8fe8910c293
author Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100 committer Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100

 tc/m_police.c |    2 +-
 tc/q_htb.c    |    4 ++--
 tc/q_tbf.c    |    4 ++--
 tc/tc_core.c  |    5 +++++
 tc/tc_core.h  |    1 +
 5 files changed, 11 insertions(+), 5 deletions(-)
tc/m_police.c +1 -1
index 93f317c..36a7719 100644
@@ -331,7 +331,7 @@ #endif
 
 	fprintf(f, " police 0x%x ", p->index);
 	fprintf(f, "rate %s ", sprint_rate(p->rate.rate, b1));
-	buffer = ((double)p->rate.rate*tc_core_tick2usec(p->burst))/1000000;
+	buffer = tc_calc_xmitsize(p->rate.rate, p->burst);
 	fprintf(f, "burst %s ", sprint_size(buffer, b1));
 	fprintf(f, "mtu %s ", sprint_size(p->mtu, b1));
 	if (show_raw)
tc/q_htb.c +2 -2
index d5f85c3..53e3f78 100644
@@ -259,9 +259,9 @@ static int htb_print_opt(struct qdisc_ut
 				fprintf(f, "quantum %d ", (int)hopt->quantum);
 		}
 	    fprintf(f, "rate %s ", sprint_rate(hopt->rate.rate, b1));
-	    buffer = ((double)hopt->rate.rate*tc_core_tick2usec(hopt->buffer))/1000000;
+	    buffer = tc_calc_xmitsize(hopt->rate.rate, hopt->buffer);
 	    fprintf(f, "ceil %s ", sprint_rate(hopt->ceil.rate, b1));
-	    cbuffer = ((double)hopt->ceil.rate*tc_core_tick2usec(hopt->cbuffer))/1000000;
+	    cbuffer = tc_calc_xmitsize(hopt->ceil.rate, hopt->cbuffer);
 	    if (show_details) {
 		fprintf(f, "burst %s/%u mpu %s overhead %s ",
 			sprint_size(buffer, b1),
tc/q_tbf.c +2 -2
index b50519f..cbfdcd8 100644
@@ -218,7 +218,7 @@ static int tbf_print_opt(struct qdisc_ut
 	if (RTA_PAYLOAD(tb[TCA_TBF_PARMS])  < sizeof(*qopt))
 		return -1;
 	fprintf(f, "rate %s ", sprint_rate(qopt->rate.rate, b1));
-	buffer = ((double)qopt->rate.rate*tc_core_tick2usec(qopt->buffer))/1000000;
+	buffer = tc_calc_xmitsize(qopt->rate.rate, qopt->buffer);
 	if (show_details) {
 		fprintf(f, "burst %s/%u mpu %s ", sprint_size(buffer, b1),
 			1<<qopt->rate.cell_log, sprint_size(qopt->rate.mpu, b2));
@@ -230,7 +230,7 @@ static int tbf_print_opt(struct qdisc_ut
 	if (qopt->peakrate.rate) {
 		fprintf(f, "peakrate %s ", sprint_rate(qopt->peakrate.rate, b1));
 		if (qopt->mtu || qopt->peakrate.mpu) {
-			mtu = ((double)qopt->peakrate.rate*tc_core_tick2usec(qopt->mtu))/1000000;
+			mtu = tc_calc_xmitsize(qopt->peakrate.rate, qopt->mtu);
 			if (show_details) {
 				fprintf(f, "mtu %s/%u mpu %s ", sprint_size(mtu, b1),
 					1<<qopt->peakrate.cell_log, sprint_size(qopt->peakrate.mpu, b2));
tc/tc_core.c +5 -0
index 90a097d..1ca4583 100644
@@ -51,6 +51,11 @@ unsigned tc_calc_xmittime(unsigned rate,
 	return tc_core_usec2tick(1000000*((double)size/rate));
 }
 
+unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks)
+{
+	return ((double)rate*tc_core_tick2usec(ticks))/1000000;
+}
+
 /*
    rtab[pkt_len>>cell_log] = pkt_xmit_time
  */
tc/tc_core.h +1 -0
index 65611b6..ff00f92 100644
@@ -8,6 +8,7 @@ int  tc_core_usec2big(long usec);
 long tc_core_usec2tick(long usec);
 long tc_core_tick2usec(long tick);
 unsigned tc_calc_xmittime(unsigned rate, unsigned size);
+unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks);
 int tc_calc_rtable(unsigned bps, __u32 *rtab, int cell_log, unsigned mtu, unsigned mpu);
 
 int tc_setup_estimator(unsigned A, unsigned time_const, struct tc_estimator *est);
#4 lore raw

RFC 4/8 : Introduce TIME_UNITS_PER_SEC to represent internal clock resolution

In reply to Patrick McHardy

[IPROUTE]: Introduce TIME_UNITS_PER_SEC to represent internal clock resolution

Introduce TIME_UNITS_PER_SEC and conversion functions between internal resolution and resolution expected by the kernel (currently implemented as NOPs, only needed by HFSC, which currently always uses microseconds).

---
commit d81b168f4017e45343cdd723e653401058f728e9
tree 7e28041ff488f863e79d8745fde85aaed30dd4ac
parent 8b41013e2abb8eb6d3c960911d2ce137b40ccd50
author Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100 committer Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100

 tc/q_hfsc.c       |   12 ++++++------
 tc/q_tbf.c        |    8 ++++----
 tc/tc_cbq.c       |    4 ++--
 tc/tc_core.c      |   14 ++++++++++++--
 tc/tc_core.h      |    4 ++++
 tc/tc_estimator.c |    2 +-
 tc/tc_util.c      |   14 +++++++-------
 7 files changed, 36 insertions(+), 22 deletions(-)
tc/q_hfsc.c +6 -6
index 4e8c09b..f7a30f2 100644
@@ -226,7 +226,7 @@ hfsc_print_sc(FILE *f, char *name, struc
 
 	fprintf(f, "%s ", name);
 	fprintf(f, "m1 %s ", sprint_rate(sc->m1, b1));
-	fprintf(f, "d %s ", sprint_usecs(sc->d, b1));
+	fprintf(f, "d %s ", sprint_usecs(tc_core_ktime2time(sc->d), b1));
 	fprintf(f, "m2 %s ", sprint_rate(sc->m2, b1));
 }
 
@@ -320,7 +320,7 @@ hfsc_get_sc1(int *argcp, char ***argvp, 
 		return -1;
 
 	sc->m1 = m1;
-	sc->d  = d;
+	sc->d  = tc_core_time2ktime(d);
 	sc->m2 = m2;
 
 	*argvp = argv;
@@ -367,13 +367,13 @@ hfsc_get_sc2(int *argcp, char ***argvp, 
 		return -1;
 	}
 
-	if (dmax != 0 && ceil(umax * 1000000.0 / dmax) > rate) {
+	if (dmax != 0 && ceil(1.0 * umax * TIME_UNITS_PER_SEC / dmax) > rate) {
 		/*
 		 * concave curve, slope of first segment is umax/dmax,
 		 * intersection is at dmax
 		 */
-		sc->m1 = ceil(umax * 1000000.0 / dmax); /* in bps */
-		sc->d  = dmax;
+		sc->m1 = ceil(1.0 * umax * TIME_UNITS_PER_SEC / dmax); /* in bps */
+		sc->d  = tc_core_time2ktime(dmax);
 		sc->m2 = rate;
 	} else {
 		/*
@@ -381,7 +381,7 @@ hfsc_get_sc2(int *argcp, char ***argvp, 
 		 * is at dmax - umax / rate
 		 */
 		sc->m1 = 0;
-		sc->d  = ceil(dmax - umax * 1000000.0 / rate); /* in usec */
+		sc->d  = tc_core_time2ktime(ceil(dmax - umax * TIME_UNITS_PER_SEC / rate));
 		sc->m2 = rate;
 	}
 
tc/q_tbf.c +4 -4
index cbfdcd8..a102696 100644
@@ -161,9 +161,9 @@ static int tbf_parse_opt(struct qdisc_ut
 	}
 
 	if (opt.limit == 0) {
-		double lim = opt.rate.rate*(double)latency/1000000 + buffer;
+		double lim = opt.rate.rate*(double)latency/TIME_UNITS_PER_SEC + buffer;
 		if (opt.peakrate.rate) {
-			double lim2 = opt.peakrate.rate*(double)latency/1000000 + mtu;
+			double lim2 = opt.peakrate.rate*(double)latency/TIME_UNITS_PER_SEC + mtu;
 			if (lim2 < lim)
 				lim = lim2;
 		}
@@ -245,9 +245,9 @@ static int tbf_print_opt(struct qdisc_ut
 	if (show_raw)
 		fprintf(f, "limit %s ", sprint_size(qopt->limit, b1));
 
-	latency = 1000000*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2usec(qopt->buffer);
+	latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2usec(qopt->buffer);
 	if (qopt->peakrate.rate) {
-		double lat2 = 1000000*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2usec(qopt->mtu);
+		double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2usec(qopt->mtu);
 		if (lat2 > latency)
 			latency = lat2;
 	}
tc/tc_cbq.c +2 -2
index 0abcc9d..c7b3a2d 100644
@@ -38,7 +38,7 @@ unsigned tc_cbq_calc_maxidle(unsigned bn
 		if (vxmt > maxidle)
 			maxidle = vxmt;
 	}
-	return tc_core_usec2tick(maxidle*(1<<ewma_log)*1000000);
+	return tc_core_usec2tick(maxidle*(1<<ewma_log)*TIME_UNITS_PER_SEC);
 }
 
 unsigned tc_cbq_calc_offtime(unsigned bndw, unsigned rate, unsigned avpkt,
@@ -53,5 +53,5 @@ unsigned tc_cbq_calc_offtime(unsigned bn
 		offtime *= pow(g, -(double)minburst) - 1;
 	else
 		offtime *= 1 + (pow(g, -(double)(minburst-1)) - 1)/(1-g);
-	return tc_core_usec2tick(offtime*1000000);
+	return tc_core_usec2tick(offtime*TIME_UNITS_PER_SEC);
 }
tc/tc_core.c +12 -2
index 1ca4583..07dc4ba 100644
@@ -46,14 +46,24 @@ long tc_core_tick2usec(long tick)
 	return tick/tick_in_usec;
 }
 
+long tc_core_time2ktime(long time)
+{
+	return time;
+}
+
+long tc_core_ktime2time(long ktime)
+{
+	return ktime;
+}
+
 unsigned tc_calc_xmittime(unsigned rate, unsigned size)
 {
-	return tc_core_usec2tick(1000000*((double)size/rate));
+	return tc_core_usec2tick(TIME_UNITS_PER_SEC*((double)size/rate));
 }
 
 unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks)
 {
-	return ((double)rate*tc_core_tick2usec(ticks))/1000000;
+	return ((double)rate*tc_core_tick2usec(ticks))/TIME_UNITS_PER_SEC;
 }
 
 /*
tc/tc_core.h +4 -0
index ff00f92..b31813d 100644
@@ -4,9 +4,13 @@ #define _TC_CORE_H_ 1
 #include <asm/types.h>
 #include <linux/pkt_sched.h>
 
+#define TIME_UNITS_PER_SEC	1000000
+
 int  tc_core_usec2big(long usec);
 long tc_core_usec2tick(long usec);
 long tc_core_tick2usec(long tick);
+long tc_core_time2ktime(long time);
+long tc_core_ktime2time(long ktime);
 unsigned tc_calc_xmittime(unsigned rate, unsigned size);
 unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks);
 int tc_calc_rtable(unsigned bps, __u32 *rtab, int cell_log, unsigned mtu, unsigned mpu);
tc/tc_estimator.c +1 -1
index 434db0f..e559add 100644
@@ -26,7 +26,7 @@ #include "tc_core.h"
 int tc_setup_estimator(unsigned A, unsigned time_const, struct tc_estimator *est)
 {
 	for (est->interval=0; est->interval<=5; est->interval++) {
-		if (A <= (1<<est->interval)*(1000000/4))
+		if (A <= (1<<est->interval)*(TIME_UNITS_PER_SEC/4))
 			break;
 	}
 	if (est->interval > 5)
tc/tc_util.c +7 -7
index 8cdb9a1..62113fc 100644
@@ -221,13 +221,13 @@ int get_usecs(unsigned *usecs, const cha
 	if (*p) {
 		if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
 		    strcasecmp(p, "secs")==0)
-			t *= 1000000;
+			t *= TIME_UNITS_PER_SEC;
 		else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
 			 strcasecmp(p, "msecs") == 0)
-			t *= 1000;
+			t *= TIME_UNITS_PER_SEC/1000;
 		else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
 			 strcasecmp(p, "usecs") == 0)
-			t *= 1;
+			t *= TIME_UNITS_PER_SEC/1000000;
 		else
 			return -1;
 	}
@@ -241,10 +241,10 @@ void print_usecs(char *buf, int len, __u
 {
 	double tmp = usec;
 
-	if (tmp >= 1000000)
-		snprintf(buf, len, "%.1fs", tmp/1000000);
-	else if (tmp >= 1000)
-		snprintf(buf, len, "%.1fms", tmp/1000);
+	if (tmp >= TIME_UNITS_PER_SEC)
+		snprintf(buf, len, "%.1fs", tmp/TIME_UNITS_PER_SEC);
+	else if (tmp >= TIME_UNITS_PER_SEC/1000)
+		snprintf(buf, len, "%.1fms", tmp/(TIME_UNITS_PER_SEC/1000));
 	else
 		snprintf(buf, len, "%uus", usec);
 }
#5 lore raw

RFC 5/8 : Replace "usec" by "time" in function names

In reply to Patrick McHardy

[IPROUTE]: Replace "usec" by "time" in function names

Rename functions containing "usec" since they don't necessarily return usec units anymore.

---
commit c2cf24282b2a051942b18fbf894a9c1b490d925c
tree 128aa960a599aee0725d723b621db651e02ffa74
parent d81b168f4017e45343cdd723e653401058f728e9
author Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100 committer Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100

 tc/m_estimator.c |    4 ++--
 tc/q_cbq.c       |    6 +++---
 tc/q_hfsc.c      |    6 +++---
 tc/q_netem.c     |    8 ++++----
 tc/q_tbf.c       |    8 ++++----
 tc/tc_cbq.c      |    4 ++--
 tc/tc_core.c     |   14 +++++++-------
 tc/tc_core.h     |    6 +++---
 tc/tc_util.c     |   14 +++++++-------
 tc/tc_util.h     |    6 +++---
 10 files changed, 38 insertions(+), 38 deletions(-)
tc/m_estimator.c +2 -2
index d931551..a9e5dbc 100644
@@ -45,12 +45,12 @@ int parse_estimator(int *p_argc, char **
 		duparg("estimator", *argv);
 	if (matches(*argv, "help") == 0)
 		est_help();
-	if (get_usecs(&A, *argv))
+	if (get_time(&A, *argv))
 		invarg("estimator", "invalid estimator interval");
 	NEXT_ARG();
 	if (matches(*argv, "help") == 0)
 		est_help();
-	if (get_usecs(&time_const, *argv))
+	if (get_time(&time_const, *argv))
 		invarg("estimator", "invalid estimator time constant");
 	if (tc_setup_estimator(A, time_const, est) < 0) {
 		fprintf(stderr, "Error: estimator parameters are out of range.\n");
tc/q_cbq.c +3 -3
index 0000a56..913b26a 100644
@@ -500,17 +500,17 @@ static int cbq_print_opt(struct qdisc_ut
 	if (lss && show_details) {
 		fprintf(f, "\nlevel %u ewma %u avpkt %ub ", lss->level, lss->ewma_log, lss->avpkt);
 		if (lss->maxidle) {
-			fprintf(f, "maxidle %luus ", tc_core_tick2usec(lss->maxidle>>lss->ewma_log));
+			fprintf(f, "maxidle %luus ", tc_core_tick2time(lss->maxidle>>lss->ewma_log));
 			if (show_raw)
 				fprintf(f, "[%08x] ", lss->maxidle);
 		}
 		if (lss->minidle!=0x7fffffff) {
-			fprintf(f, "minidle %luus ", tc_core_tick2usec(lss->minidle>>lss->ewma_log));
+			fprintf(f, "minidle %luus ", tc_core_tick2time(lss->minidle>>lss->ewma_log));
 			if (show_raw)
 				fprintf(f, "[%08x] ", lss->minidle);
 		}
 		if (lss->offtime) {
-			fprintf(f, "offtime %luus ", tc_core_tick2usec(lss->offtime));
+			fprintf(f, "offtime %luus ", tc_core_tick2time(lss->offtime));
 			if (show_raw)
 				fprintf(f, "[%08x] ", lss->offtime);
 		}
tc/q_hfsc.c +3 -3
index f7a30f2..b190c71 100644
@@ -226,7 +226,7 @@ hfsc_print_sc(FILE *f, char *name, struc
 
 	fprintf(f, "%s ", name);
 	fprintf(f, "m1 %s ", sprint_rate(sc->m1, b1));
-	fprintf(f, "d %s ", sprint_usecs(tc_core_ktime2time(sc->d), b1));
+	fprintf(f, "d %s ", sprint_time(tc_core_ktime2time(sc->d), b1));
 	fprintf(f, "m2 %s ", sprint_rate(sc->m2, b1));
 }
 
@@ -303,7 +303,7 @@ hfsc_get_sc1(int *argcp, char ***argvp, 
 
 	if (matches(*argv, "d") == 0) {
 		NEXT_ARG();
-		if (get_usecs(&d, *argv) < 0) {
+		if (get_time(&d, *argv) < 0) {
 			explain1("d");
 			return -1;
 		}
@@ -346,7 +346,7 @@ hfsc_get_sc2(int *argcp, char ***argvp, 
 
 	if (matches(*argv, "dmax") == 0) {
 		NEXT_ARG();
-		if (get_usecs(&dmax, *argv) < 0) {
+		if (get_time(&dmax, *argv) < 0) {
 			explain1("dmax");
 			return -1;
 		}
tc/q_netem.c +4 -4
index cfd1799..6035c4f 100644
@@ -108,15 +108,15 @@ static int get_ticks(__u32 *ticks, const
 {
 	unsigned t;
 
-	if(get_usecs(&t, str))
+	if(get_time(&t, str))
 		return -1;
 
-	if (tc_core_usec2big(t)) {
-		fprintf(stderr, "Illegal %d usecs (too large)\n", t);
+	if (tc_core_time2big(t)) {
+		fprintf(stderr, "Illegal %u time (too large)\n", t);
 		return -1;
 	}
 
-	*ticks = tc_core_usec2tick(t);
+	*ticks = tc_core_time2tick(t);
 	return 0;
 }
 
tc/q_tbf.c +4 -4
index a102696..1fc05f4 100644
@@ -67,7 +67,7 @@ static int tbf_parse_opt(struct qdisc_ut
 				fprintf(stderr, "Double \"limit/latency\" spec\n");
 				return -1;
 			}
-			if (get_usecs(&latency, *argv)) {
+			if (get_time(&latency, *argv)) {
 				explain1("latency");
 				return -1;
 			}
@@ -245,13 +245,13 @@ static int tbf_print_opt(struct qdisc_ut
 	if (show_raw)
 		fprintf(f, "limit %s ", sprint_size(qopt->limit, b1));
 
-	latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2usec(qopt->buffer);
+	latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2time(qopt->buffer);
 	if (qopt->peakrate.rate) {
-		double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2usec(qopt->mtu);
+		double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2time(qopt->mtu);
 		if (lat2 > latency)
 			latency = lat2;
 	}
-	fprintf(f, "lat %s ", sprint_usecs(latency, b1));
+	fprintf(f, "lat %s ", sprint_time(latency, b1));
 
 	return 0;
 }
tc/tc_cbq.c +2 -2
index c7b3a2d..0bb262e 100644
@@ -38,7 +38,7 @@ unsigned tc_cbq_calc_maxidle(unsigned bn
 		if (vxmt > maxidle)
 			maxidle = vxmt;
 	}
-	return tc_core_usec2tick(maxidle*(1<<ewma_log)*TIME_UNITS_PER_SEC);
+	return tc_core_time2tick(maxidle*(1<<ewma_log)*TIME_UNITS_PER_SEC);
 }
 
 unsigned tc_cbq_calc_offtime(unsigned bndw, unsigned rate, unsigned avpkt,
@@ -53,5 +53,5 @@ unsigned tc_cbq_calc_offtime(unsigned bn
 		offtime *= pow(g, -(double)minburst) - 1;
 	else
 		offtime *= 1 + (pow(g, -(double)(minburst-1)) - 1)/(1-g);
-	return tc_core_usec2tick(offtime*TIME_UNITS_PER_SEC);
+	return tc_core_time2tick(offtime*TIME_UNITS_PER_SEC);
 }
tc/tc_core.c +7 -7
index 07dc4ba..e27254e 100644
@@ -27,21 +27,21 @@ static __u32 t2us=1;
 static __u32 us2t=1;
 static double tick_in_usec = 1;
 
-int tc_core_usec2big(long usec)
+int tc_core_time2big(long time)
 {
-	__u64 t = usec;
+	__u64 t = time;
 
 	t *= tick_in_usec;
 	return (t >> 32) != 0;
 }
 
 
-long tc_core_usec2tick(long usec)
+long tc_core_time2tick(long time)
 {
-	return usec*tick_in_usec;
+	return time*tick_in_usec;
 }
 
-long tc_core_tick2usec(long tick)
+long tc_core_tick2time(long tick)
 {
 	return tick/tick_in_usec;
 }
@@ -58,12 +58,12 @@ long tc_core_ktime2time(long ktime)
 
 unsigned tc_calc_xmittime(unsigned rate, unsigned size)
 {
-	return tc_core_usec2tick(TIME_UNITS_PER_SEC*((double)size/rate));
+	return tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/rate));
 }
 
 unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks)
 {
-	return ((double)rate*tc_core_tick2usec(ticks))/TIME_UNITS_PER_SEC;
+	return ((double)rate*tc_core_tick2time(ticks))/TIME_UNITS_PER_SEC;
 }
 
 /*
tc/tc_core.h +3 -3
index b31813d..a139da6 100644
@@ -6,9 +6,9 @@ #include <linux/pkt_sched.h>
 
 #define TIME_UNITS_PER_SEC	1000000
 
-int  tc_core_usec2big(long usec);
-long tc_core_usec2tick(long usec);
-long tc_core_tick2usec(long tick);
+int  tc_core_time2big(long time);
+long tc_core_time2tick(long time);
+long tc_core_tick2time(long tick);
 long tc_core_time2ktime(long time);
 long tc_core_ktime2time(long ktime);
 unsigned tc_calc_xmittime(unsigned rate, unsigned size);
tc/tc_util.c +7 -7
index 62113fc..b73fae9 100644
@@ -209,7 +209,7 @@ char * sprint_rate(__u32 rate, char *buf
 	return buf;
 }
 
-int get_usecs(unsigned *usecs, const char *str)
+int get_time(unsigned *time, const char *str)
 {
 	double t;
 	char *p;
@@ -232,26 +232,26 @@ int get_usecs(unsigned *usecs, const cha
 			return -1;
 	}
 
-	*usecs = t;
+	*time = t;
 	return 0;
 }
 
 
-void print_usecs(char *buf, int len, __u32 usec)
+void print_time(char *buf, int len, __u32 time)
 {
-	double tmp = usec;
+	double tmp = time;
 
 	if (tmp >= TIME_UNITS_PER_SEC)
 		snprintf(buf, len, "%.1fs", tmp/TIME_UNITS_PER_SEC);
 	else if (tmp >= TIME_UNITS_PER_SEC/1000)
 		snprintf(buf, len, "%.1fms", tmp/(TIME_UNITS_PER_SEC/1000));
 	else
-		snprintf(buf, len, "%uus", usec);
+		snprintf(buf, len, "%uus", time);
 }
 
-char * sprint_usecs(__u32 usecs, char *buf)
+char * sprint_time(__u32 time, char *buf)
 {
-	print_usecs(buf, SPRINT_BSIZE-1, usecs);
+	print_time(buf, SPRINT_BSIZE-1, time);
 	return buf;
 }
 
tc/tc_util.h +3 -3
index 0778693..b713cf1 100644
@@ -46,17 +46,17 @@ extern int get_rate(unsigned *rate, cons
 extern int get_percent(unsigned *percent, const char *str);
 extern int get_size(unsigned *size, const char *str);
 extern int get_size_and_cell(unsigned *size, int *cell_log, char *str);
-extern int get_usecs(unsigned *usecs, const char *str);
+extern int get_time(unsigned *time, const char *str);
 extern void print_rate(char *buf, int len, __u32 rate);
 extern void print_size(char *buf, int len, __u32 size);
 extern void print_percent(char *buf, int len, __u32 percent);
 extern void print_qdisc_handle(char *buf, int len, __u32 h);
-extern void print_usecs(char *buf, int len, __u32 usecs);
+extern void print_time(char *buf, int len, __u32 time);
 extern char * sprint_rate(__u32 rate, char *buf);
 extern char * sprint_size(__u32 size, char *buf);
 extern char * sprint_qdisc_handle(__u32 h, char *buf);
 extern char * sprint_tc_classid(__u32 h, char *buf);
-extern char * sprint_usecs(__u32 usecs, char *buf);
+extern char * sprint_time(__u32 time, char *buf);
 extern char * sprint_percent(__u32 percent, char *buf);
 
 extern void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtattr **xstats);
#6 lore raw

RFC 6/8 : Add sprint_ticks() function and use in CBQ

In reply to Patrick McHardy

[IPROUTE]: Add sprint_ticks() function and use in CBQ

Add helper function to print ticks to avoid assumptions about clock resolution in CBQ.

---
commit 5950296ff76ba81593928a2ee89757d69b2acba9
tree aca072937195b2011c9f64a305716ddfc1b40c66
parent c2cf24282b2a051942b18fbf894a9c1b490d925c
author Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100 committer Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100

 tc/q_cbq.c   |    7 ++++---
 tc/q_netem.c |    6 ------
 tc/tc_util.c |    5 +++++
 tc/tc_util.h |    1 +
 4 files changed, 10 insertions(+), 9 deletions(-)
tc/q_cbq.c +4 -3
index 913b26a..f2b4ce8 100644
@@ -418,6 +418,7 @@ static int cbq_print_opt(struct qdisc_ut
 	struct tc_cbq_wrropt *wrr = NULL;
 	struct tc_cbq_fopt *fopt = NULL;
 	struct tc_cbq_ovl *ovl = NULL;
+	SPRINT_BUF(b1);
 
 	if (opt == NULL)
 		return 0;
@@ -500,17 +501,17 @@ static int cbq_print_opt(struct qdisc_ut
 	if (lss && show_details) {
 		fprintf(f, "\nlevel %u ewma %u avpkt %ub ", lss->level, lss->ewma_log, lss->avpkt);
 		if (lss->maxidle) {
-			fprintf(f, "maxidle %luus ", tc_core_tick2time(lss->maxidle>>lss->ewma_log));
+			fprintf(f, "maxidle %s ", sprint_ticks(lss->maxidle>>lss->ewma_log, b1));
 			if (show_raw)
 				fprintf(f, "[%08x] ", lss->maxidle);
 		}
 		if (lss->minidle!=0x7fffffff) {
-			fprintf(f, "minidle %luus ", tc_core_tick2time(lss->minidle>>lss->ewma_log));
+			fprintf(f, "minidle %s ", sprint_ticks(lss->minidle>>lss->ewma_log, b1));
 			if (show_raw)
 				fprintf(f, "[%08x] ", lss->minidle);
 		}
 		if (lss->offtime) {
-			fprintf(f, "offtime %luus ", tc_core_tick2time(lss->offtime));
+			fprintf(f, "offtime %s ", sprint_ticks(lss->offtime, b1));
 			if (show_raw)
 				fprintf(f, "[%08x] ", lss->offtime);
 		}
tc/q_netem.c +0 -6
index 6035c4f..67a2ff3 100644
@@ -120,12 +120,6 @@ static int get_ticks(__u32 *ticks, const
 	return 0;
 }
 
-static char *sprint_ticks(__u32 ticks, char *buf)
-{
-	return sprint_usecs(tc_core_tick2usec(ticks), buf);
-}
-
-
 static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
 			   struct nlmsghdr *n)
 {
tc/tc_util.c +5 -0
index b73fae9..a7e4257 100644
@@ -255,6 +255,11 @@ char * sprint_time(__u32 time, char *buf
 	return buf;
 }
 
+char * sprint_ticks(__u32 ticks, char *buf)
+{
+	return sprint_time(tc_core_tick2time(ticks), buf);
+}
+
 int get_size(unsigned *size, const char *str)
 {
 	double sz;
tc/tc_util.h +1 -0
index b713cf1..eade72d 100644
@@ -57,6 +57,7 @@ extern char * sprint_size(__u32 size, ch
 extern char * sprint_qdisc_handle(__u32 h, char *buf);
 extern char * sprint_tc_classid(__u32 h, char *buf);
 extern char * sprint_time(__u32 time, char *buf);
+extern char * sprint_ticks(__u32 ticks, char *buf);
 extern char * sprint_percent(__u32 percent, char *buf);
 
 extern void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtattr **xstats);
#7 lore raw

RFC 7/8 : Handle different kernel clock resolutions

In reply to Patrick McHardy

[IPROUTE]: Handle different kernel clock resolutions

---
commit 0e0db5d408bdac33eadd9d947c0e6904df26ab8f
tree 950a6f47287bec01e5996bec3f1141b60f3f6f6a
parent 5950296ff76ba81593928a2ee89757d69b2acba9
author Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100 committer Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100

 tc/tc_core.c |   26 +++++++++++++++++++-------
 1 files changed, 19 insertions(+), 7 deletions(-)
tc/tc_core.c +19 -7
index e27254e..58155fb 100644
@@ -23,9 +23,8 @@ #include <string.h>
 
 #include "tc_core.h"
 
-static __u32 t2us=1;
-static __u32 us2t=1;
 static double tick_in_usec = 1;
+static double clock_factor = 1;
 
 int tc_core_time2big(long time)
 {
@@ -48,12 +47,12 @@ long tc_core_tick2time(long tick)
 
 long tc_core_time2ktime(long time)
 {
-	return time;
+	return time * clock_factor;
 }
 
 long tc_core_ktime2time(long ktime)
 {
-	return ktime;
+	return ktime / clock_factor;
 }
 
 unsigned tc_calc_xmittime(unsigned rate, unsigned size)
@@ -98,16 +97,29 @@ int tc_calc_rtable(unsigned bps, __u32 *
 
 int tc_core_init()
 {
-	FILE *fp = fopen("/proc/net/psched", "r");
+	FILE *fp;
+	__u32 clock_res;
+	__u32 t2us;
+	__u32 us2t;
 
+	fp = fopen("/proc/net/psched", "r");
 	if (fp == NULL)
 		return -1;
 
-	if (fscanf(fp, "%08x%08x", &t2us, &us2t) != 2) {
+	if (fscanf(fp, "%08x%08x%08x", &t2us, &us2t, &clock_res) != 3) {
 		fclose(fp);
 		return -1;
 	}
 	fclose(fp);
-	tick_in_usec = (double)t2us/us2t;
+
+	/* compatibility hack: for old iproute binaries (ignoring
+	 * the kernel clock resolution) the kernel advertises a
+	 * tick multiplier of 1000 in case of nano-second resolution,
+	 * which really is 1. */
+	if (clock_res == 1000000000)
+		t2us = us2t;
+
+	clock_factor  = (double)clock_res / TIME_UNITS_PER_SEC;
+	tick_in_usec = (double)t2us / us2t * clock_factor;
 	return 0;
 }
#8 lore raw

RFC 8/8 : Increase internal clock resolution to nsec

In reply to Patrick McHardy

[IPROUTE]: Increase internal clock resolution to nsec

---
commit 8a76c51f61dd3881bba35f8c73aaa92eabaf50da
tree d4b252b801a14ee19ed77d4a06daaacd8c17b495
parent 0e0db5d408bdac33eadd9d947c0e6904df26ab8f
author Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100 committer Patrick McHardy <[email protected]> Sat, 03 Mar 2007 20:30:50 +0100

 tc/tc_core.h |    2 +-
 tc/tc_util.c |    7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)
tc/tc_core.h +1 -1
index a139da6..28bf97a 100644
@@ -4,7 +4,7 @@ #define _TC_CORE_H_ 1
 #include <asm/types.h>
 #include <linux/pkt_sched.h>
 
-#define TIME_UNITS_PER_SEC	1000000
+#define TIME_UNITS_PER_SEC	1000000000
 
 int  tc_core_time2big(long time);
 long tc_core_time2tick(long time);
tc/tc_util.c +6 -1
index a7e4257..a07c6aa 100644
@@ -228,6 +228,9 @@ int get_time(unsigned *time, const char 
 		else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
 			 strcasecmp(p, "usecs") == 0)
 			t *= TIME_UNITS_PER_SEC/1000000;
+		else if (strcasecmp(p, "ns") == 0 || strcasecmp(p, "nsec")==0 ||
+			 strcasecmp(p, "nsecs") == 0)
+			t *= TIME_UNITS_PER_SEC/1000000000;
 		else
 			return -1;
 	}
@@ -245,8 +248,10 @@ void print_time(char *buf, int len, __u3
 		snprintf(buf, len, "%.1fs", tmp/TIME_UNITS_PER_SEC);
 	else if (tmp >= TIME_UNITS_PER_SEC/1000)
 		snprintf(buf, len, "%.1fms", tmp/(TIME_UNITS_PER_SEC/1000));
+	else if (tmp >= TIME_UNITS_PER_SEC/1000000)
+		snprintf(buf, len, "%.1fus", tmp/(TIME_UNITS_PER_SEC/1000000));
 	else
-		snprintf(buf, len, "%uus", time);
+		snprintf(buf, len, "%uns", time);
 }
 
 char * sprint_time(__u32 time, char *buf)
#9 lore raw
In reply to Patrick McHardy
Quoted 33 lines · On Sun, 4 Mar 2007 20:14:53 +0100 (MET) Patrick McHardy <[email protected]>…

This patchset consists of four parts:

- minor TBF time conversion fix

- consolidation of time calculations: consolidate commonly used expressions with the goal of making it easier to audit for integer overflows when increasing the internally used clock resolution.

- support for detecting the clock resolution used by the kernel and converting time values as necessary.

- finally, increase the internally used clock resolution to nano-seconds

These patches have been tested (well, TBF and HFSC) with both old kernels and patched kernels using nano-second resolution.

 tc/m_estimator.c  |    4 +--
 tc/m_police.c     |    2 -
 tc/q_cbq.c        |   15 +++++++------
 tc/q_hfsc.c       |   18 +++++++--------
 tc/q_htb.c        |    4 +--
 tc/q_netem.c      |   14 +++---------
 tc/q_tbf.c        |   22 +++++++++----------
 tc/tc_cbq.c       |    8 +++----
 tc/tc_core.c      |   61 ++++++++++++++++++++++++++++++++++++++----------------
 tc/tc_core.h      |   13 +++++++----
 tc/tc_estimator.c |    2 -
 tc/tc_red.c       |    2 -
 tc/tc_util.c      |   40 ++++++++++++++++++++++-------------
 tc/tc_util.h      |    7 +++---
 14 files changed, 125 insertions(+), 87 deletions(-)
Quoted 9 lines

Patrick McHardy:
[IPROUTE]: tbf: fix latency printing
[IPROUTE]: Use tc_calc_xmittime() where appropriate
[IPROUTE]: Introduce tc_calc_xmitsize and use where appropriate [IPROUTE]: Introduce TIME_UNITS_PER_SEC to represent internal clock resolution [IPROUTE]: Replace "usec" by "time" in function names
[IPROUTE]: Add sprint_ticks() function and use in CBQ
[IPROUTE]: Handle different kernel clock resolutions
[IPROUTE]: Increase internal clock resolution to nsec

applied all

Signature · 1 line
Stephen Hemminger <[email protected]>
#10 lore raw
Quoted 14 lines · Stephen Hemminger
Quoted 9 lines · On Sun, 4 Mar 2007 20:14:53 +0100 (MET) Patrick McHardy <[email protected]>…

Patrick McHardy:
[IPROUTE]: tbf: fix latency printing
[IPROUTE]: Use tc_calc_xmittime() where appropriate
[IPROUTE]: Introduce tc_calc_xmitsize and use where appropriate [IPROUTE]: Introduce TIME_UNITS_PER_SEC to represent internal clock resolution [IPROUTE]: Replace "usec" by "time" in function names
[IPROUTE]: Add sprint_ticks() function and use in CBQ
[IPROUTE]: Handle different kernel clock resolutions
[IPROUTE]: Increase internal clock resolution to nsec

Quoted 1 line

applied all

Thanks Stephen, but actually I think the last patch (increase clock resolution) shouldn't go in yet. I'm not done yet looking at all the compatibility issues and it does change the range of valid values for everything dealing with times. Most places I looked at still accept reasonable ranges, but I would feel more comfortable to make sure everything is fine first.