improve(CompositeArray): performance gain by flattening binary tree
The vtkCompositeArray performance was lagging due to the internal binary tree structure. Flattening it out allowed for a considerable reduction in the overhead of the composite array.
This commit is contained in:
parent
08c4b0ad52
commit
d52d7d24cf
|
@ -37,7 +37,7 @@ int TestCompositeImplicitBackend(int, char*[])
|
|||
std::iota(rightRange.begin(), rightRange.end(), 10);
|
||||
|
||||
// Make structure
|
||||
vtkCompositeImplicitBackend<int> composite(left, right);
|
||||
vtkCompositeImplicitBackend<int> composite(std::vector<vtkDataArray*>({ left, right }));
|
||||
|
||||
// Do checks on structure
|
||||
for (int i = 0; i < 20; ++i)
|
||||
|
@ -62,7 +62,8 @@ int TestCompositeImplicitBackend(int, char*[])
|
|||
auto rightMultiRange = vtk::DataArrayValueRange<3>(rightMulti);
|
||||
std::iota(rightMultiRange.begin(), rightMultiRange.end(), 30);
|
||||
|
||||
vtkCompositeImplicitBackend<int> compositeMulti(leftMulti, rightMulti);
|
||||
vtkCompositeImplicitBackend<int> compositeMulti(
|
||||
std::vector<vtkDataArray*>({ leftMulti, rightMulti }));
|
||||
|
||||
for (int i = 0; i < 60; ++i)
|
||||
{
|
||||
|
|
|
@ -48,8 +48,9 @@
|
|||
* rightArr->SetNumberOfComponents(1);
|
||||
* rightArr->SetNumberOfTuples(1);
|
||||
* rightArr->SetValue(0, 1);
|
||||
* std::vector<vtkDataArray*> arrays({leftArr, rightArr});
|
||||
* vtkNew<vtkCompositeArray<int>> compositeArr;
|
||||
* compositeArr->SetBackend(std::make_shared<vtkCompositeImplicitBackend<int>>(leftArr, rightArr));
|
||||
* compositeArr->SetBackend(std::make_shared<vtkCompositeImplicitBackend<int>>(arrays));
|
||||
* compositeArr->SetNumberOfComponents(1);
|
||||
* compositeArr->SetNumberOfTuples(2);
|
||||
* CHECK(compositArr->GetValue(1) == 1);
|
||||
|
|
|
@ -14,14 +14,6 @@ vtkSmartPointer<vtkCompositeArray<T>> ConcatenateDataArrays(
|
|||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (arrays.size() == 1)
|
||||
{
|
||||
vtkNew<vtkCompositeArray<T>> composite;
|
||||
composite->SetBackend(std::make_shared<vtkCompositeImplicitBackend<T>>(arrays[0], nullptr));
|
||||
composite->SetNumberOfComponents(arrays[0]->GetNumberOfComponents());
|
||||
composite->SetNumberOfTuples(arrays[0]->GetNumberOfTuples());
|
||||
return composite;
|
||||
}
|
||||
vtkIdType nComps = arrays[0]->GetNumberOfComponents();
|
||||
for (auto arr : arrays)
|
||||
{
|
||||
|
@ -31,35 +23,14 @@ vtkSmartPointer<vtkCompositeArray<T>> ConcatenateDataArrays(
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
std::vector<vtkSmartPointer<vtkDataArray>> lifetimeBuffer;
|
||||
lifetimeBuffer.assign(arrays.begin(), arrays.end());
|
||||
std::vector<vtkSmartPointer<vtkCompositeArray<T>>> newComps;
|
||||
while (lifetimeBuffer.size() != 1)
|
||||
{
|
||||
newComps.clear();
|
||||
for (int i = 0; i < static_cast<int>(lifetimeBuffer.size() - 1); i += 2)
|
||||
{
|
||||
vtkNew<vtkCompositeArray<T>> composite;
|
||||
composite->SetBackend(
|
||||
std::make_shared<vtkCompositeImplicitBackend<T>>(lifetimeBuffer[i], lifetimeBuffer[i + 1]));
|
||||
composite->SetNumberOfComponents(lifetimeBuffer[i]->GetNumberOfComponents());
|
||||
composite->SetNumberOfTuples(
|
||||
lifetimeBuffer[i]->GetNumberOfTuples() + lifetimeBuffer[i + 1]->GetNumberOfTuples());
|
||||
newComps.emplace_back(composite);
|
||||
}
|
||||
if (lifetimeBuffer.size() % 2 != 0)
|
||||
{
|
||||
vtkNew<vtkCompositeArray<T>> composite;
|
||||
composite->SetBackend(
|
||||
std::make_shared<vtkCompositeImplicitBackend<T>>(newComps.back(), lifetimeBuffer.back()));
|
||||
composite->SetNumberOfComponents(lifetimeBuffer.back()->GetNumberOfComponents());
|
||||
composite->SetNumberOfTuples(
|
||||
newComps.back()->GetNumberOfTuples() + lifetimeBuffer.back()->GetNumberOfTuples());
|
||||
newComps.back() = composite;
|
||||
}
|
||||
lifetimeBuffer.assign(newComps.begin(), newComps.end());
|
||||
}
|
||||
return newComps[0];
|
||||
vtkNew<vtkCompositeArray<T>> composite;
|
||||
composite->SetBackend(std::make_shared<vtkCompositeImplicitBackend<T>>(arrays));
|
||||
composite->SetNumberOfComponents(nComps);
|
||||
int nTuples = 0;
|
||||
std::for_each(arrays.begin(), arrays.end(),
|
||||
[&nTuples](vtkDataArray* arr) { nTuples += arr->GetNumberOfTuples(); });
|
||||
composite->SetNumberOfTuples(nTuples);
|
||||
return composite;
|
||||
}
|
||||
VTK_ABI_NAMESPACE_END
|
||||
}
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
* This structure can be classified as a closure and can be called using syntax similar to a
|
||||
* function call.
|
||||
*
|
||||
* The class implements a binary tree like structure for facilitating fast access.
|
||||
* The class implements a flat binary tree like structure for facilitating fast access.
|
||||
*
|
||||
* At construction it takes two arrays in order to represent their concatenation.
|
||||
* At construction it takes an array arrays in order to represent their concatenation.
|
||||
*
|
||||
* An example of potential usage in a vtkImplicitArray
|
||||
* ```
|
||||
|
@ -39,7 +39,8 @@
|
|||
* rightArr->SetValue(0, 1);
|
||||
* vtkNew<vtkImplicitArray<vtkCompositeImplicitBackend<int>>> compositeArr; // easier with
|
||||
* `vtkNew<vtkCompositeArray<int>> compositeArr;` if applicable
|
||||
* compositeArr->SetBackend(std::make_shared<vtkCompositeImplicitBackend<int>>(leftArr, rightArr));
|
||||
* std::vector<vtkDataArray*> arrays({leftArr, rightArr});
|
||||
* compositeArr->SetBackend(std::make_shared<vtkCompositeImplicitBackend<int>>(arrays));
|
||||
* CHECK(compositArr->GetValue(1) == 1);
|
||||
* ```
|
||||
*
|
||||
|
@ -48,7 +49,9 @@
|
|||
* > information.
|
||||
*/
|
||||
#include "vtkCommonImplicitArraysModule.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
VTK_ABI_NAMESPACE_BEGIN
|
||||
class vtkDataArray;
|
||||
|
@ -58,11 +61,10 @@ class vtkCompositeImplicitBackend
|
|||
public:
|
||||
/**
|
||||
* Constructor for the backend
|
||||
* @param leftArr the array starting the composite at index 0
|
||||
* @param rightArr the array following the leftArr and starting at index
|
||||
* @param arrays std::vector of arrays to composite together
|
||||
* leftArr->GetNumberOfTuples()
|
||||
*/
|
||||
vtkCompositeImplicitBackend(vtkDataArray* leftArr, vtkDataArray* rightArr);
|
||||
vtkCompositeImplicitBackend(const std::vector<vtkDataArray*>& arrays);
|
||||
~vtkCompositeImplicitBackend();
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,41 +26,37 @@ VTK_ABI_NAMESPACE_BEGIN
|
|||
template <typename ValueType>
|
||||
struct vtkCompositeImplicitBackend<ValueType>::Internals
|
||||
{
|
||||
Internals(vtkDataArray* leftArr, vtkDataArray* rightArr)
|
||||
: Left(leftArr)
|
||||
, Right(rightArr)
|
||||
template <class Iterator>
|
||||
Internals(Iterator first, Iterator last)
|
||||
{
|
||||
if (!this->Left && !this->Right)
|
||||
this->Arrays.assign(first, last);
|
||||
if (this->Arrays.size() > 0)
|
||||
{
|
||||
vtkWarningWithObjectMacro(nullptr, "Creating composite array with two nullptrs");
|
||||
this->Ranges.resize(this->Arrays.size());
|
||||
std::transform(first, last, this->Ranges.begin(),
|
||||
[](vtkDataArray* arr) { return vtk::DataArrayValueRange(arr); });
|
||||
this->Offsets.resize(this->Arrays.size() - 1);
|
||||
std::size_t runningSum = 0;
|
||||
std::transform(this->Ranges.begin(), this->Ranges.end() - 1, this->Offsets.begin(),
|
||||
[&runningSum](vtk::detail::SelectValueRange<vtkDataArray*,
|
||||
vtk::detail::DynamicTupleSize>::type& range) {
|
||||
runningSum += range.size();
|
||||
return runningSum;
|
||||
});
|
||||
}
|
||||
auto checkNullRectify = [](vtkSmartPointer<vtkDataArray>& arr) {
|
||||
if (!arr)
|
||||
{
|
||||
arr = vtkSmartPointer<vtkAOSDataArrayTemplate<ValueType>>::New();
|
||||
arr->SetNumberOfComponents(1);
|
||||
arr->SetNumberOfTuples(0);
|
||||
}
|
||||
};
|
||||
checkNullRectify(this->Left);
|
||||
checkNullRectify(this->Right);
|
||||
this->LeftRange = vtk::DataArrayValueRange(this->Left);
|
||||
this->RightRange = vtk::DataArrayValueRange(this->Right);
|
||||
this->Offset = this->LeftRange.size();
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkDataArray> Left;
|
||||
vtk::detail::SelectValueRange<vtkDataArray*, vtk::detail::DynamicTupleSize>::type LeftRange;
|
||||
vtkSmartPointer<vtkDataArray> Right;
|
||||
vtk::detail::SelectValueRange<vtkDataArray*, vtk::detail::DynamicTupleSize>::type RightRange;
|
||||
int Offset = -1;
|
||||
std::vector<vtkSmartPointer<vtkDataArray>> Arrays;
|
||||
std::vector<vtk::detail::SelectValueRange<vtkDataArray*, vtk::detail::DynamicTupleSize>::type>
|
||||
Ranges;
|
||||
std::vector<std::size_t> Offsets;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template <typename ValueType>
|
||||
vtkCompositeImplicitBackend<ValueType>::vtkCompositeImplicitBackend(
|
||||
vtkDataArray* leftArr, vtkDataArray* rightArr)
|
||||
: Internal(std::unique_ptr<Internals>(new Internals(leftArr, rightArr)))
|
||||
const std::vector<vtkDataArray*>& arrays)
|
||||
: Internal(std::unique_ptr<Internals>(new Internals(arrays.begin(), arrays.end())))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -72,8 +68,9 @@ vtkCompositeImplicitBackend<ValueType>::~vtkCompositeImplicitBackend() = default
|
|||
template <typename ValueType>
|
||||
ValueType vtkCompositeImplicitBackend<ValueType>::operator()(int idx) const
|
||||
{
|
||||
return static_cast<ValueType>((idx < this->Internal->Offset)
|
||||
? this->Internal->LeftRange[idx]
|
||||
: this->Internal->RightRange[idx - this->Internal->Offset]);
|
||||
auto itPos =
|
||||
std::upper_bound(this->Internal->Offsets.begin(), this->Internal->Offsets.end(), idx);
|
||||
int locIdx = itPos == this->Internal->Offsets.begin() ? idx : idx - *(itPos - 1);
|
||||
return this->Internal->Ranges[std::distance(this->Internal->Offsets.begin(), itPos)][locIdx];
|
||||
}
|
||||
VTK_ABI_NAMESPACE_END
|
||||
|
|
Loading…
Reference in New Issue