Hi,
if you noticed weak newqueue performance, it was because one component
of it was missing. After a discussion with claudio I made this diff,
which makes a timeout per HFSC-enabled interface and pushes the data
every hardclock tick, similarly to what oldtbr_timeout() used to do.
This way, in the future, we can:
- Replace splnet() with mtx_enter(&ifp->lock) directly (here).
- Replace the current coarse 1/HZ timing with a proper high resolution
one. This should be done directly in hfsc_dequeue by setting the
exact value (or maybe slightly more, to accumulate more dequeues into
one if_start call) instead of just "1 tick all the time".
The timing details will probably become clearer when we switch from
TAILQs to RB trees and stop spending huge amounts of time going back
and forth over all of the active classes.
This diff applies to our current tree, to make it work with unlimited v3
diff, you obviously need to substitute some ->'s for .'s.
comments? ok?
--
Martin Pelikan
Index: hfsc.c
===================================================================
RCS file: /cvs/src/sys/net/hfsc.c,v
retrieving revision 1.1
diff -u -p -r1.1 hfsc.c
--- hfsc.c 12 Oct 2013 11:39:17 -0000 1.1
+++ hfsc.c 27 Oct 2013 22:53:50 -0000
@@ -74,6 +74,7 @@ int hfsc_addq(struct hfsc_class *, str
struct mbuf *hfsc_getq(struct hfsc_class *);
struct mbuf *hfsc_pollq(struct hfsc_class *);
void hfsc_purgeq(struct hfsc_class *);
+void hfsc_deferred(void *);
void hfsc_update_cfmin(struct hfsc_class *);
void hfsc_set_active(struct hfsc_class *, int);
void hfsc_set_passive(struct hfsc_class *);
@@ -140,6 +141,9 @@ hfsc_attach(struct ifnet *ifp)
hif->hif_eligible = hfsc_ellist_alloc();
hif->hif_ifq = (struct ifqueue *)&ifp->if_snd; /* XXX cast temp */
ifp->if_snd.ifq_hfsc = hif;
+ timeout_set(&hif->hif_defer, hfsc_deferred, ifp);
+ /* XXX HRTIMER don't schedule it yet, only when some packets wait. */
+ timeout_add(&hif->hif_defer, 1);
return (0);
}
@@ -147,6 +151,7 @@ hfsc_attach(struct ifnet *ifp)
int
hfsc_detach(struct ifnet *ifp)
{
+ timeout_del(&ifp->if_snd.ifq_hfsc->hif_defer);
free(ifp->if_snd.ifq_hfsc, M_DEVBUF);
ifp->if_snd.ifq_hfsc = NULL;
@@ -557,6 +562,7 @@ hfsc_dequeue(struct ifqueue *ifq, int re
cl = tcl;
}
+ /* XXX HRTIMER plan hfsc_deferred precisely here. */
if (cl == NULL)
return (NULL);
}
@@ -601,6 +607,21 @@ hfsc_dequeue(struct ifqueue *ifq, int re
}
return (m);
+}
+
+void
+hfsc_deferred(void *arg)
+{
+ struct ifnet *ifp = arg;
+ int s;
+
+ s = splnet();
+ if (HFSC_ENABLED(&ifp->if_snd) && !IFQ_IS_EMPTY(&ifp->if_snd))
+ if_start(ifp);
+ splx(s);
+
+ /* XXX HRTIMER nearest virtual/fit time is likely less than 1/HZ. */
+ timeout_add(&ifp->if_snd.ifq_hfsc->hif_defer, 1);
}
int
Index: hfsc.h
===================================================================
RCS file: /cvs/src/sys/net/hfsc.h,v
retrieving revision 1.1
diff -u -p -r1.1 hfsc.h
--- hfsc.h 12 Oct 2013 11:39:17 -0000 1.1
+++ hfsc.h 27 Oct 2013 22:53:50 -0000
@@ -33,6 +33,8 @@
#ifndef _HFSC_H_
#define _HFSC_H_
+#include <sys/timeout.h>
+
/* hfsc class flags */
#define HFSC_RED 0x0001 /* use RED */
#define HFSC_ECN 0x0002 /* use RED/ECN */
@@ -242,6 +244,7 @@ struct hfsc_if {
u_int hif_classid; /* class id sequence number */
hfsc_ellist_t *hif_eligible; /* eligible list */
+ struct timeout hif_defer; /* for queues that weren't ready */
};
#define HFSC_CLK_SHIFT 8