☰
iMX8嵌入式存储性能测试实战:eMMC与SD卡读写IOPS优化指南
2026/10/15 20:05:00 网站建设 项目流程

1. 为什么存储性能测试值得单独拎出来做

拿到一块 iMX8 的板子,大多数人第一反应是跑个 CPU 跑分、看看 GPU 渲染帧率,存储这块往往被一句“能启动就行”带过。但实际做过嵌入式项目的人都知道,存储性能才是决定系统响应速度和长期稳定性的隐形天花板。你系统启动慢、应用加载卡顿、数据库写入延迟高,很多时候不是 CPU 算力不够,而是 eMMC 或 SD 卡的读写带宽和 IOPS 拖了后腿。

iMX8 系列覆盖了从 iMX8QuadMax 到 iMX8M Mini 等多个型号,不同型号支持的存储接口差异很大——有的支持 eMMC 5.1 HS400,有的只到 HS200,SD 卡控制器版本也不一样。再加上实际板子上用的存储芯片品牌、容量、工艺批次不同,标称参数和实测结果之间经常有肉眼可见的差距。所以,存储性能测试不是走个过场,而是硬件选型、系统调优、量产验证三个环节都绕不开的硬功夫。

这篇内容适合谁看?如果你正在做 iMX8 平台的 BSP 移植、系统裁剪、应用性能优化,或者你是个刚接触嵌入式 Linux 的开发者,想搞清楚怎么科学地测一块板子的存储到底行不行,那接下来的内容应该能帮你省下不少翻文档和踩坑的时间。我会从测试方案设计、工具选型、实操步骤、数据解读到问题排查,把整个流程拆开讲清楚。

2. 测试方案的整体设计与思路拆解

2.1 先搞清楚你要测什么

存储性能测试不是跑一个 dd 命令看个数字就完事了。你得先明确测试目标:是测顺序读写带宽,还是随机读写 IOPS,还是混合读写场景下的延迟表现?这三个指标对应的实际场景完全不同。

顺序读写主要影响大文件传输、固件升级、视频录制这类连续数据流场景。随机读写 IOPS 则直接决定了系统启动时加载大量小文件的速度、数据库事务处理能力、以及应用冷启动的响应时间。混合读写更贴近真实使用——系统运行时既有日志写入又有配置读取,还有缓存刷新。

对于 iMX8 平台,我一般建议至少覆盖以下几个维度:

  • eMMC 顺序读/写带宽(块大小 128KB 到 1MB)
  • eMMC 随机读/写 IOPS(块大小 4KB,队列深度 1 到 32)
  • SD 卡顺序读/写带宽(对比不同 UHS 模式)
  • 文件系统层性能(ext4、f2fs、squashfs 等不同格式的差异)
  • 长时间写入稳定性(持续写入 30 分钟以上看是否降速)

2.2 测试工具怎么选

嵌入式 Linux 下测存储性能,常用的工具就那么几个,但各有各的适用场景和坑。

dd是最简单的,几乎每个 BusyBox 里都有。但它的问题也很明显:默认只做顺序读写,而且受 page cache 影响极大,不绕过缓存的话测出来的数字好看但不真实。用iflag=direct和oflag=direct可以绕过缓存,但 BusyBox 的 dd 不一定支持这些 flag,得用完整版 coreutils 的 dd。

fio是功能最全的,支持顺序、随机、混合读写,能控制队列深度、块大小、运行时长,还能输出详细的延迟分布。但 fio 在嵌入式平台上编译需要依赖 libaio,而且运行时会占用一定 CPU 资源,在低端 iMX8M Mini 上可能影响测试结果。建议在 iMX8QuadMax 或 iMX8QuadXPlus 这类性能富余的型号上跑 fio,Mini 上可以用简化配置。

hdparm主要用于测硬盘,对 eMMC 和 SD 卡的支持有限,不太推荐。

bonnie++适合测文件系统层性能,但需要较大的测试空间和较长的运行时间,适合做对比测试而非快速验证。

iozone功能全面但操作复杂,在嵌入式环境下编译和运行都比较重。

我的建议是:快速验证用 dd + direct IO,深度分析用 fio,文件系统对比用 bonnie++。下面这张表可以帮你快速决策:

工具适用场景优点缺点
dd快速顺序读写验证简单、随处可用功能单一、易受缓存影响
fio全面性能分析灵活、指标详细编译依赖多、占CPU
bonnie++文件系统对比贴近实际文件操作耗时长、占空间大
iozone综合基准测试项丰富操作复杂、资源占用高

2.3 测试环境搭建的关键考量

测试之前,有几个环境因素必须先固定下来,否则数据没有可比性。

CPU 调频策略:iMX8 默认的 cpufreq governor 可能是 ondemand 或 schedutil,频率会动态变化。测试存储性能时,CPU 频率波动会影响中断处理和数据处理速度,建议临时把 governor 设为 performance,锁定最高频率。命令是echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor,对每个核心都执行一遍。

温度控制:eMMC 和 SD 卡在高温下会触发热保护降速。如果板子没有散热片,连续测试几分钟后温度可能就上去了。建议测试前确认散热条件,必要时加个小风扇或者间隔测试。

后台负载:确保测试期间没有其他进程在大量读写存储。可以用iostat或vmstat先观察一下基线负载。另外,系统日志服务可能会周期性写盘,测试前最好临时停掉或者把日志级别调高。

文件系统状态:新格式化的分区和用了一段时间的分区,性能表现可能不同。eMMC 的 FTL 层需要一定时间来建立映射表,刚擦除的块写入性能可能偏低。建议先做一次全盘写入预热,再开始正式测试。

3. 核心细节解析与实操要点

3.1 eMMC 与 SD 卡的接口差异

iMX8 的 eMMC 接口通常走 uSDHC 控制器,支持到 HS400 模式,理论带宽 400MB/s(8 位总线,200MHz 时钟,双沿采样)。但实际能跑到多少,取决于几个因素:eMMC 芯片本身是否支持 HS400、PCB 走线信号完整性、以及 BSP 里的时序配置是否正确。

SD 卡这边,iMX8 一般支持到 UHS-I SDR104,理论带宽 104MB/s。但注意,SD 卡控制器和 eMMC 控制器可能是同一个 uSDHC 的不同实例,共享带宽资源。如果你同时挂了一个高速 eMMC 和一个 SD 卡,两者同时读写时可能互相影响。

检查当前接口模式的命令:

# 查看 eMMC 当前速度模式 cat /sys/kernel/debug/mmc0/ios # 查看 SD 卡当前速度模式 cat /sys/kernel/debug/mmc1/ios

输出里会显示clock、bus width、timing spec等字段。如果 timing spec 显示的是mmc hs200而不是mmc hs400,说明要么芯片不支持,要么配置没生效。这时候测出来的带宽上限就被卡在 200MB/s 了。

3.2 块大小与队列深度的选择逻辑

块大小(block size)直接决定了单次传输的数据量和命令开销的比例。块太小,命令开销占比高,带宽上不去;块太大,对于随机读写场景又不现实,因为实际应用很少一次读写 1MB 的随机数据。

对于顺序读写测试,我一般从 4KB 开始,逐步增加到 1MB,观察带宽变化曲线。通常在 128KB 到 256KB 之间会达到峰值,再大就趋于平缓。对于随机读写,固定 4KB 块大小,因为这是大多数文件系统和数据库的默认页大小。

队列深度(queue depth)影响的是控制器的并发处理能力。eMMC 5.1 支持命令队列(CQ),可以同时处理多个读写请求。队列深度设为 1 时,测的是单命令延迟;设为 32 时,测的是控制器的并发吞吐能力。实际应用中,文件系统的 readahead 和 writeback 机制会自然形成一定的队列深度,所以测试时至少覆盖 QD1 和 QD32 两个点。

3.3 绕过缓存与不绕过缓存的区别

这是最容易踩坑的地方。Linux 的 page cache 会把最近读写的数据缓存在内存里,如果你用 dd 不加 direct flag,第二次读同一块数据时可能直接从内存返回,测出来的“读带宽”其实是内存带宽,能到几个 GB/s,完全失真。

写测试更隐蔽:dd 写数据时,数据先写到 page cache 就返回了,实际还没落到存储上。你以为写完了,其实后台还在慢慢刷。要测真实写入性能,必须用oflag=direct绕过缓存,或者写完后执行sync并计时。

但 direct IO 也有代价:它要求块大小和偏移量按扇区对齐,而且对于某些文件系统,direct IO 的性能可能比 buffered IO 还差,因为失去了合并和预读的优化。所以我的做法是:顺序读写用 direct IO 测真实带宽,随机读写用 buffered IO 加 fio 的 fsync 控制来测实际 IOPS。

3.4 测试数据的可重复性保障

存储性能测试最怕的就是数据不可重复。同样的板子,今天测出来写 150MB/s,明天变成 120MB/s,你就不知道是板子有问题还是测试方法有问题。

保证可重复性的几个要点:

  • 每次测试前清空 page cache:echo 3 > /proc/sys/vm/drop_caches
  • 使用固定大小的测试文件,提前用dd或fio创建好
  • 测试文件放在独立分区,避免和其他数据混在一起
  • 记录测试时的环境温度、CPU 频率、内核版本
  • 每个测试项至少跑 3 次,取平均值和标准差

注意:drop_caches只清 page cache 和 dentry/inode cache,不影响 eMMC 内部的缓存。eMMC 芯片自己也有缓存,连续测试时后面的结果可能受前面影响。建议每个测试项之间间隔 30 秒以上,让存储芯片有时间完成内部垃圾回收。

4. 实操过程与核心环节实现

4.1 环境准备与基线检查

先确认系统信息,把该记录的都记录下来:

# 内核版本 uname -a # 查看存储设备 lsblk cat /proc/partitions # 查看 eMMC 详细信息 cat /sys/block/mmcblk0/device/name cat /sys/block/mmcblk0/device/manfid cat /sys/block/mmcblk0/device/serial # 查看当前速度模式 cat /sys/kernel/debug/mmc0/ios

然后锁定 CPU 频率:

for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do echo performance > $cpu done

检查当前频率是否生效:

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

4.2 用 dd 做快速顺序读写测试

先创建一个测试文件,大小建议 512MB 到 1GB,太小了统计意义不够,太大了测试时间太长:

# 创建测试文件(buffered 写入,先不测性能) dd if=/dev/zero of=/data/testfile bs=1M count=512 conv=fsync

然后清缓存,做 direct 读测试:

sync echo 3 > /proc/sys/vm/drop_caches # 顺序读测试 dd if=/data/testfile of=/dev/null bs=1M count=512 iflag=direct

记录输出中的速度值。重复 3 次,取平均。

写测试:

sync echo 3 > /proc/sys/vm/drop_caches # 顺序写测试 dd if=/dev/zero of=/data/testfile bs=1M count=512 oflag=direct conv=fsync

注意conv=fsync确保数据真正落盘后再返回。如果不加这个,dd 返回时数据可能还在缓存里。

4.3 用 fio 做全面性能分析

fio 的配置文件方式比命令行参数更清晰,也方便保存和复用。下面是一个典型的顺序读测试配置:

[global] ioengine=libaio direct=1 runtime=60 time_based=1 group_reporting=1 filename=/data/fio_testfile size=512M [seq-read] bs=128k rw=read numjobs=1 iodepth=8

随机读写测试配置:

[global] ioengine=libaio direct=1 runtime=60 time_based=1 group_reporting=1 filename=/data/fio_testfile size=512M [rand-read] bs=4k rw=randread numjobs=1 iodepth=32 [rand-write] bs=4k rw=randwrite numjobs=1 iodepth=32

运行:

fio seq-read.fio fio rand-read-write.fio

fio 的输出里重点关注这几个指标:

  • bw:带宽,单位可以是 KB/s 或 MB/s
  • iops:每秒 IO 操作数
  • lat (usec):延迟,看 avg 和 99.00th 百分位
  • clat:完成延迟,比总延迟更能反映存储本身性能

4.4 文件系统层对比测试

如果你在选型阶段纠结用 ext4 还是 f2fs,可以做个对比测试。方法是在 eMMC 上分两个分区,分别格式化成不同文件系统,然后用相同的 fio 配置跑一遍。

# 格式化测试分区 mkfs.ext4 /dev/mmcblk0p3 mkfs.f2fs /dev/mmcblk0p4 # 挂载 mkdir -p /mnt/ext4 /mnt/f2fs mount /dev/mmcblk0p3 /mnt/ext4 mount /dev/mmcblk0p4 /mnt/f2fs

然后修改 fio 配置里的 filename 指向不同挂载点,分别运行。

根据我的经验,ext4 在顺序读写上通常略优于 f2fs,但 f2fs 在随机写入和长期使用后的碎片化控制上表现更好。如果你的产品是监控设备、行车记录仪这类持续写入场景,f2fs 更合适;如果是通用计算平台,ext4 的兼容性和工具链支持更成熟。

4.5 长时间写入稳定性测试

这个测试最容易被忽略,但恰恰是量产中最容易出问题的地方。eMMC 在持续写入时,FTL 层需要不断做垃圾回收,当空闲块耗尽时,写入性能会断崖式下降。

测试方法:用 fio 做持续 30 分钟的顺序写入,每秒记录一次带宽:

[global] ioengine=libaio direct=1 runtime=1800 time_based=1 filename=/data/stability_test size=1G bs=1M rw=write iodepth=4 [write-stability]

同时开另一个终端,每秒采样一次:

while true; do cat /sys/block/mmcblk0/stat >> /tmp/emmc_stat.log sleep 1 done

测试结束后分析带宽曲线。如果前 5 分钟能跑 150MB/s,后面掉到 30MB/s,说明 eMMC 的垃圾回收机制跟不上,这种芯片在高负载写入场景下会出问题。

5. 常见问题与排查技巧实录

5.1 测出来的带宽远低于标称值

这是最常见的问题。iMX8 配 HS400 eMMC,标称 400MB/s,实测只有 80MB/s,差了好几倍。排查思路按优先级来:

第一步,确认速度模式。看/sys/kernel/debug/mmc0/ios里的 timing spec。如果是mmc hs200甚至mmc hs,那带宽上限就被卡住了。HS200 单沿 200MHz 8bit 理论 200MB/s,实际能到 150MB/s 左右;HS400 双沿理论 400MB/s,实际 250-300MB/s。

第二步,检查总线宽度。bus width 应该是 8 bit。如果显示 4 bit,要么是硬件设计只接了 4 根数据线,要么是设备树配置错了。

第三步,看时钟频率。clock 应该是 200000000(200MHz)。如果只有 50000000,说明高速模式没使能。

第四步,检查设备树配置。iMX8 的 uSDHC 节点里,bus-width、non-removable、no-sd、no-sdio这些属性要配对。eMMC 还要配置mmc-hs400-1_8v或mmc-hs200-1_8v。

第五步,排查信号完整性。如果配置都对但速度上不去,可能是 PCB 走线问题。eMMC 的 CLK、CMD、DAT 线需要等长匹配,阻抗控制在 50 欧姆。这个问题在打样阶段就要用示波器看眼图,量产阶段基本没法改。

5.2 随机读写 IOPS 异常低

4KB 随机读 IOPS 只有几百,正常 eMMC 应该在 5000 以上。可能的原因:

  • 队列深度没设对。iodepth=1 时 IOPS 受限于单命令延迟,eMMC 单命令延迟大概 100-200us,算下来 IOPS 也就 5000-10000。要测并发能力,把 iodepth 提到 32。
  • 没有启用命令队列。eMMC 5.1 的 CQ 功能需要在设备树里使能,并且内核配置要打开CONFIG_MMC_CQHCI。检查/sys/kernel/debug/mmc0/下有没有 cq 相关节点。
  • 文件系统开销。如果测试文件在 ext4 上,元数据操作会拖累随机 IOPS。可以试试直接对块设备测试(fio 的 filename 设为/dev/mmcblk0p3),排除文件系统影响。
  • CPU 瓶颈。iMX8M Mini 的 CPU 性能有限,处理中断和 IO 调度可能成为瓶颈。用top看一下测试时 CPU 占用率,如果某个核心跑满 100%,说明是 CPU 限制而非存储限制。

5.3 写入测试时系统卡死或报错

这个比较危险,可能是硬件问题也可能是软件配置问题。

内核日志:dmesg | tail -50看有没有 mmc 相关的错误,比如mmc0: Timeout waiting for hardware interrupt或mmcblk0: error -110 transferring data。-110 是 ETIMEDOUT,说明命令超时,通常是信号质量或时序配置问题。

电源问题:eMMC 在高速写入时电流需求较大,如果电源纹波超标或者供电不足,会导致写入失败。用示波器看 VCC 和 VCCQ 的电压是否稳定。

温度问题:如果板子摸起来烫手,可能是过热保护。eMMC 一般 85 度以上会降速,105 度以上可能拒绝写入。加散热片或者降低环境温度再试。

文件系统错误:如果之前测试过程中断电过,文件系统可能损坏。用fsck.ext4 -f /dev/mmcblk0p3修复后再测。

5.4 不同批次板子性能差异大

量产阶段最头疼的问题。同一款 eMMC,不同批次测出来带宽差 20% 以上。可能的原因:

  • eMMC 芯片批次不同。不同批次的 NAND 晶圆,读写速度本身就有差异。这个只能通过来料检验筛选。
  • PCB 阻抗控制不一致。板厂每次压合的阻抗可能有偏差,影响高速信号质量。
  • 焊接质量。BGA 封装的 eMMC,如果回流焊温度曲线不对,可能有虚焊或冷焊,导致信号完整性下降。
  • 测试环境温度不同。夏天和冬天车间温度差 20 度,eMMC 性能也会有差异。

应对策略:制定明确的测试标准,比如顺序读不低于 200MB/s,随机写 IOPS 不低于 3000。每批板子抽检 5%,低于标准的批次退回或降级使用。

5.5 常见问题速查表

现象可能原因排查方法解决方向
带宽远低于标称速度模式未使能查 /sys/kernel/debug/mmc0/ios改设备树、检查硬件
随机 IOPS 低队列深度不足确认 iodepth 设置提高 iodepth、启用 CQ
写入超时信号完整性差dmesg 看 -110 错误查 PCB 走线、降速测试
持续写入降速垃圾回收跟不上看长时间写入曲线换更高规格 eMMC
批次差异大芯片或 PCB 不一致抽检多批次对比制定来料标准
系统卡死电源或温度问题测电压、摸温度改电源设计、加散热

实操心得:测试 eMMC 性能时,我习惯先用dd快速摸个底,如果 direct 读能到 200MB/s 以上,说明硬件基本没问题,再用 fio 做精细测试。如果 dd 就卡在 80MB/s,别急着上 fio,先把速度模式和设备树查清楚,大概率是配置问题。

6. 数据解读与性能优化建议

6.1 怎么判断测试结果是否正常

拿到一组数据后,怎么知道是好是坏?我一般用以下几个基准来判断:

对于 iMX8QuadMax 配 HS400 eMMC(比如常见的 32GB 或 64GB 规格):

  • 顺序读:250-300MB/s 算正常,低于 200MB/s 需要排查
  • 顺序写:150-200MB/s 算正常,低于 100MB/s 需要排查
  • 4KB 随机读 IOPS(QD32):8000-15000 算正常
  • 4KB 随机写 IOPS(QD32):3000-8000 算正常
  • 4KB 随机读延迟(QD1):100-200us 算正常

对于 iMX8M Mini 配 HS200 eMMC:

  • 顺序读:150-180MB/s
  • 顺序写:80-120MB/s
  • 4KB 随机读 IOPS(QD32):5000-10000

SD 卡这边,UHS-I SDR104 模式下:

  • 顺序读:80-95MB/s
  • 顺序写:60-80MB/s(取决于卡本身)
  • 4KB 随机读 IOPS:2000-5000

如果实测值只有基准的一半,先别怀疑板子,检查测试方法。direct IO 有没有加?缓存有没有清?CPU 频率有没有锁?这些因素排除后再看硬件。

6.2 从测试数据反推优化方向

测试的目的不是得到一个数字,而是指导优化。如果顺序读达标但随机写很差,说明存储芯片的随机写入能力弱,可以考虑:

  • 在文件系统层启用 writeback 模式,合并小写入
  • 应用层加写缓存,批量提交
  • 换用带 DRAM 缓存的 eMMC 芯片(如果有的话)

如果顺序写前期快后期慢,说明垃圾回收策略有问题,可以:

  • 预留更多 OP(over-provisioning)空间,减少 GC 压力
  • 调整文件系统的 discard 策略,及时回收无效块
  • 在应用层做写入限速,避免瞬间打满

如果 SD 卡性能波动大,可能是卡的质量问题。不同品牌的 SD 卡,甚至同品牌不同容量,性能差异都很大。建议在选型阶段多测几张卡,选性能稳定且一致性好的型号。

6.3 内核配置对存储性能的影响

有几个内核配置项会直接影响存储性能,值得关注:

IO 调度器:iMX8 默认可能是mq-deadline或none。对于 eMMC 这种自带队列管理的设备,none通常性能最好,因为不需要内核再做排序。可以通过echo none > /sys/block/mmcblk0/queue/scheduler切换。

readahead 大小:默认可能是 128KB,对于顺序读场景,增大到 512KB 或 1MB 可以提升吞吐。echo 1024 > /sys/block/mmcblk0/queue/read_ahead_kb。

文件系统挂载选项:ext4 用noatime可以减少元数据写入,data=writeback比data=ordered性能更好但安全性略低。f2fs 可以调整gc_urgent和gc_idle参数来平衡性能和寿命。

eMMC 缓存策略:有些 eMMC 支持 cache flush 和 reliable write,在设备树里配置mmc-cache-enable可以提升写入性能,但要注意断电数据安全。

6.4 测试报告应该包含什么

如果你要把测试结果交给团队或客户,一份完整的报告应该包含:

  • 硬件平台信息:SoC 型号、eMMC/SD 卡型号和容量、PCB 版本
  • 软件环境:内核版本、文件系统类型、挂载选项
  • 测试工具和版本:fio 版本、dd 来源
  • 测试条件:CPU 频率、环境温度、是否清缓存
  • 原始数据:每个测试项的多次结果,不要只给平均值
  • 分析结论:哪些指标达标、哪些不达标、可能的原因
  • 优化建议:针对不达标项的具体改进方向

我见过太多人只丢一个“读写 200MB/s”的结论,结果别人复现不出来。把测试条件写清楚,数据才有参考价值。

7. 一些踩坑之后的个人体会

做 iMX8 存储性能测试这几年,最大的感受是:测试方法比测试工具重要,环境控制比测试数据重要。同样一块板子,不同的人测出来的数字可能差一倍,问题往往出在缓存没清、频率没锁、温度没控这些细节上。

另外,不要迷信标称参数。eMMC 厂商 datasheet 上写的 400MB/s 是理论峰值,实际能跑到 70% 就算不错了。SD 卡更是重灾区,标称 U3 的卡实际写入可能只有 30MB/s。选型阶段一定要实测,而且要多测几批样品。

最后,存储性能测试不是一次性的活。系统升级、内核更新、文件系统调整之后,都值得重新跑一遍基线测试。我习惯在项目关键节点都留一份测试数据,后面出问题时可以快速对比,判断是硬件老化还是软件改动导致的性能变化。

这个内容后续还可以这样扩展:加入 PCIe NVMe 存储的对比测试,或者针对特定应用场景(比如视频录制、数据库)做定制化的 IO 模式测试。如果你有这方面的需求,可以沿着这个框架继续往下做。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询