使用Python进行NVMe吞吐量测试

时间:2018-01-17 15:29:25

标签: python linux file-io nvme

目前我需要进行一些吞吐量测试。我的硬件设置是我有一个Samsung 950 Pro连接到NVMe控制器,该控制器通过PCIe端口连接到主板。我有一个Linux nvme设备对应于我在文件系统上的某个位置安装的设备。

我希望用Python来做到这一点。我打算在安装SSD的文件系统上打开一个文件,记录时间,将一些n长度的字节流写入文件,记录时间,然后使用os模块文件操作实用程序关闭文件。这是衡量写入吞吐量的函数。

def perform_timed_write(num_bytes, blocksize, fd):
    """
    This function writes to file and records the time

    The function has three steps. The first is to write, the second is to
    record time, and the third is to calculate the rate.

    Parameters
    ----------
    num_bytes: int
        blocksize that needs to be written to the file
    fd: string
        location on filesystem to write to

    Returns
    -------
    bytes_per_second: float
        rate of transfer
    """
    # generate random string
    random_byte_string = os.urandom(blocksize)

    # open the file
    write_file = os.open(fd, os.O_CREAT | os.O_WRONLY | os.O_NONBLOCK)        
    # set time, write, record time
    bytes_written = 0
    before_write = time.clock()
    while bytes_written < num_bytes:
        os.write(write_file, random_byte_string)
        bytes_written += blocksize
    after_write = time.clock()

    #close the file
    os.close(write_file)

    # calculate elapsed time
    elapsed_time = after_write - before_write

    # calculate bytes per second
    bytes_per_second = num_bytes / elapsed_time


    return bytes_per_second

我的其他测试方法是使用Linux fio实用程序。 https://linux.die.net/man/1/fio

将SSD安装在/ fsmnt / fs1后,我使用此作业文件测试吞吐量

;Write to 1 file on partition
[global]
ioengine=libaio
buffered=0
rw=write
bs=4k
size=1g
openfiles=1

[file1]
directory=/fsmnt/fs1

我注意到Python函数返回的写入速度明显高于fio的写入速度。因为Python是如此高级别,所以你放弃了很多控制。我想知道Python是否正在做一些事情来欺骗它的速度更高。有谁知道为什么Python会产生比fio生成的写入速度高得多的写入速度?

2 个答案:

答案 0 :(得分:1)

你的Python程序比你的fio工作更好的原因是因为这不是一个公平的比较,他们正在测试不同的东西:

  • 您禁止fio使用Linux的缓冲区缓存(使用buffered=0direct=1相同),告诉它执行O_DIRECT操作。根据您指定的作业,fio必须发送一个4k写入,然后等待该写入完成在设备(并且该确认必须一直返回到fio)才能进行可以发送下一个。

  • 在触摸SSD之前,允许您的Python脚本发送可以在多个级别缓冲的写入(例如,在C库的用户空间内,然后再在内核的缓冲区缓存中)。这通常意味着写入将被累积并合并在一起,然后发送到较低级别,从而产生具有较少开销的较大I / O.此外,由于您在理论上没有进行任何明确的刷新,因此在程序退出之前不必将I / O发送到磁盘(实际上这取决于许多因素,例如您执行的I / O数量, Linux可以为缓冲区预留的RAM量,文件系统保存脏数据的最长时间,等待I / O的时间等等!您的os.close(write_file)将变为fclose() which says this in its Linux man page

      

    请注意,fclose()仅刷新C库提供的用户空间缓冲区。为了确保数据物理存储在磁盘上,必须刷新内核缓冲区,例如,使用sync(2)或fsync(2)。

    事实上,在你致电os.close()之前,你需要花费最后的时间,所以你甚至可能会省略最后的批次&#34;数据仅发送到内核,更不用说SSD了!

你的Python脚本更接近这个fio工作:

[global]
ioengine=psync
rw=write
bs=4k
size=1g

[file1]
filename=/fsmnt/fio.tmp

即使这个fio仍然处于劣势,因为你的Python程序有用户空间缓冲(所以bs=8k可能更接近)。

关键的一点是你的Python程序并没有真正测试你指定的块大小的SSD的速度,你原来的fio工作有点奇怪,受到严格限制(libaio ioengine是异步的但是深度为1,在我们到达behaviour of Linux AIO when using filesystems之前,你无法从中受益,并且对你的Python程序做了不同的事情。如果与最大缓冲区的大小相比,你没有做更多的缓冲I / O(在Linux上,内核的缓冲区大小与RAM一致),如果缓冲的I / O很小,则运动转向示范缓冲的有效性。

答案 1 :(得分:0)

如果您需要NVMe设备的确切性能,fio是最佳选择。 FIO可以直接将测试数据写入设备,而无需任何文件系统。这是一个示例:

[global]
ioengine=libaio
invalidate=1
iodepth=32
time_based
direct=1
filename=/dev/nvme0n1

[write-nvme]
stonewall
bs=128K
rw=write
numjobs=1
runtime=10000

SPDK是另一种选择。在https://github.com/spdk/spdk/tree/master/examples/nvme/perf有一个性能测试的例子。

基于SPDK的

Pynvme是Python扩展。您可以使用其ioworker()编写性能测试。