-
Notifications
You must be signed in to change notification settings - Fork 6
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
Fix RAII issue by introducing wrapper classes for backend plans #208
base: main
Are you sure you want to change the base?
Conversation
e302632
to
05a023b
Compare
I would go a step further and make these RAII classes unique-owners. That implies to disallow shallow copy either by simply deleting copy constructor and assignment or make them allocate and copy a new plan if backends offer such a copy function. We can keep the move semantics but we have to keep track if the current object must call class ScopedCufftPlanType {
private:
cufftHandle m_plan;
public:
ScopedCufftPlanType() {
cufftResult cufft_rt = cufftCreate(&m_plan);
KOKKOSFFT_THROW_IF(cufft_rt != CUFFT_SUCCESS, "cufftCreate failed");
}
ScopedCufftPlanType(ScopedCufftPlanType const& rhs) = delete;
ScopedCufftPlanType(ScopedCufftPlanType&& rhs) = delete;
~ScopedCufftPlanType() noexcept {
cufftResult cufft_rt = cufftDestroy(m_plan);
if (cufft_rt != CUFFT_SUCCESS) Kokkos::abort("cufftDestroy failed");
}
ScopedCufftPlanType& operator=(ScopedCufftPlanType const& rhs) = delete;
ScopedCufftPlanType& operator=(ScopedCufftPlanType&& rhs) = delete;
cufftHandle plan() const noexcept { return m_plan; }
}; The I notice that we could also improve the error messages, I see that |
I would prefer to disallow both copy and move, because it may be unsafe for some backends.
Does it return a shallow copy of the
That is true. We can improve the error messages |
Ok for me. I don't think there should be any problem with implementing the move semantics later. It requires us to only pass these objects by reference.
I mean if we do ScopedCufftPlanType plan1;
ScopedCufftPlanType plan2;
plan2 = plan1; This compiles fine and |
That is right. This does not work in the current implementation. Yes, for safety, it is better to disallow copy |
e510c5e
to
46a3630
Compare
fft/src/KokkosFFT_ROCM_types.hpp
Outdated
void allocate_work_buffer(std::size_t workbuffersize) { | ||
m_buffer = BufferViewType("workbuffer", workbuffersize); | ||
} | ||
rocfft_plan &plan() { return m_plan; } |
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.
rocfft_plan &plan() { return m_plan; } | |
rocfft_plan plan() const noexcept { return m_plan; } |
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.
Sure
fft/src/KokkosFFT_ROCM_plans.hpp
Outdated
[](rocfft_plan_description* desc) { | ||
rocfft_plan_description_destroy(*desc); | ||
}); |
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.
[](rocfft_plan_description* desc) { | |
rocfft_plan_description_destroy(*desc); | |
}); | |
[](rocfft_plan_description* desc) { | |
rocfft_plan_description_destroy(*desc); | |
delete desc; | |
}); |
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.
I introduced a wrapper for description as well for RAII. This part has been removed
fft/src/KokkosFFT_ROCM_plans.hpp
Outdated
[](rocfft_plan_description* desc) { | ||
rocfft_plan_description_destroy(*desc); | ||
}); | ||
rocfft_status status = rocfft_plan_description_create(&(*description)); |
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.
I think we can improve the situation by also wrapping rocfft_plan_description
.
In case rocfft_plan_description_create
fails, the next KOKKOSFFT_THROW_IF
will throw, calling the destructor of description
thus calling rocfft_plan_description_destroy
even though the rocfft_plan_description
object has not been initialised.
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.
I have introduced a wrapper accordingly
fft/src/KokkosFFT_ROCM_plans.hpp
Outdated
plan = std::make_unique<PlanType>(); | ||
status = rocfft_plan_create(&(*plan), place, fft_direction, precision, | ||
status = rocfft_plan_create(&(plan->plan()), place, fft_direction, precision, | ||
reversed_fft_extents.size(), // Dimension | ||
reversed_fft_extents.data(), // Lengths | ||
howmany, // Number of transforms | ||
description // Description | ||
howmany, // Number of transforms | ||
*description // Description |
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.
Why not making this part of the constructor of ScopedRocfftPlan
?
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.
I moved the logic into the constructor
7a6946c
to
a6ccd56
Compare
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.
@tpadioleau
Thank you for reviews. I have fixed accordingly
if constexpr (std::is_same_v<plan_type, fftwf_plan>) { | ||
if (m_is_created) fftwf_destroy_plan(m_plan); | ||
} else { | ||
if (m_is_created) fftw_destroy_plan(m_plan); | ||
} |
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.
I may expect that fftw_plan_many_dft
may fail if we request too much memory
fft/src/KokkosFFT_ROCM_types.hpp
Outdated
void allocate_work_buffer(std::size_t workbuffersize) { | ||
m_buffer = BufferViewType("workbuffer", workbuffersize); | ||
} | ||
rocfft_plan &plan() { return m_plan; } |
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.
Sure
fft/src/KokkosFFT_ROCM_plans.hpp
Outdated
[](rocfft_plan_description* desc) { | ||
rocfft_plan_description_destroy(*desc); | ||
}); |
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.
I introduced a wrapper for description as well for RAII. This part has been removed
fft/src/KokkosFFT_ROCM_plans.hpp
Outdated
[](rocfft_plan_description* desc) { | ||
rocfft_plan_description_destroy(*desc); | ||
}); | ||
rocfft_status status = rocfft_plan_description_create(&(*description)); |
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.
I have introduced a wrapper accordingly
fft/src/KokkosFFT_ROCM_plans.hpp
Outdated
plan = std::make_unique<PlanType>(); | ||
status = rocfft_plan_create(&(*plan), place, fft_direction, precision, | ||
status = rocfft_plan_create(&(plan->plan()), place, fft_direction, precision, | ||
reversed_fft_extents.size(), // Dimension | ||
reversed_fft_extents.data(), // Lengths | ||
howmany, // Number of transforms | ||
description // Description | ||
howmany, // Number of transforms | ||
*description // Description |
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.
I moved the logic into the constructor
Resolves #197
In this PR, we try to resolve RAII issues by introducing a thin wrapper for backend fft plans.
Following modifications are made,
KokkosFFT_FFTW_Types.hpp
file including theFFTW
plan wrapper class and common code bases related fftwFFTW
,cufft
,hipfft
, androcfft
(Scoped***Plan
)For CUDA, we have
Info
andBuffer
that are required only for rocfft are moved insiderocfft
helper classcleanup_threads()
in the destructor of FFTW helper classdestroy_plan_and_info
since it is automatically done in destructors of helper classesQuestions
cufft
andhipfft
. Should we raise assertions in constructor if it fails?