Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 56 additions & 18 deletions .github/actions/benchmark_epilogue/action.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: "Benchmark Epilogue"
description: "Processes coverage information with lcov and uploads it to coveralls/codecov"
inputs:
workspace:
required: True
description: "Source code / workspace"
compiler:
required: True
description: 'Compiler used to build benchmark'
Expand All @@ -13,29 +16,64 @@ inputs:
build-output-dir:
required: true
description: 'Build output directory'
base_ref:
required: true
description: 'Base ref for PR/comparison'
cpp_compiler:
required: true
description: 'Cpp compiler to use'
c_compiler:
required: true
description: 'C compiler to use'
build_type:
required: true
description: 'Build type (release/debug)'

runs:
using: "composite"
steps:
- name: Archive benchmark results
uses: actions/upload-artifact@v4
- name: Checkout target branch (BASE)
uses: actions/checkout@v4
with:
name: benchmark_${{ inputs.os }}_${{ inputs.compiler }}_${{ inputs.stdlib }}_json
path: ${{ inputs.build-output-dir }}/benchmark/benchmark_result.json
ref: ${{ inputs.base_ref }}

# Download previous benchmark result from cache (if exists)
- name: Download previous benchmark data
uses: actions/cache@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
path: ./cache
key: benchmark_${{ inputs.os }}_${{ inputs.compiler }}_${{ inputs.stdlib }}
python-version: '3.11'

- name: Install benchmark compare.py requirements
shell: bash
run: |
pip install --upgrade setuptools
pip install -r ${{ inputs.build-output-dir}}/_deps/benchmark-src/tools/requirements.txt

- name: Benchmark Workflow
shell: bash
run: |
mv ${{ inputs.build-output-dir }}/benchmark/benchmark_result.json ${{ inputs.build-output-dir }}/benchmark/benchmark_result_new.json
cmake -B ${{ inputs.build-output-dir}} -S ${{ inputs.workspace }} \
--preset benchmark_${{ inputs.os }}_${{ inputs.compiler }}_${{ inputs.stdlib }} \
-DCMAKE_CXX_COMPILER=${{ inputs.cpp_compiler }} \
-DCMAKE_C_COMPILER=${{ inputs.c_compiler }} \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }}
cmake --build ${{ inputs.build-output-dir}} --target benchmark --config ${{ inputs.build_type }} --parallel
ctest --test-dir ${{ inputs.build-output-dir}} --build-config ${{ inputs.build_type }} --output-on-failure --parallel
mv ${{ inputs.build-output-dir }}/benchmark/benchmark_result.json ${{ inputs.build-output-dir }}/benchmark/benchmark_result_ref.json

- name: Compare Benchmarks
shell: bash
run: |
python3 ${{ inputs.build-output-dir}}/_deps/benchmark-src/tools/compare.py benchmarks \
${{ inputs.build-output-dir }}/benchmark/benchmark_result_ref.json \
${{ inputs.build-output-dir }}/benchmark/benchmark_result_new.json \
| tee ${{ inputs.build-output-dir }}/benchmark/comparison.txt

- name: Store benchmark result
uses: benchmark-action/github-action-benchmark@v1
- name: Archive benchmark results
uses: actions/upload-artifact@v4
with:
tool: 'googlecpp'
# Where the output from the benchmark tool is stored
output-file-path: ${{ inputs.build-output-dir }}/benchmark/benchmark_result.json
# Where the previous data file is stored
external-data-json-path: ./cache/benchmark_result.json
# Workflow will fail when an alert happens
fail-on-alert: true
name: benchmark_${{ inputs.os }}_${{ inputs.compiler }}_${{ inputs.stdlib }}_json
path: |
${{ inputs.build-output-dir }}/benchmark/benchmark_result_ref.json
${{ inputs.build-output-dir }}/benchmark/benchmark_result_new.json
${{ inputs.build-output-dir }}/benchmark/comparison.txt
5 changes: 5 additions & 0 deletions .github/workflows/cmake-multi-platform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@ jobs:
- uses: ./.github/actions/benchmark_epilogue
if: matrix.preset == 'benchmark'
with:
workspace: ${{ github.workspace }}
cpp_compiler: ${{ matrix.cpp_compiler }}
c_compiler: ${{ matrix.c_compiler }}
build_type: ${{ matrix.build_type }}
base_ref: ${{ github.event.pull_request.base.ref }}
os: ${{ matrix.os }}
compiler: ${{ matrix.compiler }}
stdlib: ${{ matrix.stdlib }}
Expand Down
2 changes: 1 addition & 1 deletion benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,5 @@ target_link_libraries(bitlib-bench PRIVATE

add_test(
NAME BenchmarkTest
COMMAND $<TARGET_FILE:bitlib-bench> --benchmark_format=json --benchmark_out=benchmark_result.json
COMMAND $<TARGET_FILE:bitlib-bench> --benchmark_format=json --benchmark_out=benchmark_result.json --benchmark_min_warmup_time=0.001 --benchmark_min_time=0.01s
)
220 changes: 107 additions & 113 deletions include/bitlib/bit-algorithms/bit_algorithm_details.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,17 @@ constexpr bool is_within(
template <class T, class InputIt>
T get_word(bit_iterator<InputIt> first, size_t len=binary_digits<T>::value)
{
using native_word_type = typename bit_iterator<InputIt>::word_type;
constexpr T digits = binary_digits<native_word_type>::value;
assert(digits >= len);
using non_const_T = std::remove_cv_t<T>;
non_const_T offset = digits - first.position();
non_const_T ret_word = *first.base() >> first.position();

// We've already assigned enough bits
if (len <= offset) {
return ret_word;
}
using native_word_type = typename bit_iterator<InputIt>::word_type;
constexpr T digits = binary_digits<native_word_type>::value;
assert(digits >= len);
using non_const_T = std::remove_cv_t<T>;
non_const_T offset = digits - first.position();
non_const_T ret_word = lsr(*first.base(), first.position());

// We've already assigned enough bits
if (len <= offset) {
return ret_word;
}

InputIt it = std::next(first.base());
len -= offset;
Expand Down Expand Up @@ -214,63 +214,57 @@ void write_word(src_type src, bit_iterator<OutputIt> dst_bit_it,
src_type len=binary_digits<src_type>::value
)
{
using dst_type = typename bit_iterator<OutputIt>::word_type;
constexpr dst_type dst_digits = binary_digits<dst_type>::value;
constexpr dst_type src_digits = binary_digits<src_type>::value;

if constexpr (dst_digits >= src_digits) {
if (dst_bit_it.position() == 0 && len == dst_digits) {
*dst_bit_it.base() = src;
}
else {
*dst_bit_it.base() = _bitblend<src_type>(
*dst_bit_it.base(),
src << dst_bit_it.position(),
dst_bit_it.position(),
std::min<src_type>(
dst_digits - dst_bit_it.position(),
len
)
);
if (len > dst_digits - dst_bit_it.position()) {
OutputIt overflow_dst = std::next(dst_bit_it.base());
*overflow_dst = _bitblend<src_type>(
*overflow_dst,
src >> (dst_digits - dst_bit_it.position()),
0,
len - (dst_digits - dst_bit_it.position())
);
}
}
using dst_type = typename bit_iterator<OutputIt>::word_type;
constexpr dst_type dst_digits = binary_digits<dst_type>::value;
constexpr dst_type src_digits = binary_digits<src_type>::value;

if constexpr (dst_digits >= src_digits) {
if (dst_bit_it.position() == 0 && len == dst_digits) {
*dst_bit_it.base() = src;
} else {
OutputIt it = dst_bit_it.base();
if (dst_bit_it.position() != 0) {
*it = _bitblend(
*it,
static_cast<dst_type>(src),
static_cast<dst_type>(-1) << dst_bit_it.position()
);
len -= dst_digits - dst_bit_it.position();
// TODO would it be faster to jsut shift src every time it is
// passed as an argument and keep track of how much we need to
// shift?
src >>= dst_digits - dst_bit_it.position();
++it;
}
while (len >= dst_digits) {
*it = static_cast<dst_type>(src);
src >>= dst_digits;
len -= dst_digits;
++it;
}
if (len > 0 ) {
*it = _bitblend(
*it,
static_cast<dst_type>(src),
(1 << len) - 1
);
}
*dst_bit_it.base() = _bitblend<src_type>(
*dst_bit_it.base(),
src << dst_bit_it.position(),
dst_bit_it.position(),
std::min<src_type>(
dst_digits - dst_bit_it.position(),
len));
if (len > dst_digits - dst_bit_it.position()) {
OutputIt overflow_dst = std::next(dst_bit_it.base());
*overflow_dst = _bitblend<src_type>(
*overflow_dst,
lsr(src, (dst_digits - dst_bit_it.position())),
0,
len - (dst_digits - dst_bit_it.position()));
}
}
} else {
OutputIt it = dst_bit_it.base();
if (dst_bit_it.position() != 0) {
*it = _bitblend(
*it,
static_cast<dst_type>(src),
static_cast<dst_type>(-1) << dst_bit_it.position());
len -= dst_digits - dst_bit_it.position();
// TODO would it be faster to jsut shift src every time it is
// passed as an argument and keep track of how much we need to
// shift?
src = lsr(src, dst_digits - dst_bit_it.position());
++it;
}
while (len >= dst_digits) {
*it = static_cast<dst_type>(src);
src = lsr(src, dst_digits);
len -= dst_digits;
++it;
}
if (len > 0) {
*it = _bitblend(
*it,
static_cast<dst_type>(src),
_mask<dst_type>(len));
}
}
return;
}

Expand Down Expand Up @@ -367,56 +361,56 @@ WordType _shift_towards_msb(WordType word, std::size_t n) {
* is undefined
*/
template <class It>
[[deprecated("Unused")]]
typename bit_iterator<It>::word_type _padded_read(bit_iterator<It> first,
bit_iterator<It> last, const bit::bit_value bv) {

using word_type = typename bit_iterator<It>::word_type;

constexpr std::size_t num_digits = binary_digits<word_type>::value;
const std::size_t first_position = first.position();
const std::size_t last_position = last.position();
const word_type read = *(first.base());
constexpr word_type all_ones = _all_ones();

word_type mask;

if (_is_aligned_lsb(first)) {
if (_in_same_word(first, last)) {
// Case 1
if (bv == bit0) {
mask = _shift_towards_lsb(all_ones, num_digits - last_position);
return read & mask;
} else {
mask = _shift_towards_msb(all_ones, last_position);
return read | mask;
}
} else {
// Case 0
return read;
}
bit_iterator<It> last, const bit::bit_value bv) {
using word_type = typename bit_iterator<It>::word_type;

constexpr std::size_t num_digits = binary_digits<word_type>::value;
const std::size_t first_position = first.position();
const std::size_t last_position = last.position();
const word_type read = *(first.base());
constexpr word_type all_ones = _all_ones();

word_type mask;

if (_is_aligned_lsb(first)) {
if (_in_same_word(first, last)) {
// Case 1
if (bv == bit0) {
mask = _shift_towards_lsb(all_ones, num_digits - last_position);
return read & mask;
} else {
mask = _shift_towards_msb(all_ones, last_position);
return read | mask;
}
} else {
// Case 0
return read;
}
} else {
if (!_in_same_word(first, last)) {
// Case 2
if (bv == bit0) {
mask = _shift_towards_msb(all_ones, first_position);
return read & mask;
} else {
mask = _shift_towards_lsb(all_ones, num_digits - first_position);
return read | mask;
}
} else {
if (!_in_same_word(first, last)) {
// Case 2
if (bv == bit0) {
mask = _shift_towards_msb(all_ones, first_position);
return read & mask;
} else {
mask = _shift_towards_lsb(all_ones, num_digits - first_position);
return read | mask;
}
} else {
// Case 3
if (bv == bit0) {
mask = _shift_towards_msb(all_ones, first_position);
mask &= _shift_towards_lsb(all_ones, num_digits - last_position);
return read & mask;
} else {
mask = _shift_towards_lsb(all_ones, num_digits - first_position);
mask |= _shift_towards_msb(all_ones, last_position);
return read | mask;
}
}
// Case 3
if (bv == bit0) {
mask = _shift_towards_msb(all_ones, first_position);
mask &= _shift_towards_lsb(all_ones, num_digits - last_position);
return read & mask;
} else {
mask = _shift_towards_lsb(all_ones, num_digits - first_position);
mask |= _shift_towards_msb(all_ones, last_position);
return read | mask;
}
}
}
}
// -------------------------------------------------------------------------- //

Expand Down
10 changes: 4 additions & 6 deletions include/bitlib/bit-algorithms/copy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,10 @@ constexpr bit_iterator<RandomAccessIt2> copy(bit_iterator<RandomAccessIt1> first
}
}
if (remaining_bits_to_copy > 0) {
*it = _bitblend(
*it,
get_word<word_type>(first, remaining_bits_to_copy),
static_cast<word_type>(
(static_cast<word_type>(1) << remaining_bits_to_copy) - 1)
);
*it = _bitblend(
*it,
get_word<word_type>(first, remaining_bits_to_copy),
_mask<word_type>(remaining_bits_to_copy));
}
}
return d_first + total_bits_to_copy;
Expand Down
2 changes: 1 addition & 1 deletion include/bitlib/bit-algorithms/count.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ count(
iterator_type it = first.base();

if (first.position() != 0) {
word_type first_value = *first.base() >> first.position();
word_type first_value = lsr(*first.base(), first.position());
result = _popcnt(first_value);
++it;
}
Expand Down
Loading