이것은 내 자신의 실험적인 병렬 버전의 grep 이므로 대규모 디렉토리 트리에 대한 액세스 속도를 높이기 위한 다양한 전략을 테스트할 수 있습니다. 플래시 스토리지 또는 SSD에서는 일반 grep을 최대 8배까지 쉽게 능가할 수 있습니다.
옵션:
Usage: ./greppin [-rIOLlsSH] [-n <cores>] <regex> <path>
-2 -- use PCRE2 instead of PCRE
-O -- print file offset of match
-l -- do not print the matching line (Useful if you want
to see _all_ offsets; if you also print the line, only
the first match in the line counts)
-s -- single match; dont search file further after first match
(similar to grep on a binary)
-H -- use hyperscan lib for scanning
-S -- only for hyperscan: interpret pattern as string literal instead of regex
-L -- machine has low mem; half chunk-size (default 2GB)
may be used multiple times
-I -- enable highlighting of matches (useful)
-n -- Use multiple cores in parallel (omit for single core)
-r -- recurse on directory
Grab은 pcre 라이브러리를 사용하므로 기본적으로 grep -P -a
와 동일합니다. Perl 호환 정규 표현식은 기본 정규 표현식과 특성이 다르기 때문에 -P
가 중요합니다.
두 개의 지점이 있습니다. master
와 greppin
. Master는 대부분의 POSIX 시스템에서 컴파일하고 실행해야 하는 '전통적인' 그랩 입니다. greppin
최적화되고 병렬화된 nftw()
및 readdir()
버전이 함께 제공됩니다. 이는 master
브랜치가 이미 제공하는 속도 향상에 더해 다시 두 배의 속도를 제공합니다. greppin
브랜치는 Linux, BSD 및 OSX에서 실행됩니다. greppin
정규식 패턴을 JIT 코드로 컴파일할 때 가능한 경우 CPU의 SIMD 지침(AVX2, AVX512 등)을 활용하려고 시도하는 Intel의 하이퍼스캔 라이브러리에 대한 지원도 함께 제공됩니다.
아마도 greppin
브랜치를 구축하고 싶을 것입니다:
$ git checkout greppin
[...]
$ cd src; make
[...]
pcre 및 pcre2 라이브러리 패키지가 설치되어 있는지 확인하십시오. BSD 시스템에서는 make
대신 gmake
필요합니다. greppin의 다중 정규식 엔진 및 하이퍼스캔 지원을 통해 최첨단 기술을 사용하려면 먼저 다음을 가져와서 구축해야 합니다.
$ git clone https://github.com/intel/hyperscan
[...]
$ cd hyperscan
$ mkdir build; cd build
$ cmake -DFAT_RUNTIME=1 -DBUILD_STATIC_AND_SHARED=1 ..
[...]
$ make
[...]
이는 대부분의 성능을 위해 런타임에 올바른 컴파일 패턴을 선택하기 위해 모든 CPU 제품군에 대한 지원을 포함하는 소위 하이퍼스캔 라이브러리의 뚱뚱한 런타임을 구축합니다. 빌드가 완료되면 이에 대해 greppin을 빌드합니다.
(복제된 저장소 내부)
$ cd src
$ HYPERSCAN_BUILD=/path/to/hyperscan/build make -f Makefile.hs
[...]
그러면 -H
옵션이 런타임에 다른 엔진을 로드하여 가능한 모든 성능 비트를 활용하도록 하는 greppin
바이너리가 생성됩니다.
이미 설치된 libs에 연결할 수 있지만 API는 최근 5.x 버전에 일부 기능을 추가했으며 대부분의 배포판은 4.x와 함께 제공됩니다.
Grab 은 mmap(2)
사용하고 줄바꿈을 계산하지 않고 전체 파일 blob과 일치합니다( grep은 일치하는 항목이 없더라도 수행함[2012년 내 grep 코드 검토 기준; 오늘날 상황은 다를 수 있음]). read(2)
보다 빠릅니다 - 파일을 작은 덩어리로 나누고 개행 횟수를 계산합니다. 가능한 경우 Grab은 PCRE JIT 기능도 사용합니다. 그러나 속도 향상은 큰 파일 트리나 빠른 HDD 또는 SSD에서만 측정할 수 있습니다. 후자의 경우, 재귀적으로 그리고 병렬로 일치시키면 속도가 정말 획기적으로(최대 3배 더 빠름) 향상될 수 있습니다. 스토리지가 병목 현상을 일으키기 때문에 HDD에서 검색을 병렬화하는 것은 의미가 없습니다. 검색하는 데 선형적으로 작업을 수행하는 것보다 더 많은 시간이 걸리기 때문입니다.
또한 Grab은 너무 작아서 정규식을 포함할 수 없는 파일을 건너뜁니다. 재귀 검색에서 더 큰 정규식의 경우 파일을 열지 않고도 꽤 많은 양의 파일을 건너뛸 수 있습니다.
아주 새로운 pcre lib가 필요합니다. 일부 이전 시스템에서는 PCRE_INFO_MINLENGTH
및 pcre_study()
누락으로 인해 빌드가 실패할 수 있습니다.
파일은 1Gig 단위로 mmap되고 일치됩니다. 더 큰 파일의 경우 청크의 마지막 4096바이트(1페이지)가 겹쳐지므로 1Gig 경계에서 일치하는 항목을 찾을 수 있습니다. 이 경우 일치 항목이 두 배가 된 것을 볼 수 있습니다(그러나 오프셋은 동일함).
grep 대 Grab 을 측정하는 경우 각 실행 사이에 dentry 및 페이지 캐시를 삭제해야 한다는 점을 명심하세요. echo 3 > /proc/sys/vm/drop_caches
grep 은 바이너리 파일을 발견하면 '바이너리 파일 일치'만 인쇄하는 반면, -s
지정되지 않는 한 Grab은 모든 일치 항목을 인쇄합니다. 따라서 속도 테스트를 위해서는 전체 파일 검색을 강제하기 위해 데이터에 존재 하지 않는 표현식을 검색해야 합니다.
Grab은 인덱싱 없이 큰 디렉토리 트리를 빠르게 grep하도록 만들어졌습니다. 원래 grep 에는 훨씬 더 완전한 옵션 세트가 있습니다. 단일 파일 일치의 속도 향상은 측정 가능한 경우 매우 작습니다.
SSD의 경우 멀티코어 옵션이 적합합니다. HDD의 경우에는 그렇지 않습니다. 헤드가 스레드 사이에 앞뒤로 위치해야 하므로 잠재적으로 지역성 원칙을 파괴하고 성능을 저하시킬 수 있습니다.
greppin
브랜치는 nftw()
의 자체 잠금 없는 병렬 버전을 제공하므로 첫 번째 코어가 디렉토리 트리를 빌드할 때 N - 1개 코어의 유휴 시간을 작업에 사용할 수도 있습니다.
주의할 점: Grab은 디렉토리를 물리적으로 순회합니다. 즉, 심볼릭 링크를 따르지 않습니다.
spot
find
의 병렬 버전입니다. 여러분이 알고 있는 가장 자주 사용되는 옵션을 지원합니다. 더 이상 설명할 내용이 없습니다. 그냥 시도해 보세요.
이는 SSD 검색을 통해 4코어 시스템의 속도 향상을 보여줍니다.
root@linux:~# echo 3 > /proc/sys/vm/drop_caches
root@linux:~# time grep -r foobardoesnotexist /source/linux
real 0m34.811s
user 0m3.710s
sys 0m10.936s
root@linux:~# echo 3 > /proc/sys/vm/drop_caches
root@linux:~# time grab -r foobardoesnotexist /source/linux
real 0m31.629s
user 0m4.984s
sys 0m8.690s
root@linux:~# echo 3 > /proc/sys/vm/drop_caches
root@linux:~# time grab -n 2 -r foobardoesnotexist /source/linux
real 0m15.203s
user 0m3.689s
sys 0m4.665s
root@linux:~# echo 3 > /proc/sys/vm/drop_caches
root@linux:~# time grab -n 4 -r foobardoesnotexist /source/linux
real 0m13.135s
user 0m4.023s
sys 0m5.581s
greppin
분기 사용:
root@linux:~# echo 3 > /proc/sys/vm/drop_caches
root@linux:~# time grep -a -P -r linus /source/linux/|wc -l
16918
real 1m12.470s
user 0m49.548s
sys 0m6.162s
root@linux:~# echo 3 > /proc/sys/vm/drop_caches
root@linux:~# time greppin -n 4 -r linus /source/linux/|wc -l
16918
real 0m8.773s
user 0m4.670s
sys 0m5.837s
root@linux:~#
예! ~ 9대 대 ~ 72대! 이는 4코어 SSD 시스템에서 기존 grep보다 8배 빠른 속도입니다.
동일한 결과가 나왔다는 것을 증명하기 위해:
root@linux:~# echo 3 > /proc/sys/vm/drop_caches
root@linux:~# greppin -n 4 -r linus /source/linux/|sort|md5sum
a1f9fe635bd22575a4cce851e79d26a0 -
root@linux:~# echo 3 > /proc/sys/vm/drop_caches
root@linux:~# grep -P -a -r linus /source/linux/|sort|md5sum
a1f9fe635bd22575a4cce851e79d26a0 -
root@linux:~#
단일 코어 비교에서 속도 향상은 커널이 실제로 grep을 예약하는 CPU에 따라 달라지므로 잡기가 더 빠를 수도 있고 그렇지 않을 수도 있습니다(대부분 그렇습니다). 단일 코어 테스트 간에 로드가 동일하면 큰 파일 트리에서 검색할 때 Grab의 속도가 향상됩니다. 멀티 코어 설정에서는 그랩 이 도움이 될 수 있습니다.
프로젝트는 여기에서 찾을 수 있습니다.
벤치마크 테이블 내부의 주요 속도 향상은 ripgrep이 특별한 옵션 없이 호출될 때 많은 파일(특히 도트 파일)을 무시하고 바이너리 파일을 단일 일치 대상( grep 과 유사)으로 처리한다는 사실에서 비롯됩니다. 비슷한 결과를 얻으려면 다음 사항에 유의하세요(4는 코어 수).
echo 3 > /proc/sys/vm/drop_caches
-j 4 -a --no-unicode --no-pcre2-unicode -uuu --mmap
ripgrep 에 추가합니다. 기본적으로 3배 느린 유니코드와 일치하고 '무시'를 건너뛰어 속도 손실을 보상하려고 하기 때문입니다. 기반 파일. -e
는 -P
보다 빠르므로 -e
선택하는 것이 좋지만 PCRE만큼 강력하지는 않습니다./dev/null
로 리디렉션합니다.-H -n 4
추가하십시오. -H
아주 소수의 예외를 제외하고 PCRE와 호환됩니다(하이퍼스캔 문서에 따르면).setfattr -n user.pax.flags -v "m" /path/to/binary
grsec 시스템에서 실행하고 rwx JIT 매핑이 필요한 경우 그럼 그냥 가서 타이밍을 확인하세요. 하이퍼스캔을 사용하지 않는 경우에도 greppin
PCRE2 표현식(PCRE2 대 PCRE2)을 사용할 때 rg
보다 훨씬 빠르며 가장 빠른 표현식(-e 대 하이퍼스캔)을 비교할 때 여전히 더 빠릅니다.