-
Notifications
You must be signed in to change notification settings - Fork 749
Improved performance of LeafNode ValueIters #2026
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -219,31 +219,60 @@ class LeafNode | |
| public SparseIteratorBase< | ||
| MaskIterT, ValueIter<MaskIterT, NodeT, ValueT, TagT>, NodeT, ValueT> | ||
| { | ||
| using ValueType = std::conditional_t<std::is_const_v<NodeT>, ValueT, | ||
| std::remove_const_t<ValueT>>; | ||
| using BaseT = SparseIteratorBase<MaskIterT, ValueIter, NodeT, ValueT>; | ||
|
|
||
| ValueIter() {} | ||
| ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {} | ||
| ValueIter(const MaskIterT& iter, NodeT* parent) | ||
| : BaseT(iter, parent) | ||
| // Unlike other value iterators, cache the buffer data as part of | ||
| // the iterators members to avoid the cost of going through the | ||
| // leaf buffer atomic/checking API | ||
| , mData([&]() { OPENVDB_ASSERT(parent); return parent->buffer().data(); }()) {} | ||
|
|
||
| ValueT& getItem(Index pos) const { return this->parent().getValue(pos); } | ||
| ValueT& getValue() const { return this->parent().getValue(this->pos()); } | ||
| ValueT& getItem(Index pos) const { return mData[pos]; } | ||
| ValueT& getValue() const { return this->getItem(this->pos()); } | ||
|
|
||
| // Note: setItem() can't be called on const iterators. | ||
| void setItem(Index pos, const ValueT& value) const | ||
| { | ||
| this->parent().setValueOnly(pos, value); | ||
| if constexpr (std::is_const_v<NodeT>) { | ||
| static_assert(!std::is_const_v<NodeT>, | ||
| "ValueIter::setItem cannot be called on const iterators"); | ||
| } | ||
| else { | ||
| OPENVDB_ASSERT(pos < SIZE); | ||
| OPENVDB_ASSUME(pos < SIZE); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interested to know more about this. Is this related to the fact that pos is unsigned and thus can wrap around?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, one reason I dislike unsigned numbers is you an do these one-sided comparisons as a negative will be very large.... SO this is the equivalent of |
||
| mData[pos] = value; | ||
| } | ||
| } | ||
| // Note: setValue() can't be called on const iterators. | ||
| void setValue(const ValueT& value) const | ||
| { | ||
| this->parent().setValueOnly(this->pos(), value); | ||
| } | ||
| void setValue(const ValueT& value) const { this->setItem(this->pos(), value); } | ||
|
|
||
| // Note: modifyItem() can't be called on const iterators. | ||
| template<typename ModifyOp> | ||
| void modifyItem(Index n, const ModifyOp& op) const { this->parent().modifyValue(n, op); } | ||
| void modifyItem(Index n, const ModifyOp& op) const | ||
| { | ||
| if constexpr (std::is_const_v<NodeT>) { | ||
| static_assert(!std::is_const_v<NodeT>, | ||
| "ValueIter::modifyItem cannot be called on const iterators"); | ||
| } | ||
| else { | ||
| OPENVDB_ASSERT(n < SIZE); | ||
| OPENVDB_ASSUME(n < SIZE); | ||
| op(mData[n]); | ||
| this->parent().setValueOn(n); | ||
| } | ||
| } | ||
| // Note: modifyValue() can't be called on const iterators. | ||
| template<typename ModifyOp> | ||
| void modifyValue(const ModifyOp& op) const { this->parent().modifyValue(this->pos(), op); } | ||
| void modifyValue(const ModifyOp& op) const | ||
| { | ||
| this->modifyItem(this->pos(), op); | ||
| } | ||
| private: | ||
| ValueType* mData; | ||
| }; | ||
|
|
||
| /// Leaf nodes have no children, so their child iterators have no get/set accessors. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| OpenVDB: | ||
| - Improvements: | ||
| - Significantly improved the performance of all LeafNode ValueIterators, | ||
| up to 5x on some platforms and up to 10x when delay loading is enabled. | ||
| Construction of a ValueIterator from a leaf node now requests the leaf | ||
| buffers ahead of iteration to avoid potentially expensive API calls. | ||
| - Added OPENVDB_ASSUME macros to mimic builtin assume and C++23 assume | ||
| attributes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How substantial is this assume attribute for the performance improvement of ValueAccessors? GCC13 is still not even in the VFX reference platform. Would something like this possibly be a viable alternative until then: