ls
ordina effettivamente i file e cerca di elencarli, il che diventa un enorme sovraccarico se stiamo cercando di elencare più di un milione di file all'interno di una directory. Come menzionato in questo link, possiamo usare strace
o find
elencare i file. Tuttavia, anche quelle opzioni mi sembravano irrealizzabili poiché avevo 5 milioni di file. Dopo un po 'di googling, ho scoperto che se si elencano le directory usando getdents()
, si suppone di essere più veloce, perché ls
, find
e Python
librerie usano readdir()
che è più lento, ma utilizza getdents()
sotto.
Possiamo trovare il codice C per elencare i file usando getdents()
da qui :
/*
* List directories using getdents() because ls, find and Python libraries
* use readdir() which is slower (but uses getdents() underneath.
*
* Compile with
* ]$ gcc getdents.c -o getdents
*/
#define _GNU_SOURCE
#include <dirent.h> /* Defines DT_* constants */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
struct linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
#define BUF_SIZE 1024*1024*5
int
main(int argc, char *argv[])
{
int fd, nread;
char buf[BUF_SIZE];
struct linux_dirent *d;
int bpos;
char d_type;
fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
if (fd == -1)
handle_error("open");
for ( ; ; ) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
d_type = *(buf + bpos + d->d_reclen - 1);
if( d->d_ino != 0 && d_type == DT_REG ) {
printf("%s\n", (char *)d->d_name );
}
bpos += d->d_reclen;
}
}
exit(EXIT_SUCCESS);
}
Copia il programma C sopra nella directory in cui devono essere elencati i file. Quindi eseguire i comandi seguenti.
gcc getdents.c -o getdents
./getdents
Esempio di tempi : getdents
può essere molto più veloce di ls -f
, a seconda della configurazione del sistema. Ecco alcuni tempi che dimostrano un aumento della velocità 40x per elencare una directory contenente circa 500k file su un mount NFS in un cluster di calcolo. Ogni comando è stato eseguito 10 volte in successione immediata, prima getdents
, quindi ls -f
. La prima esecuzione è significativamente più lenta di tutte le altre, probabilmente a causa di errori nella pagina di cache NFS. (A parte: su questo mount, il d_type
campo non è affidabile, nel senso che molti file appaiono come di tipo "sconosciuto".)
command: getdents $bigdir
usr:0.08 sys:0.96 wall:280.79 CPU:0%
usr:0.06 sys:0.18 wall:0.25 CPU:97%
usr:0.05 sys:0.16 wall:0.21 CPU:99%
usr:0.04 sys:0.18 wall:0.23 CPU:98%
usr:0.05 sys:0.20 wall:0.26 CPU:99%
usr:0.04 sys:0.18 wall:0.22 CPU:99%
usr:0.04 sys:0.17 wall:0.22 CPU:99%
usr:0.04 sys:0.20 wall:0.25 CPU:99%
usr:0.06 sys:0.18 wall:0.25 CPU:98%
usr:0.06 sys:0.18 wall:0.25 CPU:98%
command: /bin/ls -f $bigdir
usr:0.53 sys:8.39 wall:8.97 CPU:99%
usr:0.53 sys:7.65 wall:8.20 CPU:99%
usr:0.44 sys:7.91 wall:8.36 CPU:99%
usr:0.50 sys:8.00 wall:8.51 CPU:100%
usr:0.41 sys:7.73 wall:8.15 CPU:99%
usr:0.47 sys:8.84 wall:9.32 CPU:99%
usr:0.57 sys:9.78 wall:10.36 CPU:99%
usr:0.53 sys:10.75 wall:11.29 CPU:99%
usr:0.46 sys:8.76 wall:9.25 CPU:99%
usr:0.50 sys:8.58 wall:9.13 CPU:99%
ls
usi--color
o-F
perché ciò significherebbe fare unlstat(2)
per ogni file.