PERFORCE change 137686 for review

Sam Leffler sam at FreeBSD.org
Fri Mar 14 05:24:13 UTC 2008


http://perforce.freebsd.org/chv.cgi?CH=137686

Change 137686 by sam at sam_ebb on 2008/03/14 05:24:04

	Major overhaul:
	o consolidate various driver-specific hacks by refining
	  the api's; drivers can accumulate stats on each tx done
	  or through periodic polling (e.g. ural which collects
	  stats through cmds) and effect rate selection according
	  to a sampling interval
	o do the initial tx rate selection in ieee80211_amrr_node_init
	  (probably need to refine for 11b rate sets to start 5.5
	  instead of 11)
	o de-obfuscate some of the code
	o eliminate dependence on ni_txrate for tracking the current
	  rate index since it's now for reporting current tx rate
	o handle ni_txrate updates
	o automatically add sysctl knobs to net.wlan.X
	o fix rate downshifting so it requires "is_enough" frames;
	  otherwise this can happen if 1 frame is sent successfully
	  with a retransmit (algorithm is stil utter crap but this
	  at least eliminates one of the major causes of rapid rate
	  oscillation)

Affected files ...

.. //depot/projects/vap/sys/net80211/ieee80211_amrr.c#7 edit
.. //depot/projects/vap/sys/net80211/ieee80211_amrr.h#5 edit

Differences ...

==== //depot/projects/vap/sys/net80211/ieee80211_amrr.c#7 (text+ko) ====

@@ -53,68 +53,87 @@
 	((amn)->amn_retrycnt > (amn)->amn_txcnt / 3)
 #define is_enough(amn)		\
 	((amn)->amn_txcnt > 10)
-#define is_min_rate(ni)		\
-	((ni)->ni_txrate == 0)
-#define is_max_rate(ni)		\
-	((ni)->ni_txrate == (ni)->ni_rates.rs_nrates - 1)
-#define increase_rate(ni)	\
-	((ni)->ni_txrate++)
-#define decrease_rate(ni)	\
-	((ni)->ni_txrate--)
-#define reset_cnt(amn)		\
-	do { (amn)->amn_txcnt = (amn)->amn_retrycnt = 0; } while (0)
+
+static void amrr_sysctlattach(struct ieee80211_amrr *amrr,
+	struct sysctl_ctx_list *ctx, struct sysctl_oid *tree);
 
 /* number of references from net80211 layer */
 static	int nrefs = 0;
 
 void
+ieee80211_amrr_setinterval(struct ieee80211_amrr *amrr, int msecs)
+{
+	int t;
+
+	if (msecs < 100)
+		msecs = 100;
+	t = msecs_to_ticks(msecs);
+	amrr->amrr_interval = (t < 1) ? 1 : t;
+}
+
+void
 ieee80211_amrr_init(struct ieee80211_amrr *amrr,
-    struct ieee80211vap *vap, int amin, int amax)
+    struct ieee80211vap *vap, int amin, int amax, int interval)
 {
 	/* XXX bounds check? */
 	amrr->amrr_min_success_threshold = amin;
 	amrr->amrr_max_success_threshold = amax;
-	amrr->amrr_vap = vap;
+	ieee80211_amrr_setinterval(amrr, interval);
+
+	amrr_sysctlattach(amrr, vap->iv_sysctl, vap->iv_oid);
+}
+
+void
+ieee80211_amrr_cleanup(struct ieee80211_amrr *amrr)
+{
 }
 
 void
 ieee80211_amrr_node_init(struct ieee80211_amrr *amrr,
-    struct ieee80211_amrr_node *amn)
+    struct ieee80211_amrr_node *amn, struct ieee80211_node *ni)
 {
+	const struct ieee80211_rateset *rs = &ni->ni_rates;
+
+	amn->amn_amrr = amrr;
 	amn->amn_success = 0;
 	amn->amn_recovery = 0;
 	amn->amn_txcnt = amn->amn_retrycnt = 0;
 	amn->amn_success_threshold = amrr->amrr_min_success_threshold;
+
+	/* pick initial rate */
+	for (amn->amn_rix = rs->rs_nrates - 1;
+	     amn->amn_rix > 0 && (rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) > 72;
+	     amn->amn_rix--)
+		;
+	ni->ni_txrate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+	amn->amn_ticks = ticks;
 }
 
-/*
- * Update ni->ni_txrate.
- */
-void
-ieee80211_amrr_choose(struct ieee80211_amrr *amrr, struct ieee80211_node *ni,
-    struct ieee80211_amrr_node *amn)
+static int
+amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
+    struct ieee80211_node *ni)
 {
-	int need_change = 0;
+	int rix = amn->amn_rix;
+
+	KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt));
 
-	if (is_success(amn) && is_enough(amn)) {
+	if (is_success(amn)) {
 		amn->amn_success++;
 		if (amn->amn_success >= amn->amn_success_threshold &&
-		    !is_max_rate(ni)) {
+		    rix + 1 < ni->ni_rates.rs_nrates) {
 			amn->amn_recovery = 1;
 			amn->amn_success = 0;
-			increase_rate(ni);
-			IEEE80211_DPRINTF(amrr->amrr_vap, IEEE80211_MSG_RATECTL,
+			rix++;
+			IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_RATECTL,
 			    "AMRR increasing rate %d (txcnt=%d retrycnt=%d)\n",
-			    ni->ni_rates.rs_rates[ni->ni_txrate] &
-				IEEE80211_RATE_VAL,
+			    ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
 			    amn->amn_txcnt, amn->amn_retrycnt);
-			need_change = 1;
 		} else {
 			amn->amn_recovery = 0;
 		}
 	} else if (is_failure(amn)) {
 		amn->amn_success = 0;
-		if (!is_min_rate(ni)) {
+		if (rix > 0) {
 			if (amn->amn_recovery) {
 				amn->amn_success_threshold *= 2;
 				if (amn->amn_success_threshold >
@@ -125,19 +144,76 @@
 				amn->amn_success_threshold =
 				    amrr->amrr_min_success_threshold;
 			}
-			decrease_rate(ni);
-			IEEE80211_DPRINTF(amrr->amrr_vap, IEEE80211_MSG_RATECTL,
+			rix--;
+			IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_RATECTL,
 			    "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)\n",
-			    ni->ni_rates.rs_rates[ni->ni_txrate] &
-				IEEE80211_RATE_VAL,
+			    ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
 			    amn->amn_txcnt, amn->amn_retrycnt);
-			need_change = 1;
 		}
 		amn->amn_recovery = 0;
 	}
 
-	if (is_enough(amn) || need_change)
-		reset_cnt(amn);
+	/* reset counters */
+	amn->amn_txcnt = 0;
+	amn->amn_retrycnt = 0;
+
+	return rix;
+}
+
+/*
+ * Return the rate index to use in sending a data frame.
+ * Update our internal state if it's been long enough.
+ * If the rate changes we also update ni_txrate to match.
+ */
+int
+ieee80211_amrr_choose(struct ieee80211_node *ni,
+    struct ieee80211_amrr_node *amn)
+{
+	struct ieee80211_amrr *amrr = amn->amn_amrr;
+	int rix;
+
+	if (is_enough(amn) && ticks - amn->amn_ticks > amrr->amrr_interval) {
+		rix = amrr_update(amrr, amn, ni);
+		if (rix != amn->amn_rix) {
+			/* update public rate */
+			ni->ni_txrate =
+			    ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL;
+			amn->amn_rix = rix;
+		}
+	} else
+		rix = amn->amn_rix;
+	return rix;
+}
+
+static int
+amrr_sysctl_interval(SYSCTL_HANDLER_ARGS)
+{
+	struct ieee80211_amrr *amrr = arg1;
+	int msecs = ticks_to_msecs(amrr->amrr_interval);
+	int error;
+
+	error = sysctl_handle_int(oidp, &msecs, 0, req);
+	if (error || !req->newptr)
+		return error;
+	ieee80211_amrr_setinterval(amrr, msecs);
+	return 0;
+}
+
+static void
+amrr_sysctlattach(struct ieee80211_amrr *amrr,
+    struct sysctl_ctx_list *ctx, struct sysctl_oid *tree)
+{
+
+	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "amrr_rate_interval", CTLTYPE_INT | CTLFLAG_RW, amrr,
+	    0, amrr_sysctl_interval, "I", "amrr operation interval (ms)");
+	/* XXX bounds check values */
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "amrr_max_sucess_threshold", CTLFLAG_RW,
+	    &amrr->amrr_max_success_threshold, 0, "");
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "amrr_min_sucess_threshold", CTLFLAG_RW,
+	    &amrr->amrr_min_success_threshold, 0, "");
 }
 
 /*

==== //depot/projects/vap/sys/net80211/ieee80211_amrr.h#5 (text+ko) ====

@@ -37,7 +37,7 @@
 struct ieee80211_amrr {
 	u_int	amrr_min_success_threshold;
 	u_int	amrr_max_success_threshold;
-	struct ieee80211vap *amrr_vap;
+	int	amrr_interval;		/* update interval (ticks) */
 };
 
 #define IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD	 1
@@ -47,18 +47,55 @@
  * Rate control state for a given node.
  */
 struct ieee80211_amrr_node {
+	struct ieee80211_amrr *amn_amrr;/* backpointer */
+	int	amn_rix;		/* current rate index */
+	int	amn_ticks;		/* time of last update */
+	/* statistics */
+	u_int	amn_txcnt;
 	u_int	amn_success;
+	u_int	amn_success_threshold;
 	u_int	amn_recovery;
-	u_int	amn_success_threshold;
-	u_int	amn_txcnt;
 	u_int	amn_retrycnt;
 };
 
-void	ieee80211_amrr_init(struct ieee80211_amrr *,
-	    struct ieee80211vap *, int, int);
+void	ieee80211_amrr_init(struct ieee80211_amrr *, struct ieee80211vap *,
+	    int, int, int);
+void	ieee80211_amrr_cleanup(struct ieee80211_amrr *);
+void	ieee80211_amrr_setinterval(struct ieee80211_amrr *, int);
 void	ieee80211_amrr_node_init(struct ieee80211_amrr *,
+	    struct ieee80211_amrr_node *, struct ieee80211_node *);
+int	ieee80211_amrr_choose(struct ieee80211_node *,
 	    struct ieee80211_amrr_node *);
-void	ieee80211_amrr_choose(struct ieee80211_amrr *, struct ieee80211_node *,
-	    struct ieee80211_amrr_node *);
+
+#define	IEEE80211_AMRR_SUCCESS	1
+#define	IEEE80211_AMRR_FAILURE	0
+
+/*
+ * Update statistics with tx complete status.  Ok is non-zero
+ * if the packet is known to be ACK'd.  Retries has the number
+ * retransmissions (i.e. xmit attempts - 1).
+ */
+static __inline void
+ieee80211_amrr_tx_complete(struct ieee80211_amrr_node *amn,
+    int ok, int retries)
+{
+	amn->amn_txcnt++;
+	if (ok)
+		amn->amn_success++;
+	amn->amn_retrycnt += retries;
+}
 
+/*
+ * Set tx count/retry statistics explicitly.  Intended for
+ * drivers that poll the device for statistics maintained
+ * in the device.
+ */
+static __inline void
+ieee80211_amrr_tx_update(struct ieee80211_amrr_node *amn,
+    int txcnt, int success, int retrycnt)
+{
+	amn->amn_txcnt = txcnt;
+	amn->amn_success = success;
+	amn->amn_retrycnt = retrycnt;
+}
 #endif /* _NET80211_IEEE80211_AMRR_H_ */


More information about the p4-projects mailing list