Chinaunix

标题: 有关rps的一个疑问。。。 [打印本页]

作者: chishanmingshen    时间: 2013-03-25 09:27
标题: 有关rps的一个疑问。。。
本帖最后由 chishanmingshen 于 2013-03-25 09:31 编辑


疑问从此帖来:

http://bbs.chinaunix.net/forum.p ... ;extra=#pid23811516

在“处理完”就用期望cpu,还是会错啊。

问题见16楼,请指点,谢谢!
作者: chishanmingshen    时间: 2013-03-29 10:25
看来是基于一个假设这么优化的:
发出去一个请求,其应答的所有报文可以在一个软中断中到达并处理完。

感觉这就是一个优化,不是一个完美的解决方案,所以还是会有问题。。。


作者: junnyg    时间: 2013-04-13 18:10
本帖最后由 junnyg 于 2013-04-13 18:25 编辑

回复 2# chishanmingshen
以前看过一点RPS和RFS的资料,实现是在netif_receive_skb函数中增加目标CPU的筛选代码,并唤起目标CPU的软中断处理
netif_receive_skb(struct sk_buff *skb)
        cpu = get_rps_cpu(skb->dev, skb, &rflow);根据数据包选择一个CPU
        enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
                sd = &per_cpu(softnet_data, cpu);得到每CPU变量softnet_data
                __skb_queue_tail(&sd->input_pkt_queue, skb);将数据包加入接收队列
                ____napi_schedule(sd, &sd->backlog);启动backlog,结构是napi_struct
  1. if (unlikely(tcpu != next_cpu) &&  /*old_cpu 与 期望cpu不一致*/
  2. 2371                     (tcpu == RPS_NO_CPU || !cpu_online(tcpu) || /*判断old_cpu的合法性,是否已被下线等*/
  3. 2372                      ((int)(per_cpu(softnet_data, tcpu).input_queue_head -
  4. 2373                       rflow->last_qtail)) >= 0)) { /* 在这里判断old_cpu上是不是已经处理该流的历史包了 */
  5. 2374                         tcpu = rflow->cpu = next_cpu; /*如果条件都满足,则使用期望cpu,并更新rflow上的历史cpu值 */
  6. 2375                         if (tcpu != RPS_NO_CPU)
  7. 2376                                 rflow->last_qtail = per_cpu(softnet_data, /*更新rflow上记录的历史包在目标cpu上的包处理链表上的位置 */
  8. 2377                                     tcpu).input_queue_head;
  9. 2378                 }
  10. 2379                 if (tcpu != RPS_NO_CPU && cpu_online(tcpu)) {
  11. 2380                         *rflowp = rflow;
  12. 2381                         cpu = tcpu;
  13. 2382                         goto done;
  14. 2383                 }
复制代码
个人对你问题的理解:

我的疑问:
这样,只是一个软中断的包都传给同一个cpu,但是多个软中断之间的cpu是不同的?假设每个软中断都会把本轮的queue里的包处理完。
不太明白你的意思,谈下自己的理解:
1. 每个流的包都会计算出一个期望CPU
2. 由于多线程模型等因素,当前流包上一次处理的包的cpu和当前计算的期望CPU可能不一致
3. 如果一致则直接将包挂到期望CPU的软中断包处理链表上,并唤起期望CPU的软中断服务
4. 如果不一致则需要检查当前流的包在old_cpu上处理的状态,通过检查(int)(per_cpu(softnet_data, tcpu).input_queue_head - rflow->last_qtail)) 是否>= 0,意思是old_cpu链表上当前正在处理的节点位置已经超过保存的上次挂上的包的位置了,那么可以直接使用期望CPU来处理当前包了
5. 如果old_cpu还没处理到上次挂的包,那就只能把包挂到old_cpu上了,这样才能保证包的保序



   
作者: chishanmingshen    时间: 2013-04-13 20:54
回复 3# junnyg


1. 每个流的包都会计算出一个期望CPU
2. 由于多线程模型等因素,当前流包上一次处理的包的cpu和当前计算的期望CPU可能不一致
3. 如果一致则直接将包挂到期望CPU的软中断包处理链表上,并唤起期望CPU的软中断服务
4. 如果不一致则需要检查当前流的包在old_cpu上处理的状态,通过检查(int)(per_cpu(softnet_data, tcpu).input_queue_head - rflow->last_qtail)) 是否>= 0,意思是old_cpu链表上当前正在处理的节点位置已经超过保存的上次挂上的包的位置了,那么可以直接使用期望CPU来处理当前包了
5. 如果old_cpu还没处理到上次挂的包,那就只能把包挂到old_cpu上了,这样才能保证包的保序
========================================================
红色就是我的疑问:
如你2中所说,由于多线程的原因会导致期望cpu不准。这样,在4中使用期望cpu不是一样会不准么?

请指点,谢谢~~

   
作者: junnyg    时间: 2013-04-13 21:04
回复 4# chishanmingshen
期望cpu与old_cpu的值不一致,不是期望cpu不准,而是基于以下模型:
1. 线程1在cpu1上对该socket调用了recvmsg所以第一个包在cpu1得到了处理
2. 线程2在cpu2上也对该socket调用了recvmsg所以第二个包到来时期望cpu是2,old_cpu是1
这个时候,理想的情况是将包给cpu2执行,因为这个包是希望给线程2处理的,而前面所讲的算法的目的是避免乱序,在保证不乱序的情况下,优先使用期望CPU


   
作者: junnyg    时间: 2013-04-13 21:18
回复 4# chishanmingshen
没权限发短消息。。我的qq在个人资料里,有时间可以一起学习交流


   
作者: chishanmingshen    时间: 2013-04-13 21:41
回复 5# junnyg

4. 如果不一致则需要检查当前流的包在old_cpu上处理的状态,通过检查(int)(per_cpu(softnet_data, tcpu).input_queue_head - rflow->last_qtail)) 是否>= 0,意思是old_cpu链表上当前正在处理的节点位置已经超过保存的上次挂上的包的位置了,那么可以直接使用期望CPU来处理当前包了
5. 如果old_cpu还没处理到上次挂的包,那就只能把包挂到old_cpu上了,这样才能保证包的保序
==============================================================================================
我的意思就是仅仅保证了“保存的上次挂上的包”分到old_cpu中去,“之后的包”还是会分到期望cpu了。“之后的包“就是分错cpu的。

所以,我说这个处理仅仅是优化,不能保证所有的包都分到old_cpu中去。



   
作者: junnyg    时间: 2013-04-13 21:55
回复 7# chishanmingshen
4. 如果不一致则需要检查当前流的包在old_cpu上处理的状态,通过检查(int)(per_cpu(softnet_data, tcpu).input_queue_head - rflow->last_qtail)) 是否>= 0,意思是old_cpu链表上当前正在处理的节点位置已经超过保存的上次挂上的包的位置了,那么可以直接使用期望CPU来处理当前包了
5. 如果old_cpu还没处理到上次挂的包,那就只能把包挂到old_cpu上了,这样才能保证包的保序
==============================================================================================
我的意思就是仅仅保证了“保存的上次挂上的包”分到old_cpu中去,“之后的包”还是会分到期望cpu了。“之后的包“就是分错cpu的。

所以,我说这个处理仅仅是优化,不能保证所有的包都分到old_cpu中去。
==============================================================================================
如果不存在多线程访问,那么理论上一个socket流是只有一个期望cpu值的,那就能保证这个流在一个希望访问它的应用程序的cpu上处理
如果存在多线程访问,则存在期望cpu值被更改的情况,在这种情况下保证的是这个包在正确的cpu上被它希望的应用程序处理,而不是保证这个流上的包,在一个cpu上处理,然后被其他cpu的应用程序访问,你说的 “之后的包“就是分错cpu的。和我的想法有偏差



   
作者: chishanmingshen    时间: 2013-04-14 10:10
回复 8# junnyg


再想想,我还是不能理解~~



   




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2