Commit graph

19 commits

Author SHA1 Message Date
NOT XVilka
80f14bf6fc
librz/util/vector: minor RzVector/RzPVector performance optimizations (#6467)
* util/vector: hoist quicksort scratch buffers out of the recursion

vector_quick_sort allocated its two element-sized scratch buffers (t and
pivot) with malloc/free on every recursive call. For a vector of n elements
the sort makes O(n) recursive calls, i.e. O(n) malloc/free pairs purely for
scratch space, and each call could also fail half-way through the sort.

Split the function into a small entry point that allocates the two buffers
once and a recursive worker that receives them as scratch. The buffers are
reused across the whole recursion (each partition step finishes using them
before recursing, and the recursion is sequential, so sharing one pair is
safe). Small elements -- the common case, including every RzPVector-backed
sort -- use stack buffers and allocate nothing at all; only elements larger
than 256 bytes fall back to a single heap allocation for the whole sort.

The element movement and rand()-based pivot selection are unchanged, so the
result is identical for any input (verified byte-for-byte against the previous
implementation for ascending and descending orders over many random arrays).

* util/vector: evaluate the comparator once per element in the quicksort

The partition loop tested the element against the pivot with two separate
calls to the comparator:

    if ((cmp(VEC_INDEX(a, i), pivot, user) < 0 && !reverse) ||
        (cmp(VEC_INDEX(a, i), pivot, user) > 0 && reverse)) {

Because cmp is an opaque function pointer the compiler cannot common up the
two calls, so depending on the result and the reverse flag the comparator was
invoked up to twice per element. Compute the result once into a local and test
that:

    int c = cmp(VEC_INDEX(a, i), pivot, user);
    if ((c < 0 && !reverse) || (c > 0 && reverse)) {

This halves comparator calls in the worst case and is a clear win whenever the
comparator is non-trivial (the common case for struct elements). Measured on a
shared host: ~12-14% faster for int sorting and ~30% faster with a moderately
expensive comparator. The ordering is unchanged (verified byte-for-byte).

* util/vector: simplify rz_pvector_remove_data index computation

The index of the located slot was computed as

    size_t index = (el - (void **)vec->v.a) * sizeof(void **) / vec->v.elem_size;

For an RzPVector the element size is always sizeof(void *), so the
`* sizeof(void **) / vec->v.elem_size` factor is identically 1 and the pointer
difference `el - (void **)vec->v.a` already yields the index directly. Drop the
redundant scaling, which removes a multiply and a divide and makes the intent
clear. Behaviour is unchanged.

* test/unit: add RzVector sort and rz_pvector_remove_data regression tests

The existing sort tests only sort 4-5 small elements and there was no test for
rz_pvector_remove_data. Add coverage for the code paths exercised by the sort
changes and the remove_data cleanup:

  - test_vector_sort_large       sort 2000 heavily-duplicated ut32 values
                                 ascending and descending, verifying the result
                                 is ordered and a permutation of the input (vs a
                                 reference qsort). Drives the recursion deeply
                                 and the shared scratch buffers.
  - test_vector_sort_large_elem  sort 400 elements of 304 bytes each, taking the
                                 heap-allocated scratch fallback, and check the
                                 full payload (not just the key) stays consistent
                                 through all the element moves.
  - test_pvector_remove_data     remove interior, first and last elements by
                                 value while preserving order, and confirm
                                 removing an absent value is a no-op.

All pass on both the previous and the optimized implementation (the sort and
remove_data changes are behaviour-preserving).

* test/bench: benchmark rz_vector_sort and rz_pvector_sort

bench_vector.c benchmarked only remove_at and swap. Add sort benchmarks so the
suite covers the functions touched by the sort optimizations and can be run
against the old and new librz for before/after numbers:

  - rz_vector_sort over 4k ut64 with a cheap comparator
  - rz_vector_sort over 4k ut64 with a deliberately expensive comparator
    (shows the effect of evaluating the comparator once per element)
  - rz_pvector_sort over 4k pointers (reference; pvector sort is unchanged)

Each iteration refills the buffer from an unsorted master copy via a single
memcpy before sorting; that overhead is identical across builds so the measured
delta reflects the sort.

---------

Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-06-10 00:22:26 +08:00
Rot127
6d7c38cf5b
Graph - (tiny) performance improvements (#6382)
* Fix revert if adding a node failed.

* Reduce allocations by keeping only a single RzGraphEdge object per edge around.

* Add benchmark for graph deletion and addition of nodes/edges

* Use rz_pvector_remove_at_unsorted to save some runtime.

* Use realloc and memmove for matrix graphs on capacity increase.

* Add helper to determine memory usage.

* Add benchmark

* Revert matrix capacity extension to simple and jsut as fast loop.

* Missing type annotations
2026-05-31 22:00:25 +00:00
wargio
f366095030 Implement special compare for bytes and always compare mem-aligned. 2026-06-01 01:45:59 +08:00
NOT XVilka
9960ae3bed
test/bench: add benchmark for RzDiff (#6398)
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-05-27 18:36:58 +08:00
Rot127
c6820479c6
test/bench: add geometric stats to benchmarks (#6403)
* Add option to replace (geometric) invalid values with another value.
* Add geometric Mean and Std Dev to benchmarks.
* Add Doxygen documentation
* Add a README to the bench dir as intro.
2026-05-26 16:15:02 +08:00
Rot127
702250eb4f
test/bench: measure standard deviation for benchmarks (#6390)
* Add Welfords square of sums algorithm for variance and std deviation calculations.
* Add standard deviation to benchmarks
* Simplify Welford
* Add geometric mean and standard deviation to Welford Sums
2026-05-25 05:08:06 +08:00
Rot127
12a16c812b
Add order ignoring remove_at version with better performance. (#6389)
* Add order ignoring remove_at version with better performance.

* Optimize rz_vector_swap by using stack memory for small elements.

* Add benchmark for rz_vector_swap
2026-05-22 20:54:49 +00:00
Giovanni
2f0dcd65b2
Revert "Implement Pool Node allocation for RzList (#6203)" (#6313)
This reverts commit d3a97d5ef8.
2026-05-04 22:45:00 +08:00
Farhan Saiyed
d3a97d5ef8
Implement Pool Node allocation for RzList (#6203) 2026-05-03 08:52:31 +08:00
Rot127
a489ff8b60
Change benchmark table header (#6265)
* Change benchmark table header to prevent misconceptions that we measure the CPU ops counter.

* Preserve unit for average iteration duration.
2026-04-21 18:37:36 +00:00
Farhan Saiyed
183a0376c7
librz/util: rz_list_purge speedup (#6179)
* Add RzList testbench
* Optimize the rz_list_purge() function
2026-04-09 02:51:44 +08:00
Anton Angelov
98670969eb
Build the benchmarks as part of the CI (#5965)
* Build the benchmarks as part of 'linux-meson-gcc-tests' step
* Fix bench_il build error
* Add macro to avoid compiler optimization on benchmarked code
* Fix incorrect format specifier
* Cast to uint64_t
2026-03-08 13:15:18 +08:00
Anton Angelov
f6651af904
librz/util: new CTZ implementation (#5963) 2026-03-08 03:18:07 +08:00
Anton Angelov
95f94ae258
refactor: SwissTable implementation for ht (#5860)
* Add ht benchmarks
* Initial implementation
* Finalize native per-group lookup support
* Lookup SSE2 implementation
* Improve hashing
* Add support for custom elem_size
* Avoid double h2 hashing when reserving slot
* Make custom elem_size support conditional
* Fix issues with bitwise and default lookup implementations
* Implement deletion trick optimization
* Track growth_size instead of deleted_slots
* Refactor SDB to access ht via API instead of internals
* Modify SDB tests which rely on hashtable order
* Fix SDB build warnings
* Fix bug with finding next power of two
* foreach_kv to return a bool result
* Change SDB diff order expected by serialize_analysis unit test
* Fix bug in the bitwise lookup implementation
* Remove second call to rz_core_init() which causes memory leaks
* Update some regression tests to accept reordered output
* Adapt ht clear to new implementation
* Use fini_kv_pair and fix 1 potential leak on malloc failure
* Fix cmd/types test after merge
* Avoid second call to calsize_key and avoid iter leaks on malloc failure
* Improve hash distribution
* Extend benchmark suite
* Fix bug with string hashing
* Branchless write to mirrored ctrl bytes
* Simplify string hash and remove potential UB
* Move RZ_PREFETCH macro to rz_types.h
* Add SSE2 discovery in Meson
* Forward SDB string hash function to ht string hash
* Try to revert test_cpu_profiles() to avoid relying on a baked SDB file
* Revert SDB/CDB hash function change
* Fix SDB reference to HT hash function instead of CDB hash
* Change calloc to malloc
* Avoid storing/checking key_len and key_value if they are ut64
* Improve string hash function
* Rename default hash functions
* Improve bench code
* linter.yml: set clang-path to point to llvm-18
2026-03-02 12:31:35 +08:00
Anton Angelov
0ff186d8e2
Improve performance of mem.c::read_n_bits() (#5819)
* Add micro benchmark
* Add implementation for rz_bv_set_from_buffer_*()
* Implementation for BE host
* Fix incorrect size parameter when calling rz_bv_set_from_buffer
* Warning when reading beyond ST64_MAX
2026-01-26 12:19:21 +08:00
Anton Angelov
b2fb8bbec5
Improve performance of rz_bv_add_inplace() (#5751)
* Add rz_bv_add_inplace benchmark for 256-bit vectors

* Improve performance of rz_bv_add

* Simplify helper function and fix bug

* Minor changes
2026-01-11 00:14:19 +00:00
Rot127
472819aa92
librz/util: add in-place bitvector operations (#5569)
* Add an in-place addition of bitvectors.

* Decouple _elem_len from assumption it has just enough bytes to hold len in bits.

* Add in-place copy of bits.

* Use default copy bits bitvector function.

* Mark stack allocated bit vector.

* Add inplace variant of complement_1

* Implement inplace bitvecotr not.

* Add inplace variant of rz_bv_and

* Implement inplace variant of rz_bv_or

* Implement inplace variant of rz_bv_xor

* Constify rz_bv_lsb/msb

* Implement inplace variant of rz_bv_neg

* Fix inplace add. Add inplace SUB

* Remove prefix

* Remove invalid const

* Implement in-place casting of bit vectors.

* Add a hash test

* Fix unnecessary &

* Prevent OOB reads & writes by copying only the minimum of bytes.

* Add inplace MUL

* Add ble version for bitvector set/get with bytes.

* Add documentation for inplace bitvector functions.

* Add bench of add/sub() and sub/add_inplace().

* Remove rz_bv_copy_nbits_inplace because it was the same as rz_bv_copy_nbits.
2025-12-23 13:56:06 +08:00
Anton Angelov
0a14a7a1da
Improve performance of rz_bv_set_range() (#5562)
* Add microbenchmarks

* New implementation for rz_bv_set_range()

* Remove rz_ prefix from static function names
2025-12-04 14:44:19 +08:00
Anton Angelov
c186f1ec83
Enhance performance of rz_bv_copy_nbits (#5541)
* Add benchmark for rz_bv_copy_nbits
* Improve performance for large to large and small to small bitvector copy
* Fix bug with nbit=64 and simplify code
* Add test for same bitvector copy
* Move bit copy logic to separate function in rz_bits.h + improve comments
* Support same vector copy for unaligned case
* Expect non-null RzTable in bench utils and add comments
* Test against reference implementation instead of hardcoded values
2025-11-23 21:52:23 +08:00