From: Wolfgang Bangerth <bangerth@math.tamu.edu>
Date: Wed, 15 Apr 2015 18:32:46 +0000 (-0500)
Subject: Avoid the use of _mm_malloc/_mm_free in favor of posix_memalign.
X-Git-Tag: v8.3.0-rc1~248^2
X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F808%2Fhead;p=dealii.git

Avoid the use of _mm_malloc/_mm_free in favor of posix_memalign.

This has the additional advantage that free() can be used and we don't have to be
special on both sides of memory allocation/deallocation.
---

diff --git a/doc/news/changes.h b/doc/news/changes.h
index d3ef58962d..3590125d3f 100644
--- a/doc/news/changes.h
+++ b/doc/news/changes.h
@@ -352,6 +352,16 @@ inconvenience this causes.
 
 
 <ol>
+  <li> Fixed: There were a number of places in the library where we unconditionally
+  called functions <code>_mm_malloc()/_mm_free()</code> to allocate and free
+  memory with a known alignment. This function, however, is only available on
+  systems with x86 or x64_64 compatible processors. These places have now been
+  replaced by calling <code>posix_memalign()</code> instead, a function that
+  should be more widely available.
+  <br>
+  (Wolfgang Bangerth, 2015/04/15)
+  </li>
+
   <li> Deprecated: The library uses functions such as CellAccessor::subdomain_id(),
   TriaAccessor::manifold_id(), etc, but used the deviant spelling
   TriaAccessor::boundary_indicator(), TriaAccessor::set_boundary_indicator(),
diff --git a/include/deal.II/base/aligned_vector.h b/include/deal.II/base/aligned_vector.h
index 534510b3b7..ed1dcc97bd 100644
--- a/include/deal.II/base/aligned_vector.h
+++ b/include/deal.II/base/aligned_vector.h
@@ -1,6 +1,6 @@
 // ---------------------------------------------------------------------
 //
-// Copyright (C) 2011 - 2014 by the deal.II authors
+// Copyright (C) 2011 - 2015 by the deal.II authors
 //
 // This file is part of the deal.II library.
 //
@@ -21,16 +21,13 @@
 #include <deal.II/base/std_cxx11/type_traits.h>
 #include <deal.II/base/exceptions.h>
 #include <deal.II/base/memory_consumption.h>
+#include <deal.II/base/utilities.h>
 #include <deal.II/base/parallel.h>
 #include <boost/serialization/array.hpp>
 #include <boost/serialization/split_member.hpp>
 
 #include <cstring>
 
-#if DEAL_II_COMPILER_VECTORIZATION_LEVEL > 0
-#include <emmintrin.h>
-#endif
-
 
 
 DEAL_II_NAMESPACE_OPEN
@@ -538,16 +535,10 @@ AlignedVector<T>::reserve (const size_type size_alloc)
 
       const size_type size_actual_allocate = new_size * sizeof(T);
 
-#if DEAL_II_COMPILER_VECTORIZATION_LEVEL > 0
-
       // allocate and align along 64-byte boundaries (this is enough for all
       // levels of vectorization currently supported by deal.II)
-      T *new_data = static_cast<T *>(_mm_malloc (size_actual_allocate, 64));
-#else
-      T *new_data = static_cast<T *>(malloc (size_actual_allocate));
-#endif
-      if (new_data == 0)
-        throw std::bad_alloc();
+      T *new_data;
+      Utilities::System::posix_memalign ((void **)&new_data, 64, size_actual_allocate);
 
       // copy data in case there was some content before and release the old
       // memory with the function corresponding to the one used for allocating
@@ -558,11 +549,7 @@ AlignedVector<T>::reserve (const size_type size_alloc)
         {
           dealii::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)
@@ -582,11 +569,7 @@ AlignedVector<T>::clear ()
         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;
diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h
index 7a45c412da..4200224e60 100644
--- a/include/deal.II/base/utilities.h
+++ b/include/deal.II/base/utilities.h
@@ -375,6 +375,22 @@ namespace Utilities
      */
     std::string get_time ();
 
+    /**
+     * Call the system function posix_memalign, or a replacement function if not
+     * available, to allocate memory with a certain minimal alignment. The
+     * first argument will then return a pointer to this memory block that can
+     * be released later on through a standard <code>free</code> call.
+     *
+     * @param memptr The address of a pointer variable that will after this call
+     *   point to the allocated memory.
+     * @param alignment The minimal alignment of the memory block, in bytes.
+     * @param size The size of the memory block to be allocated, in bytes.
+     *
+     * @note This function checks internally for error codes, rather than
+     *   leaving this task to the calling site.
+     */
+    void posix_memalign (void **memptr, size_t alignment, size_t size);
+
     /**
      * @deprecated Use Utilities::MPI::job_supports_mpi() instead.
      */
diff --git a/include/deal.II/lac/parallel_vector.templates.h b/include/deal.II/lac/parallel_vector.templates.h
index eb3495e21f..1511dd8985 100644
--- a/include/deal.II/lac/parallel_vector.templates.h
+++ b/include/deal.II/lac/parallel_vector.templates.h
@@ -24,10 +24,6 @@
 #include <deal.II/lac/petsc_parallel_vector.h>
 #include <deal.II/lac/trilinos_vector.h>
 
-#ifndef _MSC_VER
-#  include <mm_malloc.h>
-#endif
-
 DEAL_II_NAMESPACE_OPEN
 
 
@@ -61,14 +57,16 @@ namespace parallel
           Assert (((allocated_size > 0 && val != 0) ||
                    val == 0), ExcInternalError());
           if (val != 0)
-            _mm_free(val);
-          val = static_cast<Number *>(_mm_malloc (sizeof(Number)*new_alloc_size, 64));
+            free(val);
+
+          Utilities::System::posix_memalign ((void **)&val, 64, sizeof(Number)*new_alloc_size);
+
           allocated_size = new_alloc_size;
         }
       else if (new_alloc_size == 0)
         {
           if (val != 0)
-            _mm_free(val);
+            free(val);
           val = 0;
           allocated_size = 0;
         }
diff --git a/include/deal.II/lac/vector.templates.h b/include/deal.II/lac/vector.templates.h
index bcfe8b6190..eef2276507 100644
--- a/include/deal.II/lac/vector.templates.h
+++ b/include/deal.II/lac/vector.templates.h
@@ -42,14 +42,9 @@
 #include <iostream>
 #include <iomanip>
 
-#ifndef _MSC_VER
-#  include <mm_malloc.h>
-#endif
-
 DEAL_II_NAMESPACE_OPEN
 
 
-
 namespace internal
 {
   typedef types::global_dof_index size_type;
@@ -2050,8 +2045,9 @@ Vector<Number>::allocate()
 {
   // make sure that we don't create a memory leak
   Assert (val == 0, ExcInternalError());
-  val = static_cast<Number *>(_mm_malloc (sizeof(Number)*max_vec_size, 64));
-  Assert (val != 0, ExcOutOfMemory());
+
+  // then allocate memory with the proper alignment requirements of 64 bytes
+  Utilities::System::posix_memalign ((void **)&val, 64, sizeof(Number)*max_vec_size);
 }
 
 
@@ -2060,7 +2056,7 @@ template <typename Number>
 void
 Vector<Number>::deallocate()
 {
-  _mm_free(val);
+  free(val);
   val = 0;
 }
 
diff --git a/source/base/utilities.cc b/source/base/utilities.cc
index 579a725049..e3d872b5b6 100644
--- a/source/base/utilities.cc
+++ b/source/base/utilities.cc
@@ -33,6 +33,10 @@
 #include <limits>
 #include <sstream>
 
+#ifndef DEAL_II_MSVC
+#  include <stdlib.h>
+#endif
+
 #ifdef DEAL_II_MSVC
 #  include <winsock2.h>
 #endif
@@ -628,6 +632,23 @@ namespace Utilities
     }
 
 
+    void posix_memalign (void **memptr, size_t alignment, size_t size)
+    {
+#ifndef DEAL_II_MSVC
+      const int ierr = ::posix_memalign (memptr, alignment, size);
+
+      AssertThrow (ierr == 0, ExcOutOfMemory());
+      AssertThrow (*memptr != 0, ExcOutOfMemory());
+#else
+      // Windows does not appear to have posix_memalign. just use the
+      // regular malloc in that case
+      *memptr = malloc (size);
+      AssertThrow (*memptr != 0, ExcOutOfMemory());
+#endif
+    }
+
+
+
     bool job_supports_mpi ()
     {
       return Utilities::MPI::job_supports_mpi();