perf(palette): trust dirent d_type instead of a per-entry stat
The per-entry metadata() call makes FatFS re-walk the directory by path every time — ~32ms/file on the card, 35s for a 1098-file tree. esp-idf's FAT VFS always fills d_type (DT_DIR/DT_REG from the FILINFO readdir already holds, never unknown) and Rust std maps file_type() onto it stat-free, so the walk is now one readdir pass per directory.
This commit is contained in:
@@ -585,24 +585,27 @@ fn walk_files(dir: &std::path::Path, depth: usize, out: &mut Vec<String>) {
|
||||
let Ok(entries) = std::fs::read_dir(dir) else {
|
||||
return;
|
||||
};
|
||||
let paths: Vec<_> = entries.flatten().map(|e| e.path()).collect();
|
||||
for path in paths {
|
||||
// Keep the dirent's own file type: esp-idf's FAT VFS always fills d_type
|
||||
// (DT_DIR/DT_REG, straight from the FILINFO readdir already holds), so
|
||||
// `file_type()` is free. A per-entry `metadata()` stat instead re-walks
|
||||
// the directory by path every time — measured at ~32ms/file on the SD
|
||||
// card, it turned a 1098-file walk into 35s.
|
||||
let children: Vec<_> = entries
|
||||
.flatten()
|
||||
.filter_map(|e| e.file_type().ok().map(|t| (e.path(), t)))
|
||||
.collect();
|
||||
for (path, ftype) in children {
|
||||
let Some(name) = path.file_name().and_then(|n| n.to_str()) else {
|
||||
continue;
|
||||
};
|
||||
if name.starts_with('.') {
|
||||
continue;
|
||||
}
|
||||
// Stat rather than trust d_type — FatFS's dirent type can read back
|
||||
// as unknown; a plain metadata call is reliable here.
|
||||
let Ok(meta) = std::fs::metadata(&path) else {
|
||||
continue;
|
||||
};
|
||||
if meta.is_file() {
|
||||
if ftype.is_file() {
|
||||
if let Some(p) = path.to_str() {
|
||||
out.push(p.to_string());
|
||||
}
|
||||
} else if meta.is_dir() {
|
||||
} else if ftype.is_dir() {
|
||||
walk_files(&path, depth + 1, out);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user