]> https://gitweb.dealii.org/ - dealii-svn.git/commitdiff
Put AlignedVector into its own file
authorkronbichler <kronbichler@0785d39b-7218-0410-832d-ea1e28bc413d>
Tue, 18 Feb 2014 21:37:44 +0000 (21:37 +0000)
committerkronbichler <kronbichler@0785d39b-7218-0410-832d-ea1e28bc413d>
Tue, 18 Feb 2014 21:37:44 +0000 (21:37 +0000)
git-svn-id: https://svn.dealii.org/trunk@32508 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/include/deal.II/base/aligned_vector.h [new file with mode: 0644]
deal.II/include/deal.II/base/vectorization.h
deal.II/source/distributed/tria.cc

diff --git a/deal.II/include/deal.II/base/aligned_vector.h b/deal.II/include/deal.II/base/aligned_vector.h
new file mode 100644 (file)
index 0000000..c013786
--- /dev/null
@@ -0,0 +1,776 @@
+// ---------------------------------------------------------------------
+// $Id$
+//
+// Copyright (C) 2011 - 2014 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+#ifndef __deal2__aligned_vector_h
+#define __deal2__aligned_vector_h
+
+#include <deal.II/base/config.h>
+#include <deal.II/base/std_cxx1x/type_traits.h>
+#include <deal.II/base/exceptions.h>
+#include <deal.II/base/memory_consumption.h>
+#include <deal.II/base/parallel.h>
+#include <deal.II/base/vectorization.h>
+
+
+#if DEAL_II_COMPILER_VECTORIZATION_LEVEL > 0
+#include <mm_malloc.h>
+#endif
+
+
+
+DEAL_II_NAMESPACE_OPEN
+
+
+/**
+ * This is a replacement class for std::vector to be used in combination with
+ * VectorizedArray and derived data types. It allocates memory aligned to
+ * addresses of a vectorized data type (in order to avoid segmentation faults
+ * when a variable of type VectorizedArray which the compiler assumes to be
+ * aligned to certain memory addresses does not actually follow these
+ * rules). This could also be achieved by proving std::vector with a
+ * user-defined allocator. On the other hand, writing an own small vector
+ * class lets us implement parallel copy and move operations with TBB, insert
+ * deal.II-style assertions, and cut some unnecessary functionality. Note that
+ * this vector is a bit more memory-consuming than std::vector because of
+ * alignment, so it is recommended to only use this vector on long vectors.
+ *
+ * @p author Katharina Kormann, Martin Kronbichler, 2011
+ */
+template < class T >
+class AlignedVector
+{
+public:
+  /**
+   * Declare standard types used in all containers. These types parallel those
+   * in the <tt>C++</tt> standard libraries <tt>vector<...></tt> class.
+   */
+  typedef T                   value_type;
+  typedef value_type         *pointer;
+  typedef const value_type   *const_pointer;
+  typedef value_type         *iterator;
+  typedef const value_type   *const_iterator;
+  typedef value_type         &reference;
+  typedef const value_type   &const_reference;
+  typedef std::size_t         size_type;
+
+  /**
+   * Empty constructor. Sets the vector size to zero.
+   */
+  AlignedVector ();
+
+  /**
+   * Sets the vector size to the given size and initializes all elements with
+   * T().
+   */
+  AlignedVector (const size_type size);
+
+  /**
+   * Destructor.
+   */
+  ~AlignedVector ();
+
+  /**
+   * Copy constructor.
+   */
+  AlignedVector (const AlignedVector<T> &vec);
+
+  /**
+   * Assignment to the input vector @p vec.
+   */
+  AlignedVector &
+  operator = (const AlignedVector<T> &vec);
+
+  /**
+   * Change the size of the vector. It keeps old elements previously available
+   * but does not initialize the newly allocated memory, leaving it in an
+   * undefined state.
+   */
+  void resize_fast (const size_type size);
+
+  /**
+   * Change the size of the vector. It keeps old elements previously
+   * available, and initializes each element with the specified data. If the
+   * new vector size is shorter than the old one, the memory is not released
+   * unless the new size is zero.
+   */
+  void resize (const size_type size_in,
+               const T        &init = T());
+
+  /**
+   * Reserve memory space for @p size elements. If the argument @p size is set
+   * to zero, all previously allocated memory is released.
+   *
+   * In order to avoid too frequent reallocation (which involves copy of the
+   * data), this function doubles the amount of memory occupied when the given
+   * size is larger than the previously allocated size.
+   */
+  void reserve (const size_type size_alloc);
+
+  /**
+   * Releases all previously allocated memory and leaves the vector in a state
+   * equivalent to the state after the default constructor has been called.
+   */
+  void clear ();
+
+  /**
+   * Inserts an element at the end of the vector, increasing the vector size
+   * by one. Note that the allocated size will double whenever the previous
+   * space is not enough to hold the new element.
+   */
+  void push_back (const T in_data);
+
+  /**
+   * Returns the last element of the vector (read and write access).
+   */
+  reference back ();
+
+  /**
+   * Returns the last element of the vector (read-only access).
+   */
+  const_reference back () const;
+
+  /**
+   * Inserts several elements at the end of the vector given by a range of
+   * elements.
+   */
+  template <typename ForwardIterator>
+  void insert_back (ForwardIterator begin,
+                    ForwardIterator end);
+
+  /**
+   * Swaps the given vector with the calling vector.
+   */
+  void swap (AlignedVector<T> &vec);
+
+  /**
+   * Returns whether the vector is empty, i.e., its size is zero.
+   */
+  bool empty () const;
+
+  /**
+   * Returns the size of the vector.
+   */
+  size_type size () const;
+
+  /**
+   * Returns the capacity of the vector, i.e., the size this vector can hold
+   * without reallocation. Note that capacity() >= size().
+   */
+  size_type capacity () const;
+
+  /**
+   * Read-write access to entry @p index in the vector.
+   */
+  reference
+  operator [] (const size_type index);
+
+  /**
+   * Read-only access to entry @p index in the vector.
+   */
+  const_reference operator [] (const size_type index) const;
+
+  /**
+   * Returns a read and write pointer to the beginning of the data array.
+   */
+  iterator begin ();
+
+  /**
+   * Returns a read and write pointer to the end of the data array.
+   */
+  iterator end ();
+
+  /**
+   * Returns a read-only pointer to the beginning of the data array.
+   */
+  const_iterator begin () const;
+
+  /**
+   * Returns a read-only pointer to the end of the data array.
+   */
+  const_iterator end () const;
+
+  /**
+   * Returns the memory consumption of the allocated memory in this class. If
+   * the underlying type @p T allocates memory by itself, this memory is not
+   * counted.
+   */
+  size_type memory_consumption () const;
+
+private:
+
+  /**
+   * Pointer to actual class data.
+   */
+  T *_data;
+
+  /**
+   * Pointer to the end of valid data fields.
+   */
+  T *_end_data;
+
+  /**
+   * Pointer to the end of the allocated memory.
+   */
+  T *_end_allocated;
+};
+
+
+// ------------------------------- inline functions --------------------------
+
+/**
+ * This namespace defines the copy and set functions used in
+ * AlignedVector. These functions operate in parallel when there are enough
+ * elements in the vector.
+ */
+namespace internal
+{
+  /**
+   * Move and class that actually issues the copy commands in
+   * AlignedVector. This class is based on the specialized for loop base class
+   * ParallelForLoop in parallel.h whose purpose is the following: When
+   * calling a parallel for loop on AlignedVector with apply_to_subranges, it
+   * generates different code for every different argument we might choose (as
+   * it is templated). This gives a lot of code (e.g. it triples the memory
+   * required for compiling the file matrix_free.cc and the final object size
+   * is several times larger) which is completely useless. Therefore, this
+   * class channels all copy commands through one call to apply_to_subrange
+   * for all possible types, which makes the copy operation much cleaner
+   * (thanks to a virtual function, whose cost is negligible in this context).
+   *
+   * @relates AlignedVector
+   */
+  template <typename T>
+  class AlignedVectorMove : private parallel::ParallelForInteger
+  {
+    static const std::size_t minimum_parallel_grain_size = 160000/sizeof(T)+1;
+  public:
+    /**
+     * Constructor. Issues a parallel call if
+     * there are sufficiently many elements,
+     * otherwise work in serial. Copies the data
+     * from source to destination and then calls
+     * destructor on the source. If the optional
+     * argument is set to true, the source is left
+     * untouched instead.
+     */
+    AlignedVectorMove (T *source_begin,
+                       T *source_end,
+                       T *destination,
+                       bool copy_only = false)
+      :
+      source_ (source_begin),
+      destination_ (destination),
+      copy_only_ (copy_only)
+    {
+      Assert (source_end >= source_begin, ExcInternalError());
+      const std::size_t size = source_end - source_begin;
+      if (size < minimum_parallel_grain_size)
+        apply_to_subrange (0, size);
+      else
+        apply_parallel (0, size, minimum_parallel_grain_size);
+    }
+
+    /**
+     * This method moves elements from the source
+     * to the destination given in the constructor
+     * on a subrange given by two integers.
+     */
+    virtual void apply_to_subrange (const std::size_t begin,
+                                    const std::size_t end) const
+    {
+      // for classes trivial assignment can use
+      // memcpy
+      if (std_cxx1x::is_trivial<T>::value == true)
+        std::memcpy (destination_+begin, source_+begin, (end-begin)*sizeof(T));
+      else if (copy_only_ == false)
+        for (std::size_t i=begin; i<end; ++i)
+          {
+            // initialize memory, copy, and destruct
+            new (&destination_[i]) T;
+            destination_[i] = source_[i];
+            source_[i].~T();
+          }
+      else
+        for (std::size_t i=begin; i<end; ++i)
+          {
+            new (&destination_[i]) T;
+            destination_[i] = source_[i];
+          }
+    }
+
+  private:
+    T *source_;
+    T *destination_;
+    const bool copy_only_;
+  };
+
+  /**
+   * Class that issues the set commands for AlignedVector.
+   *
+   * @relates AlignedVector
+   */
+  template <typename T>
+  class AlignedVectorSet : private parallel::ParallelForInteger
+  {
+    static const std::size_t minimum_parallel_grain_size = 160000/sizeof(T)+1;
+  public:
+    /**
+     * Constructor. Issues a parallel call if
+     * there are sufficiently many elements,
+     * otherwise work in serial.
+     */
+    AlignedVectorSet (const std::size_t size,
+                      const T &element,
+                      T *destination)
+      :
+      element_ (element),
+      destination_ (destination),
+      trivial_element (false)
+    {
+      if (size == 0)
+        return;
+
+      if (std_cxx1x::is_trivial<T>::value == true)
+        {
+          const unsigned char zero [sizeof(T)] = {};
+          if (std::memcmp(zero, &element, sizeof(T)) == 0)
+            trivial_element = true;
+        }
+      if (size < minimum_parallel_grain_size)
+        apply_to_subrange (0, size);
+      else
+        apply_parallel (0, size, minimum_parallel_grain_size);
+    }
+
+  private:
+
+    /**
+     * This sets elements on a subrange given by
+     * two integers.
+     */
+    virtual void apply_to_subrange (const std::size_t begin,
+                                    const std::size_t end) const
+    {
+      // for classes with trivial assignment of zero
+      // can use memset
+      if (std_cxx1x::is_trivial<T>::value == true && trivial_element)
+        std::memset (destination_+begin, 0, (end-begin)*sizeof(T));
+      else
+        for (std::size_t i=begin; i<end; ++i)
+          {
+            // initialize memory and set
+            new (&destination_[i]) T;
+            destination_[i] = element_;
+          }
+    }
+
+    const T &element_;
+    mutable T *destination_;
+    bool trivial_element;
+  };
+} // end of namespace internal
+
+
+#ifndef DOXYGEN
+
+
+template < class T >
+inline
+AlignedVector<T>::AlignedVector ()
+  :
+  _data (0),
+  _end_data (0),
+  _end_allocated (0)
+{}
+
+
+
+template < class T >
+inline
+AlignedVector<T>::AlignedVector (const size_type size)
+  :
+  _data (0),
+  _end_data (0),
+  _end_allocated (0)
+{
+  if (size > 0)
+    resize (size);
+}
+
+
+
+template < class T >
+inline
+AlignedVector<T>::~AlignedVector ()
+{
+  clear();
+}
+
+
+
+template < class T >
+inline
+AlignedVector<T>::AlignedVector (const AlignedVector<T> &vec)
+  :
+  _data (0),
+  _end_data (0),
+  _end_allocated (0)
+{
+  // do not invalidate old data
+  resize_fast (vec._end_data - vec._data);
+  internal::AlignedVectorMove<T> (vec._data, vec._end_data, _data, true);
+}
+
+
+
+template < class T >
+inline
+AlignedVector<T>&
+AlignedVector<T>::operator = (const AlignedVector<T> &vec)
+{
+  clear();
+  resize_fast (vec._end_data - vec._data);
+  internal::AlignedVectorMove<T> (vec._data, vec._end_data, _data, true);
+  return *this;
+}
+
+
+
+template < class T >
+inline
+void
+AlignedVector<T>::resize_fast (const size_type size)
+{
+  reserve (size);
+  _end_data = _data + size;
+}
+
+
+template < class T >
+inline
+void
+AlignedVector<T>::resize (const size_type size_in,
+                          const T        &init)
+{
+  const size_type old_size = size();
+  if (std_cxx1x::is_trivial<T>::value == false && size_in < old_size)
+    {
+      // call destructor on fields that are released
+      while (_end_data != _data+size_in)
+        (--_end_data)->~T();
+    }
+
+  resize_fast (size_in);
+  // now _size is set correctly, need to set the
+  // values
+  if (size_in > old_size)
+    internal::AlignedVectorSet<T> (size_in-old_size, init,
+                                   _data+old_size);
+}
+
+
+
+template < class T >
+inline
+void
+AlignedVector<T>::reserve (const size_type size_alloc)
+{
+  const size_type old_size = _end_data - _data;
+  const size_type allocated_size = _end_allocated - _data;
+  if (size_alloc > allocated_size)
+    {
+      // if we continuously increase the size of the vector, we might be
+      // reallocating a lot of times. therefore, try to increase the size more
+      // aggressively
+      size_type new_size = size_alloc;
+      if (size_alloc < (2 * allocated_size))
+        new_size = 2 * allocated_size;
+
+      const size_type size_actual_allocate = new_size * sizeof(T);
+
+#if DEAL_II_COMPILER_VECTORIZATION_LEVEL > 0
+
+      // allocate and align along boundaries of the size of
+      // VectorizedArray<double>, which is 16 bytes for SSE and 32 bytes for
+      // AVX
+      T *new_data = static_cast<T *>(_mm_malloc (size_actual_allocate,
+                                                 sizeof(VectorizedArray<double>)));
+#else
+      T *new_data = static_cast<T *>(malloc (size_actual_allocate));
+#endif
+      if (new_data == 0)
+        throw std::bad_alloc();
+
+      // copy data in case there was some content before and release the old
+      // memory with the function corresponding to the one used for allocating
+      std::swap (_data, new_data);
+      _end_data = _data + old_size;
+      _end_allocated = _data + new_size;
+      if (_end_data != _data)
+        {
+          internal::AlignedVectorMove<T>(new_data, new_data + old_size,
+                                         _data);
+#if DEAL_II_COMPILER_VECTORIZATION_LEVEL > 0
+          _mm_free(new_data);
+#else
+          free(new_data);
+#endif
+        }
+    }
+  else if (size_alloc == 0)
+    clear();
+}
+
+
+
+template < class T >
+inline
+void
+AlignedVector<T>::clear ()
+{
+  if (_data != 0)
+    {
+      if (std_cxx1x::is_trivial<T>::value == false)
+        while (_end_data != _data)
+          (--_end_data)->~T();
+
+#if DEAL_II_COMPILER_VECTORIZATION_LEVEL > 0
+      _mm_free(_data);
+#else
+      free(_data);
+#endif
+    }
+  _data = 0;
+  _end_data = 0;
+  _end_allocated = 0;
+}
+
+
+
+template < class T >
+inline
+void
+AlignedVector<T>::push_back (const T in_data)
+{
+  Assert (_end_data <= _end_allocated, ExcInternalError());
+  if (_end_data == _end_allocated)
+    reserve (std::max(2*capacity(),static_cast<size_type>(16)));
+  if (std_cxx1x::is_trivial<T>::value == false)
+    new (_end_data) T;
+  *_end_data++ = in_data;
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::reference
+AlignedVector<T>::back ()
+{
+  AssertIndexRange (0, size());
+  T *field = _end_data - 1;
+  return *field;
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::const_reference
+AlignedVector<T>::back () const
+{
+  AssertIndexRange (0, size());
+  const T *field = _end_data - 1;
+  return *field;
+}
+
+
+
+template < class T >
+template <typename ForwardIterator>
+inline
+void
+AlignedVector<T>::insert_back (ForwardIterator begin,
+                               ForwardIterator end)
+{
+  const unsigned int old_size = size();
+  reserve (old_size + (end-begin));
+  for ( ; begin != end; ++begin, ++_end_data)
+    {
+      if (std_cxx1x::is_trivial<T>::value == false)
+        new (_end_data) T;
+      *_end_data = *begin;
+    }
+}
+
+
+
+template < class T >
+inline
+void
+AlignedVector<T>::swap (AlignedVector<T> &vec)
+{
+  std::swap (_data, vec._data);
+  std::swap (_end_data, vec._end_data);
+  std::swap (_end_allocated, vec._end_allocated);
+}
+
+
+
+template < class T >
+inline
+bool
+AlignedVector<T>::empty () const
+{
+  return _end_data == _data;
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::size_type
+AlignedVector<T>::size () const
+{
+  return _end_data - _data;
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::size_type
+AlignedVector<T>::capacity () const
+{
+  return _end_allocated - _data;
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::reference
+AlignedVector<T>::operator [] (const size_type index)
+{
+  AssertIndexRange (index, size());
+  return _data[index];
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::const_reference
+AlignedVector<T>::operator [] (const size_type index) const
+{
+  AssertIndexRange (index, size());
+  return _data[index];
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::iterator
+AlignedVector<T>::begin ()
+{
+  return _data;
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::iterator
+AlignedVector<T>::end ()
+{
+  return _end_data;
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::const_iterator
+AlignedVector<T>::begin () const
+{
+  return _data;
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::const_iterator
+AlignedVector<T>::end () const
+{
+  return _end_data;
+}
+
+
+
+template < class T >
+inline
+typename AlignedVector<T>::size_type
+AlignedVector<T>::memory_consumption () const
+{
+  size_type memory = sizeof(this);
+  memory += sizeof(T) * capacity();
+  return memory;
+}
+
+
+#endif // ifndef DOXYGEN
+
+
+/**
+ * Relational operator == for AlignedVector
+ *
+ * @relates AlignedVector
+ */
+template < class T >
+bool operator == (const AlignedVector<T> &lhs,
+                  const AlignedVector<T> &rhs)
+{
+  if (lhs.size() != rhs.size())
+    return false;
+  for (typename AlignedVector<T>::const_iterator lit = lhs.begin(),
+         rit = rhs.begin(); lit != lhs.end(); ++lit, ++rit)
+    if (*lit != *rit)
+      return false;
+  return true;
+}
+
+
+
+
+/**
+ * Relational operator != for AlignedVector
+ *
+ * @relates AlignedVector
+ */
+template < class T >
+bool operator != (const AlignedVector<T> &lhs,
+                  const AlignedVector<T> &rhs)
+{
+  return !(operator==(lhs, rhs));
+}
+
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
index ec48938935dd9d0fba2b98eca8b282a901e3c5f4..cdb80174643737d2bf3d5929371a649914902ad5 100644 (file)
@@ -1,7 +1,7 @@
 // ---------------------------------------------------------------------
 // $Id$
 //
-// Copyright (C) 2011 - 2013 by the deal.II authors
+// Copyright (C) 2011 - 2014 by the deal.II authors
 //
 // This file is part of the deal.II library.
 //
 #define __deal2__vectorization_h
 
 #include <deal.II/base/config.h>
-#include <deal.II/base/std_cxx1x/type_traits.h>
 #include <deal.II/base/exceptions.h>
-#include <deal.II/base/memory_consumption.h>
-#include <deal.II/base/parallel.h>
 
 #include <cmath>
-#include <cstring>
 
 // Note:
 // The flag DEAL_II_COMPILER_VECTORIZATION_LEVEL is essentially constructed
 // according to the following scheme
+// #ifdef __AVX512F__
+// #define DEAL_II_COMPILER_VECTORIZATION_LEVEL 3
 // #ifdef __AVX__
 // #define DEAL_II_COMPILER_VECTORIZATION_LEVEL 2
 // #elif defined (__SSE2__)
 // In addition to checking the flags __AVX__ and __SSE2__, a configure test
 // ensures that these feature are not only present but also working properly.
 
-#if DEAL_II_COMPILER_VECTORIZATION_LEVEL == 2 // AVX
+#if DEAL_II_COMPILER_VECTORIZATION_LEVEL >= 2 // AVX, AVX-512
 #include <immintrin.h>
-#include <mm_malloc.h>
 #elif DEAL_II_COMPILER_VECTORIZATION_LEVEL == 1 // SSE2
 #include <emmintrin.h>
-#include <mm_malloc.h>
 #endif
 
 
@@ -71,10 +67,359 @@ namespace std
 DEAL_II_NAMESPACE_OPEN
 
 
-// for safety, also check that __AVX__ is defined in case the user manually
+// for safety, also check that __AVX512F__ is defined in case the user manually
 // set some conflicting compile flags which prevent compilation
 
-#if DEAL_II_COMPILER_VECTORIZATION_LEVEL == 2  && defined(__AVX__)
+#if DEAL_II_COMPILER_VECTORIZATION_LEVEL == 3  && defined(__AVX512F__)
+
+/**
+ * Specialization of VectorizedArray class for double and AVX-512.
+ */
+template <>
+class VectorizedArray<double>
+{
+public:
+  /**
+   * This gives the number of vectors collected in this class.
+   */
+  static const unsigned int n_array_elements = 8;
+
+  /**
+   * This function can be used to set all data fields to a given scalar.
+   */
+  VectorizedArray &
+  operator = (const double x)
+  {
+    data = _mm256_set_pd(x, x, x, x, x, x, x, x);
+    return *this;
+  }
+
+  /**
+   * Access operator.
+   */
+  double &
+  operator [] (const unsigned int comp)
+  {
+    AssertIndexRange (comp, 8);
+    return *(reinterpret_cast<double *>(&data)+comp);
+  }
+
+  /**
+   * Constant access operator.
+   */
+  const double &
+  operator [] (const unsigned int comp) const
+  {
+    AssertIndexRange (comp, 8);
+    return *(reinterpret_cast<const double *>(&data)+comp);
+  }
+
+  /**
+   * Addition.
+   */
+  VectorizedArray &
+  operator += (const VectorizedArray &vec)
+  {
+    // if the compiler supports vector arithmetics, we can simply use +=
+    // operator on the given data type. Otherwise, we need to use the built-in
+    // intrinsic command for __m512d
+#ifdef DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS
+    data += vec.data;
+#else
+    data = _mm512_add_pd(data,vec.data);
+#endif
+    return *this;
+  }
+
+  /**
+   * Subtraction.
+   */
+  VectorizedArray &
+  operator -= (const VectorizedArray &vec)
+  {
+#ifdef DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS
+    data -= vec.data;
+#else
+    data = _mm512_sub_pd(data,vec.data);
+#endif
+    return *this;
+  }
+  /**
+   * Multiplication.
+   */
+  VectorizedArray &
+  operator *= (const VectorizedArray &vec)
+  {
+#ifdef DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS
+    data *= vec.data;
+#else
+    data = _mm512_mul_pd(data,vec.data);
+#endif
+    return *this;
+  }
+
+  /**
+   * Division.
+   */
+  VectorizedArray &
+  operator /= (const VectorizedArray &vec)
+  {
+#ifdef DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS
+    data /= vec.data;
+#else
+    data = _mm512_div_pd(data,vec.data);
+#endif
+    return *this;
+  }
+
+  /**
+   * Actual data field. Since this class represents a POD data type, it
+   * remains public.
+   */
+  __m512d data;
+
+private:
+  /**
+   * Returns the square root of this field. Not for use in user code. Use
+   * sqrt(x) instead.
+   */
+  VectorizedArray
+  get_sqrt () const
+  {
+    VectorizedArray res;
+    res.data = _mm512_sqrt_pd(data);
+    return res;
+  }
+
+  /**
+   * Returns the absolute value of this field. Not for use in user code. Use
+   * abs(x) instead.
+   */
+  VectorizedArray
+  get_abs () const
+  {
+    // to compute the absolute value, perform bitwise andnot with -0. This
+    // will leave all value and exponent bits unchanged but force the sign
+    // value to +.
+    __m256d mask = _mm256_set_pd (-0., -0., -0., -0., -0., -0., -0., -0.);
+    VectorizedArray res;
+    res.data = _mm256_andnot_pd(mask, data);
+    return res;
+  }
+
+  /**
+   * Returns the component-wise maximum of this field and another one. Not for
+   * use in user code. Use max(x,y) instead.
+   */
+  VectorizedArray
+  get_max (const VectorizedArray &other) const
+  {
+    VectorizedArray res;
+    res.data = _mm512_max_pd (data, other.data);
+    return res;
+  }
+
+  /**
+   * Returns the component-wise minimum of this field and another one. Not for
+   * use in user code. Use min(x,y) instead.
+   */
+  VectorizedArray
+  get_min (const VectorizedArray &other) const
+  {
+    VectorizedArray res;
+    res.data = _mm512_min_pd (data, other.data);
+    return res;
+  }
+
+  /**
+   * Make a few functions friends.
+   */
+  template <typename Number2> friend VectorizedArray<Number2>
+  std::sqrt (const VectorizedArray<Number2> &);
+  template <typename Number2> friend VectorizedArray<Number2>
+  std::abs  (const VectorizedArray<Number2> &);
+  template <typename Number2> friend VectorizedArray<Number2>
+  std::max  (const VectorizedArray<Number2> &, const VectorizedArray<Number2> &);
+  template <typename Number2> friend VectorizedArray<Number2>
+  std::min  (const VectorizedArray<Number2> &, const VectorizedArray<Number2> &);
+};
+
+
+
+/**
+ * Specialization for float and AVX.
+ */
+template<>
+class VectorizedArray<float>
+{
+public:
+  /**
+   * This gives the number of vectors collected in this class.
+   */
+  static const unsigned int n_array_elements = 16;
+
+  /**
+   * This function can be used to set all data fields to a given scalar.
+   */
+  VectorizedArray &
+  operator = (const float x)
+  {
+    data = _mm256_set_ps(x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x);
+    return *this;
+  }
+
+  /**
+   * Access operator.
+   */
+  float &
+  operator [] (const unsigned int comp)
+  {
+    AssertIndexRange (comp, 16);
+    return *(reinterpret_cast<float *>(&data)+comp);
+  }
+
+  /**
+   * Constant access operator.
+   */
+  const float &
+  operator [] (const unsigned int comp) const
+  {
+    AssertIndexRange (comp, 16);
+    return *(reinterpret_cast<const float *>(&data)+comp);
+  }
+
+  /**
+   * Addition.
+   */
+  VectorizedArray &
+  operator += (const VectorizedArray &vec)
+  {
+#ifdef DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS
+    data += vec.data;
+#else
+    data = _mm512_add_ps(data,vec.data);
+#endif
+    return *this;
+  }
+
+  /**
+   * Subtraction.
+   */
+  VectorizedArray &
+  operator -= (const VectorizedArray &vec)
+  {
+#ifdef DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS
+    data -= vec.data;
+#else
+    data = _mm512_sub_ps(data,vec.data);
+#endif
+    return *this;
+  }
+  /**
+   * Multiplication.
+   */
+  VectorizedArray &
+  operator *= (const VectorizedArray &vec)
+  {
+#ifdef DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS
+    data *= vec.data;
+#else
+    data = _mm512_mul_ps(data,vec.data);
+#endif
+    return *this;
+  }
+
+  /**
+   * Division.
+   */
+  VectorizedArray &
+  operator /= (const VectorizedArray &vec)
+  {
+#ifdef DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS
+    data /= vec.data;
+#else
+    data = _mm512_div_ps(data,vec.data);
+#endif
+    return *this;
+  }
+
+  /**
+   * Actual data field. Since this class represents a POD data type, it
+   * remains public.
+   */
+  __m512 data;
+
+private:
+
+  /**
+   * Returns the square root of this field. Not for use in user code. Use
+   * sqrt(x) instead.
+   */
+  VectorizedArray
+  get_sqrt () const
+  {
+    VectorizedArray res;
+    res.data = _mm512_sqrt_ps(data);
+    return res;
+  }
+
+  /**
+   * Returns the absolute value of this field. Not for use in user code. Use
+   * abs(x) instead.
+   */
+  VectorizedArray
+  get_abs () const
+  {
+    // to compute the absolute value, perform
+    // bitwise andnot with -0. This will leave all
+    // value and exponent bits unchanged but force
+    // the sign value to +.
+    __m256 mask = _mm512_setzero_ps (-0.f, -0.f, -0.f, -0.f, -0.f, -0.f, -0.f, -0.f,
+                                     -0.f, -0.f, -0.f, -0.f, -0.f, -0.f, -0.f, -0.f);
+    VectorizedArray res;
+    res.data = _mm512_andnot_ps(mask, data);
+    return res;
+  }
+
+  /**
+   * Returns the component-wise maximum of this field and another one. Not for
+   * use in user code. Use max(x,y) instead.
+   */
+  VectorizedArray
+  get_max (const VectorizedArray &other) const
+  {
+    VectorizedArray res;
+    res.data = _mm512_max_ps (data, other.data);
+    return res;
+  }
+
+  /**
+   * Returns the component-wise minimum of this field and another one. Not for
+   * use in user code. Use min(x,y) instead.
+   */
+  VectorizedArray
+  get_min (const VectorizedArray &other) const
+  {
+    VectorizedArray res;
+    res.data = _mm512_min_ps (data, other.data);
+    return res;
+  }
+
+  /**
+   * Make a few functions friends.
+   */
+  template <typename Number2> friend VectorizedArray<Number2>
+  std::sqrt (const VectorizedArray<Number2> &);
+  template <typename Number2> friend VectorizedArray<Number2>
+  std::abs  (const VectorizedArray<Number2> &);
+  template <typename Number2> friend VectorizedArray<Number2>
+  std::max  (const VectorizedArray<Number2> &, const VectorizedArray<Number2> &);
+  template <typename Number2> friend VectorizedArray<Number2>
+  std::min  (const VectorizedArray<Number2> &, const VectorizedArray<Number2> &);
+};
+
+
+#elif DEAL_II_COMPILER_VECTORIZATION_LEVEL == 2  && defined(__AVX__)
 
 /**
  * Specialization of VectorizedArray class for double and AVX.
@@ -1392,554 +1737,6 @@ operator - (const VectorizedArray<Number> &u)
 
 
 
-/**
- * This namespace defines the copy and set functions used in
- * AlignedVector. These functions operate in parallel when there are enough
- * elements in the vector.
- */
-namespace internal
-{
-  /**
-   * Move and class that actually issues the copy commands in
-   * AlignedVector. This class is based on the specialized for loop base class
-   * ParallelForLoop in parallel.h whose purpose is the following: When
-   * calling a parallel for loop on AlignedVector with apply_to_subranges, it
-   * generates different code for every different argument we might choose (as
-   * it is templated). This gives a lot of code (e.g. it triples the memory
-   * required for compiling the file matrix_free.cc and the final object size
-   * is several times larger) which is completely useless. Therefore, this
-   * class channels all copy commands through one call to apply_to_subrange
-   * for all possible types, which makes the copy operation much cleaner
-   * (thanks to a virtual function, whose cost is negligible in this context).
-   *
-   * @relates AlignedVector
-   */
-  template <typename T>
-  class AlignedVectorMove : private parallel::ParallelForInteger
-  {
-    static const std::size_t minimum_parallel_grain_size = 160000/sizeof(T)+1;
-  public:
-    /**
-     * Constructor. Issues a parallel call if
-     * there are sufficiently many elements,
-     * otherwise work in serial. Copies the data
-     * from source to destination and then calls
-     * destructor on the source. If the optional
-     * argument is set to true, the source is left
-     * untouched instead.
-     */
-    AlignedVectorMove (T *source_begin,
-                       T *source_end,
-                       T *destination,
-                       bool copy_only = false)
-      :
-      source_ (source_begin),
-      destination_ (destination),
-      copy_only_ (copy_only)
-    {
-      Assert (source_end >= source_begin, ExcInternalError());
-      const std::size_t size = source_end - source_begin;
-      if (size < minimum_parallel_grain_size)
-        apply_to_subrange (0, size);
-      else
-        apply_parallel (0, size, minimum_parallel_grain_size);
-    }
-
-    /**
-     * This method moves elements from the source
-     * to the destination given in the constructor
-     * on a subrange given by two integers.
-     */
-    virtual void apply_to_subrange (const std::size_t begin,
-                                    const std::size_t end) const
-    {
-      // for classes trivial assignment can use
-      // memcpy
-      if (std_cxx1x::is_trivial<T>::value == true)
-        std::memcpy (destination_+begin, source_+begin, (end-begin)*sizeof(T));
-      else if (copy_only_ == false)
-        for (std::size_t i=begin; i<end; ++i)
-          {
-            // initialize memory, copy, and destruct
-            new (&destination_[i]) T;
-            destination_[i] = source_[i];
-            source_[i].~T();
-          }
-      else
-        for (std::size_t i=begin; i<end; ++i)
-          {
-            new (&destination_[i]) T;
-            destination_[i] = source_[i];
-          }
-    }
-
-  private:
-    T *source_;
-    T *destination_;
-    const bool copy_only_;
-  };
-
-  /**
-   * Class that issues the set commands for AlignedVector.
-   *
-   * @relates AlignedVector
-   */
-  template <typename T>
-  class AlignedVectorSet : private parallel::ParallelForInteger
-  {
-    static const std::size_t minimum_parallel_grain_size = 160000/sizeof(T)+1;
-  public:
-    /**
-     * Constructor. Issues a parallel call if
-     * there are sufficiently many elements,
-     * otherwise work in serial.
-     */
-    AlignedVectorSet (const std::size_t size,
-                      const T &element,
-                      T *destination)
-      :
-      element_ (element),
-      destination_ (destination),
-      trivial_element (false)
-    {
-      if (size == 0)
-        return;
-
-      if (std_cxx1x::is_trivial<T>::value == true)
-        {
-          const unsigned char zero [sizeof(T)] = {};
-          if (std::memcmp(zero, &element, sizeof(T)) == 0)
-            trivial_element = true;
-        }
-      if (size < minimum_parallel_grain_size)
-        apply_to_subrange (0, size);
-      else
-        apply_parallel (0, size, minimum_parallel_grain_size);
-    }
-
-  private:
-
-    /**
-     * This sets elements on a subrange given by
-     * two integers.
-     */
-    virtual void apply_to_subrange (const std::size_t begin,
-                                    const std::size_t end) const
-    {
-      // for classes with trivial assignment of zero
-      // can use memset
-      if (std_cxx1x::is_trivial<T>::value == true && trivial_element)
-        std::memset (destination_+begin, 0, (end-begin)*sizeof(T));
-      else
-        for (std::size_t i=begin; i<end; ++i)
-          {
-            // initialize memory and set
-            new (&destination_[i]) T;
-            destination_[i] = element_;
-          }
-    }
-
-    const T &element_;
-    mutable T *destination_;
-    bool trivial_element;
-  };
-} // end of namespace internal
-
-
-/**
- * This is a replacement class for std::vector to be used in combination with
- * VectorizedArray and derived data types. It allocates memory aligned to
- * addresses of a vectorized data type (for SSE, this is necessary in order to
- * avoid segfaults, and for AVX it considerably increases performance). This
- * could also be achieved by proving std::vector with a user-defined
- * allocator. On the other hand, writing an own small vector class lets us
- * insert assertions more easily, and cut some unnecessary functionality. Note
- * that this vector is a bit more memory-consuming than std::vector because of
- * alignment, so it is recommended to only use this vector on long vectors.
- *
- * @p author Katharina Kormann, Martin Kronbichler, 2011
- */
-template < class T >
-class AlignedVector
-{
-public:
-  /**
-   * Declare standard types used in all
-   * containers. These types parallel those
-   * in the <tt>C++</tt> standard libraries
-   * <tt>vector<...></tt> class.
-   */
-  typedef T                   value_type;
-  typedef value_type         *pointer;
-  typedef const value_type   *const_pointer;
-  typedef value_type         *iterator;
-  typedef const value_type   *const_iterator;
-  typedef value_type         &reference;
-  typedef const value_type   &const_reference;
-  typedef std::size_t         size_type;
-
-  /**
-   * Empty constructor. Sets the vector size to
-   * zero.
-   */
-  AlignedVector ()
-    :
-    _data (0),
-    _end_data (0),
-    _end_allocated (0)
-  {};
-
-  /**
-   * Sets the vector size to the given size and
-   * initializes all elements with T().
-   */
-  AlignedVector (const size_type size)
-    :
-    _data (0),
-    _end_data (0),
-    _end_allocated (0)
-  {
-    if (size > 0)
-      resize (size);
-  }
-
-  /**
-   * Destructor.
-   */
-  ~AlignedVector ()
-  {
-    clear();
-  }
-
-  /**
-   * Copy constructor.
-   */
-  AlignedVector (const AlignedVector<T> &vec)
-    :
-    _data (0),
-    _end_data (0),
-    _end_allocated (0)
-  {
-    // do not invalidate old data
-    resize_fast (vec._end_data - vec._data);
-    internal::AlignedVectorMove<T> (vec._data, vec._end_data, _data, true);
-  }
-
-  /**
-   * Assignment to the input vector @p vec.
-   */
-  AlignedVector &
-  operator = (const AlignedVector<T> &vec)
-  {
-    clear();
-    resize_fast (vec._end_data - vec._data);
-    internal::AlignedVectorMove<T> (vec._data, vec._end_data, _data, true);
-    return *this;
-  }
-
-  /**
-   * Change the size of the vector. It keeps old
-   * elements previously available but does not
-   * initialize the newly allocated memory,
-   * leaving it in an undefined state.
-   */
-  void resize_fast (const size_type size)
-  {
-    reserve (size);
-    _end_data = _data + size;
-  }
-
-  /**
-   * Change the size of the vector. It keeps old
-   * elements previously available, and
-   * initializes each element with the specified
-   * data. If the new vector size is shorter
-   * than the old one, the memory is not
-   * released unless the new size is zero.
-   */
-  void resize (const size_type size_in,
-               const T        &init = T())
-  {
-    const size_type old_size = size();
-    if (std_cxx1x::is_trivial<T>::value == false && size_in < old_size)
-      {
-        // call destructor on fields that are released
-        while (_end_data != _data+size_in)
-          (--_end_data)->~T();
-      }
-
-    resize_fast (size_in);
-    // now _size is set correctly, need to set the
-    // values
-    if (size_in > old_size)
-      internal::AlignedVectorSet<T> (size_in-old_size, init,
-                                     _data+old_size);
-  }
-
-  /**
-   * Reserve memory space for @p size
-   * elements. If the argument @p size is set to
-   * zero, all previously allocated memory is
-   * released.
-   *
-   * In order to avoid too frequent reallocation
-   * (which involves copy of the data), this
-   * function doubles the amount of memory
-   * occupied when the given size is larger than
-   * the previously allocated size.
-   */
-  void reserve (const size_type size_alloc)
-  {
-    const size_type old_size = _end_data - _data;
-    const size_type allocated_size = _end_allocated - _data;
-    if (size_alloc > allocated_size)
-      {
-        // if we continuously increase the size of the
-        // vector, we might be reallocating a lot of
-        // times. therefore, try to increase the size
-        // more aggressively
-        size_type new_size = size_alloc;
-        if (size_alloc < (2 * allocated_size))
-          new_size = 2 * allocated_size;
-
-        const size_type size_actual_allocate = new_size * sizeof(T);
-
-#if DEAL_II_COMPILER_VECTORIZATION_LEVEL > 0
-
-        // allocate and align along boundaries of the
-        // size of VectorizedArray<double>, which is
-        // 16 bytes for SSE and 32 bytes for AVX
-        T *new_data = static_cast<T *>(_mm_malloc (size_actual_allocate,
-                                                   sizeof(VectorizedArray<double>)));
-#else
-        T *new_data = static_cast<T *>(malloc (size_actual_allocate));
-#endif
-        if (new_data == 0)
-          throw std::bad_alloc();
-
-        // copy data in case there was some content
-        // before and release the old memory with the
-        // function corresponding to the one used for
-        // allocating
-        std::swap (_data, new_data);
-        _end_data = _data + old_size;
-        _end_allocated = _data + new_size;
-        if (_end_data != _data)
-          {
-            internal::AlignedVectorMove<T>(new_data, new_data + old_size,
-                                           _data);
-#if DEAL_II_COMPILER_VECTORIZATION_LEVEL > 0
-            _mm_free(new_data);
-#else
-            free(new_data);
-#endif
-          }
-      }
-    else if (size_alloc == 0)
-      clear();
-  }
-
-  /**
-   * Releases all previously allocated memory
-   * and leaves the vector in a state equivalent
-   * to the state after the default constructor
-   * has been called.
-   */
-  void clear ()
-  {
-    if (_data != 0)
-      {
-        if (std_cxx1x::is_trivial<T>::value == false)
-          while (_end_data != _data)
-            (--_end_data)->~T();
-
-#if DEAL_II_COMPILER_VECTORIZATION_LEVEL > 0
-        _mm_free(_data);
-#else
-        free(_data);
-#endif
-      }
-    _data = 0;
-    _end_data = 0;
-    _end_allocated = 0;
-  };
-
-  /**
-   * Inserts an element at the end of the
-   * vector, increasing the vector size by
-   * one. Note that the allocated size will
-   * double whenever the previous space is not
-   * enough to hold the new element.
-   */
-  void push_back (const T in_data)
-  {
-    Assert (_end_data <= _end_allocated, ExcInternalError());
-    if (_end_data == _end_allocated)
-      reserve (std::max(2*capacity(),static_cast<size_type>(16)));
-    if (std_cxx1x::is_trivial<T>::value == false)
-      new (_end_data) T;
-    *_end_data++ = in_data;
-  }
-
-  /**
-   * Returns the last element of the vector
-   * (read and write access).
-   */
-  reference back ()
-  {
-    AssertIndexRange (0, size());
-    T *field = _end_data - 1;
-    return *field;
-  }
-
-  /**
-   * Returns the last element of the vector
-   * (read-only access).
-   */
-  const_reference back () const
-  {
-    AssertIndexRange (0, size());
-    const T *field = _end_data - 1;
-    return *field;
-  }
-
-  /**
-   * Inserts several elements at the end of the
-   * vector given by a range of elements.
-   */
-  template <typename ForwardIterator>
-  void insert_back (ForwardIterator begin,
-                    ForwardIterator end)
-  {
-    const unsigned int old_size = size();
-    reserve (old_size + (end-begin));
-    for ( ; begin != end; ++begin, ++_end_data)
-      {
-        if (std_cxx1x::is_trivial<T>::value == false)
-          new (_end_data) T;
-        *_end_data = *begin;
-      }
-  }
-
-  /**
-   * Swaps the given vector with the calling
-   * vector.
-   */
-  void swap (AlignedVector<T> &vec)
-  {
-    std::swap (_data, vec._data);
-    std::swap (_end_data, vec._end_data);
-    std::swap (_end_allocated, vec._end_allocated);
-  }
-
-  /**
-   * Returns the size of the vector.
-   */
-  size_type size () const
-  {
-    return _end_data - _data;
-  }
-
-  /**
-   * Returns the capacity of the vector, i.e.,
-   * the size this vector can hold without
-   * reallocation. Note that capacity() >=
-   * size().
-   */
-  size_type capacity () const
-  {
-    return _end_allocated - _data;
-  }
-
-  /**
-   * Read-write access to entry @p index in the
-   * vector.
-   */
-  reference
-  operator [] (const size_type index)
-  {
-    AssertIndexRange (index, size());
-    return _data[index];
-  };
-
-  /**
-   * Read-only access to entry @p index in the
-   * vector.
-   */
-  const_reference operator [] (const size_type index) const
-  {
-    AssertIndexRange (index, size());
-    return _data[index];
-  };
-
-  /**
-   * Returns a read and write pointer to the
-   * beginning of the data array.
-   */
-  iterator begin ()
-  {
-    return _data;
-  }
-
-  /**
-   * Returns a read and write pointer to the
-   * end of the data array.
-   */
-  iterator end ()
-  {
-    return _end_data;
-  }
-
-  /**
-   * Returns a read-only pointer to the
-   * beginning of the data array.
-   */
-  const_iterator begin () const
-  {
-    return _data;
-  }
-
-  /**
-   * Returns a read-only pointer to the
-   * end of the data array.
-   */
-  const_iterator end () const
-  {
-    return _end_data;
-  }
-
-  /**
-   * Returns the memory consumption of the
-   * allocated memory in this class. If the
-   * underlying type @p T allocates memory by
-   * itself, this memory is not counted.
-   */
-  size_type memory_consumption () const
-  {
-    size_type memory = sizeof(this);
-    memory += sizeof(T) * capacity();
-    return memory;
-  }
-
-private:
-
-  /**
-   * Pointer to actual class data.
-   */
-  T *_data;
-
-  /**
-   * Pointer to the end of valid data fields.
-   */
-  T *_end_data;
-
-  /**
-   * Pointer to the end of the allocated memory.
-   */
-  T *_end_allocated;
-};
-
-
 DEAL_II_NAMESPACE_CLOSE
 
 
index c9f3b4434e7edc9ce834884318940d403dc0c892..c50275614af3b5a7e79ba0e067ce706e6ad58640 100644 (file)
@@ -3897,7 +3897,7 @@ namespace parallel
       for (i = 0; i < l; i++)
         {
           typename dealii::Triangulation<dim,spacedim>::cell_iterator cell (triangulation, i, dealii_index);
-          child_id = internal::p4est::functions<dim>::quadrant_ancestor_id (&quad, i + 1);
+          child_id = dealii::internal::p4est::functions<dim>::quadrant_ancestor_id (&quad, i + 1);
           Assert (cell->has_children (), ExcMessage ("p4est quadrant does not correspond to a cell!"));
           dealii_index = cell->child_index(child_id);
         }

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.