固态硬盘:nvme 命令队列 sq/cq 的奥秘 -ag尊龙凯时

作者:ag尊龙凯时-尊龙凯时最新z6com 时间:2023-01-16 阅读数:127人阅读

#标题创作挑战#

  • 1.什么是sq和cq?
  • 2.有多少平方cq?
  • 3.如何更新新加坡/cq
  • 4.sq/cq执行流程
  • 主机和ssd如何同步队列信息?
  • 队列优先级
  • 摘要
  • nvme的速度(通过pcie)远远高于ahci的速度(通过sata)。其中一个重要原因是nvme的排队人数远远高于ahci。nvme的队列深度达到64k,支持的队列数量最大可达64k。ahci只有一个队列,队列深度只有32。作为nvme的重点,本文将介绍命令队列sq和cq。

    nvme定义了两种命令:管理命令和io命令。


    当主机想要发出管理命令时,它需要一个放置管理命令的队列。这个队列称为管理提交队列,简称为admin sq。

    当设备完成管理命令时,它将生成相应的完成响应。此时,它还需要一个队列来放置完成,这个队列被称为管理完成队列,简称为管理cq。

    同样,当执行io命令时,会有两个对应的队列,即io sq和io cq。

    nvme规范在管理服务区/cq和io服务区/cq上有不同的协议:

    只有一对管理sq/cq,最多可以有64k对io sq/cq。

    admin sq/cq的队列深度为2 ~ 4k;io sq/cq的队列深度为2~64k,受限于cap中报告的控制器支持的最大队列大小。mqes场。

    nvme 实际产品中, sq/cq 的数目一般是 128 组, 没有见到 64k 这么多个. 这可能是光记录这么多 sq/cq 信息, 也需要很多ram 吧. 使用 128 组sq/cq的速度已经是绰绰有余了.
    admin sq和cq是一对一的,而io sq和cq可以一对一,也可以多对一。3.如何更新新加坡/cq

    admin和io的sq/cq放在主机端的内存中;

    sq通过主机添加任务,cq通过nvme控制器添加信息。

    sq/cq是一个队列,因此应该有一个队列头和一个队列尾。每个队列都是一个fifo管道,由一个16位id值标识,该值是在创建队列时分配给队列的。nvme规范中定义的sq/cq都是循环队列,可以理解为一个圆(如下图所示),但实际内存很长(如下图所示)。


    tail: 指向队列中的下一个空位;head:指向下一个要执行的命令的位置。

    随着新消息添加到队列中,尾指针不断向前移动。因为内存是不变的,一旦指针移动到队列内存中的最后一个store 空,如果再移动就需要循环回到内存的开头。因此,内存实际上是作为一个环来回收的。

    当队列为空时,head==tail,尾指针和头指针指向同一位置;

    当队列为满时,head==tail 1; 尾指针的下一个指针是头指针, 可以看出队列中有一个槽位不能使用当你有sq来发布命令时,你为什么需要cq?
    cq可以实现异步处理,这样ssd就可以继续处理任务,而不需要等待主机检查上一条命令的处理结果。也方便了主机,发出命令后可以做其他事情。等到空在cq免费查询结果。

    为什么应该有一个以上的sq/cq
    原因有两个:
    原因一:如果你是边看视频边下载资源,方便主机设置优先级
    。当你被卡住的时候,你一定想看优先级更高的视频。拥有多个sq是一个优势。

    第二,ssd更有主动权选择一定的加权调度算法来执行命令(比如write sq执行几个read sq执行几个)。

    可以用sq/cq 执行命令吗?

    参照nvme规范中命令执行的过程,如下图所示:


    在nvme spec中command执行的流程有八步。(1)主机提交新命令。当主机发布新命令时,将其放入主机内存sq;

    (2)主机通知控制器提取命令。主机命令写入sq后,设备此时并不知道此事。因此,此时主机需要向控制器发送一条消息,通知nvme控制器:“您有一个新的命令请求”。这个过程是通过更新控制器内部的寄存器sq tail门铃来完成的。

    (3)nvme控制器从sq提取命令。取消命令后,需要在控制器内部的sq磁头指针寄存器中更新磁头的位置。nvme不指定存储在队列中的命令的执行顺序,控制器可以一次取出多个命令进行批处理。

    (4) nvme控制器执行从sq提取的命令。命令在队列中的执行顺序是不固定的(这可能导致请求先提交后处理),这涉及到nvme规范定义的命令仲裁机制。当执行读取/连线命令时,该过程也将与主机存储器传输数据。

    (5) nvme控制器将命令的完成状态写入cq。此时,控制器需要更新cq尾指针寄存器。

    (6)nvme控制器通知主机检查命令的完成状态。通过发送msi-x中断消息,控制器告诉主机:“我已经执行完了您提交的命令。请检查结果!”。

    (7)主持人在cq检查完工信息。

    (8)主机通知控制器完成信息已经被处理。这时,主持人在控制器内更新cq头门铃。告诉管制员:“你发回来的命令执行结果我已经知道了!”。

    执行nvme命令需要两种寄存器:门铃寄存器和指针寄存器。门铃,简称db,是nvme规范定义的寄存器;指针寄存器是由主制造商定义的寄存器。

    总共四个寄存器都放在控制器存储器中。也就是说,管制员知道sq tail/head和cq tail/head的所有信息。

    并且主机只知道它已经更新的两条信息sq tail和cq head。

    显然,主机和控制器之间的信息是不对等的。控制器如何通知主机sq头和cq尾的信息?

    将控制器sq头和cq尾的信息写入完成消息。sq头指针是sq头的信息。

    主持人怎么知道cq的尾巴位置?答案是通过相位标记位。


    p代表着phase tag bit。cq队列中所有的位置会被初始为0, 当有新的completion信息写入时,phase tag bit被置为1. host通过读取host 内存中cq的phase tag bit信息就能判断中cq tail的位置。在奇数轮(1,3,5 …)中,相位标记位从1变为0的位置是cq尾部位置。在偶数轮(2,4,6 …)中,相位从0变为1的位置是cq尾位置。

    io命令与admin命令的过程基本一致,主要区别是io命令也传输数据。

    nvme还定义了使用不同队列的调度策略,用于区分不同优先级的任务。管理队列具有最高优先级,而io队列可以定义绝对优先级或加权循环(wrr)调度策略。

    但是这个策略并不完美:
    在驱动中,每个cpu独占一个队列。但是如果按照队列的优先级来支持调度,就需要在应用层按照任务来划分队列,这两个需求是矛盾的。

    无论是绝对优先级还是wrr都不是符合用户直觉的方式,尤其是dba的使用习惯。

    本文介绍了nvme的关键点 sq/cq队列。我们分析了sq/cq的基本知识和工作流程,这对于我们理解主机和ssd之间的协作非常有帮助。这里只是一个基本的介绍,关于sq/cq的使用还有很多细节。

    阅读:
    谈nvme的多队列技术和io调度

    nvme系列的第二个话题:队列管理


    网站地图