このページの内容

マクロ

#define XXH_SCALAR   0
 XXH_VECTORに指定できる値。
#define XXH_NO_LONG_LONG
 64ビットのコードを無効にする場合に定義します。
#define XXH_FORCE_MEMORY_ACCESS   0
 アライメントされていないメモリーへのアクセス方法を制御します。
#define XXH_SIZE_OPT   0
 xxHashのサイズ最適化の程度を制御します。
#define XXH_FORCE_ALIGN_CHECK   0
 0以外に定義すると、アライメントされた入力用の特別な処理経路を追加します(XXH32() と XXH64() のみ)。
#define XXH_NO_INLINE_HINTS   0
 0以外の場合、すべての関数を staticとして指定します。
#define XXH3_INLINE_SECRET   0
 XXH3のwithSecretコードをインライン化するかどうかを決めます。
#define XXH32_ENDJMP   0
 XXH32_finalizeでジャンプを使用するかどうかを決めます。
#define XXH_OLD_NAMES
#define XXH_NO_STREAM
 ストリーミングAPIを無効にします。
#define XXH_DEBUGLEVEL   0
 デバッグレベルを設定します。
#define XXH_CPU_LITTLE_ENDIAN   XXH_isLittleEndian()
 対象がリトルエンディアンかどうかを示します。
#define XXH_VECTOR   XXH_SCALAR
 XXH3用に選択されるベクトル化の実装を上書きします。
#define XXH_VECTOR   XXH_SCALAR
 XXH3用に選択されるベクトル化の実装を上書きします。
#define XXH_ACC_ALIGN   8
 XXH3のアキュムレーターの最小アライメントを選択します。
#define XXH3_NEON_LANES   XXH_ACC_NB
 XXH3でのNEONとスカラーの比率を制御します。

詳細説明

xxHashの動作を制御する各種マクロ。

マクロ定義の説明

◆ XXH_SCALAR

#define XXH_SCALAR   0

XXH_VECTORに指定できる値。

明示的に設定しない場合は自動的に決まります。移植可能なスカラー版です。

◆ XXH_NO_LONG_LONG

#define XXH_NO_LONG_LONG

64ビットのコードを無効にする場合に定義します。

使用するのが XXH32ファミリー のみで、厳密なC90コンパイラーを使う場合に役立ちます。

◆ XXH_FORCE_MEMORY_ACCESS

#define XXH_FORCE_MEMORY_ACCESS   0

アライメントされていないメモリーへのアクセス方法を制御します。

デフォルトでは、アライメントされていないメモリーへのアクセスに memcpy()を使用します。これは安全で移植可能です。

ただし、対象とコンパイラーの組み合わせによっては、生成されるアセンブリーが最適ではありません。

次の切り替えにより、性能改善のために別のアクセス方法を選択できます。

指定可能な選択肢:
  • XXH_FORCE_MEMORY_ACCESS=0 (デフォルト): memcpy
    使用する方法: memcpy()。安全で移植可能です。多くの現代的なコンパイラーは関数呼び出しを取り除き、アライメントされていないアクセスとして扱います。
  • XXH_FORCE_MEMORY_ACCESS=1: __attribute__((aligned(1)))
    コンパイラー拡張に依存するため、移植可能ではありません。この方法は、コンパイラーが対応している場合に安全です。また、一般に memcpyと同等以上の速度が得られます。
  • XXH_FORCE_MEMORY_ACCESS=2:直接キャスト
    直接キャストして参照先を読み出します。この方法はコンパイラーには依存しませんが、アライメントされていないポインターの参照先を直接読み出すため、C標準に違反します。アライメントされていないメモリーアクセスに対応しない対象では、不具合のあるコードを生成する可能性があります。ただし、状況によっては最高の性能を得られる唯一の既知の方法です。
  • XXH_FORCE_MEMORY_ACCESS=3:バイトシフト
    これも移植可能です。小さな呼び出しをインライン化しない古いコンパイラーでは、最適なコードを生成できる場合があります。該当する呼び出し: memcpy() 。また、ネイティブのバイト交換命令を持たないビッグエンディアンシステムでは、より高速になる可能性があります。ただし、対象がアライメントされていないアクセスに対応していても、一部のコンパイラーは文字どおりのバイトシフトを生成します。
    警告
    方法1と2は実装定義の動作に依存します。あるコンパイラー・プラットフォーム・最適化レベルで動作しても、別の条件では不正なデータを読み込んだり、クラッシュしたりする可能性があるため、慎重に使ってください。
    詳細は https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html を参照してください。

方法は次の優先順位で選んでください(0 > 3 > 1 > 2)。

◆ XXH_SIZE_OPT

#define XXH_SIZE_OPT   0

xxHashのサイズ最適化の程度を制御します。

xxHashはコンパイルすると、比較的大きなバイナリーになりがちです。主な原因は、 XXH3ファミリー の性能を高めるために、強制インライン化と定数畳み込みを多用していることです。

一方、速度よりサイズを重視する開発者もいます。この選択肢は、生成コードのサイズを大きく減らせます。GCCまたはClangで -Os または -Oz を使用するとデフォルトで1、それ以外では0に定義されます。

これらのサイズ最適化の大部分は手動で制御できます。

値は0から2までの数値です。

  • XXH_SIZE_OPT == 0:デフォルト。xxHashはサイズ最適化を行わず、速度を優先します。
  • XXH_SIZE_OPT == 1:デフォルトとなるオプション: -Os と -Oz。xxHashはより保守的に動作し、コードサイズを増やす工夫を無効にします。未定義の場合、次の設定を含意します: XXH_NO_INLINE_HINTS == 1, XXH_FORCE_ALIGN_CHECK == 0、および XXH3_NEON_LANES == 8。
  • XXH_SIZE_OPT == 2:xxHashは可能な限り小さくしようとします。性能が大きく低下するかもしれません。例えば、ワンショット関数は単にストリーミングAPIを使います。

◆ XXH_FORCE_ALIGN_CHECK

#define XXH_FORCE_ALIGN_CHECK   0

0以外に定義すると、アライメントされた入力用の特別な処理経路を追加します(XXH32() と XXH64() のみ)。

これは、アライメントされていないメモリーへのアクセス性能が十分でないアーキテクチャーで重要な性能改善手法です。

入力のアライメントを確認し、条件を満たす場合は32ビット・64ビットの直接読み込みによる「高速経路」を使います。これにより、 読み込み速度が大幅に 向上します。

この確認にはハッシュごとに最初の分岐が1回必要です。通常は無視できる程度ですが、コストはゼロではありません。

さらに、アライメントされたアドレスとされていないアドレスに同じメモリーアクセス命令を使う場合(x86やaarch64など)は、処理経路を追加しても役に立ちません。

この場合、このマクロを0にしてアライメント確認を取り除けます。コードは常にアライメントされていないメモリーアクセスを使うようになります。このアクセスの性能が良いことが知られているx86、x64、ARM64、および一部のARMチップでは、確認は自動的に無効になります。

また、デフォルトで無効になる条件は XXH_SIZE_OPT >= 1です。

この選択肢はXXH3には影響せず、XXH32とXXH64だけに影響します。

◆ XXH_NO_INLINE_HINTS

#define XXH_NO_INLINE_HINTS   0

0以外の場合、すべての関数を staticとして指定します。

デフォルトでは、xxHashはほぼすべての内部関数を強制的にインライン化させようとします。

通常はジャンプの削減と定数畳み込みの改善によって性能が向上しますが、バイナリーサイズが大幅に増えるため、望ましくない場合があります。

また、アーキテクチャーによっては、強制インライン化が性能を損なう場合もあります。

XXH_NO_INLINE_HINTSはすべての内部関数をstaticとして指定し、インライン化の判断を完全にコンパイラーへ委ねます。

最適化しない場合(-O0)、GCCまたはClangで -fno-inline を使う場合、または XXH_SIZE_OPT >= 1の場合、これは自動的に定義されます。

◆ XXH3_INLINE_SECRET

#define XXH3_INLINE_SECRET   0

XXH3のwithSecretコードをインライン化するかどうかを決めます。

secretのサイズが既知の場合、コンパイラーは次の関数の性能を改善できます: XXH3_64bits_withSecret() と XXH3_128bits_withSecret()。

ただし、secretのサイズが不明の場合は利点がありません。これはxxHashをグローバルシンボルとしてコンパイルする場合に発生します。そのため、 XXH_INLINE_ALL が 未 定義の場合、これは0に定義されます。

また、GCC 12以降ではデフォルトが0です。このコンパイラーには、関数ポインターが 場合によっては -Ogで強制インライン化される問題があり、この最適化レベルを自動検出することは不可能です。

◆ XXH32_ENDJMP

#define XXH32_ENDJMP   0

XXH32_finalizeでジャンプを使用するかどうかを決めます。

性能上の理由から、 XXH32_finalize は最終処理で複数の分岐を使います。通常は性能面で有利ですが、具体的なアーキテクチャーによってはjmpが有利な場合もあります。

この設定によって差が生じる可能性があるのは、非常に小さな入力だけです。

◆ XXH_NO_STREAM

#define XXH_NO_STREAM

ストリーミングAPIを無効にします。

xxHashをインライン化せず、ストリーミング関数を使用しない場合、それらを無効にするとコードサイズを大きく削減できます。特に効果があるのは、 XXH3ファミリー で、定数畳み込みされた自身のコピーを生成しがちです。

◆ XXH_DEBUGLEVEL

#define XXH_DEBUGLEVEL   0

デバッグレベルを設定します。

XXH_DEBUGLEVELは外部で定義することを想定しており、通常はコンパイラーのコマンドラインオプションを使います。値は数値でなければなりません。

◆ XXH_CPU_LITTLE_ENDIAN

#define XXH_CPU_LITTLE_ENDIAN   XXH_isLittleEndian()

対象がリトルエンディアンかどうかを示します。

対象がリトルエンディアンの場合は1、ビッグエンディアンの場合は0に定義します。例えばコンパイラーのコマンドラインで、外部から定義できます。

未定義の場合は、代わりに実行時確認を使います(通常は定数畳み込みされます)。

注記
必ずしも整数定数として定義されるとは限りません。
関連項目
実行時確認についてはXXH_isLittleEndian()を参照。

◆ XXH_VECTOR [1/2]

#define XXH_VECTOR   XXH_SCALAR

XXH3用に選択されるベクトル化の実装を上書きします。

SIMDを無効にする場合は0、または次のマクロに認められたその他の値に定義できます: XXH_VECTOR。

未定義の場合は、定義済みのマクロから最適な実装を決定します。

◆ XXH_VECTOR [2/2]

#define XXH_VECTOR   XXH_SCALAR

XXH3用に選択されるベクトル化の実装を上書きします。

SIMDを無効にする場合は0、または次のマクロに認められたその他の値に定義できます: XXH_VECTOR。

未定義の場合は、定義済みのマクロから最適な実装を決定します。

◆ XXH_ACC_ALIGN

#define XXH_ACC_ALIGN   8

XXH3のアキュムレーターの最小アライメントを選択します。

SIMDを使う場合は、そのベクトル型が必要とするアライメントに合わせます。例えばAVX2では32です。

デフォルト:自動検出。

◆ XXH3_NEON_LANES

#define XXH3_NEON_LANES   XXH_ACC_NB

XXH3でのNEONとスカラーの比率を制御します。

2、4、6、8のいずれかに設定できます。

ARM Cortex CPUは、パイプラインの使われ方に 非常に 敏感です。

例えばCortex-A73は1サイクルに3マイクロオペレーションを発行できますが、そのうちNEONは2つだけです。NEON命令だけを使うと、CPUの処理帯域の2/3しか使えません。

これはCortex-A76などの、より高度なコアでさらに顕著です。1サイクルに8マイクロオペレーションを発行できますが、同時に発行できるNEONマイクロオペレーションは依然として2つです。

そのため、パイプラインを最大限に使うには、NEONを6レーン、スカラーを2レーン動かすことが有利で、デフォルトではこの構成を選びます。

これはAppleのプロセッサーや32ビットプロセッサーには当てはまりません。これらはすべてNEONにする方が良く動作するため、デフォルトは8です。また、サイズ最適化ビルドも8レーンを使います。

この変更は、大部分の他のCPUに悪影響を与えず、大きなマイクロオペレーションバッファーを持つCPUに利点をもたらします:

チップセット 発行方式 NEONのみ 6:2混合 差
Snapdragon 730 (A76) 2 NEON/8マイクロオペレーション 8.8 GB/s 10.1 GB/s ~16%
Snapdragon 835 (A73) 2 NEON/3マイクロオペレーション 5.1 GB/s 5.3 GB/s ~5%
Marvell PXA1928 (A53) インオーダー・2命令同時発行 1.9 GB/s 1.9 GB/s 0%
Apple M1 4 NEON/8マイクロオペレーション 37.3 GB/s 36.1 GB/s ~-3%

また、GCCの不適切なコード生成の一部も改善し、ほぼclangと同じ速度になるようです。

WASM SIMD128使用時にこの値を2または6にすると、SIMDeが2レーンをスカラー化するため、実質的には4よりも悪くなります。

関連項目
XXH3_accumulate_512_neon()