Commit 17341a5c by Tobias Fuchs

Merge branch 'embb392_partitioner' into development

parents 52a5d250 1b725190
...@@ -31,109 +31,104 @@ namespace embb { ...@@ -31,109 +31,104 @@ namespace embb {
namespace algorithms { namespace algorithms {
namespace internal { namespace internal {
template<typename ForwardIterator> template<typename RAI>
ChunkDescriptor<ForwardIterator>::ChunkDescriptor(ForwardIterator first, ChunkDescriptor<RAI>::ChunkDescriptor(
ForwardIterator last) : RAI first, RAI last) :
first(first), last(last) { first_(first), last_(last) {
} }
template<typename ForwardIterator> template<typename RAI>
ForwardIterator ChunkDescriptor<ForwardIterator>::GetFirst() const { RAI ChunkDescriptor<RAI>::GetFirst() const {
return first; return first_;
} }
template<typename ForwardIterator> template<typename RAI>
ForwardIterator ChunkDescriptor<ForwardIterator>::GetLast() const { RAI ChunkDescriptor<RAI>::GetLast() const {
return last; return last_;
} }
template<typename ForwardIterator> template<typename RAI>
BlockSizePartitioner<ForwardIterator>::BlockSizePartitioner( BlockSizePartitioner<RAI>::BlockSizePartitioner(
ForwardIterator first, ForwardIterator last, size_t chunkSize) : RAI first, RAI last, size_t chunkSize) :
first(first), last(last), chunkSize(chunkSize) { first_(first), last_(last), chunk_size_(chunkSize) {
elements_count = static_cast<size_t>(std::distance(first, last)); elements_count_ = static_cast<size_t>(std::distance(first_, last_));
chunks = elements_count / chunkSize; chunks_ = elements_count_ / chunk_size_;
if (elements_count % chunkSize != 0) if (elements_count_ % chunk_size_ != 0) {
chunks++; chunks_++;
}
} }
template<typename ForwardIterator> template<typename RAI>
size_t BlockSizePartitioner<ForwardIterator>::Size() { size_t BlockSizePartitioner<RAI>::Size() {
return chunks; return chunks_;
} }
template<typename ForwardIterator> template<typename RAI>
const ChunkDescriptor<ForwardIterator> const ChunkDescriptor<RAI>
BlockSizePartitioner<ForwardIterator>::operator[]( BlockSizePartitioner<RAI>::operator[](
size_t const& index) const { size_t const & index) const {
ForwardIterator first_new = first; typedef typename std::iterator_traits<RAI>::difference_type
std::advance(first_new, index * chunkSize); difference_type;
RAI first_new(first_);
ForwardIterator last_new = first_new; first_new += static_cast<difference_type>(chunk_size_ * index);
RAI last_new(first_new);
if (index >= chunks - 1) { if (index >= chunks_ - 1) {
last_new = last; last_new = last_;
} else { } else {
std::advance(last_new, chunkSize); last_new += static_cast<difference_type>(chunk_size_);
} }
return ChunkDescriptor<RAI>(first_new, last_new);
return ChunkDescriptor<ForwardIterator>(first_new, last_new);
} }
template<typename ForwardIterator> template<typename RAI>
size_t ChunkPartitioner<ForwardIterator>::Size() { size_t ChunkPartitioner<RAI>::Size() {
return size; return size_;
} }
template<typename ForwardIterator> template<typename RAI>
ChunkPartitioner<ForwardIterator>::ChunkPartitioner(ForwardIterator first, ChunkPartitioner<RAI>::ChunkPartitioner(
ForwardIterator last, size_t amountChunks) : RAI first, RAI last, size_t amountChunks) :
first(first), last(last) { first_(first), last_(last) {
if (amountChunks > 0) { if (amountChunks > 0) {
size = amountChunks; size_ = amountChunks;
} else { } else {
// if no concrete chunk size was given, use number of cores... // if no concrete chunk size was given, use number of cores
embb::tasks::Node& node = embb::tasks::Node::GetInstance(); embb::tasks::Node& node = embb::tasks::Node::GetInstance();
size = node.GetWorkerThreadCount(); size_ = node.GetWorkerThreadCount();
} }
elements_count_ = static_cast<size_t>(std::distance(first_, last_));
elements_count = static_cast<size_t>(std::distance(first, last)); if (size_ > elements_count_) {
if (size > elements_count) {
// if we want to make more chunks than we have elements, correct // if we want to make more chunks than we have elements, correct
// the number of chunks // the number of chunks
size = elements_count; size_ = elements_count_;
} }
standard_chunk_size = elements_count / size; standard_chunk_size_ = elements_count_ / size_;
bigger_chunk_count = elements_count % size; bigger_chunk_count_ = elements_count_ % size_;
} }
template<typename ForwardIterator> template<typename RAI>
const ChunkDescriptor<ForwardIterator> const ChunkDescriptor<RAI>
ChunkPartitioner<ForwardIterator>::operator[]( ChunkPartitioner<RAI>::operator[](
size_t const& index) const { size_t const& index) const {
typedef typename std::iterator_traits<ForwardIterator>::difference_type typedef typename std::iterator_traits<RAI>::difference_type
difference_type; difference_type;
// Number of element preceding elements in the given chunk
size_t prec_elements_count = 0; size_t prec_elements_count = 0;
if (index <= bigger_chunk_count_) {
if (index <= bigger_chunk_count) { prec_elements_count = index * (standard_chunk_size_ + 1);
prec_elements_count = index * (standard_chunk_size + 1);
} else { } else {
prec_elements_count = (standard_chunk_size + 1) * bigger_chunk_count prec_elements_count =
+ standard_chunk_size * (index - bigger_chunk_count); (standard_chunk_size_ + 1) * bigger_chunk_count_ +
(standard_chunk_size_ * (index - bigger_chunk_count_));
} }
size_t cur_elements_count = (index < bigger_chunk_count_)
size_t cur_elements_count = ? (standard_chunk_size_ + 1)
(index < bigger_chunk_count) ? : standard_chunk_size_;
(standard_chunk_size + 1) : standard_chunk_size; RAI first_new(first_);
first_new += static_cast<difference_type>(prec_elements_count);
ForwardIterator first_new = first; RAI last_new(first_new);
std::advance(first_new, prec_elements_count); last_new += static_cast<difference_type>(cur_elements_count);
return ChunkDescriptor<RAI>(first_new, last_new);
first_new = first + static_cast<difference_type>(prec_elements_count);
ForwardIterator last_new = first_new;
std::advance(last_new, cur_elements_count);
return ChunkDescriptor<ForwardIterator>(first_new, last_new);
} }
} // namespace internal } // namespace internal
......
...@@ -38,14 +38,14 @@ namespace internal { ...@@ -38,14 +38,14 @@ namespace internal {
* Describes a single partition of a 1-dimensional * Describes a single partition of a 1-dimensional
* partitioning, using first and last iterator. * partitioning, using first and last iterator.
* *
* \tparam ForwardIterator Type of the iterator. * \tparam RAI Type of the iterator.
*/ */
template<typename ForwardIterator> template<typename RAI>
class ChunkDescriptor { class ChunkDescriptor {
private: private:
ForwardIterator first; RAI first_;
ForwardIterator last; RAI last_;
public: public:
/** /**
...@@ -54,7 +54,7 @@ class ChunkDescriptor { ...@@ -54,7 +54,7 @@ class ChunkDescriptor {
* \param first The first iterator. * \param first The first iterator.
* \param last The last iterator * \param last The last iterator
*/ */
ChunkDescriptor(ForwardIterator first, ForwardIterator last); ChunkDescriptor(RAI first, RAI last);
/** /**
* Gets the first iterator. * Gets the first iterator.
...@@ -63,7 +63,7 @@ class ChunkDescriptor { ...@@ -63,7 +63,7 @@ class ChunkDescriptor {
* *
* \waitfree * \waitfree
*/ */
ForwardIterator GetFirst() const; RAI GetFirst() const;
/** /**
* Gets the last iterator. * Gets the last iterator.
...@@ -72,7 +72,7 @@ class ChunkDescriptor { ...@@ -72,7 +72,7 @@ class ChunkDescriptor {
* *
* \waitfree * \waitfree
*/ */
ForwardIterator GetLast() const; RAI GetLast() const;
}; };
/** /**
...@@ -80,9 +80,9 @@ class ChunkDescriptor { ...@@ -80,9 +80,9 @@ class ChunkDescriptor {
* *
* Describes the interface for accessing a 1-dimensional partitioning. * Describes the interface for accessing a 1-dimensional partitioning.
* *
* \tparam ForwardIterator Type of the iterator. * \tparam RAI Type of the iterator.
*/ */
template<typename ForwardIterator> template<typename RAI>
class IPartitioner { class IPartitioner {
public: public:
virtual ~IPartitioner() {} virtual ~IPartitioner() {}
...@@ -106,7 +106,7 @@ class IPartitioner { ...@@ -106,7 +106,7 @@ class IPartitioner {
* *
* \waitfree * \waitfree
*/ */
virtual const ChunkDescriptor<ForwardIterator> operator[]( virtual const ChunkDescriptor<RAI> operator[](
size_t const& index) const = 0; size_t const& index) const = 0;
}; };
...@@ -129,16 +129,16 @@ class IPartitioner { ...@@ -129,16 +129,16 @@ class IPartitioner {
* 2: [6,7,8,9,10] * 2: [6,7,8,9,10]
* 3: [11,12,13] * 3: [11,12,13]
* *
* \tparam ForwardIterator Type of the iterator. * \tparam RAI Type of the iterator.
*/ */
template<typename ForwardIterator> template<typename RAI>
class BlockSizePartitioner : IPartitioner < ForwardIterator > { class BlockSizePartitioner : IPartitioner < RAI > {
private: private:
ForwardIterator first; RAI first_;
ForwardIterator last; RAI last_;
size_t chunkSize; size_t chunk_size_;
size_t elements_count; size_t elements_count_;
size_t chunks; size_t chunks_;
public: public:
/** /**
...@@ -150,7 +150,7 @@ class BlockSizePartitioner : IPartitioner < ForwardIterator > { ...@@ -150,7 +150,7 @@ class BlockSizePartitioner : IPartitioner < ForwardIterator > {
* \param chunkSize (Optional) size of the chunk. * \param chunkSize (Optional) size of the chunk.
*/ */
BlockSizePartitioner( BlockSizePartitioner(
ForwardIterator first, ForwardIterator last, size_t chunkSize = 1); RAI first, RAI last, size_t chunkSize = 1);
/** /**
* See IPartitioner * See IPartitioner
...@@ -164,7 +164,7 @@ class BlockSizePartitioner : IPartitioner < ForwardIterator > { ...@@ -164,7 +164,7 @@ class BlockSizePartitioner : IPartitioner < ForwardIterator > {
* *
* \waitfree * \waitfree
*/ */
virtual const ChunkDescriptor<ForwardIterator> operator[]( virtual const ChunkDescriptor<RAI> operator[](
size_t const& index) const; size_t const& index) const;
}; };
...@@ -196,17 +196,17 @@ class BlockSizePartitioner : IPartitioner < ForwardIterator > { ...@@ -196,17 +196,17 @@ class BlockSizePartitioner : IPartitioner < ForwardIterator > {
* 4: [10,11] * 4: [10,11]
* 5: [12,13] * 5: [12,13]
* *
* \tparam ForwardIterator Type of the iterator. * \tparam RAI Type of the iterator.
*/ */
template<typename ForwardIterator> template<typename RAI>
class ChunkPartitioner : IPartitioner < ForwardIterator > { class ChunkPartitioner : IPartitioner < RAI > {
private: private:
size_t size; size_t size_;
size_t elements_count; size_t elements_count_;
ForwardIterator first; RAI first_;
ForwardIterator last; RAI last_;
size_t standard_chunk_size; size_t standard_chunk_size_;
size_t bigger_chunk_count; size_t bigger_chunk_count_;
public: public:
/** /**
...@@ -227,7 +227,7 @@ class ChunkPartitioner : IPartitioner < ForwardIterator > { ...@@ -227,7 +227,7 @@ class ChunkPartitioner : IPartitioner < ForwardIterator > {
* \param last The last. * \param last The last.
* \param amountChunks (Optional) the amount chunks. * \param amountChunks (Optional) the amount chunks.
*/ */
ChunkPartitioner(ForwardIterator first, ForwardIterator last, ChunkPartitioner(RAI first, RAI last,
size_t amountChunks = 0); size_t amountChunks = 0);
/** /**
...@@ -235,7 +235,7 @@ class ChunkPartitioner : IPartitioner < ForwardIterator > { ...@@ -235,7 +235,7 @@ class ChunkPartitioner : IPartitioner < ForwardIterator > {
* *
* \waitfree * \waitfree
*/ */
virtual const ChunkDescriptor<ForwardIterator> operator[]( virtual const ChunkDescriptor<RAI> operator[](
size_t const& index) const; size_t const& index) const;
}; };
......
...@@ -33,9 +33,15 @@ ...@@ -33,9 +33,15 @@
#include <vector> #include <vector>
#include <list> #include <list>
PartitionerTest::PartitionerTest() { PartitionerTest::PartitionerTest()
CreateUnit("algorithms partitioner test"). : partitioned_array_size_(16384) {
Add(&PartitionerTest::TestBasic, this); // Size of array to be partitioned should be power of 2
CreateUnit("TestBasic")
.Add(&PartitionerTest::TestBasic, this);
CreateUnit("TestLargeRange")
.Pre(&PartitionerTest::TestLargeRangePre, this)
.Add(&PartitionerTest::TestLargeRange, this)
.Post(&PartitionerTest::TestLargeRangePost, this);
} }
void PartitionerTest::TestBasic() { void PartitionerTest::TestBasic() {
...@@ -70,3 +76,62 @@ void PartitionerTest::TestBasic() { ...@@ -70,3 +76,62 @@ void PartitionerTest::TestBasic() {
PT_EXPECT_EQ_MSG(partitioner2.Size(), size_t(3), "Check count of partitions"); PT_EXPECT_EQ_MSG(partitioner2.Size(), size_t(3), "Check count of partitions");
} }
void PartitionerTest::TestLargeRangePre() {
partitioned_array_ = new int[partitioned_array_size_];
for (size_t i = 0; i < partitioned_array_size_; ++i) {
partitioned_array_[i] = static_cast<int>(i);
}
}
void PartitionerTest::TestLargeRangePost() {
delete[] partitioned_array_;
}
void PartitionerTest::TestLargeRange() {
// Test chunk partitioner with increasing number of chunks:
for (size_t num_chunks = 2;
num_chunks < partitioned_array_size_;
num_chunks *= 2) {
embb::algorithms::internal::ChunkPartitioner<int *>
chunk_partitioner(
partitioned_array_,
partitioned_array_ + partitioned_array_size_,
num_chunks);
int last_value_prev = -1;
PT_EXPECT_EQ(num_chunks, chunk_partitioner.Size());
// Iterate over chunks in partition:
for (size_t chunk = 0; chunk < chunk_partitioner.Size(); ++chunk) {
int first_value = *(chunk_partitioner[chunk].GetFirst());
int last_value = *(chunk_partitioner[chunk].GetLast() - 1);
PT_EXPECT_LT(first_value, last_value);
// Test seams between chunks: chunk[i].last + 1 == chunk[i+1].first
PT_EXPECT_EQ((last_value_prev + 1), first_value);
last_value_prev = last_value;
}
}
// Test block size partitioner with increasing chunk size:
for (size_t block_size = 1;
block_size < partitioned_array_size_;
block_size *= 2) {
embb::algorithms::internal::BlockSizePartitioner<int *>
chunk_partitioner(
partitioned_array_,
partitioned_array_ + partitioned_array_size_,
block_size);
int last_value_prev = -1;
// Iterate over chunks in partition:
for (size_t chunk = 0; chunk < chunk_partitioner.Size(); ++chunk) {
int first_value = *(chunk_partitioner[chunk].GetFirst());
int last_value = *(chunk_partitioner[chunk].GetLast() - 1);
if (block_size == 1) {
PT_EXPECT_EQ(first_value, last_value);
} else {
PT_EXPECT_LT(first_value, last_value);
}
// Test seams between chunks: chunk[i].last + 1 == chunk[i+1].first
PT_EXPECT_EQ((last_value_prev + 1), first_value);
last_value_prev = last_value;
}
}
}
...@@ -35,6 +35,13 @@ class PartitionerTest : public partest::TestCase { ...@@ -35,6 +35,13 @@ class PartitionerTest : public partest::TestCase {
private: private:
void TestBasic(); void TestBasic();
void TestLargeRangePre();
void TestLargeRangePost();
void TestLargeRange();
int * partitioned_array_;
size_t partitioned_array_size_;
}; };
#endif // ALGORITHMS_CPP_TEST_PARTITIONER_TEST_H_ #endif // ALGORITHMS_CPP_TEST_PARTITIONER_TEST_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment