Мы наконец-то зарелизили CRC32C библиотеку в abseil. Я её всю перехерачил по перфу и по API, и спасибо коллегам из C++ команды, что они её дотащили до OSS.



Поглядеть:

https://github.com/abseil/abseil-cpp/blob/master/absl/crc



Уроки и фичи:



* CRC хорошая полиномиальная чексумма, она стриминговая, вы можете добавлять чанки:



crc32c_t crc = 0;

crc = ExtendCrc32c(crc, chunk);



Неважно как вы дробите эти чанки, если в конкатенации получаются те же данные, то чексумма совпадёт. Это позволяет сервисам типа мап редьюса разделять динамически данные на чанки разной длины и проверять в конце, что всё сходится.



* В проде >75% вызовов до 64 байт. Поэтому мы выиграли очень много перфа, когда компилятор инлайнил с помощью PGO код в релизных сборках.



* В проде оказался большой хвост степеней двоек -- 4KB, 1MB, 4MB чексуммы доминировали какие-то проценты вычислений.



* Intel очень хорошие писала гайды о том, как надо имплементировать CRC32{C}, и, конечно, мы это и сделали.



* Только вот не одним Intel мы живём, а также есть куча разного парка железа типа AMD, старых интелов и тд. В итоге мы очень внимательно подбирали размеры буфферов для CLMUL fold и CRC fold. Получилась весьма забавная табличка что где лучше работает. CLMUL на AMD всё ещё очень медленный.



* На удивление мы побили все бенчмарки на Arm'ах N1+ и библиотеку ISA-L, которую инженеры из Arm сами пишут. Притом гайды от Intel отлично легли, и код получился унифицированным (но не обошлось и без проблем).



* Мы не ставили цели бить Apple. За самым быстрым CRC для Apple можно обратиться сюда (спойлер: они прошли по тонкой грани, когда смогли сделать fusion двух инструкций, до сих пор спорят, разрешает ли так делать лицензия Arm):

https://dougallj.wordpress.com/2022/05/22/faster-crc32-on-the-apple-m1/



* Имплементация от dougallj@ плохая на серверах. На наших T2A инстансах мы получили



dougallj@: 21.84123gb/s

Goog: 33.268118gb/s



* Оказалось, что людям нужно API как MemcpyCRC32C, чтобы скопировать и вычислять чексуммы одновременно. Это получается много где быстрее, так как можно контролировать чанки по которым зовёшь memcpy и утилизируя все пайплайны процессора.



* Non-temporal memcpy
оказались полезными нашему самому низкому storage layer. Пока мы не взялись релизить флажок, но мы сделаем это в итоге. Non-temporal инструкции (проходящие мимо кешей процессора) забавные, конечно, на микробенчмарках полная ерунда, в проде чуть получше и мы реально разгрузили приличную часть давления на память с помощью них. К сожалению, не на всех процессорах, а на одном нашли даже дефект :)



* Было забавно, к сожалению, чтобы так красиво фаниться, не очень много проектов существует.