Loading

CFQ 的问题分析一则(一)

最近在研究 blkio cgroup,想通过同时运行几个 dd 命令,测试不同 group 的速率。理想情况下,group 的速率与 blkio weight 成比例,但……

问题

Q. 使用 dd 命令读取文件,不同权重的 cgroup IO 速率一致

分析过程

不同 group 权重不同,但速率一致,首先想到 group 调度问题。

研究代码,cfq group 会在 block peek request -> expire queue 时重新计算调度时间,key 为 vt。

这里插一句,代码里的 key 是由 vt - min_vt 计算而来的,但插入时,rbtree 其他节点的 key 也要减去 min_vt 所以实际上 key 就是 vt。

Log 异常

Q1. 对 vt、vfr、next_vt 打点后,发现下次调度到这个 group 时,之前的 vt 被覆盖掉了。

Q2. queue 过期时显示已用时间片 sl_used 是 4ms,但从分配 queue 开始到 group 过期只有 0.Xms

Log 异常分析

A1. 研究全部 cfq log,发现 queue 和 group 会在下发请求后销毁。
从 blktrace log 分析,第二个 request 来的太迟 (0.7ms)。
导致 cfq queue 和 cfq group 在 queue expire 时被销毁了(0.1ms)。

A2. 选取下一个 req 时,还没有新 request,所以判断过期。
计算 sl_used 时,req 还没有返回,导致按 max(now-dispatch_time, jiffies2nsec(1))算。
因为 CONFIG_HZ=250 所以 sl_used 是 4ms。

这里为什么最小是 1 jiffies,因为磁盘慢,寻道时间不会太短。所以要把这个时间也算上。

结论

A. 对于低 weight 进程创建的请求,重新建立 group 会覆盖的之前算好的调度时间,使之偏前,导致速率一致。

解决方案

  1. 测试方面:使用异步同时下发多个请求
  2. 调参方面:调整 group_idle 参数,在 idle 时让 queue 和 group 空转,多等待下一个 request 一会儿。

总结

  1. cfq 调度时考虑寻道、sector 相邻之类的问题,在 flash 上完全没有必要,反而拖累正常调度。
  2. cfq 按机械硬盘估计时间,已经不适用于 flash。

附录 1: blktrace log

一个 request 的 blktrace log,包含其所在 cfq queue log。为了方便计算时间,把所有时刻都减去了一个值。

1. request remap,queue,getrq,plug,insert。以及分配 cfq group 和 queue
  8,32   0    11479    0.000039078 30588  A  RA 12102920 + 256 <- (253,9) 12102920
  8,32   0    11480    0.000039693 30588  A  RA 31304968 + 256 <- (259,36) 12102920
  8,32   0    11481    0.000041770 30588  Q  RA 31304968 + 256 [dd]
  8,32   0    11482    0.000050462 30588  G  RA 31304968 + 256 [dd]
  8,32   0    11483    0.000051308 30588  P   N [dd]
  8,32   0    11484    0.000056539 30588  I  RA 31304968 + 256 [dd]
  8,32   0        0    0.000059078     0  m   N cfq30588SN insert_request
  8,32   0        0    0.000060539     0  m   N cfq30588SN add_to_rr
  8,32   0        0    0.000063693     0  m   N cfq_group_notify_queue_add: vfr=1536 vt=521987226 minvt=521987176 key=50 nxtvt=521987176
  8,32   0    11485    0.000066078 30588  U   N [dd] 1
... expire actived queue

2. 调度该 request 所在的 cfq group 和 queue。最后 dispatch request。
  8,32   0        0    0.000079001     0  m   N cfq_get_next_cfqg: nowvt=521987226
  8,32   0        0    0.000080308     0  m   N cfq workload slice:37500000
  8,32   0        0    0.000081847     0  m   N cfq30588SN set_active wl_class:0 wl_type:1
  8,32   0        0    0.000085770     0  m   N cfq30588SN dispatch_insert
  8,32   0        0    0.000087616     0  m   N cfq30588SN dispatched a request
  8,32   0        0    0.000088847     0  m   N cfq30588SN activate rq, drv=2
  8,32   0    11486    0.000089231 30588  D  RA 31304968 + 256 [dd]

... insert another request

3. 因为中途没有 request 到来,所以 queue 为空,group 中只有这一个 queue。
driver 拿下一个 request 时,把当前 queue 废弃、销毁,一并销毁 group。
  8,32   1        0    0.000172001     0  m   N cfq30588SN slice expired t=0
  8,32   1        0    0.000175308     0  m   N cfq_group_served_add: oldvfr=1536 vfr=3510 vt=521998148 oldvt=521987226 minvt=521987226 key=10922 nxtvt=521987276
  8,32   1        0    0.000177231     0  m   N cfq30588SN sl_used=4,000,000ns disp=1 charge=1 iops=1 sect=256 sl_used=0.004000000s
  8,32   1        0    0.000181231     0  m   N cfq30588SN del_from_rr
  8,32   1        0    0.000181770     0  m   N del_from_rr group
  8,32   1        0    0.000182770     0  m   N cfq_group_notify_queue_del: nxtvt=521987276
... schedule another cfq queue

4. request 完成。
  8,32   1     8573    0.000564616 30582  C  RA 31304968 + 256 [0]
  8,32   1        0    0.000593231     0  m   N cfq30588SN complete rqnoidle 0
... other log

5. 该进程的下一个 request 到来。
  8,32   0    11489    0.000789231 30588  Q  RA 31305224 + 256 [dd]

参考链接

  1. blkio-controller.txt
  2. CFQ调度与blkio的权重控制
  3. cfq-iosched.txt
  4. linux io的cfq代码理解
  5. 一个IO的传奇一生(10)-- CFQ调度算法
  6. linux的CFQ调度器解析(1)
  7. linux的CFQ调度器解析(2)
  8. linux的CFQ调度器解析(3)
  9. Linux的IO调度
  10. linux IO Block layer 解析
  11. btrace.8
  12. blktrace.8
  13. blkparse.1
posted @ 2022-11-30 11:21  liuchao719  阅读(127)  评论(0编辑  收藏  举报