-
-
Notifications
You must be signed in to change notification settings - Fork 713
BUG: Fix CastImageFilter for VariableLengthVector #5661
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
BUG: Fix CastImageFilter for VariableLengthVector #5661
Conversation
| { | ||
| if (m_NumElements != 0) | ||
| { | ||
| m_Data = this->AllocateElements(m_NumElements); |
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 does this interact with "LetArrayManageMemory"? It seems like m_LetArrayManageMemory should always be "true" for this case.
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.
Good point, I oversaw this. So this is not a good fix then... I suggest modifying the iterator Get function then.
|
I'm a bit lost and happy to get some advice. I hope the issue is clearly explained in the current commit log. The current proposal is not adequate as pointed out by @hjmjohnson's comment. I see two potential alternatives:
with a copy I'm concerned that people actually do not expect a difference in behavior between the two so I would lean towards the first suggestion. Any thought? |
|
What I suggest is to revert @blowekamp commit 6a60327... What do you think @blowekamp? |
Modules/Filtering/ImageFilterBase/test/itkCastImageFilterTest.cxx
Outdated
Show resolved
Hide resolved
Modules/Filtering/ImageFilterBase/test/itkCastImageFilterTest.cxx
Outdated
Show resolved
Hide resolved
Modules/Filtering/ImageFilterBase/test/itkCastImageFilterTest.cxx
Outdated
Show resolved
Hide resolved
|
I do not have time to look at this closely today. But this change has the potential to cause threaded-per-pixel memory allocations which can make filters runs 100s time slower. |
99fa978 to
ff1ffe0
Compare
I understand but the bug I encountered demonstrates that it is tricky and counter intuitive to use an iterator on a VariableVectorLength. I can limit this PR to patching the CastImageFilter if you want but I'm afraid the problem occurs in other places. |
One alternative proposition: create a private member |
|
The compilers should have gotten better over the last 10 years, they should be better at applying return value optimization. We could try reverting this, and measure performance. ~100x performance difference would be painfully obvious. I doubt it will have such an impact. |
|
Just a couple notes as I get into this.
|
|
Looking at the CastImageFilter:
That first line use to copy of the VariableLengthVector breaking the reference to the data buffer, but some how it changes to retain a reference to the data buffer.
Per pixel memory allocation with 50+ cores was historically rather slow. Likely small memory concurrent mallocs have improved, but iterative per-pixel memory allocation is still a HUGE performance issue. |
|
I have not disputed that, I merely suggested checking whether the compiler is now smart enough to generate same or similar assembly code for both variants of |
|
The change to add support to VariableLengthVector to the CastImageFilter occurred here: 87c3fb1 We can quickly address the issue with the filter with the following change: corrected If I have this correct conceptually, an ImageIterator's "Get" method should return a copy to the pixel, while the "Value" method should return a reference. In this case the PixelAccessor for the VectorImage is returning a (modifiable) reference and it is getting modified in the filter. This fix will be more involved, if needed. |
I agree, it would be very nice to have this in CastImageFilter.
which returns |
ff1ffe0 to
b819ed6
Compare
Done in the latest force-push. If you agree, let's merge this PR to fix CastImageFilter and then I'll open an issue with the minimal example above. BTW, |
| ImageScanlineIterator outputIt(outputPtr, outputRegionForThread); | ||
|
|
||
| OutputPixelType value{ outputIt.Get() }; | ||
| itk::NumericTraits<typename OutputPixelType::ValueType> value[componentsPerPixel]; |
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.
Sorry I posted the wrong diff, this is what I had working:
+ const auto &outputValue{outputIt.Get()};
+ auto value{ outputValue };
It was not an elegant way to force a copy, and I began looking at other constructs.
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.
Sorry I only saw this after pushing yet another version. Let me know which version you prefer, they're all fine to me.
b819ed6 to
380a7c1
Compare
|
@blowekamp Your suggestion was not compiling so I force-pushed a different version, see changes here. |
|
@SimonRit I timed a couple options and this seems clean and perfrom the best: Sorry I didn't have a working diff to start. |
The `Get` function of `VectorImage` iterators calls the `VariableLengthVector` constructor parameterized by a const pointer and a vector length (see `DefaultVectorPixelAccessor::Get`). The `m_Data` pointer of the constructed VariableLengthVector which is returned is pointing to the returned pixel data. This was a problem in CastImageFitler. A `CastImageFilter` test has been added to reproduce the issue: when a `VectorImage` was casted to an `Image< Vector <`, the first pixel of the region was taking the value of the last pixel of the region. The test illustrated this by creating an image filled with 0 except the first pixel. The casted image was completely full of 0 before bug correction. Co-authored-by: Bradley Lowekamp <[email protected]>
380a7c1 to
921c5ba
Compare
|
I updated the branch with the recommendation. |
Thanks for this. I approve my PR 😄 and I have opened #5668 to track the issue. |
4fcc20a
into
InsightSoftwareConsortium:main
|
We should consider porting the fix to the 5.4 branch. |
The
Getfunction ofVectorImageiterators calls theVariableLengthVectorconstructor parameterized by a const pointer and a vector length (seeDefaultVectorPixelAccessor::Get). Them_Datapointer of the constructed VariableLengthVector which was returned was then pointing to the returned pixel data. This led to an unexpected behavior inCastImageFilter::DynamicThreadedGenerateDataDispatchedwhere modifications to the local variableof
CastImageFilter::DynamicThreadedGenerateDataDispatchedwere actually modifying the pixel of the image at the iterator position. The problem might occur elsewhere so it is safer to copy the data when a VariableLengthVector is constructed from a const pointer despite the potential loss in performances.A
CastImageFiltertest has been added to illustrate the issue: when aVectorImagewas casted to anImage< Vector <, the first pixel of the region was taking the value of the last pixel of the region. The test illustrated this by creating an image filled with 0 except the first pixel. The casted image was completely full of 0 before bug correction.PR Checklist
Refer to the ITK Software Guide for
further development details if necessary.