关于qemu IO下发linux aio与协程一起使用的优点理解

1 qemu IO逻辑梳理

1.1 qemu下发IO接口调用

梳理qemu 下发IO数据的函数调用关系,对理解qemu下发IO数据逻辑会很有帮助,省略无关接口的调用可以突出核心逻辑,本次函数接口梳理省略了qemu main_loop接口调用,选择性罗列qemu main_loop处理下发IO数据时回调函数中子函数之间的调用关系,每个方框表示一个函数调用或一个循环逻辑条件,两方框头有长缩进,代表函数间是调用关系,两方框头持平表示同一函数中顺序调用关系,并用虚线连接,两方框头短缩进表示一种循环逻辑。

图1 qemu下发IO数据函数接口调用逻辑关系

假设在没有写入错误的情况下根据上图所示的函数调用关系进行分析,blk_aio_prwv表示qemu main_loop处理向blk设备下发IO数的核心调用函数,在该函数中通过qemu_coroutine_create创建协程,协程回调函数为blk_aio_write_entry在协程回调函数中通过io_submit提交IO数据,接着使用io_getevents_advance_and_peek获取所有IO提交状态返回事件,如果没有获取到IO提交状态返回事件则退出laio_do_submit执行qemu_corotine_yield函数暂停协程执行,回到主事件循环的blk_aio_prwv的函数中,此时协程没有返回值因此不会执行reply_bh_schedule_oneshot_event函数创建下半部事件;如果获取到了事件,则根据事件event变量找到对应IO提交协程,使用aio_co_wake切换到该协程上的暂停点下,而先前IO提交的暂停点在laio_co_submit函数中子函数qemu_corotine_yield函数下一条指令上,下一条指令为return返回状态,此时raw_co_prw函数有了返回值,blk_co_do_pwritev_part也就有了返回值,因此会执行blk_aio_complete函数向gues反馈IO下发数据状态,执行完上一个能够获取到IO提交返回事件所在协程后会回到本次IO提交所在协程的aio_co_wake处,如果本次IO提交没有返回提交状态事件,则同样会走qemu_corotine_yield处退出协程,不同的是此时blk_co_do_pwritev_part已经有了返回值因此会执行reply_bh_schedule_oneshot_event函数创建一次性的下半部事件源,接着进入主事件循环中。

主事件循环中的处理:

图2主事件循环中的相关函数

由图一的描述可知,如果有IO数据完成对guest反馈则会在main_loop中插入下半部事件,因此下一轮循环中会执行该下半部的回调函数为blk_aio_complete_bh,又由于有aio的事件产生所以也会执qemu_laio_process_completions行监督IO返回事件的回调函数qemu_aio_completion_cb,该回调函数的主要功能是通过调用qemu_laio_process_completions函数实现对IO提交返回状态的监督以及对应协程的切换完成对gues反馈IO提交状态。

1.2 一次IO提交逻辑

有了前面两个逻辑流程的说明我们先看一下在IO压力较小时,一次IO数据提交的完整流程,如下图所示:

图3 单次处理函数调用逻辑

左图是第一次循环处理IO数据接口调用关系,因为没有获取到IO提交返回状态因此会yield出协程,并回到main_loop中,如果没有事件产生的话此时main_loop为阻塞状态,在一段时间后异步IO提交返回了事件,main_loop中感到了并调用相应回调函数即执行qemu_laio_completion_cb函数,获取IO提交返回事件event并切换到相应协程并执行blk_aio_complete向guest反馈提交状态。在该场景下并不能体现qemu下发IO使用aio与协程结合的优点,因为即便不使用协程也是需要两次循环才能完成一次IO下发和反馈。

1.3高压状态下IO提交逻辑

图4 qemu aio数据流程

以上为了突出协程调度因此在图4中只保留关键函数,从上图可以开到,第一次下发IO创建协程coroutine1并使用laio_do_submit提交IO数据由于没有获取得到提交IO数据的返回事件因此执行yield函数暂停协程,并继续执行主事件循环中的其他函数。当第二次提交时同样灭有获取到第一次和第二次提交IO数据的返回事件,当第三次提交时获取到第一次IO提交以及第二次IO提交的返回状态因此会通过wake函数唤醒第一次提交时暂停的协程,由于协程上下文在数据结构中以队列的形式保存因此依次执行协程暂停之后的函数,这里协程暂停之后的函数为blk_aio_complete,该函数的作用是通过虚拟中断通知guest IO数据下发状态。由于没有获取到第三次IO提交的返回状态因此暂停提交第三次IO数据的协程,依次类推嵌套循环执行,由该逻辑可以看出在高压状态下只需要一次循环就可以实现一次IO的提交。

总结:

qemu 协程加异步IO接口处理流程:

1:qemu数据流中创建协程调用aio接口提交IO数据;

2:如果aio提交没有得到及时的状态返回,为了充分使用cpu,程序通过协程yeild出该协程,继续接收guest信号处理其他IO数据;

3:在处理其他IO数据时,仍然重复获取先前异步aio接口提交IO数据的状态返回,以及本次提交IO数据的返回状态;

4:如果能够获取到先前IO提交返回的状态则通过wake接口唤醒先前IO所在协程,继续执行未完成的反馈gues信息的接口;

5:执行完能够获取所有IO提交状态的协程之后再返回到本次提交IO的所在协程,依次循环嵌套执行。

使用协程完成这种操作的目的是在一套异步IO代码中实现对IO数据的提交以及向guest反馈IO写入状态换言之不要执行多余的循环代码,以提高IO写入效率。

补充:qemu如何通过event获取对应协程的?

qemu 通过event获取协程逻辑

我们通过io_getevents_advance_and_peek获取到events后,遍历所有event,因为每个iocb对应唯一的event,所以通过event获取到iocb指针,而iocb又唯一对应一个qemu_laiocb;qemu_laiocb的数据结构为:

qemu_laiocb数据结构绑定者co(协程上下文)以及qiov下发的数据,因而能通过event找到对应IO提交的所在协程的上下文。

2 打印日志验证理解

2.1 日志打印位置设置

为了验证以上理论先梳理qemu 异步IO下发函数调用逻辑:

为了说明图一中的qemu 提交IO数据逻辑在每个函数的调用开始的地方打印日志格式为(文件路径:函数名:行号)类似于:

图5 函数调用日志打印

为了说明协程切换的关系在协程暂停前后,以及协程唤醒前打印日志如图:

图6 协程暂停前后日志打印

图7 协程切换日志打印

为了说明协程产生了切换,在协程切换前打印协程上下文地址以及所在协程上下文地址:

图8 协程上下文日志打印

2.2 打印日志分析

添加上述日志之后,在虚拟机qemu日志里可获取如下日志信息:

情况1:压力较小时的一条IO数据下发

图9 一次IO下发逻辑日志打印

可以看出调用逻辑为两轮循环1:row_co_prw->laio_co_submit->ioq_submit->yield

上面的逻辑为异步IO提交数据,但没有获取到提交返回事件2:qemu_laio_completion_cb->qemu_laio_process_completions_and_submit->qemu_laio_process_completions->qemu_laio_process_completion->wake->blk_aio_complete

上面的逻辑为接受到异步IO返回的事件触发事件循环调用回调函数唤醒对应协程,向gues反馈IO下发状态,对应图3的逻辑流程。

情况2压力较小时的嵌套IO下发

图10 调用下半部事件的情况

由上面的日志可以看到日志图10与日志图9的区别是调用了blk_aio_complete_bh函数,具体为图2流程所描述情况

情况3压力较大时的IO下发:

图11 大量IO没有获取到返回状态

图12 依次切入到获取IO提交状态的协程中

上述日志验证的是图4说明的情况,大量IO没有得到相应,又同时有大量IO响应。

3 qemu IO中的fd

在qemu IO处理的逻辑中有三个fd;

1:异步IO 提交时使用的event_fd,该event_fd的个数跟事件循环中的context个数相关,一般为一个与提交的IO数量无关,该event_fd的作用为获取异步IO事件,其对应的回调函数qemu_laio_completion_cb

2:bh事件对应的bh_fd,该fb只有一个与主事件循环绑定一个事件循环一个bh_fd

3:磁盘设备的fd

还有一个fd为连接guest与host的fd,该fd的回调函数调用blk_co_pwritev,接受guest下发的信号

  • 30
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值