Linux에서 특정한 디렉토리가 차지하는 용량을 효율적이고, 빠르게 계산하는 법(Fast, efficient way to calculate directory size recursively on linux)

[주의] 아직 업데이트 중인 글입니다.

Standard unix command 중에서 '특정 directory와 하위 파일들이 파일시스템에서 차지하는 용량의 총합'을 알아낼 수 있는 가장 대표적인 방법으로 'du -s' ~ 'du --max-depth=0'가 있다.

du command는 glibc의 fts를 이용하여 file system hierarchy를 (default)preorder로 recursive하게 traversing하여 모든 파일/디렉토리에 대하여 stat system call을 호출한다. 더 자세한 구현 내용은 Unix 'coreutils' repository의 'du.c'를 읽어보면 되겠다. (사실상 위의 두줄이 전부다.)

glibc의 fts module implementation을 읽어보지 않아서, 실제로 directory tree traversing이 recursive하게 이루어지는지를 알 수는 없다. (설마?) 만약, 그렇다면 pre-order traversing 을iterative하게 바꾸면 속도가 좀 빨라지긴 할 것이다 .일단 이건 논외로 하고(...) 다른 대책으로는 다음과 같은 해결방법들이 있을 수 있다.

해결방법(?)

(1) 모든 subdirectory들을 recursive하게 방문하면서 계산한다.
(2) file과 관련된 system call이 일어날 때마다 어딘가에 subdirectory summarized size를 caching 한다. (장난하냐?)

File system '전체'의 free space에 대한 정보는 file system header에 operation이 일어날 때마다 항상 업데이트되기 때문에 df command로 (2)가 가능하지만, single directory에서는 이게 안된다(꼼수가 있긴 한데, 나중에 실험해보고 업데이트 해야겠다.) 젠장!

그런데 내가(혹은 독자가) 이 문제를 왜 고민하고 있는가? 바로 directory/file 개수가 많아질수록 명령어 실행 속도가 linear하게 느려진다는 것이다.(체감상으론 기하급수적이지만서도......) NFS(Network File System)에서는 더욱 처참해진다.

[NFS에서의 du command 실행속도]


지금으로선, 이 문제를 해결하기 위해서는 해결방법 (1)을 채택하는 수 밖에 없을 것 같다. 그래서 일단 google god로부터 얻은 신탁과, 내 머리속에서 나온 방법을 나름대로 종합하여 Implementation 해보기로 했다.

성능비교를 위해서 나의 컴퓨터 i5-3337U와 Samsung 840 SSD + Windows BASH에서 'du -sh' command로 1초정도 걸리도록 아래와 같이 테스트 파일들을 굉장히 'Naive'하게 만들었다.
for i in $(seq 1 3000) do;
mkdir directory_enumeration_test/$i;
truncate -s 1K directory_enumeration_test/$i/$i;
done;

Implmentation

(1) du -s [directory path]
(2) find [directory path] -printf %k"\n" | awk '{ sum += $1 } END { print sum }'
Reference [2]에서 찾은 example인데, du command보다 빠를 이유가 한 개도 없는 방법이다. 속는셈 치고 돌려봤는데 역시나......

(3) Parallelization
(3-1) GNU parallel package 이용하기
Reference [4]에서 찾은 example인데, [4]에서는 subdirectory들의 size 총합을 계산하는 부분이 빠져있어서, (2)와 비슷하게 awk만 추가했다.

time parallel -X --gnu du -s ::: directory_enumeration_test/* | awk '{ sum += $1 } END { print sum }'

(3-2) 'coreutils' repository의 du.c 를 linux native thread library를 이용해서 병렬화하기.
최후의 대안, 현재 작성중.

응? 그런데오히려 성능이 감소했다...... 뭐가 원인인지는 아직 잘 모르겠다. 조금이나마 나아지거나 같은 시간이 걸릴것을 기대했는데, 오히려 떨어지다니. gnu parallel command에 대해서 내가 아직 잘 모르거나, fork 시간때문에 성능이 감소했을 수 있...나?

현재까지의 결론. 더 빠른 대안따위는 없다.

Reference
[1] https://wiki.xdroop.com/space/Linux/Parallel+du
[2] https://www.linuxquestions.org/questions/linux-general-1/any-fast-way-to-know-the-total-file-size-under-a-folder-140208/
[3] https://www.unix.com/shell-programming-and-scripting/239117-fastest-way-calculating-directory.html
[4] https://stackoverflow.com/questions/24605656/run-du-on-parallel
[5] 'du.c' on coreutils github repository

댓글

이 블로그의 인기 게시물

Proof of well-known 'Intersection Of Three Planes' formula.

영화 'Call me by your name'의 OST 중 'Visions of Gideons' 번역 및 해석