Quando você executa ls
sem argumentos, ele abre apenas um diretório, lê todo o conteúdo, classifica e imprime.
Quando você executa ls *
, primeiro o shell se expande *
, o que é efetivamente o mesmo que o simples ls
, cria um vetor de argumento com todos os arquivos no diretório e chamadas atuais ls
. ls
depois, processa esse vetor de argumento e para cada argumento e chama access(2)
o arquivo para verificar sua existência. Em seguida, imprimirá a mesma saída que a primeira (simples) ls
. O processamento do vetor de argumento grande e do shell ls
provavelmente envolverá muita alocação de memória de pequenos blocos, o que pode levar algum tempo. No entanto, como havia pouco sys
e user
tempo, mas muito real
tempo, a maior parte do tempo seria gasta aguardando disco, em vez de usar a CPU para alocar memória.
Cada chamada para access(2)
precisará ler o inode do arquivo para obter as informações de permissão. Isso significa muito mais leituras e buscas em disco do que simplesmente ler um diretório. Não sei quão caras essas operações são no seu GPFS, mas como a comparação que você mostrou com ls -l
um tempo de execução semelhante ao caso curinga, o tempo necessário para recuperar as informações do inode parece dominar. Se o GPFS tiver uma latência um pouco mais alta que o sistema de arquivos local em cada operação de leitura, esperamos que seja mais pronunciado nesses casos.
A diferença entre o caso curinga e ls -l
50% pode ser explicada pela ordem dos inodes no disco. Se os inodes fossem dispostos sucessivamente na mesma ordem que os nomes dos arquivos no diretório e ls -l
stat (2) editas os arquivos na ordem dos diretórios antes da classificação, ls -l
possivelmente leriam a maioria dos inodes em uma varredura. Com o curinga, o shell classificará os nomes dos arquivos antes de passá-los para ls
, portanto ls
, provavelmente lerá os inodes em uma ordem diferente, adicionando mais movimento da cabeça do disco.
Note-se que sua time
saída não incluirá o tempo gasto pelo shell para expandir o curinga.
Se você realmente deseja ver o que está acontecendo, use strace(1)
:
strace -o /tmp/ls-star.trace ls *
strace -o /tmp/ls-l-star.trace ls -l *
e veja quais chamadas do sistema estão sendo executadas em cada caso.
¹ Não sei se access(2)
é realmente usado ou algo mais como stat(2)
. Mas ambos provavelmente exigem uma pesquisa de inode (não tenho certeza se access(file, 0)
ignoraria uma pesquisa de inode.)
ls
ele pode apenas perguntar ao sistema de arquivos "para que servem os filhos do inodepwd
"ls *
ele deve perguntar "quais são os filhos (e qual é o arquivo) do inodea
" seguido de b, c, d, etc. etc. Uma consulta versus muitas.