這是我自己的實驗性並行版本的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
scrap使用PCRE庫,因此基本上相當於grep -P -a
。 -P
很重要,因為 Perl 相容正規表示式與基本正規表示式有不同的特徵。
有兩個分支。 master
和greppin
。 Master 是「傳統」的抓取工具,應該在大多數 POSIX 系統上編譯和運行。 greppin
附帶了自己優化和並行化的nftw()
和readdir()
版本,這在master
分支已經提供的加速基礎上再次將速度提高了一倍。 greppin
分支在 Linux、BSD 和 OSX 上運行。 greppin
也支援 Intel 的 hyperscan 函式庫,在將正規表示式模式編譯為 JIT 程式碼時,如果可能的話,這些函式庫會嘗試利用 CPU 的 SIMD 指令(AVX2、AVX512 等)。
您很可能想要建立greppin
分支:
$ git checkout greppin
[...]
$ cd src; make
[...]
確保您已安裝pcre和pcre2庫包。在 BSD 系統上,您需要gmake
而不是make
。如果您想使用greppin 的多個正規表示式引擎和 hyperscan 支援來實現尖端技術,您首先需要取得並建立:
$ git clone https://github.com/intel/hyperscan
[...]
$ cd hyperscan
$ mkdir build; cd build
$ cmake -DFAT_RUNTIME=1 -DBUILD_STATIC_AND_SHARED=1 ..
[...]
$ make
[...]
這將建立所謂的 hyperscan 庫的胖運行時,其中包含對所有 CPU 系列的支持,以便在運行時選擇正確的編譯模式以獲得最佳性能。建置完成後,您可以針對該建置greppin :
(在抓取克隆倉庫內)
$ cd src
$ HYPERSCAN_BUILD=/path/to/hyperscan/build make -f Makefile.hs
[...]
這將產生一個greppin
二進位文件,使-H
選項能夠在運行時加載不同的引擎,嘗試利用所有可能的性能位。
您可以將其連結到已安裝的庫,但該 API 最近剛剛在 5.x 版本中添加了一些功能,並且大多數發行版都附帶 4.x。
scrap使用mmap(2)
並匹配整個檔案 blob,而不計算換行符(即使沒有匹配, grep也會這樣做 [截至我 2012 年的 grep 程式碼審查;今天的情況可能有所不同]),這是很多比read(2)
更快 - 將檔案分成小塊併計算換行符。如果可用, grab也使用 PCRE JIT 功能。然而,加速只能在大型文件樹或快速 HDD 或 SSD 上進行測量。在後一種情況下,如果遞歸且並行匹配,加速效果可能會非常顯著(最多快 3 倍)。由於儲存是瓶頸,因此在 HDD 上並行搜尋是沒有意義的,因為搜尋比僅以線性方式執行操作需要更多時間。
此外, grab會跳過太小而無法包含正規表示式的檔案。對於遞歸搜尋中較大的正規表示式,這可以跳過大量文件,甚至無需打開它們。
需要一個相當新的pcre庫,在某些較舊的系統上,建置可能會因為缺少PCRE_INFO_MINLENGTH
和pcre_study()
而失敗。
檔案以 1Gig 的區塊進行映射和匹配。對於較大的文件,區塊的最後 4096 位元組(1 頁)會重疊,以便可以找到 1 Gig 邊界上的匹配項。在這種情況下,您會看到匹配加倍(但偏移量相同)。
如果您測量grep與grab ,請記住在每次運行之間刪除目錄項目和頁面快取: echo 3 > /proc/sys/vm/drop_caches
請注意,如果grep檢測到二進位文件,則它只會列印“二進位檔案匹配”,而grab將列印所有匹配,除非給出-s
。因此,對於速度測試,您必須搜尋資料中不存在的表達式,以便強制搜尋整個檔案。
抓取是為了在大型目錄樹中快速 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 秒 vs. ~ 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會看到加速。在多核心設定上, grab可以受益於corse。
該項目可以在這裡找到。
其基準表中的主要加速源自於以下事實: ripgrep在沒有特殊選項的情況下呼叫時會忽略許多檔案(尤其是點檔案),並將二進位檔案視為單一符合目標(類似於grep )。為了獲得可比較的結果,請記住(4 是核心數):
echo 3 > /proc/sys/vm/drop_caches
-j 4 -a --no-unicode --no-pcre2-unicode -uuu --mmap
添加到ripgrep ,因為它默認匹配慢 3 倍的 Unicode,並嘗試通過跳過 'ignore' 來補償速度損失基於文件。 -e
比-P
更快,所以最好選擇-e
,但這不如 PCRE 強大/dev/null
以避免基於 tty 的影響-H -n 4
加入greppin 。 -H
與 PCRE 相容,只有極少數例外(根據 hyperscan 文件)setfattr -n user.pax.flags -v "m" /path/to/binary
如果您在 grsec 系統上運行並且需要 rwx JIT 映射然後繼續檢查時間。即使不使用 hyperscan,在使用 PCRE2 表達式(PCRE2 與 PCRE2)時, greppin
也明顯快於rg
並且在比較最快的表達式(-e 與 hyperscan)時仍然更快。