[libc-commits] [libc] [libc][stdlib] Optimize bsearch() by reordering comparison branches (PR #230823)
Kuan-Wei Chiu via libc-commits
libc-commits at lists.llvm.org
Sat Oct 10 11:25:38 PDT 2026
visitorckw wrote:
For local benchmarking on x86-64, I used the following test program:
```c++
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <stdint.h>
#define N 1024
#define REPS 100000
int arr[N];
int seq_keys[N];
int rand_keys[N];
int miss_keys[N];
__attribute__((noinline, aligned(64))) void *
my_bsearch(const void *key, const void *array, size_t array_size,
size_t elem_size, int (*compare)(const void *, const void *)) {
if (key == nullptr || array == nullptr || array_size == 0 || elem_size == 0)
return nullptr;
while (array_size > 0) {
size_t mid = array_size / 2;
const void *elem =
reinterpret_cast<const uint8_t *>(array) + mid * elem_size;
int compare_result = compare(key, elem);
#if AFTER
if (compare_result < 0) {
array_size = mid;
} else if (compare_result > 0) {
array_size -= (mid + 1);
array = reinterpret_cast<const uint8_t *>(elem) + elem_size;
} else {
return const_cast<void *>(elem);
}
#else
if (compare_result == 0)
return const_cast<void *>(elem);
if (compare_result < 0) {
array_size = mid;
} else {
array_size -= (mid + 1);
array = reinterpret_cast<const uint8_t *>(elem) + elem_size;
}
#endif
}
return nullptr;
}
__attribute__((noinline, aligned(64))) int cmp(const void *a, const void *b) {
int x = *(const int *)a;
int y = *(const int *)b;
return (x > y) - (x < y);
}
double bench(const int *keys, int reps) {
auto start = std::chrono::steady_clock::now();
for (int r = 0; r < reps; r++) {
for (int i = 0; i < N; i++) {
void *p = my_bsearch(&keys[i], arr, N, sizeof(int), cmp);
asm volatile("" : : "r"(p) : "memory");
}
}
auto end = std::chrono::steady_clock::now();
return std::chrono::duration<double>(end - start).count();
}
int main() {
srand(0);
for (int i = 0; i < N; i++) {
arr[i] = i * 2;
seq_keys[i] = i * 2;
miss_keys[i] = i * 2 + 1;
}
for (int i = 0; i < N; i++)
rand_keys[i] = arr[rand() % N];
bench(seq_keys, 1000);
printf("sequential: %.3f s\n", bench(seq_keys, REPS));
bench(rand_keys, 1000);
printf("random: %.3f s\n", bench(rand_keys, REPS));
bench(miss_keys, 1000);
printf("miss: %.3f s\n", bench(miss_keys, REPS));
return 0;
}
```
Result:
- Before:
```
sequential: 2.518 s
random: 2.738 s
miss: 2.822 s
```
- After:
```
sequential: 2.394 s
random: 2.628 s
miss: 2.641 s
```
https://github.com/llvm/llvm-project/pull/230823
More information about the libc-commits
mailing list