iis worker process内存占用大_vpp中process节点跳转及相关协程处理机制简介

1. VPP中process 协程节点示意

VPP进程
├── main线程
│ ├── process协程1
│ ├── process协程2
│ └── process协程3
│ └── process协程...
├── worker线程1
└── worker线程2
└── worker线程...

所有的VLIB_NODE_TYPE_PROCESS结点登记的任务均被处理为使用jmp机制的协程。worker线程由 pthread_create 新建是传统意义上的线程模型,每个 worker线程都被绑定到相应的核上。

2. jmp 原理

2.1 jmp栈保存的数据结构定义

struct clib_longjmp_t

681a5533bc57f2d4e547a06f6ec4b598.png

X64寄存器

879ce9652a5c7742bd28a2e73037a5f4.png

存放 rbx, rbp, r12, r13, r14, r15, eip, rsp 寄存器

源码备注的 eip 寄存器应该为 rdx寄存器

2.2 寄存器简介

clib_longjmp_t 结构体里面有8个寄存器,利用8个寄存器实现跳转功能

编号

寄存器

作用

1

%rbx

被调用者保存

2

%rbp

被调用者保存

3

%r12

被调用者保存

4

%r13

被调用者保存

5

%r14

被调用者保存

6

%r15

被调用者保存

7

%rdx

第三个参数

实际过程中利用它进行中转

8

%rsp

栈指针

cb505500786a47f777872a591f9ab3b0.png

•%rax 

        作为函数返回值使用。

•%rsp 

        栈指针寄存器,指向栈顶

•%rdi,%rsi,%rdx,%rcx,%r8,%r9

        用作函数参数,依次对应第1参数,第2参数...

•%rbx,%rbp,%r12,%r13,%14,%15 

        用作数据存储,遵循被调用者使用规则,

        调用子函数之前要备份它,以防他被修改

•%r10,%r11 

        用作数据存储,遵循调用者使用规则,使用之前要先保存原值

fdce2b6b486146b1401805e9fafe001c.png

2.3 重要指令

mov 与 lea区别

lea: load effective address, 将一个内存地址直接赋给目的操作数,例如:lea eax,[ebx+8]就是将ebx+8这个值直接赋给eax,而不是把ebx+8处的内存地址里的数据赋给eax。而mov指令则恰恰相反,例如:mov eax,[ebx+8]则是把内存地址为ebx+8处的数据赋给eax。

xchgl 交换寄存器
push :将一个寄存器中的数据入栈
pop :出栈用一个寄存器接收数据

2.4 利用TEST实例说明跳转设计

VPP拽出来的三个文件 longjmp.S,longjmp.h,test_longjmp.c,经过简单修改,点击原文链接下载:

 longjmp.S 中三个重要函数:

  1. clib_setjmp

    d3986db70bab04960f5c8532fc0b93ae.png

  2. clib_longjmp

    27b7a4507e26e82833270110b162ba41.png

  3. clib_calljmp

    338f903ed65354c472f6b5e7155c801f.png

详细内容注解见示例,并利用GDB查看相关寄存器

38e00e0342bb9c0c23abc24f3bf5a031.png

示例中如果 f2 设置为0 则会无限循环

3. VPP中 利用jmp 原理实现协程的应用

需要恢复执行的 process 有两种原因:

1.等待的时钟已经到时(即定时器到期)

2.等待的事件已经发生。
process 等待时钟的时候利用epoll机制,让定时器到时后或event发生调度它重新执行
执行的调用代码在 main线程主循环里

一般process 节点都是这样 结构

static uword xxx_process ( ...){    初始化...       while(1)    {        vlib_process_wait_for_event_or_clock(...);        或        vlib_process_wait_for_event(...);               逻辑执行操作...    }    return xxx;}

例如:nat_ha_process 节点

10c477c160f24d6a653b9aae8c14271b.png

3.1 process 节点startup 流程调用栈

-->> vlib_main

 -->> -->> vlib_main_loop

 -->> -->> -->> vlib_main_or_worker_loop

 -->> -->> -->> -->> dispatch_process (while1前)

 -->> -->> -->> -->> -->> vlib_process_startup

startup过程 四次 jmp 操作
clib_setjmp 设置return_longjmp -> ② clib_calljmp 调用 vlib_process_bootstrap 进入相应的process节点(出入点vlib_process_wait_for_event_or_clock/vlib_process_wait_for_event) -> ③ clib_setjmp 设置return_resumejmp -> ④ clib_longjmp 跳到 ①的return_longjmp位置

1. clibsetjmp :设置 p->returnlongjmp返回: VLIB_PROCESS_RETURN_LONGJMP_RETURN位置: vlib_process_startup line 1525

bc84e3cb424345791a459977d9811156.png

设置 process sarttup 刚进入时候 的jmp 保存到对应process 节点的 p->return_longjmp 位置,开始进入的时候 返回值为 VLIB_PROCESS_RETURN_LONGJMP_RETURN ,调用后
依赖 第四步 longjmp 参数2 (n)返回值

2. clib_calljmp 调用 vlib_process_bootstrap返回: VLIB_PROCESS_RESUME_LONGJMP_SUSPEND 取决于步骤4 clib_longjmp 返回值位置: vlib_process_startup line 1527

b8e020825aaad8d906b1febaafce4a39.png

调用 vlib_process_bootstrap 函数,进一步调用 process_node 的func (process节点真实运行逻辑)如:vrrp_periodic_process / nat_ha_process 等这些节点循环在开头处都会 调用 vlib_process_wait_forevent/vlib_process_wait_for_event_or_clock
设置逻辑节点 的 栈信息,为以后调用做准备,(步骤3)

3. clib_setjmp :设置 p->resume_longjmp 返回: VLIB_PROCESS_RESUME_LONGJMP_SUSPEND位置: vlib_process_wait_for_event line 604

52037a1c5ef30b77348142460e8c3243.png

设置 p->resume_longjmp 即 不同process 节点的调用栈,记录到对应的p(vlib_process_t)结构体中。

4. clib_longjmp 跳转到 p->return_longjmp 位置返回: VLIB_PROCESS_RETURN_LONGJMP_SUSPEND位置: vlib_process_wai_tfor_event line 606

58ca1956c079bb468830d65c30bd795f.png

返回最开始处(步骤1)设置的 process 节点返回处调用栈
状态VLIB_PROCESS_RETURN_LONGJMP_SUSPEND 往下继续走:如图

953d35a663664df1b6020fabfd9a8426.png

最终process节点初始化完的状态
resume 状态 为 susped
return 状态 为 susped
flags标记VLIB_PROCESS_RESUME_LONGJMP_SUSPEND
VLIB_PROCESS_RETURN_LONGJMP_SUSPEND

3.2 process 节点主循环 流程调用栈

主线程 thread0

-->> vlib_main

-->>-->> vlib_main_loop

-->>-->>-->> vlib_main_or_worker_loop

-->>-->>-->>-->> dispatch_suspended_process (while1中)

-->>-->>-->>-->>-->>-->> vlib_process_resume

startup过程中 四次 jmp 操作
① clib_setjmp 设置return_longjmp -> ② clib_longjmp 跳到startup 步骤3 设置的resume_longjmp位置 -> ③ 执行process 逻辑(出入点vlib_process_wait_for_event_or_clock/vlib_process_wait_for_event)-> ④ clib_setjmp 设置return_resumejmp -> ⑤ clib_longjmp 跳到 ①的return_longjmp位置

1. clibsetjmp :设置 p->returnlongjmp返回: VLIB_PROCESS_RETURN_LONGJMP_RETURN位置: vlib_process_resume line 1540

c3b12203481450fc8f303ea5fe43a116.png

2. clib_longjmp :跳转到 p->resume_longjmp返回: VLIB_PROCESS_RESUME_LONGJMP_RESUME位置: vlib_process_resume line 1542
跳转到 startup时候 步骤3 设置 p->resume_longjmp 的位置设置 返回值为VLIB_PROCESS_RESUME_LONGJMP_RESUME

5c5add79c407f8dfed97a399dbb5a16a.png

3. vlib_process_wait_for_event_or_clock
process 节点 继续从 vlib_process_wait_for_event_or_clock 后继续执行
所有process 节点已进入 while(1)循环 都调用clib_process_wait_for_event_or_clock

c895f99eb3e2fd08e61821e00042ed62.png

转一圈后又调用vlib_process_wait_for_event_or_clock。

4. clibsetjmp :设置 p->resumelongjmp 返回: VLIB_PROCESS_RESUME_LONGJMP_SUSPEND位置:vlib_process_wait_for_event  line 604

52037a1c5ef30b77348142460e8c3243.png

与startup 时步骤3 一样
设置 p->resume_longjmp 即 不同process 节点的调用栈,记录到对应的p(vlib_process_t)结构体中。

5. cliblongjmp 跳转到 p->returnlongjmp 位置返回:VLIB_PROCESS_RETURN_LONGJMP_SUSPEND位置:vlib_process_wait_for_event  line 606
与startup 时步骤4 一样
只不过此时设置 的return_longjmp 不一样,是步骤1中设置的return_longjmp

b551ab53e07fc8faecdedbead057073f.png

4. 节点实例

以unix_cli_process 为例

3dbfdf284875a7ba1907cca74bf03145.png

该函数为while (1)的形式,说明该node函数将一直执行直到应用进程退出为止。
而在开始的时候这里先调用了vlib_process_wait_for_event函数,检查是否由事件需要处理。

4d7f3e78df9e27609fec4602edf3f4ae.png

•检查non_empty_event_type_bitmap是否置位,

•如有说明有需要处理的事件则立刻返回进行处理,不走if里面的流程

•否则说明该process node任然需要等待事件,

•设置标志位 VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT

•暂不需要分配CPU时间,可以进入suspend状态。

•所以,这里先记录下当前的位置(记为resume_longjmp),

•然后再跳回return_longjmp所记录的位置,完成一次结点调度过程。

备注:event触发调度 相关使用的是1t_3w_1024sl_ov类型时间轮,另作分析。

原文链接提取码:zsul

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值