|
| 1 | +--- |
| 2 | +layout: default |
| 3 | +title: 一种基于ESP32丰富连接能力的移动存储设备 -- 测试TF读写速度 |
| 4 | +tags: [Rust on ESP, ESP32, SPI, SDMMC, TFCARD] |
| 5 | +nav_order: {{ page.date }} |
| 6 | +sync_wexin: 1 |
| 7 | +--- |
| 8 | + |
| 9 | + |
| 10 | +# 一种基于ESP32丰富连接能力的移动存储设备 – 测试TF读写速度 |
| 11 | + |
| 12 | + |
| 13 | +## 前言 |
| 14 | + |
| 15 | +在前面的文章中我已经验证了TF卡读写功能,证实了我们可以通过ESP-IDF的接口访问FAT格式的TF卡。为了验证通过WebDAV协议访问TF卡的体验,我将WebDAV前端和TF卡访问功能集成到了一起,使得WebDAV模块可以从TF卡挂载的位置读取文件。本文是我的测试过程。 |
| 16 | + |
| 17 | +本系列其他文章 |
| 18 | + |
| 19 | +1. [基于ESP32的移动存储设备](https://paul356.github.io/2024/10/31/mobile-storage.html) |
| 20 | +2. [一种基于ESP32丰富连接能力的移动存储设备 – 电路设计](https://paul356.github.io/2024/12/12/mobile-storage-pcb.html) |
| 21 | +3. [一种基于ESP32丰富连接能力的移动存储设备 – 测试SD卡读写](https://paul356.github.io/2024/12/27/mobile-storage-sd-card-test.html) |
| 22 | +4. [一种基于ESP32丰富连接能力的移动存储设备 – 验证屏幕显示](https://paul356.github.io/2025/01/06/mobile-storage-display.html) |
| 23 | + |
| 24 | + |
| 25 | +## 测试micro-storage |
| 26 | + |
| 27 | +本文使用的代码都可以在代码仓库[esp-webdav](https://github.com/paul356/esp-webdav)中找到。 |
| 28 | + |
| 29 | + |
| 30 | +### 测试顺序读取速度 |
| 31 | + |
| 32 | +我们希望测得TF卡的顺序读取速度,因为通过WebDAV协议访问基本上不会有随机读取的场景,我就没有测试随机读写场景。为了测试无干扰下的TF卡顺序读取速度,我写了一个顺序读取一个大文件的函数。 |
| 33 | + |
| 34 | +```Rust |
| 35 | +async fn test_file_perf(mount_point: &str) -> anyhow::Result<()> { |
| 36 | + let file_path = format!("{}/habanera.mp4", mount_point); |
| 37 | + |
| 38 | + tokio::task::spawn(async move { |
| 39 | + let mut file = tokio::fs::File::open(file_path).await?; |
| 40 | + let mut read_buf = std::vec![0;32*1024]; |
| 41 | + let mut read_size: usize = 0; |
| 42 | + |
| 43 | + let beg = tokio::time::Instant::now(); |
| 44 | + |
| 45 | + for _i in 0..400 { |
| 46 | + let size = file.read(&mut read_buf).await?; |
| 47 | + read_size += size; |
| 48 | + } |
| 49 | + |
| 50 | + info!("[Async] Read {} bytes in {:?}", read_size, beg.elapsed()); |
| 51 | + |
| 52 | + Ok::<_, anyhow::Error>(()) |
| 53 | + }).await? |
| 54 | +} |
| 55 | + |
| 56 | +fn test_file_sync(mount_point: &str) -> anyhow::Result<()> { |
| 57 | + let file_path = format!("{}/habanera.mp4", mount_point); |
| 58 | + let mut file = std::fs::File::open(file_path)?; |
| 59 | + let mut read_buf = std::vec![0;32*1024]; |
| 60 | + let mut read_size: usize = 0; |
| 61 | + |
| 62 | + let beg = tokio::time::Instant::now(); |
| 63 | + |
| 64 | + use std::io::Read; |
| 65 | + for _i in 0..400 { |
| 66 | + let size = file.read(&mut read_buf).unwrap(); |
| 67 | + read_size += size; |
| 68 | + } |
| 69 | + |
| 70 | + info!("[Sync] Read {} bytes in {:?}", read_size, beg.elapsed()); |
| 71 | + |
| 72 | + Ok::<_, anyhow::Error>(()) |
| 73 | +} |
| 74 | + |
| 75 | +``` |
| 76 | + |
| 77 | +用于测试的文件位于TF根目录下,大约有100MB。测试方法很简单,每次读取32KB的文件内容,连续请求200次,最后获取消耗的时间。 |
| 78 | + |
| 79 | +```text |
| 80 | +I (1709) micro_storage: [Sync] Read 13107200 bytes in 1.593215s |
| 81 | +... |
| 82 | +I (21727) micro_storage: [Async] Read 13107200 bytes in 4.229245s |
| 83 | +``` |
| 84 | + |
| 85 | +我共测试了两次,第一次使用同步接口,第二次使用了tokio库的异步接口。使用异步接口后同样的任务时间却增加了2.6秒,大概由于只有一个并发请求,增加了开销但没有带来收益。但增加的时延具体耗费在哪些事情上了,还需要进一步分析。对于ESP32这样的资源受限的平台,使用异步编程接口可能是”杀鸡用了牛刀“。同步读的速度约为7.9MB/秒,异步读的速度约为3.0MB/秒。 |
| 86 | + |
| 87 | + |
| 88 | +### 测试顺序写速度 |
| 89 | + |
| 90 | +测试顺序写速度使用了和测试顺序读类似的方法。而且也测试了一次同步接口和一次异步接口。 |
| 91 | + |
| 92 | +```Rust |
| 93 | +async fn test_wfile_perf(mount_point: &str) -> anyhow::Result<()> { |
| 94 | + let file_path = format!("{}/wfile_async.bin", mount_point); |
| 95 | + |
| 96 | + tokio::task::spawn(async move { |
| 97 | + let mut file = tokio::fs::File::create(file_path).await?; |
| 98 | + let mut write_buf = std::vec![0xfu8;32*1024]; |
| 99 | + let mut write_size: usize = 0; |
| 100 | + |
| 101 | + let beg = tokio::time::Instant::now(); |
| 102 | + |
| 103 | + for _i in 0..400 { |
| 104 | + let size = file.write(&mut write_buf).await?; |
| 105 | + write_size += size; |
| 106 | + } |
| 107 | + |
| 108 | + info!("[Async] Write {} bytes in {:?}", write_size, beg.elapsed()); |
| 109 | + |
| 110 | + Ok::<_, anyhow::Error>(()) |
| 111 | + }).await? |
| 112 | +} |
| 113 | + |
| 114 | +fn test_wfile_sync(mount_point: &str) -> anyhow::Result<()> { |
| 115 | + let file_path = format!("{}/wfile_sync.bin", mount_point); |
| 116 | + let mut file = std::fs::File::create(file_path)?; |
| 117 | + let mut write_buf = std::vec![3u8;32*1024]; |
| 118 | + let mut write_size: usize = 0; |
| 119 | + |
| 120 | + let beg = tokio::time::Instant::now(); |
| 121 | + |
| 122 | + use std::io::Write; |
| 123 | + for _i in 0..400 { |
| 124 | + let size = file.write(&mut write_buf).unwrap(); |
| 125 | + write_size += size; |
| 126 | + } |
| 127 | + |
| 128 | + info!("[Sync] Write {} bytes in {:?}", write_size, beg.elapsed()); |
| 129 | + |
| 130 | + Ok::<_, anyhow::Error>(()) |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +测试结果如下。经过计算同步写的速度大约为3MB/秒,而异步写速度只有1.8MB/秒。 |
| 135 | + |
| 136 | +```text |
| 137 | +I (6263) micro_storage: [Sync] Write 13107200 bytes in 4.11604s |
| 138 | +... |
| 139 | +I (29223) micro_storage: [Async] Write 13107200 bytes in 7.079895s |
| 140 | +``` |
| 141 | + |
| 142 | + |
| 143 | +## 总结 |
| 144 | + |
| 145 | +我们得到同步顺序读写的速度为7.9MB/秒和3MB/秒,异步接口的顺序读写性能要差一些,为3MB/秒和1.8MB/秒。前一对数字还差强人意,后一对数字就有点难看了。但是我们的WebDAV程序正是使用的异步接口,所以读写性能不会太好。本来想实际测试WebDAV程序的下载和上传性能,但是因为系统经常报告内存不够,导致系统OOM。虽然我的ESP32S3模块有8MB的SPIRAM,但是我发现启用了SPIRAM之后,会出现无法挂载TF卡的错误,我怀疑是硬件设计的问题,所以展示无法对性能进行端到端测试。 |
| 146 | + |
| 147 | + |
| 148 | +## 链接 |
| 149 | + |
| 150 | +1. esp\_webdav - <https://github.com/paul356/esp-webdav> |
0 commit comments