2019年10月14日月曜日

marisa-trie で BMI2 の PDEP 命令を使えるようにしました

簡潔ビットベクトルの select に BMI2 の PDEP 命令を使うと実装を単純化できる上に高速化できるという情報を見つけたので marisa-trie (https://github.com/s-yata/marisa-trie) に組み込んで試してみました.

PDEP を使うのは, 64-bit 整数まで絞り込んだ後になります.
marisa-trie での該当箇所は以下の通りです.(MSVC 向けの部分はカットしました.)
unit から i+1 番目の 1 になっているビットの位置を求めています.(bit_id はただのオフセットなので気にしなくて OK です.)

  1. std::size_t select_bit(std::size_t i, std::size_t bit_id, UInt64 unit) {
  2. return bit_id + ::__builtin_ctzll(_pdep_u64(1ULL << i, unit));
  3. }

select は lookup や reverse_lookup の中で特に重い処理なので,結構効果がありました.
以下, marisa-benchmark に日本語 Wikipedia のタイトル一覧(順序そのまま)を入力したときの出力を貼っておきます.
実行環境の CPU は Core i7 6800K 3.4GHz です.

まずは PDEP を使わないバイナリです.

  1. $ make clean && autoreconf && ./configure --enable-bmi && make
  2. ...
  3. $ tools/marisa-benchmark -p jawiki-20191001-all-titles-in-ns0
  4. Number of tries: 1 - 5
  5. TAIL mode: Text mode
  6. Node order: Descending weight order
  7. Cache level: Normal cache
  8. Number of keys: 1887667
  9. Total length: 40976550
  10. ------+----------+--------+--------+--------+--------+--------
  11. #tries size build lookup reverse prefix predict
  12. lookup search search
  13. [bytes] [K/s] [K/s] [K/s] [K/s] [K/s]
  14. ------+----------+--------+--------+--------+--------+--------
  15. 1 16224608 1446.04 3608.77 3206.54 3152.50 -
  16. 2 11877920 1169.76 2051.87 1898.60 1977.19 -
  17. 3 11008584 1158.67 1699.86 1695.10 1708.77 -
  18. 4 10692624 1151.92 1685.07 1632.11 1644.95 -
  19. 5 10557664 1155.25 1661.06 1597.17 1618.07 -
  20. ------+----------+--------+--------+--------+--------+--------

次に PDEP を使うバイナリです.

  1. $ make clean && ./configure --enable-native-code && make
  2. ...
  3.  
  4. $ tools/marisa-benchmark -p jawiki-20191001-all-titles-in-ns0
  5. ...
  6. ------+----------+--------+--------+--------+--------+--------
  7. #tries size build lookup reverse prefix predict
  8. lookup search search
  9. [bytes] [K/s] [K/s] [K/s] [K/s] [K/s]
  10. ------+----------+--------+--------+--------+--------+--------
  11. 1 16224608 1418.83 4134.11 3956.39 3858.28 -
  12. 2 11877920 1220.01 2357.28 2276.49 2279.57 -
  13. 3 11008584 1164.50 2037.00 1978.51 1985.62 -
  14. 4 10692624 1158.25 1915.64 1929.95 1909.70 -
  15. 5 10557664 1159.29 1916.36 1902.57 1872.88 -
  16. ------+----------+--------+--------+--------+--------+--------

PDEP を使わない場合と比べて PDEP を使う場合は, lookup が 14-20% の高速化, reverse_lookup が 17-23% の高速化となりました.