BLI: refactor IndexMask for better performance and memory usage #104629

Merged
Jacques Lucke merged 254 commits from JacquesLucke/blender:index-mask-refactor into main 2023-05-24 18:11:47 +02:00
3 changed files with 47 additions and 37 deletions
Showing only changes of commit f052c8bfe3 - Show all commits

View File

@ -3,12 +3,12 @@
#pragma once
#include <array>
#include <memory_resource>
#include <optional>
#include <variant>
#include "BLI_bit_span.hh"
#include "BLI_index_range.hh"
#include "BLI_linear_allocator.hh"
#include "BLI_offset_indices.hh"
#include "BLI_offset_span.hh"
#include "BLI_span.hh"
@ -154,9 +154,11 @@ class IndexMask {
template<typename Fn> void foreach_index(Fn &&fn) const;
template<typename T>
static IndexMask from_indices(Span<T> indices, LinearAllocator<> &allocator);
static IndexMask from_bits(BitSpan bits, LinearAllocator<> &allocator, int64_t offset = 0);
static IndexMask from_expr(const Expr &expr, IndexRange universe, LinearAllocator<> &allocator);
static IndexMask from_indices(Span<T> indices, std::pmr::memory_resource &memory);
static IndexMask from_bits(BitSpan bits, std::pmr::memory_resource &memory, int64_t offset = 0);
static IndexMask from_expr(const Expr &expr,
IndexRange universe,
std::pmr::memory_resource &memory);
template<typename T> void to_indices(MutableSpan<T> r_indices) const;
void to_bits(MutableBitSpan r_bits, int64_t offset = 0) const;
@ -188,7 +190,7 @@ int64_t find_size_until_next_range(const Span<T> indices, const int64_t min_rang
template<typename Fn>
inline IndexMask grow_indices_to_ranges(const IndexMask &mask,
const Fn &fn,
LinearAllocator<> &allocator)
std::pmr::memory_resource &memory)
{
Vector<int64_t> indices;
mask.foreach_index([&](const int64_t i) {
@ -197,7 +199,7 @@ inline IndexMask grow_indices_to_ranges(const IndexMask &mask,
indices.append(new_index);
}
});
return IndexMask::from_indices<int64_t>(indices, allocator);
return IndexMask::from_indices<int64_t>(indices, memory);
}
/* -------------------------------------------------------------------- */

View File

@ -157,7 +157,15 @@ int64_t split_to_ranges_and_spans(const Span<T> indices,
return r_parts.size() - old_parts_num;
}
template<typename T> IndexMask to_index_mask(const Span<T> indices, LinearAllocator<> &allocator)
template<typename T>
static MutableSpan<T> allocate_array(std::pmr::memory_resource &memory, const int64_t n)
{
void *buffer = memory.allocate(sizeof(T) * size_t(n), alignof(T));
return MutableSpan<T>(static_cast<T *>(buffer), n);
}
template<typename T>
IndexMask to_index_mask(const Span<T> indices, std::pmr::memory_resource &memory)
{
if (indices.is_empty()) {
return {};
@ -168,8 +176,8 @@ template<typename T> IndexMask to_index_mask(const Span<T> indices, LinearAlloca
const Vector<IndexRange> split_ranges = split_by_chunk(indices);
const int64_t chunks_num = split_ranges.size();
MutableSpan<Chunk> chunks = allocator.allocate_array<Chunk>(chunks_num);
MutableSpan<int64_t> chunk_ids = allocator.allocate_array<int64_t>(chunks_num);
MutableSpan<Chunk> chunks = allocate_array<Chunk>(memory, chunks_num);
MutableSpan<int64_t> chunk_ids = allocate_array<int64_t>(memory, chunks_num);
static const int16_t *static_offsets = get_static_indices_array().data();
@ -234,11 +242,11 @@ template<typename T> IndexMask to_index_mask(const Span<T> indices, LinearAlloca
{
std::lock_guard lock{scope_mutex};
remaining_indices_by_segment = allocator.allocate_array<const int16_t *>(
segments_in_chunks.size());
remaining_indices = allocator.allocate_array<int16_t>(index_allocations_num);
remaining_cumulative_segment_sizes = allocator.allocate_array<int16_t>(
segments_in_chunks.size() + chunks_to_postprocess.size());
remaining_indices_by_segment = allocate_array<const int16_t *>(memory,
segments_in_chunks.size());
remaining_indices = allocate_array<int16_t>(memory, index_allocations_num);
remaining_cumulative_segment_sizes = allocate_array<int16_t>(
memory, segments_in_chunks.size() + chunks_to_postprocess.size());
}
const OffsetIndices<int64_t> segments_by_chunk = segments_per_chunk_cumulative.as_span();
@ -297,7 +305,7 @@ template<typename T> IndexMask to_index_mask(const Span<T> indices, LinearAlloca
BLI_assert(remaining_cumulative_segment_sizes.is_empty());
});
MutableSpan<int64_t> cumulative_chunk_sizes = allocator.allocate_array<int64_t>(chunks_num + 1);
MutableSpan<int64_t> cumulative_chunk_sizes = allocate_array<int64_t>(memory, chunks_num + 1);
int64_t cumulative_size = 0;
for (const int64_t i : chunks.index_range()) {
cumulative_chunk_sizes[i] = cumulative_size;
@ -333,7 +341,7 @@ template<typename T> void from_index_mask(const IndexMask &mask, MutableSpan<T>
static IndexMask bits_to_index_mask(const BitSpan bits,
const int64_t start,
LinearAllocator<> &allocator)
std::pmr::memory_resource &memory)
{
Vector<int64_t> indices;
for (const int64_t i : bits.index_range()) {
@ -341,7 +349,7 @@ static IndexMask bits_to_index_mask(const BitSpan bits,
indices.append(i + start);
}
}
return unique_sorted_indices::to_index_mask<int64_t>(indices, allocator);
return unique_sorted_indices::to_index_mask<int64_t>(indices, memory);
}
static void index_mask_to_bits(const IndexMask &mask, const int64_t start, MutableBitSpan r_bits)
@ -352,16 +360,16 @@ static void index_mask_to_bits(const IndexMask &mask, const int64_t start, Mutab
}
template<typename T>
IndexMask IndexMask::from_indices(const Span<T> indices, LinearAllocator<> &allocator)
IndexMask IndexMask::from_indices(const Span<T> indices, std::pmr::memory_resource &memory)
{
return unique_sorted_indices::to_index_mask(indices, allocator);
return unique_sorted_indices::to_index_mask(indices, memory);
}
IndexMask IndexMask::from_bits(const BitSpan bits,
LinearAllocator<> &allocator,
std::pmr::memory_resource &memory,
const int64_t offset)
{
return bits_to_index_mask(bits, offset, allocator);
return bits_to_index_mask(bits, offset, memory);
}
static Set<int64_t> eval_expr(const Expr &base_expr, const IndexRange universe)
@ -423,13 +431,13 @@ static Set<int64_t> eval_expr(const Expr &base_expr, const IndexRange universe)
IndexMask IndexMask::from_expr(const Expr &expr,
const IndexRange universe,
LinearAllocator<> &allocator)
std::pmr::memory_resource &memory)
{
const Set<int64_t> indices_set = eval_expr(expr, universe);
Vector<int64_t> indices;
indices.extend(indices_set.begin(), indices_set.end());
std::sort(indices.begin(), indices.end());
return IndexMask::from_indices<int64_t>(indices, allocator);
return IndexMask::from_indices<int64_t>(indices, memory);
}
template<typename T> void IndexMask::to_indices(MutableSpan<T> r_indices) const
@ -442,8 +450,8 @@ void IndexMask::to_bits(MutableBitSpan r_bits, int64_t offset) const
index_mask_to_bits(*this, offset, r_bits);
}
template IndexMask IndexMask::from_indices(Span<int32_t>, LinearAllocator<> &);
template IndexMask IndexMask::from_indices(Span<int64_t>, LinearAllocator<> &);
template IndexMask IndexMask::from_indices(Span<int32_t>, std::pmr::memory_resource &);
template IndexMask IndexMask::from_indices(Span<int64_t>, std::pmr::memory_resource &);
template void IndexMask::to_indices(MutableSpan<int32_t>) const;
template void IndexMask::to_indices(MutableSpan<int64_t>) const;

View File

@ -105,10 +105,10 @@ TEST(index_mask2, SplitByChunk)
TEST(index_mask2, IndicesToMask)
{
LinearAllocator<> allocator;
std::pmr::monotonic_buffer_resource memory;
Array<int> data = {
5, 100, 16383, 16384, 16385, 20000, 20001, 50000, 50001, 50002, 100000, 101000};
IndexMask mask = IndexMask::from_indices<int>(data, allocator);
IndexMask mask = IndexMask::from_indices<int>(data, memory);
EXPECT_EQ(mask.first(), 5);
EXPECT_EQ(mask.last(), 101000);
@ -117,10 +117,10 @@ TEST(index_mask2, IndicesToMask)
TEST(index_mask2, FromBits)
{
LinearAllocator<> allocator;
std::pmr::monotonic_buffer_resource memory;
const uint64_t bits =
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111'0010'0000;
const IndexMask mask = IndexMask::from_bits(BitSpan(&bits, IndexRange(2, 40)), allocator, 100);
const IndexMask mask = IndexMask::from_bits(BitSpan(&bits, IndexRange(2, 40)), memory, 100);
Array<int> indices(5);
mask.to_indices<int>(indices);
EXPECT_EQ(indices[0], 103);
@ -167,10 +167,10 @@ TEST(index_mask2, DefaultConstructor)
TEST(index_mask2, IndicesToRanges)
{
LinearAllocator<> allocator;
const IndexMask mask = IndexMask::from_indices<int>({0, 1, 5}, allocator);
std::pmr::monotonic_buffer_resource memory;
const IndexMask mask = IndexMask::from_indices<int>({0, 1, 5}, memory);
const IndexMask new_mask = grow_indices_to_ranges(
mask, [&](const int64_t i) { return IndexRange(i * 10, 3); }, allocator);
mask, [&](const int64_t i) { return IndexRange(i * 10, 3); }, memory);
Vector<int64_t> indices(new_mask.size());
new_mask.to_indices<int64_t>(indices);
EXPECT_EQ(indices.size(), 9);
@ -187,8 +187,8 @@ TEST(index_mask2, IndicesToRanges)
TEST(index_mask2, ForeachRange)
{
LinearAllocator<> allocator;
const IndexMask mask = IndexMask::from_indices<int>({2, 3, 4, 10, 40, 41}, allocator);
std::pmr::monotonic_buffer_resource memory;
const IndexMask mask = IndexMask::from_indices<int>({2, 3, 4, 10, 40, 41}, memory);
Vector<IndexRange> ranges;
mask.foreach_range([&](const IndexRange range) { ranges.append(range); });
@ -200,11 +200,11 @@ TEST(index_mask2, ForeachRange)
TEST(index_mask2, Expr)
{
LinearAllocator<> allocator;
std::pmr::monotonic_buffer_resource memory;
const IndexMask mask1(IndexRange(10, 5));
const IndexMask mask2(IndexRange(40, 5));
const IndexMask mask3 = IndexMask::from_indices<int>({12, 13, 20, 21, 22}, allocator);
const IndexMask mask3 = IndexMask::from_indices<int>({12, 13, 20, 21, 22}, memory);
const AtomicExpr expr1{mask1};
const AtomicExpr expr2{mask2};
@ -212,7 +212,7 @@ TEST(index_mask2, Expr)
const UnionExpr union_expr({&expr1, &expr2});
const DifferenceExpr difference_expr(union_expr, {&expr3});
const IndexMask result = IndexMask::from_expr(difference_expr, IndexRange(100), allocator);
const IndexMask result = IndexMask::from_expr(difference_expr, IndexRange(100), memory);
std::cout << result << "\n";
}