mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-04 16:34:14 +08:00
mdbx: using e2k-frendly/cmov/branch-less bsearch.
https://gitflic.ru/project/erthink/bsearch-try
This commit is contained in:
parent
3de759a7be
commit
98c53555ab
93
src/core.c
93
src/core.c
@ -2277,52 +2277,73 @@ static int lcklist_detach_locked(MDBX_env *env) {
|
|||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
* LY: Binary search */
|
* LY: Binary search */
|
||||||
|
|
||||||
|
#if defined(__clang__) && __clang_major__ > 4 && defined(__ia32__)
|
||||||
|
#define WORKAROUND_FOR_CLANG_OPTIMIZER_BUG(size, flag) \
|
||||||
|
do \
|
||||||
|
__asm __volatile("" \
|
||||||
|
: "+r"(size) \
|
||||||
|
: "r" /* the `b` constraint is more suitable here, but \
|
||||||
|
cause CLANG to allocate and push/pop an one more \
|
||||||
|
register, so using the `r` which avoids this. */ \
|
||||||
|
(flag)); \
|
||||||
|
while (0)
|
||||||
|
#else
|
||||||
|
#define WORKAROUND_FOR_CLANG_OPTIMIZER_BUG(size, flag) \
|
||||||
|
do { \
|
||||||
|
/* nope for non-clang or non-x86 */; \
|
||||||
|
} while (0)
|
||||||
|
#endif /* Workaround for CLANG */
|
||||||
|
|
||||||
|
#define BINARY_SEARCH_STEP(TYPE_LIST, CMP, it, size, key) \
|
||||||
|
do { \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define SEARCH_IMPL(NAME, TYPE_LIST, TYPE_ARG, CMP) \
|
#define SEARCH_IMPL(NAME, TYPE_LIST, TYPE_ARG, CMP) \
|
||||||
static __always_inline const TYPE_LIST *NAME( \
|
static __always_inline const TYPE_LIST *NAME( \
|
||||||
const TYPE_LIST *first, unsigned length, const TYPE_ARG item) { \
|
const TYPE_LIST *it, unsigned length, const TYPE_ARG item) { \
|
||||||
const TYPE_LIST *const begin = first, *const end = begin + length; \
|
const TYPE_LIST *const begin = it, *const end = begin + length; \
|
||||||
\
|
\
|
||||||
while (length > 3) { \
|
if (MDBX_HAVE_CMOV) \
|
||||||
const unsigned whole = length; \
|
do { \
|
||||||
length >>= 1; \
|
/* Адаптивно-упрощенный шаг двоичного поиска: \
|
||||||
const TYPE_LIST *const middle = first + length; \
|
* - без переходов при наличии cmov или аналога; \
|
||||||
const unsigned left = whole - length - 1; \
|
* - допускает лишние итерации; \
|
||||||
const bool cmp = expect_with_probability(CMP(*middle, item), 0, .5); \
|
* - но ищет пока size > 2, что требует дозавершения поиска \
|
||||||
length = cmp ? left : length; \
|
* среди остающихся 0-1-2 элементов. */ \
|
||||||
first = cmp ? middle + 1 : first; \
|
const TYPE_LIST *const middle = it + (length >> 1); \
|
||||||
} \
|
length = (length + 1) >> 1; \
|
||||||
\
|
const bool flag = expect_with_probability(CMP(*middle, item), 0, .5); \
|
||||||
switch (length) { \
|
WORKAROUND_FOR_CLANG_OPTIMIZER_BUG(length, flag); \
|
||||||
case 3: \
|
it = flag ? middle : it; \
|
||||||
if (expect_with_probability(!CMP(*first, item), 0, .5)) \
|
} while (length > 2); \
|
||||||
break; \
|
else \
|
||||||
++first; \
|
while (length > 2) { \
|
||||||
__fallthrough /* fall through */; \
|
/* Вариант с использованием условного перехода. Основное отличие в \
|
||||||
case 2: \
|
* том, что при "не равно" (true от компаратора) переход делается на 1 \
|
||||||
if (expect_with_probability(!CMP(*first, item), 0, .5)) \
|
* ближе к концу массива. Алгоритмически это верно и обеспечивает \
|
||||||
break; \
|
* чуть-чуть более быструю сходимость, но зато требует больше \
|
||||||
++first; \
|
* вычислений при true от компаратора. Также ВАЖНО(!) не допускается \
|
||||||
__fallthrough /* fall through */; \
|
* спекулятивное выполнение при size == 0. */ \
|
||||||
case 1: \
|
const TYPE_LIST *const middle = it + (length >> 1); \
|
||||||
if (expect_with_probability(!CMP(*first, item), 0, .5)) \
|
length = (length + 1) >> 1; \
|
||||||
break; \
|
const bool flag = expect_with_probability(CMP(*middle, item), 0, .5); \
|
||||||
++first; \
|
if (flag) { \
|
||||||
__fallthrough /* fall through */; \
|
it = middle + 1; \
|
||||||
case 0: \
|
length -= 1; \
|
||||||
break; \
|
} \
|
||||||
default: \
|
} \
|
||||||
__unreachable(); \
|
it += length > 1 && expect_with_probability(CMP(*it, item), 0, .5); \
|
||||||
} \
|
it += length > 0 && expect_with_probability(CMP(*it, item), 0, .5); \
|
||||||
\
|
\
|
||||||
if (mdbx_audit_enabled()) { \
|
if (mdbx_audit_enabled()) { \
|
||||||
for (const TYPE_LIST *scan = begin; scan < first; ++scan) \
|
for (const TYPE_LIST *scan = begin; scan < it; ++scan) \
|
||||||
assert(CMP(*scan, item)); \
|
assert(CMP(*scan, item)); \
|
||||||
for (const TYPE_LIST *scan = first; scan < end; ++scan) \
|
for (const TYPE_LIST *scan = it; scan < end; ++scan) \
|
||||||
assert(!CMP(*scan, item)); \
|
assert(!CMP(*scan, item)); \
|
||||||
(void)begin, (void)end; \
|
(void)begin, (void)end; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
return first; \
|
return it; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user