2016-05-22 13 views
8

私は最近CloudFlare's optimized zlibで遊んでいて、結果は本当に印象的です。zlib CRC32でキャリーレス乗算アセンブリ(PCLMULQDQ)を正しく使用する方法は?

残念ながら、彼らはzlibの開発が放棄され、そのフォークが破棄されたと思われるようです。私は最終的にmanually rebase their changescurrent zlib developmentのブランチに行くことができましたが、それはお尻の本当の痛みでした。

とにかく、私はすなわち、利用することができていないCloudFlareのコード内の1つの主要最適化、fast CRC32 code implemented with the PCLMULQDQキャリーレス乗算命令は、新しいに含まれ(ハスウェル以降、私は信じている)Intelプロセッサがあるため、まだあります:

  1. 私はMac上だし、打ち鳴らす統合アセンブラやAppleの古代ガスのどちらも使用新しいGASニーモニックを理解し、 と

  2. コードは、Linuxカーネルから持ち上げられているましたGPL2はライブラリ全体をGPL2にし、基本的に私の目的には役に立たない。

だから私は周りにいくつかの狩猟をした、と私はAppleが自分のbzip2で使用しているいくつかのコードにつまずいた数時間後:arm64x86_64の両方のための手書き、ベクトル化CRC32の実装。 、

This function SHOULD NOT be called directly. It should be called in a wrapper 
function (such as crc32_little in crc32.c) that 1st align an input buffer to 16-byte (update crc along the way), 
and make sure that len is at least 16 and SHOULD be a multiple of 16. 

しかし残念ながら、私:

奇妙な話、x86_64のアセンブリのためのコメントは、arm64ソースに(のみ)ですが、このコードは、zlibのに使用できることを示しているように見えるんいくつかの試みの後、この時点で私は少し頭の中にいるようです。そして、私は実際どのようにを行うのか分からない。。だから、誰かがどのように/どこで機能を提供するかを私に見せてくれることを望んでいた。

(実行時に必要な機能が検出され、ハードウェア機能が利用できない場合はソフトウェアの実装に戻ってしまう可能性があるので、素晴らしい方法ですので、配布する必要はありませんしかし、少なくとも、ライブラリをApple PCLMULQDQベースのCRC32を正しく使用する方法を誰かが助けてくれれば、それは長い道のりになります。)

+0

。インテルのマニュアルを確認してください。 – James

答えて

4

これは、 16バイトの倍数の長さを持つ16バイトの整列バッファーでCRC合計を計算する必要があります。したがって、現在のバッファポインタをuintptr_tとしてキャストし、4LSBビットがゼロでない限り、バイトを通常のCRC-32ルーチンに送ります。 16バイトの位置合わせされたアドレスになったら、残りの長さを16の倍数に丸めて、これらのバイトを高速CRC-32に送り、残りのバイトを再び遅い計算に送ります。


ような何か:あなたはCPUID命令を実行時にハードウェア機能を列挙することができます

// a function for adding a single byte to crc 
uint32_t crc32_by_byte(uint32_t crc, uint8_t byte); 

// the assembly routine 
uint32_t _crc32_vec(uint32_t crc, uint8_t *input, int length); 

uint32_t crc = initial_value; 
uint8_t *input = whatever; 
int length = whatever; // yes, the assembly uses *int* length. 

assert(length >= 32); // if length is less than 32 just calculate byte by byte 
while ((uintptr_t)input & 0xf) { // for as long as input is not 16-byte aligned 
    crc = crc32_by_byte(crc, *input++); 
    length--; 
} 

// input is now 16-byte-aligned 
// floor length to multiple of 16 
int fast_length = (length >> 4) << 4; 
crc = _crc32_vec(crc, input, fast_length); 

// do the remaining bytes 
length -= fast_length; 
while (length--) { 
    crc = crc32_by_byte(crc, *input++) 
} 
return crc; 
関連する問題