Scheduling for I/O

http://hi.baidu.com/%B0%B5%D4%C2%C1%F7%B9%E2/blog/item/deaabad20614cdd2a9ec9adf.html

 

(没来得及仔细研究呢,貌似很attractive,呵呵)

 

所谓的Gang schedule是用在高性能计算里面的,不很适合普通的应用。现在xen里面的credit调度算法,每个物理cpu对应一个运行队列(runq),runq之间没有什么关系。当一个物理cpu上的运行队列为空时,会执行负载均衡算法(load balance)从另外一个队列中“偷”一个vcpu来执行。
在虚拟化的情况下,当含有多个虚拟机时,总vcpu的数量就会超过pcpu的数量,这个时候可能出现的一种情况是:

>>domain1的vcpu0要和domain2的vcpu0通信

>>domain3的vcpu0要和domain4的vcpu0通信

但是当domain1的vcpu0被调度之后,另一个pcpu上调度的是domain3的vcpu0。

由于是采用的高效IO机制,前者给domain2的vcpu0发送数据之后会处于poll状态,并不会直接阻塞自己;

同理domain3的vcpu0也是如此,这样就会导致两个cpu空转,一直在执行poll,直到时间片用完为止。
Gang schedule的想法是希望通过将需要通信的vcpu放在一个gang里面,调度的时候两者同时调度,这样就能够避免前面所说的空转开销。

说起来我们只要形成了Gang,然后调度的时候按照Gang来调度就OK,但事实确没这么简单。
首先如何确认两个vcpu之间在通信? 我们通过用户设置命令可以知道两个vcpu之间会有通信,但是具体什么时候是在通信,什么时候是简单的计算,这些要确认是比较复杂的。
其次,由于domain0的存在,域间通信都需要通过domain0来转发,因此一个Gang的vcpu被调度之后,还需要允许domain0的vcpu被调度起来,否则无法完成两者之间的通信,这样就意味着这个Gang是不稳定的,与传统意义上所说的Gang区别挺大的。
最后,如何测量?我们可以通过检查最后的整体mpi测试程序运行的时间,得到一个简单直观的比较;但是这个无法确认我们当前的Gang scheduler是否生效,是否如我们所期望的一样在调度,特别是当出现问题的时候我们该如何定位问题所在,进而为算法改进提供参考,否则盲目的改不仅耗人力,而且要走很多弯路!


-----------------------------------------------------------------------------------------------------------

要求:
公平、快速I/O响应

1)dom0 vcpu不放入gang中,每次runq切换仅仅切换非dom0部分(remove gang中所有可运行vcpu,同时将next gang中所有可运行vcpu放入对应runq)
2)当前运行队列为空的时候,应该切换新的gang执行
3)当有vcpu wale-up时,如果非当前gang,则设置gang优先级为最高,对gang进行重排序,然后执行gang的切换
4) gang设置有各种不同的优先级,方便调度
5)不使用定时器
6)支持扩展任意数量pcpu上的gang调度

1)每个gang中能够较容易获取对应pcpu的runq
2)每个vcpu能够较容易获取对应所在gang

 

 

解决了第一个问题如何确定相互通信的时间,算法改进之后的测试结果还是没有达到自己预期的效果,不过已经能够和没有改之前的接近了。通过对原credit和改进之后算法中调度相关数据的分析,发现恰好是自己所预测的第二个问题。原credit算法在调度的时候,每次vcpu切换中间总是会间隔有一次domain0的vcpu切换,这样保证了通信的畅通。但是改进的算法里面由于暂时没有考虑domain0的情况,因此虽然把另外一个vcpu调度起来了,但是通信数据却可能还未发送过去,导致时间片的浪费。


下面是运行is.A.2测试程序的时候的一个trace数据:
320316 CPU1  1566102695143 (+     770)  __enter_scheduler [ prev<domid:edomid> = 0x00000000 : 0x00       000000, next<domid:edomid> = 0x00000001 : 0x00000000 ]
320317 CPU1  1566102716108 (+   20965)  switch_infprev    [ old_domid = 0x00000001, runtime = 9384        ]
320318 CPU1  1566102716402 (+     294)  switch_infnext    [ new_domid = 0x00000000, time = 600, r_       time = 30000000 ]
320319 CPU1  1566102717242 (+     840)  __enter_scheduler [ prev<domid:edomid> = 0x00000001 : 0x00       000000, next<domid:edomid> = 0x00000000 : 0x00000000 ]
320320 CPU1  1566102725726 (+    8484)  page_grant_map      [ domid = 2 ]
320321 CPU1  1566102744094 (+   18368)  page_grant_unmap    [ domid = 2 ]
320322 CPU1  1566102752998 (+    8904)  do_block          [ domid = 0x00000000, edomid = 0x0000000       0 ]
320323 CPU1  1566102754097 (+    1099)  switch_infprev    [ old_domid = 0x00000000, runtime = 1636       2 ]
320324 CPU1  1566102754405 (+     308)  switch_infnext    [ new_domid = 0x00000001, time = 16362,        r_time = 30000000 ]
320325 CPU1  1566102755175 (+     770)  __enter_scheduler [ prev<domid:edomid> = 0x00000000 : 0x00       000000, next<domid:edomid> = 0x00000001 : 0x00000000 ]
320326 CPU1  1566102763659 (+    8484)  domain_wake       [ domid = 0x00000000, edomid = 0x0000000       0 ]
320327 CPU1  1566102764576 (+     917)  switch_infprev    [ old_domid = 0x00000001, runtime = 4584        ]
320328 CPU1  1566102764842 (+     266)  switch_infnext    [ new_domid = 0x00000000, time = 336, r_       time = 30000000 ]
320329 CPU1  1566102765647 (+     805)  __enter_scheduler [ prev<domid:edomid> = 0x00000001 : 0x00       000000, next<domid:edomid> = 0x00000000 : 0x00000000 ]
320330 CPU1  1566102773326 (+    7679)  page_grant_map      [ domid = 1 ]
320331 CPU1  1566102774355 (+    1029)  page_grant_map      [ domid = 1 ]
320332 CPU1  1566102775342 (+     987)  page_grant_map      [ domid = 1 ]
320333 CPU1  1566102797042 (+   21700)  page_grant_unmap    [ domid = 1 ]
320334 CPU1  1566102798050 (+    1008)  page_grant_unmap    [ domid = 1 ]
320335 CPU1  1566102798876 (+     826)  page_grant_unmap    [ domid = 1 ]
320336 CPU1  1566102808172 (+    9296)  do_block          [ domid = 0x00000000, edomid = 0x0000000       0 ]
由上面数据可以看出,domain0的特殊性对于相互通信的来说,更主要的是体现在CPU0的特殊性上面。参考前面关于域间通信的分析,当domU1要与domU2通信时,首先domU1根据请求内容设置domain0的事件标志位;当domain0被调度时首先会检查是否有事件需要处理,这个时候会对domU1的事件请求进行处理,并设置domU2的事件标志位;当domU2被调度时,会检测事件标志位,然后对事件进行处理。回去的过程类似。
检测事件标志位的任务默认是交给vcpu0来处理的(由最开始注册事件通道时候注册的vcpu处理,默认是vcpu0),因此在这个里面我们可以看到domain0的vcpu0被频繁的调度。
那么我们是否需要特殊设置domain0中vcpu0的调度呢?是否有必要在gang中对vcpu0进行考虑?分析上面的数据,我们发现还有几个特殊的事件:do_block、domain_wake,当domain0的vcpu0处理完数据之后就会执行do_block操作,当有事件时会执行domain_wake操作,因此domain0中vcpu0这个特殊的角色并不需要我们太过操心,唯一需要注意是设置gang scheduler的时候需要保证给wake up的cpu最高优先级,以保证尽快被调度。


理想调度顺序应该是:

d1u0
d0u0                 d2u0
d1u0                 d0u0
d0u0                 d2u0
d1u0                 d0u0
credit over
d3u0                d2u0
d0u0                d5u0
d3u0                d0u0
d0u0                d5u0
d3u0                d0u0
d0u0                d5u0
credit over
d4u0                d5u0
d0u0                d6u0
d4u0                d0u0
d0u0                d6u0
d4u0                d0u0
all credit over resume
d1u0                d6u0
d0u0                d2u0
d1u0                d0u0
................................


this is what we expected!!


-------------------------------------------< 测试结果依旧不甚理想 >-----------------------------------
94406 CPU0  3996531218008 (+     854)  __enter_scheduler [ prev<domid:edomid> = 0x00000000 : 0x00       000000, next<domid:edomid> = 0x00000003 : 0x00000000 ]
94407 CPU0  3996535974158 (+ 4756150)  domain_wake       [ domid = 0x00000000, edomid = 0x0000000       0 ]
94408 CPU0  3996535979009 (+    4851)  switch_infprev    [ old_domid = 0x00000003, runtime = 2039       841 ]
94409 CPU0  3996535979450 (+     441)  switch_infnext    [ new_domid = 0x00000000, time = 2820, r       _time = 30000000 ]
94410 CPU0  3996535981697 (+    2247)  __enter_scheduler [ prev<domid:edomid> = 0x00000003 : 0x00       000000, next<domid:edomid> = 0x00000000 : 0x00000000 ]
94411 CPU0  3996536087859 (+  106162)  emulate_privop      [ rip = 0x        8037d1ea ]
94412 CPU0  3996536108313 (+   20454)  do_block          [ domid = 0x00000000, edomid = 0x0000000       0 ]
94413 CPU0  3996536111295 (+    2982)  switch_infprev    [ old_domid = 0x00000000, runtime = 5703       0 ]
94414 CPU0  3996536111589 (+     294)  switch_infnext    [ new_domid = 0x00000003, time = 57030,        r_time = 30000000 ]
94415 CPU0  3996536112485 (+     896)  __enter_scheduler [ prev<domid:edomid> = 0x00000000 : 0x00       000000, next<domid:edomid> = 0x00000003 : 0x00000000 ]
94416 CPU0  3996553847587 (+17735102)  domain_wake       [ domid = 0x00000000, edomid = 0x0000000       0 ]

关键性问题不在全局,而在局部,特别是domain_wake部分
是否是之前自己的假设有误? Gang schedule并未能够解决之前自己所假设的情况
路在前方是否已是尽头?  继续。。。。

----------------------------------------< d0u0争宠>--------------------------------------------------------------
21426 CPU1  1595780076107 (+23158338)  domain_wake       [ domid = 0x00000000,        edomid = 0x00000000 ]
21427 CPU1  1595780077423 (+    1316)  switch_infprev    [ old_domid = 0x000000       04, runtime = 9928640 ]
21428 CPU1  1595780077731 (+     308)  switch_infnext    [ new_domid = 0x000000       00, time = 537, r_time = 30000000 ]
21429 CPU1  1595780078844 (+    1113)  __enter_scheduler [ prev<domid:edomid> =        0x00000004 : 0x00000000, next<domid:edomid> = 0x00000000 : 0x00000000 ]
21430 CPU1  1595780093383 (+   14539)  do_block          [ domid = 0x00000000,        edomid = 0x00000000 ]
21431 CPU1  1595780094391 (+    1008)  switch_infprev    [ old_domid = 0x000000       00, runtime = 7308 ]
21432 CPU1  1595780094664 (+     273)  switch_infnext    [ new_domid = 0x000000       01, time = 9982997, r_time = 30000000 ]
21433 CPU1  1595780095749 (+    1085)  __enter_scheduler [ prev<domid:edomid> =        0x00000000 : 0x00000000, next<domid:edomid> = 0x00000001 : 0x00000000 ]
21434 CPU1  1595780122209 (+   26460)  domain_wake       [ domid = 0x00000000,        edomid = 0x00000000 ]

compared:
8409 CPU0  1595740540394 (+  316078)  domain_wake       [ domid = 0x00000000,        edomid = 0x00000000 ]
  8410 CPU0  1595756868223 (+16327829)  domain_wake       [ domid = 0x00000000,        edomid = 0x00000000 ]
8411 CPU0  1595780186749 (+23318526)  domain_wake       [ domid = 0x00000000,        edomid = 0x00000000 ]
8412 CPU0  1595787165301 (+ 6978552)  domain_wake       [ domid = 0x00000000,        edomid = 0x00000000 ]
8413 CPU0  1595787384121 (+  218820)  domain_wake       [ domid = 0x00000000,        edomid = 0x00000000 ]
8414 CPU0  1595798656116 (+11271995)  domain_wake       [ domid = 0x00000000,        edomid = 0x00000000 ]

走自己的路,让自己无路可走!~

柳暗花明?~  是否是一处世外桃源?~

--------------------------------------------------->    <----------------------------------------------------------
161 CPU1  101337337543148 (+   36848)  unknown (0x000000000020f008)  [ 0x00000000 0x00000000 0x       00000000 0x00000000 0x00000000 ]
162 CPU1  101337380296117 (+42752969)  domain_wake       [ domid = 0x00000000, edomid = 0x00000       001 ]


39 #define TRC_PV       0x0020f000    /* Xen PV traces            */
93 #define TRC_PV_MATH_STATE_RESTORE    (TRC_PV +  8)

2947 asmlinkage void do_device_not_available(struct cpu_user_regs *regs)
2948 {
2949     struct vcpu *curr = current;
2950
2951     BUG_ON(!guest_mode(regs));
2952
2953     setup_fpu(curr);
2954
2955     if ( curr->arch.guest_context.ctrlreg[0] & X86_CR0_TS )
2956     {
2957         do_guest_trap(TRAP_no_device, regs, 0);
2958         curr->arch.guest_context.ctrlreg[0] &= ~X86_CR0_TS;
2959     }
2960     else
2961         TRACE_0D(TRC_PV_MATH_STATE_RESTORE);
2962
2963     return;
2964 }

说明当device not available的时候,会导致domain wake时间过长

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值