Skip to content

Commit

Permalink
added mutex to fftw plan creation and extended documentation on threa…
Browse files Browse the repository at this point in the history
…d-safety
  • Loading branch information
AdhocMan committed Jun 9, 2020
1 parent 0a02ef6 commit 2559102
Show file tree
Hide file tree
Showing 16 changed files with 183 additions and 28 deletions.
14 changes: 14 additions & 0 deletions docs/source/details.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ SPFFT_EXCH_UNBUFFERED

| For both *SPFFT_EXCH_BUFFERED* and *SPFFT_EXCH_COMPACT_BUFFERED*, an exchange in single precision can be selected. With transforms in double precision, the number of bytes sent and received is halved. For execution on GPUs without GPUDirect, the data transfer between GPU and host also benefits. This option can provide a significant speedup, but incurs a slight accuracy loss. The double precision values are converted to and from single precision between the transform in z and the transform in x / y, while all actual calculations are still done in the selected precision.

Thread-Safety
-------------
The creation of Grid and Transform objects is thread-safe only if:

* No FFTW library calls are executed concurrently.
* In the distributed case, MPI thread support is set to *MPI_THREAD_MULTIPLE*.


The execution of transforms is thread-safe if

* Each thread executes using its own Grid and associated Transform object.
* In the distributed case, MPI thread support is set to *MPI_THREAD_MULTIPLE*.

GPU
---
| Saving transfer time between host and GPU is key to good performance for execution with GPUs. Ideally, both input and output is located on GPU memory. If host memory pointers are provided as input or output, it is helpful to use pinned memory through the CUDA or ROCm API.
Expand Down
3 changes: 1 addition & 2 deletions docs/source/grid.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
Grid
====
.. note::
A Grid object can be safely destroyed after transforms have been created. The transforms hold a reference counted objtect containing the allocated memory, which will remain valid until all transforms are destroyed as well.

A Grid object can be safely destroyed after Transform objects have been created, since internal reference counting used to prevent the release of resources while still in use.

.. doxygenclass:: spfft::Grid
:project: SpFFT
Expand Down
3 changes: 3 additions & 0 deletions docs/source/grid_c.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
Grid
====

.. note::
A Grid handle can be safely destroyed after Transform handles have been created, since internal reference counting used to prevent the release of resources while still in use.

.. doxygenfile:: spfft/grid.h
:project: SpFFT
3 changes: 2 additions & 1 deletion docs/source/grid_float.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ GridFloat
This class is only available if single precision support is enabled, in which case the marco SPFFT_SINGLE_PRECISION is defined in config.h.

.. note::
A Grid object can be safely destroyed after transforms have been created. The transforms hold a reference counted objtect containing the allocated memory, which will remain valid until all transforms are destroyed as well.
A Grid object can be safely destroyed after Transform objects have been created, since internal reference counting used to prevent the release of resources while still in use.


.. doxygenclass:: spfft::GridFloat
:project: SpFFT
Expand Down
3 changes: 3 additions & 0 deletions docs/source/grid_float_c.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
GridFloat
=========
.. note::
A Grid handle can be safely destroyed after Transform handles have been created, since internal reference counting used to prevent the release of resources while still in use.

.. note::
These functions are only available if single precision support is enabled, in which case the marco SPFFT_SINGLE_PRECISION is defined in config.h.

Expand Down
1 change: 1 addition & 0 deletions include/spfft/grid.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ SPFFT_EXPORT SpfftError spfft_grid_create(SpfftGrid* grid, int maxDimX, int maxD
#ifdef SPFFT_MPI
/**
* Constructor for a distributed grid.
* Thread-safe if MPI thread support is set to MPI_THREAD_MULTIPLE.
*
* @param[out] grid Handle to grid.
* @param[in] maxDimX Maximum dimension in x.
Expand Down
2 changes: 2 additions & 0 deletions include/spfft/grid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class SPFFT_EXPORT Grid {
#ifdef SPFFT_MPI
/**
* Constructor for a distributed grid.
* Thread-safe if MPI thread support is set to MPI_THREAD_MULTIPLE.
*
* @param[in] maxDimX Maximum dimension in x.
* @param[in] maxDimY Maximum dimension in y.
Expand Down Expand Up @@ -116,6 +117,7 @@ class SPFFT_EXPORT Grid {

/**
* Creates a transform from this grid object.
* Thread-safe if no FFTW calls are executed concurrently.
*
* @param[in] processingUnit The processing unit type to use. Must be either SPFFT_PU_HOST or
* SPFFT_PU_GPU and be supported by the grid itself.
Expand Down
1 change: 1 addition & 0 deletions include/spfft/grid_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ SPFFT_EXPORT SpfftError spfft_float_grid_create(SpfftFloatGrid* grid, int maxDim
#ifdef SPFFT_MPI
/**
* Constructor for a single precision distributed grid.
* Thread-safe if MPI thread support is set to MPI_THREAD_MULTIPLE.
*
* @param[out] grid Handle to grid.
* @param[in] maxDimX Maximum dimension in x.
Expand Down
2 changes: 2 additions & 0 deletions include/spfft/grid_float.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class SPFFT_EXPORT GridFloat {
#ifdef SPFFT_MPI
/**
* Constructor for a distributed grid.
* Thread-safe if MPI thread support is set to MPI_THREAD_MULTIPLE.
*
* @param[in] maxDimX Maximum dimension in x.
* @param[in] maxDimY Maximum dimension in y.
Expand Down Expand Up @@ -117,6 +118,7 @@ class SPFFT_EXPORT GridFloat {

/**
* Creates a transform from this grid object.
* Thread-safe if no FFTW calls are executed concurrently.
*
* @param[in] processingUnit The processing unit type to use. Must be either SPFFT_PU_HOST or
* SPFFT_PU_GPU and be supported by the grid itself.
Expand Down
1 change: 1 addition & 0 deletions include/spfft/transform.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ typedef void* SpfftTransform;

/**
* Creates a transform from a grid handle.
* Thread-safe if no FFTW calls are executed concurrently.
*
* @param[out] transform Handle to the transform.
* @param[in] grid Handle to the grid, with which the transform is created.
Expand Down
1 change: 1 addition & 0 deletions include/spfft/transform_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ typedef void* SpfftFloatTransform;

/**
* Creates a single precision transform from a single precision grid handle.
* Thread-safe if no FFTW calls are executed concurrently.
*
* @param[out] transform Handle to the transform.
* @param[in] grid Handle to the grid, with which the transform is created.
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set(SPFFT_SOURCE_FILES
spfft/multi_transform.cpp
spfft/grid.cpp
spfft/grid_internal.cpp
fft/fftw_mutex.cpp
)

if(SPFFT_SINGLE_PRECISION)
Expand Down
39 changes: 39 additions & 0 deletions src/fft/fftw_mutex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2019 ETH Zurich, Simon Frasch
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <mutex>
#include "fft/fftw_mutex.hpp"
#include "spfft/config.h"

namespace spfft {
auto global_fftw_mutex() -> std::mutex& {
static std::mutex globMutex; // thread safe initialization since C++11
return globMutex;
}
} // namespace spfft

41 changes: 41 additions & 0 deletions src/fft/fftw_mutex.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2019 ETH Zurich, Simon Frasch
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SPFFT_FFTW_MUTEX_HPP
#define SPFFT_FFTW_MUTEX_HPP

#include <mutex>
#include "spfft/config.h"

namespace spfft {

// provides a global mutex for guarding fftw functions calls, which are not thread-safe
auto global_fftw_mutex() -> std::mutex&;

} // namespace spfft

#endif
37 changes: 28 additions & 9 deletions src/fft/fftw_plan_1d.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@
#include <fftw3.h>
#include <cassert>
#include <complex>
#include <mutex>
#include "spfft/config.h"
#include "spfft/exceptions.hpp"
#include "util/common_types.hpp"
#include "util/type_check.hpp"
#include "fft/fftw_mutex.hpp"

namespace spfft {

Expand All @@ -58,8 +60,12 @@ class FFTWPlan<double> {
if (input != output) {
flags = flags | FFTW_DESTROY_INPUT; // allow input override for out-of-place transform
}
plan_ = fftw_plan_dft_1d(size, reinterpret_cast<fftw_complex*>(input),
reinterpret_cast<fftw_complex*>(output), sign, flags);

{
std::lock_guard<std::mutex> guard(global_fftw_mutex());
plan_ = fftw_plan_dft_1d(size, reinterpret_cast<fftw_complex*>(input),
reinterpret_cast<fftw_complex*>(output), sign, flags);
}
if (!plan_) throw FFTWError();
}

Expand All @@ -76,25 +82,35 @@ class FFTWPlan<double> {
if (input != output) {
flags = flags | FFTW_DESTROY_INPUT; // allow input override for out-of-place transform
}
plan_ =
fftw_plan_many_dft(rank, n, (int)howmany, reinterpret_cast<fftw_complex*>(input), inembed,
(int)istride, (int)idist, reinterpret_cast<fftw_complex*>(output),
onembed, (int)ostride, (int)odist, sign, flags);

{
std::lock_guard<std::mutex> guard(global_fftw_mutex());
plan_ =
fftw_plan_many_dft(rank, n, (int)howmany, reinterpret_cast<fftw_complex*>(input), inembed,
(int)istride, (int)idist, reinterpret_cast<fftw_complex*>(output),
onembed, (int)ostride, (int)odist, sign, flags);
}
if (!plan_) throw FFTWError();
}

FFTWPlan(const FFTWPlan& other) = delete;

FFTWPlan(FFTWPlan&& other) noexcept {
if (plan_) fftw_destroy_plan(plan_);
if (plan_) {
std::lock_guard<std::mutex> guard(global_fftw_mutex());
fftw_destroy_plan(plan_);
}
plan_ = other.plan_;
other.plan_ = nullptr;
}

auto operator=(const FFTWPlan& other) -> FFTWPlan& = delete;

auto operator=(FFTWPlan&& other) noexcept -> FFTWPlan& {
if (plan_) fftw_destroy_plan(plan_);
if (plan_) {
std::lock_guard<std::mutex> guard(global_fftw_mutex());
fftw_destroy_plan(plan_);
}
plan_ = other.plan_;
other.plan_ = nullptr;
return *this;
Expand Down Expand Up @@ -134,7 +150,10 @@ class FFTWPlan<double> {
}

~FFTWPlan() {
if (plan_) fftw_destroy_plan(plan_);
if (plan_) {
std::lock_guard<std::mutex> guard(global_fftw_mutex());
fftw_destroy_plan(plan_);
}
plan_ = nullptr;
}

Expand Down
Loading

0 comments on commit 2559102

Please sign in to comment.