ISA-L分為了isa-l_pub版本和isa-l_crypto版本, 如圖1所示。前者主要包含了在儲存領域的一些演算法,後者主要包含的是密碼學的一些演算法,包括在最新版本中增加了高效能SM3演算法的支援。
圖 1 ISA-L 庫概況
ISA-L的運算快的主要原因是用了SIMD。那麼SIMD是什麼呢?SIMD(Single Instruction Multiple Data)的中文釋義是單指令流多資料流。顧名思義,就是單條指令,可以處理多條資料流。舉個具體例子,如圖2所示,我們存在兩個陣列,分別存了4個int,如果需要下標相同的元素相加的話,正常程式碼需要寫一個迴圈,分別加4次再存到陣列中。而在SIMD中,只需要做一次add操作就可以完成。並且SIMD中的暫存器每一個小塊的空間也是相對獨立的(當然不同指令集的操作長度也不同),和陣列一樣,下標為1的數值相加溢位後,不會影響到下標0的數值。
圖 2 SIMD add指令示例
從最早的MMX,到後來的SSE(包括SSE、SSE2、SSE3、SSE4)、AVX,AVX2,再到如今的AVX512指令集,都是SIMD的指令集。而ISA-L的核心就是對於SIMD的使用,將指令集運算細節封裝,再暴露出上層C的介面,以達到加速的目的。對於不同的SIMD指令集,運算暫存器組有如下區別:SSE :XMM0 ~ XMM7 , 提供了8個128位暫存器SSE(x86-64) : XMM0 ~ XMM15,提供了16個128位暫存器AVX(AVX-128): XMM0 ~ XMM15,暫存器同於SSE(x86-64),不同於SSE的是,提供了更為多且方便的運算指令,比如使用vshufps代替shufps。AVX2(AVX-256): YMM0 ~ YMM15,提供了16個256位暫存器。提供了更多的運算指令。AVX512:ZMM0 ~ ZMM31,提供了32個512位暫存器。提供了更多的運算指令。值得一提的是,AVX512的ZMM暫存器和AVX2的YMM暫存器有著重疊的關係,AVX2的YMM暫存器組和SSE的XMM暫存器組同樣存在著重疊的關係。 舉個例子,當你機器同時擁有AVX512和AVX2指令集時,當你操作YMM0的時候,會改變ZMM0低位256位的暫存器組。它們的關係如圖3所示:
圖 3 XMM, YMM, ZMM 暫存器之間的關係
所以,當你混用不同指令集的時候,需要注意指令集的操作範圍,防止得出來的計算結果只能正確一部分。SIMD基本原理介紹完了,那麼ISA-L是如何使用SIMD來加速運算的呢?首先,在專案include目錄下有一個multibinary.asm彙編檔案,該檔案提供了一系列的彙編方法名為mbin_dispatch_init,而在ISA-L中的每一種演算法都必須註冊這個彙編方法,該方法會檢查你的CPU flag,來獲得支援的指令集,從而進行資料流的分發。舉個例子,當你呼叫ISA-L中sha256的方法,ISA-L會檢測到你的CPU只支援AVX2,那麼會把資料流分發到AVX2的彙編演算法進行下一步操作。而當ISA-L分發好了資料流,選定了計算所用的指令集後,就會將資料流從記憶體填充到具體的暫存器,再呼叫具體的指令集進行演算法計算。一般來說,在記憶體中的資料流都是由多段buffer組成的,這樣對於SIMD來說是友好的。舉個例子,當用戶需要計算多個數據的hash結果時,使用者將資料放到記憶體中,組成一個char *的陣列。再呼叫ISA-L的介面,得到一個存了所有計算好hash的陣列。而在中間過程中,無論使用者放到記憶體中的陣列有多長,ISA-L每次只取出固定lane的資料進行計算(lane指的是一次計算能處理的最大長度,比如名為sha256_mb_x16_avx512.asm實現的axv512版本的sha256,x16代表了一次可以取16個lane的資料,對應到陣列為取16個元素),但是使用者輸入的資料中,單個元素中的char *長度可能有長有短,比如圖4 中的data2,因為資料過長,在第一次hash過程中,只處理了部分資料,得到了一箇中間值,那麼它將加入下一輪計算,而data1已經計算完成了,那麼會填充到記憶體中,不再經過下一輪計算。
圖 4 ISA-L中hash計算
除了SIMD之外,ISA-L也支援了一些比較“另類”的指令集,比如SHANI,這是為了加速少量資料HASH而設計的,之前說過SHA256的AVX512版本一次處理16個lane的資料,但是但使用者一次提交的資料數目過少,或者SIMD計算後只剩下單個或兩個過長的buffer沒有計算完,SHANI就可以加速這種情況。當然除了SHANI之外,ISA-L同樣也用了AESNI指令集對AES進行加速。另外在ISA-L中,為了減少記憶體的throughput,我們儘量的避免了在演算法過程中使用棧,為了代替棧的使用,我們儘量的使用暫存器作為暫存資料(當然這也帶來了程式碼的可讀性降低)。但是在一些情況下也是不可避免的使用了棧進行快取,比如當你的暫存器已經佔滿,不夠用的時候,或者演算法要求的預運算值會佔用比較大的空間。這也是另外一點ISA-L計算快的原因。
二ISA-L支援的演算法
isa-l_pub目前版本(v2.30.0)包含了以下演算法:EC(erasure codes) : 型別為Reed-Solomon編碼的糾錯碼,使用了GF(2^8),並且提供了一些有限域內運算的介面。CRC(Cyclic Redundancy Check) : 支援iscsi32, ieee32, t10dif, ecma64, iso64, jones64多項式的迴圈冗餘校驗,不同的標準返回的crc長度也是不同的。Raid(Redundant Array of Independent Disks) : 並不是支援磁碟陣列的標準,而是支援raid標準中經常需要用到的XOR和P + Q運算。Igzip(ISA-L GNU ZIP) : 主要支援deflate和inflate演算法,同時也支援了GNU ZIP的頭部資訊的寫入和解析。isa-l_crypto目前版本(v2.23.0)包含了以下演算法:Multi-buffer hashes : 包含了標準SHA1、SHA256、SHA512、MD5、SM3的hash演算法集。MH (Multi hashes) : 自研hash演算法,包含了mh-sha1和mh-sha256。它的設計為了序列的hash過程 ,設計核心是將單個的buffer分組為多個塊進行SIMD過程, 有興趣的讀者可以看看multi-hash-paper(在文末點選“閱讀原文”即可)。(注意:mh1-sha256得出的結果和標準sha256得出的結果並不一致。)AES(Advanced Encryption Standard) : 標準的AES演算法,支援GCM、CBC、XTS三種模式,並且支援128位、192位、256位金鑰長度。Rolling hash : 標準的劃窗hash
三ISA-L的使用
要進行編譯以及安裝庫,通常只需執行如下即可:
./autogen.sh./configuremakesudo make install
對於isa-l_pub來說,如果需要編譯target:make check : 編譯並執行基本的執行測試,測試包含了一些內建的測試集make tests : 編譯並執行基本的單元測試make perfs : 編譯並執行isa-l_pub的效能測試軟體,將會和openssl對比效能make ex : 編譯內建的example,並非所有演算法都有examplemake other : 編譯工具集,目前isa-l_pub只提供了igzip的一個工具集。make doc : 編譯建立api文件對於isa-l_crypto來說,由於isa-l_crypto並沒有額外的工具集提供,所以並沒有make other選項提供。其他的編譯target的選項和isa-l_pub一致。當你構建並安裝好ISA-L後,預設情況下標頭檔案安裝在/usr/include,庫檔案安裝在/usr/lib64/下。你可以將相應的庫和標頭檔案引入專案即可使用。但是在介面方面,ISA-L的和openssl的並不完全一致。對於一些演算法來說,ISA-L提供了example和工具來展示介面如何使用,這並不是全部演算法都包含的。這個時候,你可以參考演算法的API文件或者相應的tests來編寫自己的應用程式。再或者,如果你目前的專案使用的是openssl,想切換到isa-l,那麼你可以參考一下ISA-L中帶有rand test的測試案例,這種測試案例都是和openssl進行對比測試。拿sha256_mb/sha256_mb_rand_ssl_test.c為例,這裡ISA-L用了自己的sha256介面和openssl的介面分別運算同一串字串,得到結果進行對比測試。呼叫openssl的介面用到了SHA256()函式,但我們ISA-L的介面卻用到了三個函式:sha256_ctx_mgr_init : 初始化sha256的ctxsha256_ctx_mgr_submit : 將ctx裡面的資料提交sha256_ctx_mgr_flush : 將ctx未計算完的資料全計算完成我們介面能接收的資料是多個buffer,而非單串字串。接收多個buffer後,使用SIMD,效能自然是openssl的數倍,當然我們也能夠提供提個類似於openssl SHA256的介面,但是這並不符合ISA-L設計的初衷。
四SPDK/DPDK中 ISA-L的支援情況
在DPDK中,ISA-L幫助DPDK構建了 Compression dev和 crypto dev,具體使用情況如下:在Compression dev中使用DEFLATE介面(包含在igzip中),來幫助PMD進行壓縮/解壓操作CRC32,來幫助PMD進行資料完整性校驗在crypto dev中AES,幫助PMD進行AES的加密/解密操作HASH,幫助PMD對資料進行hash操作而在SPDK中,ISA-L作為一個git submodule被包含了進去,在很多地方也有使用ISA-L,具體如下:SPDK中提供了vbdev_crypto和vbdev_compress,這是藉助於DPDK中Compression dev和crypto dev實現的,底層同樣運行了ISA-LISA-L的CRC被SPDK封裝成了一個util,在blobstore,tcp,iscsi,ftl,ocf等模組中都有用到。