我用 VHDL 实现了自己的串行 ATA 主机总线适配器 (HBA),并将其编程到 FPGA 上。 FPGA是可以用任何数字电路进行编程的芯片。它还配备了串行收发器,可为 SATA 或 PCIe 生成高速信号。
该 SATA 控制器支持 SATA 6 Gb/s 线路速率,并使用 ATA-8 DMA-IN/OUT 命令与设备之间传输高达 32 MiB 块的数据。事实证明,该设计可以以最高速度运行(例如三星 SSD 840 Pro -> 超过 550 MiB/s)。
在对多个 SSD 和 HDD 设备进行一些测试后,我购买了一个新的 Seagate 6 TB Archive HDD(ST6000AS0002)。该硬盘的读取性能高达 190 MiB/s,但写入性能只有 30 到 40 MiB/s!
因此,我进行了更深入的研究并测量了传输的帧(是的,这可以通过 FPGA 设计实现)。据我所知,Seagate HDD 已准备好整体接收传输的前 32 MiB。此传输以 580 MiB/s 的最大线路速度进行。之后,HDD 将剩余字节停止超过800 毫秒!然后 HDD 准备好接收下一个 32 MiB,并再次停止 800 毫秒。总而言之,1 GiB 传输需要超过 30 秒,相当于大约 35 MiB/s。
我假设该 HDD 有一个 32 MiB 写入缓存,该缓存在突发周期之间刷新。小于 32 MiB 的数据传输不会显示此行为。
我的控制器使用 DMA-IN 和 DMA-OUT 命令来传输数据。我没有使用 QUEUED-DMA-IN 和 QUEUED-DMA-OUT 命令,这些命令由支持 NCQ 的 AHCI 控制器使用。在 FPGA 平台上实现 AHCI 和 NCQ 非常复杂,我的应用层不需要。
我想在我的 Linux PC 上重现此场景,但 Linux AHCI 驱动程序默认启用 NCQ。我需要禁用 NCQ,所以我找到了这个网站,描述了如何禁用 NCQ,但它不起作用。
Linux PC 仍达到 190 MiB/s 的写入性能。
> dd if=/dev/zero of=/dev/sdb bs=32M count=32
1073741824 bytes (1.1 GB) copied, 5.46148 s, 197 MB/s
我认为上面的文章有一个错误:将NCQ队列深度减少到1并不会禁用NCQ。它只允许操作系统仅使用一个队列。它仍然可以使用 QUEUED-DMA-** 命令进行传输。我需要真正禁用 NCQ,以便驱动程序向设备发出 DMA-IN/OUT 命令。
我的问题是:
- 如何禁用 NCQ?
- 如果 NCQ 队列深度 = 1,Linux 的 AHCI 驱动程序是否使用 QUEUED-DMA-** 或 DMA-** 命令?
- 我如何检查 NCQ 是否已禁用,因为
/sys/block/sdX/device/queue_depth
未在 中报告更改dmesg
?
答案1
感谢@frostschutz,我可以在没有 NCQ 功能的情况下测量 Linux 中的写入性能。内核启动参数libata.force=noncq
完全禁用了 NCQ。
关于我的希捷6TB写入性能问题,速度没有变化。 Linux 仍然达到 180 MiB/s。
但后来我有了另一个想法:
Linux 驱动程序不使用 32 MiB 块的传输。内核缓冲区要小得多,特别是在启用具有 32 个队列的 NCQ 时(32 个队列 * 32 MiB => 1 GiB AHCI 缓冲区)。
因此,我用 256 KiB 传输速度测试了 SATA 控制器,瞧,有可能达到 185 MiB/s。
所以我猜希捷 ST6000AS0002 固件无法处理大 ATA 突发传输。 ATA 标准允许最多 65.536 个逻辑块,相当于 32 MiB。
SMR - 叠瓦式磁记录
写入性能不佳的另一种可能性可能是叠瓦磁记录技术,希捷在这些存档设备中使用它。显然,我的 FPGA 实现触发了罕见的效果。
答案2
将队列深度设置为 1 ( /sys/block/sd*/device/queue_depth
) 将禁用 NCQ,无需使用内核参数libata.force=noncq
(只能在启动时设置)。
犯罪360f654e7cda850034f3f6252a7a7cff3fa77356
Date: Sat Sep 30 19:45:00 2006 +0900
[PATCH] libata: turn off NCQ if queue depth is adjusted to 1
Turn off NCQ if queue depth is adjusted to 1.