libpopcnt.h
、特殊な CPU 命令 (POPCNT、AVX2、AVX512、NEON、SVE) を使用して配列内の 1 ビットの数 (ビット数カウント) をできるだけ早くカウントするためのヘッダーのみの C/C++ ライブラリです。 libpopcnt.h
、GCC、Clang、および MSVC コンパイラーを使用して正常にテストされました。
#include "libpopcnt.h"
/*
* Count the number of 1 bits in the data array
* @data: An array
* @size: Size of data in bytes
*/
uint64_t popcnt ( const void * data , uint64_t size );
libpopcnt.h
-mavx2
のような特別なコンパイラ フラグは必要ありません。最高のパフォーマンスを得るには、 -O3
または-O2
などの最適化を有効にしてコンパイルすることのみをお勧めします。
cc -O3 program.c
c++ -O3 program.cpp
libpopcnt.h
は、次の CPU アーキテクチャ用のハードウェア アクセラレーションによるポップカウント アルゴリズムが含まれています。
x86 | POPCNT 、 AVX2 、 AVX512 |
x86-64 | POPCNT 、 AVX2 、 AVX512 |
アーム | NEON 、 SVE |
PPC64 | POPCNTD |
他の CPU アーキテクチャの場合は、高速整数ポップカウント アルゴリズムが使用されます。
x86 CPU では、 libpopcnt.h
最初にCPUID
命令を使用して CPU のサポートされている命令セットをクエリします (これは 1 回だけ実行されます)。次に、 libpopcnt.h
CPU でサポートされている最速のビット数カウント アルゴリズムを選択します。
AVX512
をサポートしている場合は、 AVX512 VPOPCNT
アルゴリズムが使用されます。AVX2
をサポートしている場合はAVX2 Harley Seal
アルゴリズムが使用されます。POPCNT
をサポートしている場合は、 POPCNT
アルゴリズムが使用されます。POPCNT
命令のない CPU の場合は、移植可能な整数アルゴリズムが使用されます。 libpopcnt.h
すべての CPU (x86、ARM、PPC、WebAssembly など) で動作することに注意してください。これはデフォルトでポータブルであり、ハードウェア アクセラレーションは CPU がサポートしている場合にのみ有効になります。 libpopcnt.h
スレッドセーフでもあります。
私たちはパフォーマンスを重視しています。たとえば、AVX512 をサポートする x86 CPU で-march=native
使用してコンパイルすると、すべてのランタイムCPUID
チェックが削除されます。
ARM SVE は、2020 年に初めてリリースされた ARM CPU 用の新しいベクトル命令セットです。ARM SVE は、128 ~ 2048 ビットの可変ベクトル長をサポートします。したがって、ARM SVE アルゴリズムは、ベクトル長が 128 ビットに制限されている ARM NEON アルゴリズムよりもはるかに高速になります。
libpopcnt の新しい ARM SVE ポップカウント アルゴリズムは、ARM NEON ポップカウント アルゴリズム (AWS Graviton3 CPU 上) より最大 3 倍高速です。残念ながら、ARM SVE へのランタイム ディスパッチは、GCC、Clang コンパイラ、libc ではまだ十分にサポートされていません。したがって、ARM CPU で libpopcnt を使用する場合、デフォルトでは (ポータブル) ARM NEON ポップカウント アルゴリズムのみが有効になります。
libpopcnt の ARM SVE ポップカウント アルゴリズムを有効にするには、コンパイラの ARM SVE オプションを使用してプログラムをコンパイルする必要があります。例:
gcc -O3 -march=armv8-a+sve program.c
g++ -O3 -march=armv8-a+sve program.cpp
cmake .
make -j
make test
上記のコマンドは、 libpopcnt.h
ベンチマークに役立つbenchmark
プログラムも構築します。以下は、2023 年の AMD EPYC 9R14 CPU で実行される使用例です。
# Usage: ./benchmark [array bytes] [iters]
./benchmark
Iters: 10000000
Array size: 16.00 KB
Algorithm: AVX512
Status: 100%
Seconds: 1.23
133.5 GB/s
libpopcnt.h
で使用されるアルゴリズムの一部は、Daniel Lemire、Nathan Kurz、Wojciech Mula による論文「Faster Population Counts using AVX2 命令」 (2016 年 11 月 23 日) で説明されています。 libpopcnt.h
で使用される AVX2 Harley Seal ポップカウント アルゴリズムは、Wojciech Muła の sse-popcount GitHub リポジトリからコピーされました。