1

目前我需要做一些吞吐量测试。我的硬件设置是三星 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

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

;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 生成的写入速度高得多?

4

2 回答 2

2

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

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

  • 在接触 SSD 之前,允许您的 Python 脚本向下发送可以在多个级别缓冲的写入(例如,在 C 库的用户空间内,然后再次在内核的缓冲区缓存中)。这通常意味着写入将被累积并合并在一起,然后再发送到较低级别,从而导致更粗的 I/O 具有更少的开销。此外,由于理论上您没有进行任何显式刷新,因此在程序退出之前不必将 I/O 发送到磁盘(实际上这将取决于许多因素,例如您执行多少 I/O、数量RAM Linux 可以留出缓冲区、文件系统保存脏数据的最长时间、您执行 I/O 的时间等)!您将在其 Linux 手册页中os.close(write_file)变成这样:fclose()

    请注意, 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 工作有点奇怪,受到严格限制(libaioioengine 是异步的,但深度为 1 你将无法要从中受益,那是在我们了解Linux AIO 在使用文件系统时的行为之前)并对你的 Python 程序做不同的事情。如果与最大缓冲区的大小相比,你没有做更多的缓冲 I/O(在 Linux 上,内核的缓冲区大小与 RAM 成比例)并且如果缓冲 I/O 很小,那么练习就变成了有效性的演示的缓冲。

于 2018-02-04T11:08:56.777 回答
1

如果您需要 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() 编写性能测试。

于 2019-01-11T16:00:35.687 回答