Bill Greiman
Well-known member
Warning: I have edited this post to add a latency measurement.
Paul is looking for better SD performance for multi-file audio projects.
I wrote a quick random I/O test for evaluating SD cards on Teensy 4.1.
I posted results for a CANVAS Go! Plus 256GB below. Run the test on your fastest card and post your result.
Here is the test:
Here is the output:
Paul is looking for better SD performance for multi-file audio projects.
I wrote a quick random I/O test for evaluating SD cards on Teensy 4.1.
I posted results for a CANVAS Go! Plus 256GB below. Run the test on your fastest card and post your result.
Here is the test:
Code:
// SD Random I/O tests.
#include "SdFat.h"
const size_t MAX_FILES = 16;
const size_t MAX_SECTORS = 64;
// Space files by 1 GiB
const uint32_t FILE_ALLOC = 1UL << 30;
// File size 1 MiB
const uint32_t FILE_SIZE = 1UL << 20;
SdFs sd;
FsFile file[MAX_FILES];
uint8_t buf[512*MAX_SECTORS];
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SS,DEDICATED_SPI, SD_SCK_MHZ(50))
#endif // HAS_SDIO_CLASS
#define error(msg) {Serial.println(msg);while (true);}
char name[] = "?.bin";
void closeFiles() {
for (uint8_t i = 0; i < MAX_FILES; i++) {
file[i].close();
}
}
void createFiles() {
uint32_t m;
Serial.println("Create files");
m = micros();
for (uint8_t i = 0; i < MAX_FILES; i++) {
// Spread files so files ping-pong.
name[0] = 'A' + ( i < MAX_FILES/2 ? i*2 : 2*i - MAX_FILES + 1 );
if (!file[i].open(name, O_RDWR | O_CREAT | O_TRUNC)) error("open create");
if (!file[i].preAllocate(FILE_ALLOC)) error("preAllocate");
}
m = micros() - m;
Serial.print("Create micros: ");
Serial.println(m);
memset(buf, 0XAA, sizeof(buf));
uint32_t nw = FILE_SIZE/sizeof(buf);
m = micros();
for (uint8_t i = 0; i < MAX_FILES; i++) {
for (uint32_t iw = 0; iw < nw; iw++) {
if (sizeof(buf) != file[i].write(buf, sizeof(buf))) error("create write");
}
}
m = micros() - m;
Serial.print("Sequential Write: ");
Serial.print(MAX_FILES*FILE_SIZE/(0.001*m));
Serial.println(" KB/sec");
closeFiles();
}
void openFiles(uint8_t opt) {
for (uint8_t i = 0; i < MAX_FILES; i++) {
name[0] = i + 'A';
if (!file[i].open(name, opt)) error("open");
}
}
void randomRead() {
Serial.print("Begin Random Read Test\nns - read size sectors,");
Serial.println(" nf - number of files, maxLat - latency micros");
uint32_t m;
uint32_t maxLat;
uint32_t lat;
for (uint8_t ns = MAX_SECTORS; ns > 0; ns /= 2) {
for (uint8_t nf = 1; nf <= MAX_FILES; nf *= 2) {
openFiles(O_RDONLY);
maxLat = 0;
uint32_t nr = FILE_SIZE/(512*ns);
m = micros();
for (uint32_t ir = 0; ir < nr; ir++) {
for (uint32_t i = 0; i < nf; i++) {
lat = micros();
if (ns*512 != file[i].read(buf, ns*512)) error("randomRead");
lat = micros() - lat;
if (lat > maxLat) {
maxLat = lat;
}
}
}
m = micros() - m;
Serial.print("ns: ");
Serial.print(ns);
Serial.print(" nf: ");
Serial.print(nf);
Serial.print(" maxLat: ");
Serial.print(maxLat);
Serial.print(" total KB/sec: ");
Serial.print(nf*FILE_SIZE/(0.001*m));
Serial.print(" file KB/sec: ");
Serial.println(FILE_SIZE/(0.001*m));
closeFiles();
}
}
Serial.println("End Random Read Test");
}
void randomWrite() {
Serial.print("Begin Random Write Test\nns - read size sectors,");
Serial.println(" nf - number of files, maxLat - latency micros");
uint32_t m;
uint32_t maxLat;
uint32_t lat;
for (uint8_t ns = MAX_SECTORS; ns > 0; ns /= 2) {
for (uint8_t nf = 1; nf <= MAX_FILES; nf *= 2) {
openFiles(O_RDWR);
maxLat = 0;
uint32_t nr = FILE_SIZE/(512*ns);
m = micros();
for (uint32_t ir = 0; ir < nr; ir++) {
for (uint32_t i = 0; i < nf; i++) {
lat = micros();
if (ns*512 != file[i].write(buf, ns*512)) error("randomWrite");
lat = micros() - lat;
if (lat > maxLat) {
maxLat = lat;
}
}
}
m = micros() - m;
Serial.print("ns: ");
Serial.print(ns);
Serial.print(" nf: ");
Serial.print(nf);
Serial.print(" maxLat: ");
Serial.print(maxLat);
Serial.print(" total KB/sec: ");
Serial.print(nf*FILE_SIZE/(0.001*m));
Serial.print(" file KB/sec: ");
Serial.println(FILE_SIZE/(0.001*m));
closeFiles();
}
}
Serial.println("End Random Write Test");
}
void removeFiles() {
uint32_t m = micros();
for (uint8_t i = 0; i < MAX_FILES; i++) {
name[0] = i + 'A';
if (!sd.remove(name)) error("removeFiles");;
}
m = micros() - m;
Serial.print("Remove micros: ");
Serial.println(m);
}
void setup() {
Serial.begin(9600);
while (!Serial) {}
Serial.println("Type any character to start");
while (!Serial.available()) {}
do {
delay(10);
} while (Serial.read() >= 0);
if (!sd.begin(SD_CONFIG)) error("sd.begin()");
createFiles();
randomRead();
randomWrite();
Serial.println("Type any character to remove files");
while (!Serial.available()) {}
removeFiles();
Serial.println("Done");
}
void loop() {
}
Here is the output:
Card: CANVAS Go! Plus 256GB
Type any character to start
Create files
Create micros: 65069
Sequential Write: 21765.24 KB/sec
Begin Random Read Test
ns - read size sectors, nf - number of files, maxLat - latency micros
ns: 64 nf: 1 maxLat: 1943 total KB/sec: 22768.90 file KB/sec: 22768.90
ns: 64 nf: 2 maxLat: 2033 total KB/sec: 18104.34 file KB/sec: 9052.17
ns: 64 nf: 4 maxLat: 2039 total KB/sec: 18095.12 file KB/sec: 4523.78
ns: 64 nf: 8 maxLat: 2032 total KB/sec: 17980.31 file KB/sec: 2247.54
ns: 64 nf: 16 maxLat: 2022 total KB/sec: 17458.01 file KB/sec: 1091.13
ns: 32 nf: 1 maxLat: 1231 total KB/sec: 22762.97 file KB/sec: 22762.97
ns: 32 nf: 2 maxLat: 1291 total KB/sec: 14847.93 file KB/sec: 7423.97
ns: 32 nf: 4 maxLat: 1292 total KB/sec: 14869.73 file KB/sec: 3717.43
ns: 32 nf: 8 maxLat: 1374 total KB/sec: 14740.39 file KB/sec: 1842.55
ns: 32 nf: 16 maxLat: 1377 total KB/sec: 13967.08 file KB/sec: 872.94
ns: 16 nf: 1 maxLat: 874 total KB/sec: 22750.62 file KB/sec: 22750.62
ns: 16 nf: 2 maxLat: 923 total KB/sec: 11198.37 file KB/sec: 5599.18
ns: 16 nf: 4 maxLat: 926 total KB/sec: 11193.62 file KB/sec: 2798.40
ns: 16 nf: 8 maxLat: 939 total KB/sec: 11128.46 file KB/sec: 1391.06
ns: 16 nf: 16 maxLat: 990 total KB/sec: 10198.61 file KB/sec: 637.41
ns: 8 nf: 1 maxLat: 470 total KB/sec: 22724.49 file KB/sec: 22724.49
ns: 8 nf: 2 maxLat: 475 total KB/sec: 12066.05 file KB/sec: 6033.03
ns: 8 nf: 4 maxLat: 478 total KB/sec: 12056.34 file KB/sec: 3014.08
ns: 8 nf: 8 maxLat: 551 total KB/sec: 12039.59 file KB/sec: 1504.95
ns: 8 nf: 16 maxLat: 552 total KB/sec: 9964.97 file KB/sec: 622.81
ns: 4 nf: 1 maxLat: 384 total KB/sec: 22669.46 file KB/sec: 22669.46
ns: 4 nf: 2 maxLat: 483 total KB/sec: 7108.65 file KB/sec: 3554.33
ns: 4 nf: 4 maxLat: 482 total KB/sec: 7115.09 file KB/sec: 1778.77
ns: 4 nf: 8 maxLat: 542 total KB/sec: 7040.71 file KB/sec: 880.09
ns: 4 nf: 16 maxLat: 607 total KB/sec: 5722.95 file KB/sec: 357.68
ns: 2 nf: 1 maxLat: 339 total KB/sec: 22565.55 file KB/sec: 22565.55
ns: 2 nf: 2 maxLat: 420 total KB/sec: 3898.04 file KB/sec: 1949.02
ns: 2 nf: 4 maxLat: 421 total KB/sec: 3899.74 file KB/sec: 974.94
ns: 2 nf: 8 maxLat: 611 total KB/sec: 3844.60 file KB/sec: 480.57
ns: 2 nf: 16 maxLat: 612 total KB/sec: 3056.48 file KB/sec: 191.03
ns: 1 nf: 1 maxLat: 317 total KB/sec: 22456.33 file KB/sec: 22456.33
ns: 1 nf: 2 maxLat: 421 total KB/sec: 1949.45 file KB/sec: 974.72
ns: 1 nf: 4 maxLat: 421 total KB/sec: 1950.89 file KB/sec: 487.72
ns: 1 nf: 8 maxLat: 615 total KB/sec: 1920.14 file KB/sec: 240.02
ns: 1 nf: 16 maxLat: 615 total KB/sec: 1525.40 file KB/sec: 95.34
End Random Read Test
Begin Random Write Test
ns - read size sectors, nf - number of files, maxLat - latency micros
ns: 64 nf: 1 maxLat: 1514 total KB/sec: 22618.12 file KB/sec: 22618.12
ns: 64 nf: 2 maxLat: 8142 total KB/sec: 13250.64 file KB/sec: 6625.32
ns: 64 nf: 4 maxLat: 22946 total KB/sec: 12404.63 file KB/sec: 3101.16
ns: 64 nf: 8 maxLat: 16905 total KB/sec: 12900.79 file KB/sec: 1612.60
ns: 64 nf: 16 maxLat: 18455 total KB/sec: 12695.76 file KB/sec: 793.48
ns: 32 nf: 1 maxLat: 790 total KB/sec: 22616.66 file KB/sec: 22616.66
ns: 32 nf: 2 maxLat: 7355 total KB/sec: 11111.86 file KB/sec: 5555.93
ns: 32 nf: 4 maxLat: 21153 total KB/sec: 11131.68 file KB/sec: 2782.92
ns: 32 nf: 8 maxLat: 16387 total KB/sec: 11203.65 file KB/sec: 1400.46
ns: 32 nf: 16 maxLat: 18029 total KB/sec: 11175.53 file KB/sec: 698.47
ns: 16 nf: 1 maxLat: 429 total KB/sec: 22610.32 file KB/sec: 22610.32
ns: 16 nf: 2 maxLat: 7679 total KB/sec: 6811.99 file KB/sec: 3405.99
ns: 16 nf: 4 maxLat: 28843 total KB/sec: 6650.26 file KB/sec: 1662.56
ns: 16 nf: 8 maxLat: 16897 total KB/sec: 7041.59 file KB/sec: 880.20
ns: 16 nf: 16 maxLat: 18537 total KB/sec: 7019.15 file KB/sec: 438.70
ns: 8 nf: 1 maxLat: 6410 total KB/sec: 19950.08 file KB/sec: 19950.08
ns: 8 nf: 2 maxLat: 7246 total KB/sec: 5005.49 file KB/sec: 2502.75
ns: 8 nf: 4 maxLat: 22441 total KB/sec: 4942.50 file KB/sec: 1235.62
ns: 8 nf: 8 maxLat: 17998 total KB/sec: 5002.65 file KB/sec: 625.33
ns: 8 nf: 16 maxLat: 19384 total KB/sec: 4969.51 file KB/sec: 310.59
ns: 4 nf: 1 maxLat: 157 total KB/sec: 22575.27 file KB/sec: 22575.27
ns: 4 nf: 2 maxLat: 23712 total KB/sec: 2425.31 file KB/sec: 1212.65
ns: 4 nf: 4 maxLat: 17437 total KB/sec: 2502.12 file KB/sec: 625.53
ns: 4 nf: 8 maxLat: 18506 total KB/sec: 2500.34 file KB/sec: 312.54
ns: 4 nf: 16 maxLat: 26724 total KB/sec: 2325.89 file KB/sec: 145.37
ns: 2 nf: 1 maxLat: 115 total KB/sec: 22556.81 file KB/sec: 22556.81
ns: 2 nf: 2 maxLat: 18399 total KB/sec: 1345.67 file KB/sec: 672.84
ns: 2 nf: 4 maxLat: 17360 total KB/sec: 1248.65 file KB/sec: 312.16
ns: 2 nf: 8 maxLat: 22839 total KB/sec: 1241.68 file KB/sec: 155.21
ns: 2 nf: 16 maxLat: 21187 total KB/sec: 1198.67 file KB/sec: 74.92
ns: 1 nf: 1 maxLat: 100 total KB/sec: 22578.67 file KB/sec: 22578.67
ns: 1 nf: 2 maxLat: 21463 total KB/sec: 717.65 file KB/sec: 358.83
ns: 1 nf: 4 maxLat: 16101 total KB/sec: 624.03 file KB/sec: 156.01
ns: 1 nf: 8 maxLat: 23741 total KB/sec: 616.63 file KB/sec: 77.08
ns: 1 nf: 16 maxLat: 25202 total KB/sec: 609.65 file KB/sec: 38.10
End Random Write Test
Type any character to remove files
Remove micros: 52473
Done
Last edited: