掌桥专利:专业的专利平台
掌桥专利
首页

一种NVMe固态硬盘测试模块及测试方法

文献发布时间:2023-06-19 13:46:35


一种NVMe固态硬盘测试模块及测试方法

技术领域

本发明涉及计算机存储测试的领域,特别是属于固态硬盘测试领域。

背景技术

现有的NVMe(non-volatile memory express缩写,非易失性内存主机控制器接口规范)固态硬盘测试程序(譬如fio),都是基于通用操作系统(Windows或者Linux)及其设备驱动程序,在内核态实现对NVMe固态硬盘的操作。如图1所示,用户态的测试脚本需要经过操作系统核心态的系统调用、虚拟文件系统、块设备驱动程序、NVMe驱动程序和PCIe驱动程序,才能最终将命令和数据送到被测固态硬盘。测试程序基于通用操作系统的内核驱动程序,导致如下问题:

1、性能损耗大。在测试IO(输入输出)到达NVMe固态硬盘之前,需要经过完整的操作系统内核态的存储软件堆栈,包括:系统调用,虚拟文件系统,块设备驱动程序,NVMe驱动程序等。现有操作系统的存储软件堆栈是在传统HDD的基础上设计并实现的,在性能上无法充分发挥NVMe固态硬盘高性能低延迟的特点。对于测试来说,这会导致:1)性能测试结果不准确。在一些测试项目上,驱动程序成为系统的性能瓶颈,无法反映待测NVMe设备的准确性能。2)测试效率低。现在NVMe固态硬盘越来越复杂,而开发周期越来越短,开发和测试的效率要求越来越高。3)无法实现大压力测试。受限于操作系统和驱动程序的性能瓶颈,测试程序产生的IO操作压力无法暴露NVMe盘在极大压力环境下的潜在问题。

2、通用操作系统及其NVMe驱动并没有实现NVMe协议要求的所有功能。在测试不同的NVMe固态硬盘时,经常会遇到一些新的功能在现有操作系统和驱动程序的基础上没有实现,因为有些功能在操作系统上的使用价值不大,没有实际的需求。

3、更长的开发周期和更难控制的质量管理。由于内核态的驱动程序开发和维护比较复杂,需要有操作系统内核的开发能力,且由于通用性的软件需要考虑到各个方面的需求,导致内核态测试驱动程序的研发存在不确定性。这个会进一步影响固态硬盘(SSD)产品的开发周期和质量控制。

发明内容

为解决上述技术问题,本发明的目的在于提供一种NVMe固态硬盘测试模块及其测试方法。

一种NVMe固态硬盘测试模块,其特征在于:该测试模块NVMe驱动模块、Python API接口和测试脚本单元三个部分;NVMe驱动模块可直接向被测NVMe固态硬盘发送命令和数据,Python API接口用于接收测试脚本单元的测试参数,并调用NVMe驱动模块的功能,测试脚本单元通过Python API接口及NVMe驱动模块实现对NVMe固态硬盘基于用户态的测试。

一种实施方式中,所述NVMe驱动模块包括NVMe底层模块和IO普通操作模块;NVMe底层模块是一个高性能、低延迟的NVMe协议的实现,提供了NVMe协议中定义的队列和命令的基本操作,IO普通操作模块与Python API接口连接,根据测试参数,通过调用NVMe底层模块的基本操作,实现向被测NVMe固态硬盘发送命令和数据,并回收命令的状态。

所述的NVMe协议中定义的队列和命令的基本操作包括:创建队列、发送命令和回收命令的状态。

所述NVMe底层模块中提供测试专用的功能,用来保证读写数据的一致性,以及方便用户调试测试脚本。

所述的测试专用功能包括:在写每一个LBA的时候,计算数据的CRC奇偶校验值,并将每个LBA的CRC校验值保存在系统内存中;在读任意一个LBA时,计算所读到数据的CRC奇偶校验值,并将其和系统内存中记录的相应LBA的CRC校验值做比较,保证数据读写的一致性;在发送命令的时候,将命令的SQE数据结构和时间戳记录到命令列表中;在回收命令后,将回收的CQE数据结构和时间戳记录到命令列表中;用户在测试脚本运行时,通过查看命令列表,可以理解测试脚本的行为,帮助调试测试脚本。

另一种实施方式中,所述的测试模块,在Python API接口和IO普通操作模块之间还包括IO代理操作模块,该IO代理操作模块供各种规则模板,根据用户脚本单元提供的规则参数产生具体的规则或者规则集合,并自发地产生负责规则要求的命令序列,IO代理操作模块通过IO普通操作模块发送命令序列里的每一个命令并回收命令状态。

进一步的,IO代理操作模块在收到规则参数后,会创建一个子进程,在这个子进程中根据规则参数来发送每一个命令。

其他实施方式中,NVMe驱动模块包括IO元数据操作模块、Buffer模块和PCIe模块;Buffer模块可以获取物理地址空间的内存,并读写这些物理内存;PCIe模块提供PCIe配置地址空间和PCIe内存地址空间的访问能力;IO元数据操作模块在物理内存中构造元数据,并向PCIe内存地址空间发出doorbell,实现对测试盘的命令发送,以及命令状态的回收。

此外,也可将三种NVMe驱动模块实施方式组合在一个测试模块中,根据测试场景不同,单独或综合使用。

本发明还公开了利用前述NVMe固态硬盘测试模块进行硬盘测试的方法:

第一步,测试脚本单元通过Python API接口调用PCIe驱动程序,将NVMe固态硬盘作为PCIe设备进行枚举,分配内存地址空间;

第二步,测试脚本单元通过Python API接口访问NVMe固态硬盘的PCIe内存地址空间中的NVMe寄存器,初始化NVMe固态硬盘,并调用NVMe驱动模块,建立发送命令和数据所必须的命令队列和回收队列;

第三步,测试脚本单元通过Python API调用NVMe驱动模块,通过读写命令队列和回收队列,向NVMe固态硬盘发送命令和数据,并获得命令的返回状态和数据;

第四步,测试脚本单元检查命令返回的状态和数据是不是符合期望,得到测试结果;

第五步,测试脚本单元通过Python API接口释放命令队列和回收队列,并释放PCIe设备的内存地址空间,测试结束。

有益效果

本发明与现有技术相比,具有以下几个优点:1、在用户态中实现NVMe固态硬盘测试专用的驱动单元,避免操作系统引入的开销,提高测试的效率及准确性;2、提供高性能、低延迟和稳定的IO序列,保障测试的准确、效率和压力;3、可以实现NVMe固态硬盘所有技术规格的测试,保证测试的覆盖率;4、通过Python API提供驱动程序的接口,提高测试脚本的开发效率。

附图说明

图1是现有的NVMe固态硬盘测试程序

图2是本发明NVMe固态硬盘测试程序

图3是本发明普通方式NVMe驱动模块

图4是本发明代理方式NVMe驱动模块

图5是本发明元数据方式NVMe驱动模块

具体实施方式

下面结合附图对本发明的具体实施方式进行详细的说明。如图2所示,本发明实现了一个用户态的NVMe固态硬盘测试专用驱动模块和测试方法,该模块包括NVMe驱动模块、Python API接口和测试脚本单元三个模块。NVMe驱动模块可直接向NVMe固态硬盘发送命令和数据。Python API接口调用NVMe驱动模块的功能,并封装成Python二进制库。测试脚本单元通过调用Python API接口实现NVMe固态硬盘的测试策略。本发明依然利用操作系统核心态中的PCIe驱动程序,实现PCIe设备的枚举和内存地址空间的映射。在完成PCIe内存地址空间映射之后,本发明的用户态NVMe驱动模块可以直接访问NVMe固态硬盘的寄存器,因此在初始化完成之后,NVMe驱动模块向NVMe寄存器发送命令和数据是不依赖核心态的PCIe驱动程序的。

测试方法包括以下步骤:

第一步,测试脚本单元通过Python API接口调用PCIe驱动程序,将NVMe固态硬盘作为PCIe设备进行枚举,分配内存地址空间。

第二步,测试脚本单元通过Python API接口访问NVMe固态硬盘的PCIe内存地址空间中的NVMe寄存器,初始化NVMe固态硬盘,并调用NVMe驱动模块,建立发送命令和数据所必须的命令队列和回收队列。NVMe固态硬盘初始化的流程由测试脚本单元定义。(一般的驱动程序直接实现了NVMe固态硬盘的初始化,本发明将初始化的过程通过测试脚本实现,提高测试的覆盖率。)

第三步,测试脚本单元通过Python API调用NVMe驱动模块,通过读写命令队列和回收队列,向NVMe固态硬盘发送命令和数据,并获得命令的返回状态和数据。

第四步,测试脚本单元检查命令返回的状态和数据是不是符合期望,得到测试结果。

第五步,测试脚本单元通过Python API接口释放命令队列和回收队列,并释放固态硬盘的内存地址空间,测试结束。

SSD(固态硬盘)测试的主要工作是IO操作,包括发送命令和数据,并回收命令状态。针对不同的测试需求,本发明提供了3种不同的IO操作方式:普通方式,代理方式,元数据方式。这3种方式各有特点:普通方式简单易用,代理方式有非常高的性能,元数据方式应用范围广。用户在开发测试脚本时根据不同的测试需求,灵活选用不同的IO操作方式,也可以多种IO操作方式组合使用。

实施例1

如图3所示,本发明的NVMe驱动模块包含一个底层的NVMe底层模块,和上层的IO普通操作模块。NVMe底层模块是一个高性能、低延迟的NVMe协议的实现,提供了NVMe协议中定义的队列操作,以及在队列上发送并回收命令的操作,具体过程如下:1.创建队列,包括SQ发送队列和CQ完成队列;2.构造命令的SQE结构,并填入SQ发送队列;3.发出doorbell,通知NVMe固态硬盘测试设备从SQ获取SQE(DUT执行相应操作,操作完成后构造CQE并填入CQ完成队列);4.从CQ完成队列中获取CQE结构,回收命令的状态。

IO普通操作模块通过NVMe底层模块向NVMe固态硬盘发送命令和数据,并同时实现了对数据的一致性检查和命令的跟踪记录。具体包括:1.在写每一个LBA的时候,计算数据的CRC奇偶校验值,并将每个LBA的CRC校验值保存在系统内存中;2.在读任意一个LBA时,计算所读到数据的CRC奇偶校验值,并将其和系统内存中记录的相应LBA的CRC校验值做比较,保证数据读写的一致性;3.在发送命令的时候,将命令的SQE数据结构和时间戳记录到命令列表中;4.在回收命令后,将回收的CQE数据结构和时间戳记录到命令列表中;5.用户在测试脚本运行时,通过查看命令列表,可以理解测试脚本的行为,帮助调试测试脚本。

IO普通操作模块通过调用上述NVMe底层模块的基本操作,实现向测试盘发送命令和数据,并回收命令的状态。发送命令的具体过程如下:1.申请Buffer,用来存放命令的数据;2.申请发送队列和回收队列;3.获取用户脚本提供的命令的起始LBA地址和LBA长度;4.获取用户脚本提供的Python回调函数;5.将步骤1-4中的数据提供给NVMe底层模块,发出一个命令;6.记录命令的完整数据结构。

发送命令之后,NVMe底层模块不等待命令完成,而是由IO普通操作模块后续调用NVMe底层模块来回收命令的状态。回收IO的具体过程如下:1.监视回收队列是否有新的CQE填入,如有,则获取一条CQE;2.通过CQE内的数据,找到对应的已发送命令;3.将CQE内的状态信息更新到该命令;4.调用命令绑定的Python回调函数,并作为参数提供CQE内的状态信息;5.记录命令返回状态的完整数据结构;6.如果是写命令,计算写入数据的CRC并按照LBA地址索引保存到系统内存;7.如果是读命令,计算读取数据的CRC,并和内存中保存的对应LBA的CRC做比较;8.如需要回收更多IO,跳转到第1步。

利用本实施例驱动模块进行测试时,执行以下步骤:

第一步,测试脚本单元通过Python API接口调用PCIe驱动程序,将NVMe固态硬盘作为PCIe设备进行枚举,分配内存地址空间。

第二步,测试脚本单元通过Python API接口访问NVMe固态硬盘PCIe内存地址空间中的NVMe寄存器,初始化NVMe固态硬盘,并调用IO普通操作模块,建立发送命令和数据所必须的命令队列和回收队列。

第三步,测试脚本单元通过Python API调用IO普通操作模块生成NVMe命令的数据结构,并提供命令的回调函数。

第四步,IO普通操作模块,将NVMe命令的数据结构和回调函数提供给NVMe底层模块,NVMe底层模块将命令的数据结构写入命令队列,并通过写固态硬盘的NVMe寄存器中的doorbell寄存器通知固态硬盘有新的命令被发送到命令队列。

第五步,IO普通操作模块计算写数据的CRC,并保存在系统内存中。

第六步,测试脚本单元通过Python API调用IO普通操作模块,IO普通操作模块调用NVMe底层模块轮询返回队列,并通过返回队列获得NVMe固态硬盘返回的命令状态。

第七步,NVMe底层模块通过IO普通操作模块提供的回调函数将命令返回状态返回给IO普通操作模块。

第八步,IO普通操作模块计算并比较读数据的CRC。

第九步,IO普通操作模块通过测试脚本单元提供的回调函数,将命令返回状态返回给测试脚本单元;测试脚本单元检查命令返回的状态和数据是不是符合期望,得到测试结果。

第十步,测试脚本单元通过Python API接口释放命令队列和回收队列,并释放固态硬盘的内存地址空间,测试结束。

实施例2

用户脚本通过IO普通操作模块可以很方便地开发IO测试脚本,但是如果要发送大量IO,需要反复调用Python API,影响性能。如图4所示。在IO普通操作模块之上增加IO代理操作模块,可解决这个问题,实现高性能大压力的测试场景。IO代理操作模块提供各种规则模板,根据用户脚本提供的规则参数产生具体的规则或者规则集合,并自发地产生负责规则要求的命令序列。IO代理操作模块通过IO普通操作模块发送命令序列里的每一个命令并回收命令状态。

IO代理操作模块提供的规则有:1.IO序列的起始LBA地址和结束LBA地址,每一个IO的LBA地址都必须在这个地址区间里面;2.LBA地址顺序递增,或是随机地址;3.IO序列的LBA地址递增间隔;4.IO操作的类型及其百分比:如读,或者写,或者读写混合;5.IO的数据样式:譬如全0,全1,或者随机数据;6.IO队列的深度和优先级;7.IO序列的持续时间或者数量,等等。

通过组合上述IO操作的规则,可以实现实际业务中向NVMe固态硬盘发出的IO序列。譬如,组合规则1,2,3,4,7,可以产生满足ZNS固态硬盘(NVMe固态硬盘的一种特殊实现,只能在各个区间内顺序写,不能随机写)要求的IO序列:规则1,起始地址是0,结束地址是999;规则2,LBA地址顺序递增;规则3,LBA地址递增间隔是100;规则4,100%写;规则7,发送50个IO。

在这个规则组合之下,产生的IO序列是:(从左到右,从上到下)

这个IO序列满足ZNS固态硬盘的要求,并实现了多个区域并发的高性能写入测试。

代理方式的IO操作在发送和回收一系列命令的过程中,会统计一些数据和状态,具体包括:发送IO的总时间和总个数;运行期间的每秒IOPS性能数据;IO响应时间的计数分布;运行状态和错误码等。

IO代理操作模块在收到规则参数后,会创建一个子进程,在这个子进程中根据规则参数来发送每一个命令,具体过程如下:1.在主进程中,测试脚本通过Python API接口,创建新的代理方式的IO操作请求,并提供各个规则的参数;2.IO代理操作模块创建子进程,并通过队列把规则参数传递给该子进程;3.子进程创建发送队列和回收队列;4.子进程创建用于命令的数据Buffer;5.子进程计算一个命令的参数:如起始LBA地址,LBA个数,命令的类型,发送命令的时间等,将其加入待发送命令列表;6.重复步骤5,直至填满发送队列的所有深度;7.子进程通过调用IO普通操作模块,将待发送命令列表中的每一个命令都发出;8.子进程通过调用IO普通操作模块,回收一笔或者多笔命令;9.子进程收集命令的响应时间、返回状态等信息,添加到统计数据中;10.在回收命令的回调函数中,计算一个新命令的参数,将其加入待发送命令列表;11.如果发送命令的时间或者个数还没有达到规则参数指定的时间或者个数,跳转到步骤7;12.子进程释放发送队列和回收队列;13.子进程释放所有数据Buffer;14.子进程通过队列把统计数据返回主进程;15.测试脚本通过Python API接口获得返回的统计数据。

测试脚本单元可以同时发起多个代理方式的IO操作请求,每个请求会创建自己的子进程,相互独立。

该实施方式下NVMe固态硬盘测试方法如下:

第一步,测试脚本单元通过Python API接口调用PCIe驱动程序,将NVMe固态硬盘作为PCIe设备进行枚举,分配内存地址空间。

第二步,测试脚本单元通过Python API接口访问固态硬盘PCIe内存地址空间中的NVMe寄存器,初始化NVMe固态硬盘。

第三步,测试脚本单元通过Python API调用IO代理操作模块,提供各个规则参数。

第四步,IO代理操作模块创建新的进程。

第五步,IO代理操作模块在新进程中调用IO普通操作模块,创建命令队列和回收队列。

第六步,IO代理操作模块根据规则,计算IO序列,包括IO的起始地址,长度和操作类型。

第七步,IO代理操作模块调用IO普通操作模块生成NVMe命令的数据结构,并提供命令的回调函数。

第八步,IO普通操作模块将NVMe命令的数据结构和回调函数提供给NVMe底层模块,NVMe底层模块将命令的数据结构写入命令队列,并通过写固态硬盘的NVMe寄存器中的doorbell寄存器通知固态硬盘有新的命令被发送到命令队列。

第九步,IO普通操作模块计算写数据的CRC,并保存在系统内存中。

第十步,IO代理操作模块调用IO普通操作模块,IO普通操作模块调用NVMe底层模块轮询返回队列,并通过返回队列获得NVMe固态硬盘返回的命令状态。

第十一步,NVMe底层模块通过IO普通操作模块提供的回调函数将命令返回状态返回给IO普通操作模块。

第十二步,IO普通操作模块计算并比较读数据的CRC。

第十三步,IO普通操作模块通过IO代理操作模块提供的回调函数,将命令返回状态返回给IO代理操作模块。IO代理操作模块检查命令返回的状态和数据是不是符合期望。

第十四步,IO代理操作模块检查IO序列,若还有IO没有被发送,跳转到第七步重复执行。

第十五步,IO代理操作模块调用IO普通操作模块,释放命令队列和返回队列。

第十六步,IO代理操作模块销毁子进程;

第十七步,测试脚本单元通过Python API接口调用IO代理操作模块,获得统计数据和状态;

第十八步,测试脚本单元通过Python API接口释放固态硬盘的内存地址空间,测试结束。

实施例3

如图5所示。IO普通操作模块和IO代理操作模块都基于NVMe底层模块,而NVMe底层模块直接构造了元数据:发送队列,回收队列,SQE/CQE,PRP,doorbell等。所以,测试脚本单元无法通过这两种IO操作方式来控制这些元数据,这会影响NVMe固态硬盘测试的覆盖率。NVMe底层模块对IO操作的具体限制有:1.只能构造合法的PRP;2.不能修改SQE的每一个字段;3.只能1个SQ绑定1个CQ;4.SQ和CQ的队列深度有限制;5.IO的数据长度限制;6.每个IO之后都会发一个doorbell。

本实施例在驱动模块中设计了一个IO元数据操作模块,如图5所示。Buffer模块可以获取物理地址空间的内存,并读写这些物理内存。PCIe模块提供PCIe配置地址空间和PCIe内存地址空间的访问能力。IO元数据操作模块在物理内存中构造元数据,并向PCIe内存地址空间发出doorbell,实现对测试盘的命令发送,以及命令状态的回收。具体过程如下:1.通过Buffer模块申请发送队列的buffer;2.在发送队列的buffer中构造发送队列数据结构;3.通过Buffer模块申请回收队列的buffer;4.在回收队列的buffer中构造回收队列数据结构;5.通过Buffer模块申请发送命令的数据buffer;6.获取数据buffer的物理地址;7.构造发送命令的SQE数据结构;8.将步骤6中的物理地址填入SQE的PRP字段;9.将命令操作符、地址等数据填入SQE;10.将SQE填入发送队列;11.获取发送队列的新的tail,并填入测试盘对应的发送队列的doorbell;12.监视回收队列中是否有新的CQE填入,若有,则获取新的CQE;13.将CQE交给测试脚本单元检查命令状态。IO元数据操作模块完全不需要依赖NVMe底层模块,因此能避免所有上述NVMe底层模块的所有限制,提高了测试脚本的覆盖率。

利用本实施例测试模块进行测试时,执行以下步骤:

第一步,测试脚本单元通过Python API接口调用PCIe模块,将NVMe固态硬盘作为PCIe设备进行枚举,分配内存地址空间。

第二步,测试脚本单元调用Python API接口通过PCIe模块访问固态硬盘的PCIe内存地址空间中的NVMe寄存器,初始化NVMe固态硬盘,使得测试脚本单元有能力直接访问NVMe寄存器。

第三步,测试脚本单元通过Python API接口调用Buffer模块,申请物理内存。

第四步,测试脚本单元在物理内存上自行构造发送队列和回收队列。

第五步,测试脚本单元自行构造命令的完整数据结构,并填入发送队列。

第六步,测试脚本单元调用Python API接口通过PCIe模块访问固态硬盘的NVMe寄存器,写doorbell,通知NVMe固态硬盘有新的命令被填入命令队列。

第七步,测试脚本单元调用Python API接口通过Buffer模块检查返回队列;当有新的命令返回后,获取返回状态的完整数据结构。

第八步,测试脚本单元调用Buffer模块释放物理内存上定义的命令队列和回收队列。

第九步,测试脚本单元检查命令返回的状态和数据是不是符合期望,得到测试结果。

第十步,测试脚本单元调用Python API接口通过PCIe模块释放PCIe设备的内存地址空间,测试结束。

此外,也可将三种NVMe驱动模块实施方式组合在一个测试模块中,根据测试场景不同,单独或综合使用。

说明书中英文缩写的含义解释如下:

NVMe:non-volatile memory express缩写,非易失性内存主机控制器接口规范IO:输入输出

DUT:device under test,被测设备

HDD:机械硬盘

SSD:固态硬盘

Python:Python编程语言

API:应用程序编程接口

PCIe:快速外设组件互连标准

SQ:发送队列

CQ:回收队列

PRP:physical region page,物理内存页指针。指向一个物理内存页,是一种传输数据时用到的散列机制(用一种数据结构记录分散的物理内存的地址)

LBA:Logical Block Address,逻辑区块地址

CRC:循环冗余校验码。用于检查数据的一致性。

Buffer:数据缓冲,用于在主机端保存输入输出请求的数据。

SQE:发送队列项,发送命令的数据结构

CQE:回收队列项,回收状态的数据结构

Doorbell:门铃。主机和NVMe设备之间相互通知对方,SQ和CQ里面有新的SQE和CQE需要处理。

以上仅为发明的优选实施例而已,并不用以限制本发明,凡在本发明的思想原则内所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。

技术分类

06120113808046