Thrill  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
aligned_alloc.hpp
Go to the documentation of this file.
1 /***************************************************************************
2  * foxxll/common/aligned_alloc.hpp
3  *
4  * Part of FOXXLL. See http://foxxll.org
5  *
6  * Copyright (C) 2002 Roman Dementiev <[email protected]>
7  * Copyright (C) 2009 Andreas Beckmann <[email protected]>
8  *
9  * Distributed under the Boost Software License, Version 1.0.
10  * (See accompanying file LICENSE_1_0.txt or copy at
11  * http://www.boost.org/LICENSE_1_0.txt)
12  **************************************************************************/
13 
14 #ifndef FOXXLL_COMMON_ALIGNED_ALLOC_HEADER
15 #define FOXXLL_COMMON_ALIGNED_ALLOC_HEADER
16 
17 #include <cassert>
18 #include <cstdlib>
19 
20 #include <tlx/logger.hpp>
21 
22 #include <foxxll/common/utils.hpp>
23 
24 namespace foxxll {
25 
26 constexpr bool debug_aligned_alloc = false;
27 
28 template <typename MustBeInt>
30  static bool may_use_realloc;
31 };
32 
33 template <typename MustBeInt>
35 
36 // meta_info_size > 0 is needed for array allocations that have overhead
37 //
38 // meta_info
39 // aligned begin of data unallocated behind data
40 // v v v
41 // ----===============#MMMM========================------
42 // ^ ^^ ^
43 // buffer result result+m_i_size+size
44 // pointer to buffer
45 // (---) unallocated, (===) allocated memory
46 
47 template <size_t Alignment>
48 inline void * aligned_alloc(size_t size, size_t meta_info_size = 0)
49 {
50  LOGC(debug_aligned_alloc) << "foxxll::aligned_alloc<" << Alignment << ">(), "
51  "size = " << size << ", meta info size = " << meta_info_size;
52 #if !defined(FOXXLL_WASTE_MORE_MEMORY_FOR_IMPROVED_ACCESS_AFTER_ALLOCATED_MEMORY_CHECKS)
53  // malloc()/realloc() variant that frees the unused amount of memory
54  // after the data area of size 'size'. realloc() from valgrind does not
55  // preserve the old memory area when shrinking, so out-of-bounds
56  // accesses can't be detected easily.
57  // Overhead: about Alignment bytes.
58  size_t alloc_size = Alignment + sizeof(char*) + meta_info_size + size;
59  auto* buffer = static_cast<char*>(std::malloc(alloc_size));
60 #else
61  // More space consuming and memory fragmenting variant using
62  // posix_memalign() instead of malloc()/realloc(). Ensures that the end
63  // of the data area (of size 'size') will match the end of the allocated
64  // block, so no corrections are neccessary and
65  // access-behind-allocated-memory problems can be easily detected by
66  // valgrind. Usually produces an extra memory fragment of about
67  // Alignment bytes.
68  // Overhead: about 2 * Alignment bytes.
69  size_t alloc_size = Alignment * div_ceil(sizeof(char*) + meta_info_size, Alignment) + size;
70  char* buffer;
71  if (posix_memalign((void**)&buffer, Alignment, alloc_size) != 0)
72  throw std::bad_alloc();
73 #endif
74  if (buffer == nullptr)
75  throw std::bad_alloc();
76  #ifdef FOXXLL_ALIGNED_CALLOC
77  memset(buffer, 0, alloc_size);
78  #endif
79  char* reserve_buffer = buffer + sizeof(char*) + meta_info_size;
80  char* result = reserve_buffer + Alignment -
81  (reinterpret_cast<size_t>(reserve_buffer) % Alignment) - meta_info_size;
82  LOGC(debug_aligned_alloc) << "foxxll::aligned_alloc<" << Alignment << ">() address "
83  << static_cast<void*>(result) << " lost " << (result - buffer) << " bytes";
84  //-tb: check that there is space for one char* before the "result" pointer
85  // delivered to the user. this char* is set below to the beginning of the
86  // allocated area.
87  assert(long(result - buffer) >= long(sizeof(char*)));
88 
89  // free unused memory behind the data area
90  // so access behind the requested size can be recognized
91  size_t realloc_size = static_cast<size_t>(result - buffer) + meta_info_size + size;
92  if (realloc_size < alloc_size && aligned_alloc_settings<int>::may_use_realloc) {
93  auto* realloced = static_cast<char*>(std::realloc(buffer, realloc_size));
94  if (buffer != realloced) {
95  // hmm, realloc does move the memory block around while shrinking,
96  // might run under valgrind, so disable realloc and retry
97  LOG1 << "foxxll::aligned_alloc: disabling realloc()";
98  std::free(realloced);
100  return aligned_alloc<Alignment>(size, meta_info_size);
101  }
102  assert(result + size <= buffer + realloc_size);
103  }
104 
105  *(reinterpret_cast<char**>(result) - 1) = buffer;
106  LOGC(debug_aligned_alloc) << "foxxll::aligned_alloc<" << Alignment << ">(), allocated at " <<
107  static_cast<void*>(buffer) << " returning " << static_cast<void*>(result);
108 
110  "foxxll::aligned_alloc<" << Alignment <<
111  ">(size = " << size << ", meta info size = " << meta_info_size <<
112  ") => buffer = " << static_cast<void*>(buffer) << ", ptr = " << static_cast<void*>(result);
113 
114  return result;
115 }
116 
117 template <size_t Alignment>
118 inline void
119 aligned_dealloc(void* ptr)
120 {
121  if (!ptr)
122  return;
123  char* buffer = *(static_cast<char**>(ptr) - 1);
124  LOGC(debug_aligned_alloc) << "foxxll::aligned_dealloc<" << Alignment << ">(), "
125  "ptr = " << ptr << ", buffer = " << static_cast<void*>(buffer);
126  std::free(buffer);
127 }
128 
129 } // namespace foxxll
130 
131 #endif // !FOXXLL_COMMON_ALIGNED_ALLOC_HEADER
132 
133 /**************************************************************************/
#define LOG1
Definition: logger.hpp:145
void aligned_dealloc(void *ptr)
constexpr bool debug_aligned_alloc
std::remove_const< Integral >::type div_ceil(Integral n, Integral2 d)
Definition: utils.hpp:64
void * malloc(size_t size) NOEXCEPT
exported malloc symbol that overrides loading from libc
void * aligned_alloc(size_t size, size_t meta_info_size=0)
void free(void *ptr) NOEXCEPT
exported free symbol that overrides loading from libc
void * realloc(void *ptr, size_t size) NOEXCEPT
exported realloc() symbol that overrides loading from libc
#define LOGC(cond)
Explicitly specify the condition for logging.
Definition: logger.hpp:137