Linux内核Adaptive-RED实现

ARED在RED的基础上实现了最大报文标记概率max_P的自动调整,以便将平均队列长度控制在目标区间内。

1 ARED初始化

在RED初始化函数red_init中,设置ARED定时器adapt_timer用于定期执行ARED算法,定时处理函数为red_adaptative_timer。

static int red_init(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack)
{
    struct red_sched_data *q = qdisc_priv(sch);

    q->qdisc = &noop_qdisc;
    q->sch = sch;
    timer_setup(&q->adapt_timer, red_adaptative_timer, 0);
    return red_change(sch, opt, extack);
}

通过TC命令设置RED队列时,如果指定了adaptive选项,将会向内核下发TC_RED_ADAPTATIVE标志,内核将启动adapt_timer定时器,时长为HZ/2,即500毫秒。

static int red_change(struct Qdisc *sch, struct nlattr *opt,
              struct netlink_ext_ack *extack)
{
    struct tc_red_qopt *ctl;

    ...
    ctl = nla_data(tb[TCA_RED_PARMS]);
    if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
        return -EINVAL;
    ...
    red_set_parms(&q->parms,
              ctl->qth_min, ctl->qth_max, ctl->Wlog,
              ctl->Plog, ctl->Scell_log,
              nla_data(tb[TCA_RED_STAB]),
              max_P);
    red_set_vars(&q->vars);

    del_timer(&q->adapt_timer);
    if (ctl->flags & TC_RED_ADAPTATIVE)
        mod_timer(&q->adapt_timer, jiffies + HZ/2);

函数red_set_params设置了ARED的参数,如下所示,ARED的最低目标avg(target_min)设置为: min_th + 0.4*(min_th - max_th),最高目标avg(target_max)设置为: min_th + 0.6*(min_th - max_th),即ARED尝试将平均队列长度avg控制在min_th和max_th的40%到60%的区间内。

注意,这里target_min和target_max都是原值,不同于p->qth_min和p->qth_max,后者使用Wlog进行了左移位。

static inline void red_set_parms(struct red_parms *p,
                 u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog,
                 u8 Scell_log, u8 *stab, u32 max_P)
{   
    int delta = qth_max - qth_min;
    
    p->qth_min  = qth_min << Wlog;
    p->qth_max  = qth_max << Wlog;

    if (delta <= 0)
        delta = 1;  
    p->qth_delta    = delta;
    ...
    
    /* RED Adaptative target :
     * [min_th + 0.4*(min_th - max_th),
     *  min_th + 0.6*(min_th - max_th)].
     */
    delta /= 5;
    p->target_min = qth_min + 2*delta;
    p->target_max = qth_min + 3*delta;

2 Adaptive-RED处理

如下为ARED的定时处理函数,其主要是对函数red_adaptative_algo的封装。

static inline void red_adaptative_timer(struct timer_list *t)
{
    struct red_sched_data *q = from_timer(q, t, adapt_timer);
    struct Qdisc *sch = q->sch;
    spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));

    spin_lock(root_lock);
    red_adaptative_algo(&q->parms, &q->vars);
    mod_timer(&q->adapt_timer, jiffies + HZ/2);
    spin_unlock(root_lock);

以下为ARED算法的实现,详情可参见: Adaptive-RED队列。首先,如果队列当前处于空闲状态,不能直接使用qavg,需要重新计算一下平均队列长度qavg。其次,由于qavg为经过Wlog左移位之后的值,这里进行还原。

static inline void red_adaptative_algo(struct red_parms *p, struct red_vars *v)
{
    unsigned long qavg;
    u32 max_p_delta;

    qavg = v->qavg;
    if (red_is_idling(v))
        qavg = red_calc_qavg_from_idle_time(p, v);

    /* v->qavg is fixed point number with point at Wlog */
    qavg >>= p->Wlog;

如果当前qavg大于目标最大值target_max,表明qavg过大,需要max_P增加Alpha。但是,当max_P已经大于MAX_P_MAX时,不再增加max_P。

    if (qavg > p->target_max && p->max_P <= MAX_P_MAX)
        p->max_P += MAX_P_ALPHA(p->max_P); /* maxp = maxp + alpha */

否则,如果qavg小于target_min,表明qavg过小,需要将max_P减小,乘以系数Beta。但是,当max_P已经小于MAX_P_MIN时,不再减小max_P的值。在max_P调整完毕之后,更新max_P_reciprocal的值。

    else if (qavg < p->target_min && p->max_P >= MAX_P_MIN)
        p->max_P = (p->max_P/10)*9; /* maxp = maxp * Beta */

    max_p_delta = DIV_ROUND_CLOSEST(p->max_P, p->qth_delta);
    max_p_delta = max(max_p_delta, 1U);
    p->max_P_reciprocal = reciprocal_value(max_p_delta);
}

根据ARED算法定义,maxp的最大值为0.5,而maxp的最小值为0.01,但是由于内核中p->max_P变量的值等于:probability * pow(2, 32),增大了2^32 倍,所以,宏MAX_P_MAX和MAX_P_MIN的定义也进行了2^32 倍的放大。

#define RED_ONE_PERCENT ((u32)DIV_ROUND_CLOSEST(1ULL<<32, 100))

#define MAX_P_MIN (1 * RED_ONE_PERCENT)
#define MAX_P_MAX (50 * RED_ONE_PERCENT)

另外,按照ARED算法,beta的值为0.9,在以上算法实现函数red_adaptative_algo中,通过(p->max_P/10)*9实现。alpha的值定义为:min(0.01, max_p / 4)两者之间的最小值,其由宏定义MAX_P_ALPHA实现:

#define MAX_P_ALPHA(val) min(MAX_P_MIN, val / 4)

内核版本 5.0

相关推荐
程序员的必经之路! 【限时优惠】 现在下单,还享四重好礼: 1、教学课件免费下载 2、课程案例代码免费下载 3、专属VIP学员群免费答疑 4、下单还送800元编程大礼包 【超实用课程内容】  根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能!   套餐中一共包含2门MySQL数据库必学的核心课程(共98课时)   课程1:《MySQL数据库从入门到实战应用》   课程2:《高性能MySQL实战课》   【哪些人适合学习这门课程?】  1)平时只接触了语言基础,并未学习任何数据库知识的人;  2)对MySQL掌握程度薄弱的人,课程可以让你更好发挥MySQL最佳性能; 3)想修炼更好的MySQL内功,工作中遇到高并发场景可以游刃有余; 4)被面试官打破沙锅问到底的问题问到怀疑人生的应聘者。 【课程主要讲哪些内容?】 课程一:《MySQL数据库从入门到实战应用》 主要从基础篇,SQL语言篇、MySQL进阶篇三个角度展开讲解,帮助大家更加高效的管理MySQL数据库。 课程二:《高性能MySQL实战课》主要从高可用篇、MySQL8.0新特性篇,性能优化篇,面试篇四个角度展开讲解,帮助大家发挥MySQL的最佳性能的优化方法,掌握如何处理海量业务数据和高并发请求 【你能收获到什么?】  1.基础再提高,针对MySQL核心知识点学透,用对; 2.能力再提高,日常工作中的代码换新貌,不怕问题; 3.面试再加分,巴不得面试官打破沙锅问到底,竞争力MAX。 【课程如何观看?】  1、登录CSDN学院 APP 在我的课程中进行学习; 2、移动端:CSDN 学院APP(注意不是CSDN APP哦)  本课程为录播课,课程永久有效观看时长 【资料开放】 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化。  下载方式:电脑登录课程观看页面,点击右侧课件,可进行课程资料的打包下载。
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页