使用 Python 进行 NVMe 吞吐量测试

问题描述 投票:0回答:3

目前我需要做一些吞吐量测试。我的硬件设置是,我有一个连接到 NVMe 控制器的 Samsung 950 Pro,该控制器通过 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 生成的写入速度高得多?

python linux file-io nvme
3个回答
2
投票

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

  • 您通过告诉 fio 执行

    buffered=0
    操作来禁止 fio 使用 Linux 的缓冲区缓存(通过使用
    direct=1
    ,与说
    O_DIRECT
    相同)。对于您指定的作业,fio 将必须发送单个 4k 写入,然后等待该写入在设备上完成(并且该确认必须一路返回到 fio),然后才能发送下一个。

  • 在接触 SSD 之前,您的 Python 脚本可以发送可以在多个级别缓冲的写入(例如,在用户空间内由 C 库,然后再次在内核的缓冲区高速缓存中)。这通常意味着写操作将被累积并合并在一起,然后再发送到较低级别,从而产生更块的 I/O,开销更少。此外,由于理论上您不执行任何显式刷新,因此在程序退出之前无需将 I/O 发送到磁盘(实际上这取决于许多因素,例如您执行了多少 I/O、数量)。 Linux 可以为缓冲区预留 RAM 的大小、文件系统保存脏数据的最长时间、执行 I/O 的时间等)!你的
  • os.close(write_file)

    将变成

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

    事实上,您在调用

    os.close()
    之前花费了最后的时间,因此您甚至可能忽略了仅将最后“批次”数据发送到内核所花费的时间,更不用说 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,你不是能够从中受益,这是在我们了解

Linux AIO 使用文件系统时的行为

)并对 Python 程序执行不同的操作之前。如果与最大缓冲区的大小相比,您没有执行更多的缓冲 I/O(并且在 Linux 上,内核的缓冲区大小随 RAM 缩放),并且如果缓冲 I/O 很小,则练习将变成有效性的演示缓冲。

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

1
投票
[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
有一个现有的性能测试示例。

Pynvme

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

您可以使用 NVMe SSD 测试工具 Penetrate (

0
投票
) 来达到您的目的。 它使用 vfio 和用户空间驱动程序直接操作设备。有数据显示,在 Gen4 x4 SSD 和平台上,1 个 IOSQ 即可实现 1.1 MIOPS 随机读取性能,并将未完成命令数限制为 16 个。

© www.soinside.com 2019 - 2024. All rights reserved.