#include <deal.II/base/std_cxx11/tuple.h>
#include <deal.II/base/std_cxx11/bind.h>
#include <deal.II/base/std_cxx11/function.h>
+#include <deal.II/base/std_cxx11/shared_ptr.h>
#include <cstddef>
TBBPartitioner()
#ifdef DEAL_II_WITH_THREADS
:
+ my_partitioner(new tbb::affinity_partitioner()),
in_use(false)
#endif
{}
#ifdef DEAL_II_WITH_THREADS
/**
- * Return a pointer to the affinity partitioner in case it is free. If
- * it is already in use (i.e., someone else called acquire without
- * releasing it afterwards), the null pointer is returned.
+ * Destructor. Check that the object is not in use any more, i.e., all
+ * loops have been completed.
*/
- tbb::affinity_partitioner *acquire()
+ ~TBBPartitioner()
+ {
+ Assert(in_use == false,
+ ExcInternalError("A vector partitioner goes out of scope, but "
+ "it appears to be still in use."));
+ }
+
+ /**
+ * Return an affinity partitioner. In case the partitioner owned by the
+ * class is free, it is returned here. In case another thread has not
+ * released it yet, a new object is created. To free the partitioner
+ * again, return it by the release_one_partitioner() call.
+ */
+ std_cxx11::shared_ptr<tbb::affinity_partitioner>
+ acquire_one_partitioner()
{
dealii::Threads::Mutex::ScopedLock lock(mutex);
if (in_use)
- return NULL;
+ return std_cxx11::shared_ptr<tbb::affinity_partitioner>(new tbb::affinity_partitioner());
in_use = true;
- return &partitioner;
+ return my_partitioner;
}
/**
- * After using the partitioner in a tbb loop through acquire(), this
- * call makes the partitioner available again.
+ * After using the partitioner in a tbb loop through
+ * acquire_one_partitioner(), this call makes the partitioner available
+ * again.
*/
- void release()
+ void release_one_partitioner(std_cxx11::shared_ptr<tbb::affinity_partitioner> &p)
{
- dealii::Threads::Mutex::ScopedLock lock(mutex);
- in_use = false;
+ if (p.get() == my_partitioner.get())
+ {
+ dealii::Threads::Mutex::ScopedLock lock(mutex);
+ in_use = false;
+ }
}
private:
/**
- * The stored partitioner
+ * The stored partitioner that can accumulate knowledge over several
+ * runs of tbb::parallel_for
*/
- tbb::affinity_partitioner partitioner;
+ std_cxx11::shared_ptr<tbb::affinity_partitioner> my_partitioner;
/**
* A flag to indicate whether the partitioner has been acquired but not
template <typename Functor>
void vectorized_transform(Functor &functor,
size_type vec_size,
- parallel::internal::TBBPartitioner *partitioner = NULL)
+ std_cxx11::shared_ptr<parallel::internal::TBBPartitioner> &partitioner)
{
#ifdef DEAL_II_WITH_THREADS
// only go to the parallel function in case there are at least 4 parallel
if (vec_size >= 4*internal::Vector::minimum_parallel_grain_size &&
MultithreadInfo::n_threads() > 1)
{
- // in case the partitioner was used by another thread, create a
- // private partitioner here for use in the loop (we could also use the
- // auto partitioner of TBB but that increases code size considerably
- // without major benefit)
- tbb::affinity_partitioner *tbb_partitioner = (partitioner == NULL) ?
- NULL : partitioner->acquire();
- tbb::affinity_partitioner private_partitioner;
- if (tbb_partitioner == NULL)
- tbb_partitioner = &private_partitioner;
+ if (partitioner.get() == NULL)
+ partitioner.reset(new parallel::internal::TBBPartitioner());
+ std_cxx11::shared_ptr<tbb::affinity_partitioner> tbb_partitioner =
+ partitioner->acquire_one_partitioner();
tbb::parallel_for (tbb::blocked_range<size_type> (0,
vec_size,
internal::Vector::minimum_parallel_grain_size),
functor,
*tbb_partitioner);
- if (partitioner != NULL)
- partitioner->release();
+ partitioner->release_one_partitioner(tbb_partitioner);
}
else if (vec_size > 0)
functor(0,vec_size);
if (PointerComparison::equal(this, &v))
return *this;
+ thread_loop_partitioner = v.thread_loop_partitioner;
if (vec_size != v.vec_size)
reinit (v, true);
dealii::internal::Vector_copy<Number,Number> copier;
copier.dst = val;
copier.src = v.val;
- internal::vectorized_transform(copier,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(copier,vec_size,thread_loop_partitioner);
return *this;
}
Vector<Number> &
Vector<Number>::operator= (const Vector<Number2> &v)
{
+ thread_loop_partitioner = v.thread_loop_partitioner;
if (vec_size != v.vec_size)
reinit (v, true);
dealii::internal::Vector_copy<Number,Number2> copier;
copier.dst = val;
copier.src = v.val;
- internal::vectorized_transform(copier,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(copier,vec_size,thread_loop_partitioner);
return *this;
}
void Vector<Number>::reinit (const size_type n,
const bool omit_zeroing_entries)
{
- thread_loop_partitioner.reset();
if (n==0)
{
if (val) deallocate();
val = 0;
max_vec_size = vec_size = 0;
+ thread_loop_partitioner.reset(new parallel::internal::TBBPartitioner());
return;
};
max_vec_size = n;
allocate();
};
- vec_size = n;
- thread_loop_partitioner.reset(new parallel::internal::TBBPartitioner());
+
+ if (vec_size != n)
+ {
+ vec_size = n;
+
+ // only reset the partitioner if we actually expect a significant vector
+ // size
+ if (vec_size > 4*internal::Vector::minimum_parallel_grain_size)
+ thread_loop_partitioner.reset(new parallel::internal::TBBPartitioner());
+ }
+
if (omit_zeroing_entries == false)
*this = static_cast<Number>(0);
}
setter.dst = val;
setter.value = s;
- internal::vectorized_transform(setter,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(setter,vec_size,thread_loop_partitioner);
return *this;
}
vector_multiply.val = val;
vector_multiply.factor = factor;
- internal::vectorized_transform(vector_multiply,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_multiply,vec_size,thread_loop_partitioner);
return *this;
}
vector_add_av.val = val;
vector_add_av.v_val = v.val;
vector_add_av.factor = a;
- internal::vectorized_transform(vector_add_av,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_add_av,vec_size,thread_loop_partitioner);
}
vector_sadd_xav.v_val = v.val;
vector_sadd_xav.a = a;
vector_sadd_xav.x = x;
- internal::vectorized_transform(vector_sadd_xav,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_sadd_xav,vec_size,thread_loop_partitioner);
}
internal::Vectorization_subtract_v<Number> vector_subtract;
vector_subtract.val = val;
vector_subtract.v_val = v.val;
- internal::vectorized_transform(vector_subtract,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_subtract,vec_size,thread_loop_partitioner);
return *this;
}
internal::Vectorization_add_factor<Number> vector_add;
vector_add.val = val;
vector_add.factor = v;
- internal::vectorized_transform(vector_add,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_add,vec_size,thread_loop_partitioner);
}
internal::Vectorization_add_v<Number> vector_add;
vector_add.val = val;
vector_add.v_val = v.val;
- internal::vectorized_transform(vector_add,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_add,vec_size,thread_loop_partitioner);
}
vector_add.w_val = w.val;
vector_add.a = a;
vector_add.b = b;
- internal::vectorized_transform(vector_add,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_add,vec_size,thread_loop_partitioner);
}
vector_sadd.val = val;
vector_sadd.v_val = v.val;
vector_sadd.x = x;
- internal::vectorized_transform(vector_sadd,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_sadd,vec_size,thread_loop_partitioner);
}
vector_sadd.x = x;
vector_sadd.a = a;
vector_sadd.b = b;
- internal::vectorized_transform(vector_sadd,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_sadd,vec_size,thread_loop_partitioner);
}
internal::Vectorization_scale<Number> vector_scale;
vector_scale.val = val;
vector_scale.v_val = s.val;
- internal::vectorized_transform(vector_scale,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_scale,vec_size,thread_loop_partitioner);
}
vector_equ.val = val;
vector_equ.u_val = u.val;
vector_equ.a = a;
- internal::vectorized_transform(vector_equ,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_equ,vec_size,thread_loop_partitioner);
}
vector_equ.v_val = v.val;
vector_equ.a = a;
vector_equ.b = b;
- internal::vectorized_transform(vector_equ,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_equ,vec_size,thread_loop_partitioner);
}
vector_equ.a = a;
vector_equ.b = b;
vector_equ.c = c;
- internal::vectorized_transform(vector_equ,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_equ,vec_size,thread_loop_partitioner);
}
vector_ratio.val = val;
vector_ratio.a_val = a.val;
vector_ratio.b_val = b.val;
- internal::vectorized_transform(vector_ratio,vec_size,thread_loop_partitioner.get());
+ internal::vectorized_transform(vector_ratio,vec_size,thread_loop_partitioner);
}