天天看点

bbr中的缩放因子BW_SCALE/BBR_SCALE

0. 前言

不知道有没有人跟我一样,看源码的时候如果想不清一个点总会特别难受,就盯着它不放。

bbr的源码最开始处就定义了这样的宏,并写了注释,可是我一开始想不通,就是想不通为什么取这个值,在网上还搜不到相关的解释。我奇怪这是不是一眼就该看懂的东西,可是我确实就是没懂吖。纠结之后选择问我老大,终于给解释明白了哈哈哈。整理以备忘,也分享给有需要的人。

/* Scale factor for rate in pkt/uSec unit to avoid truncation in bandwidth
 * estimation. The rate unit ~= (1500 bytes / 1 usec / 2^24) ~= 715 bps.
 * This handles bandwidths from 0.06pps (715bps) to 256Mpps (3Tbps) in a u32.
 * Since the minimum window is >=4 packets, the lower bound isn't
 * an issue. The upper bound isn't an issue with existing technologies.
 */
#define BW_SCALE 24
#define BW_UNIT (1 << BW_SCALE)

#define BBR_SCALE 8	/* scaling factor for fractions in BBR (e.g. gains) */
#define BBR_UNIT (1 << BBR_SCALE)
           

1. BW_UNIT

如它的名字所言,它就是一个单位,一个自定义单位,为什么需要它呢,就是方便表示罢了。比如 0.040s 可以这样表示,但如果数据都是几十秒以下的,那这时考虑换成 40ms 来表示会更方便,也不需要浮点数了。这个情况下,单位是熟知的ms,从s过来的缩放因子是1000。

搞清楚这个其实就明白了。我们最终要得到 pkt/uSec 为单位,但实际计算过程当中的数据会长什么样呢。定一包数据为1500字节好了。

1pkt/uSec = 1500B/us = 1500*8b/0.000001s = 1500*8*1000000 bps ~= 12G bps

这时我们就取pkt/uSec为单位的话,1就表示了这个速度了。要知道百兆带宽的网络,拉满了也就100Mbps啊。这个单位显然对于实际来说还太大了,我们需要更精确的。

如果定2^24为单位的话,那么 1从表示 12G可以降到 715,即

1500 bytes / 1 usec / 2^24 ~= 715 bps

这时一个u32的数可以表示的范围从[1,UINT_MAX]变成了 [715, 715*UINT_MAX],也是就是“0.06pps (715bps) to 256Mpps (3Tbps)”。这个范围对于实际运算来讲是合适的,所以可以取这个值。就是说,24只是一个合适的数,它并不是必须的或者精确的。

2. BBR_UNIT

同理地,BBR_UNIT取的单位值是8,也是为了表示方便而加入缩放因子来调整数据表示范围。

比如有这样一个数组 {5/4,3/4,1,1,1,1,1,1 },我们可以选择定义成一个浮点数的类型来存放这些比例值,也可以选择加一个缩放因子,比如取4, 然后按这样子来定义数组,那么就可以直接用int类型来表示就可以了。

static const int bbr_pacing_gain[] = {
	BBR_UNIT * 5 / 4,	/* probe for more available bw */
	BBR_UNIT * 3 / 4,	/* drain queue and/or yield bw to other flows */
	BBR_UNIT, BBR_UNIT, BBR_UNIT,	/* cruise at 1.0*bw to utilize pipe, */
	BBR_UNIT, BBR_UNIT, BBR_UNIT	/* without creating excess queue... */
};
           
BBR