我已經使用SSE2/AVX2來幫助執行B +樹搜索。下面的代碼將在AVX2的16個DWORDs整個緩存線執行二進制搜索:
// perf-critical: ensure this is 64-byte aligned. (a full cache line)
union bnode
{
int32_t i32[16];
__m256i m256[2];
};
// returns from 0 (if value < i32[0]) to 16 (if value >= i32[15])
unsigned bsearch_avx2(bnode const* const node, __m256i const value)
{
__m256i const perm_mask = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0);
// compare the two halves of the cache line.
__m256i cmp1 = _mm256_load_si256(&node->m256[0]);
__m256i cmp2 = _mm256_load_si256(&node->m256[1]);
cmp1 = _mm256_cmpgt_epi32(cmp1, value); // PCMPGTD
cmp2 = _mm256_cmpgt_epi32(cmp2, value); // PCMPGTD
// merge the comparisons back together.
//
// a permute is required to get the pack results back into order
// because AVX-256 introduced that unfortunate two-lane interleave.
//
// alternately, you could pre-process your data to remove the need
// for the permute.
__m256i cmp = _mm256_packs_epi32(cmp1, cmp2); // PACKSSDW
cmp = _mm256_permutevar8x32_epi32(cmp, perm_mask); // PERMD
// finally create a move mask and count trailing
// zeroes to get an index to the next node.
unsigned mask = _mm256_movemask_epi8(cmp); // PMOVMSKB
return _tzcnt_u32(mask)/2; // TZCNT
}
最終你會與每bnode
一個高度可預測的分支,以測試樹已到頭。
這應該可以簡單地擴展到AVX-512。
預處理和擺脫慢PERMD
指令,這將用於:
void preprocess_avx2(bnode* const node)
{
__m256i const perm_mask = _mm256_set_epi32(3, 2, 1, 0, 7, 6, 5, 4);
__m256i *const middle = (__m256i*)&node->i32[4];
__m256i x = _mm256_loadu_si256(middle);
x = _mm256_permutevar8x32_epi32(x, perm_mask);
_mm256_storeu_si256(middle, x);
}
如果你有很多樹,我會試圖讓每一棵樹搜索成爲一個並行線程。 (我們在我們構建的程序分析/轉換工具中這樣做;似乎可以合理地工作)。爲什麼不是你考慮的選擇之一?另一個想法是:如果您有多個查詢,並且您事先知道它們,可以將它們編譯成用於指導搜索的FSA。由常用查詢子條生成的FSA部分僅處理一次,節省相當可觀。 (看LR類似的模式產品技巧的解析器)。 –
反正我們會使用大量的線程。這僅僅是AVX512硬件上單個樹最高效的實現。 – user1610743