Thrill  0.1
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/core.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  TLX_LOGC(debug_aligned_alloc)
51  << "foxxll::aligned_alloc<" << Alignment << ">(), "
52  << "size = " << size << ", meta info size = " << meta_info_size;
53 #if !defined(FOXXLL_WASTE_MORE_MEMORY_FOR_IMPROVED_ACCESS_AFTER_ALLOCATED_MEMORY_CHECKS)
54  // malloc()/realloc() variant that frees the unused amount of memory
55  // after the data area of size 'size'. realloc() from valgrind does not
56  // preserve the old memory area when shrinking, so out-of-bounds
57  // accesses can't be detected easily.
58  // Overhead: about Alignment bytes.
59  size_t alloc_size = Alignment + sizeof(char*) + meta_info_size + size;
60  auto* buffer = static_cast<char*>(std::malloc(alloc_size));
61 #else
62  // More space consuming and memory fragmenting variant using
63  // posix_memalign() instead of malloc()/realloc(). Ensures that the end
64  // of the data area (of size 'size') will match the end of the allocated
65  // block, so no corrections are neccessary and
66  // access-behind-allocated-memory problems can be easily detected by
67  // valgrind. Usually produces an extra memory fragment of about
68  // Alignment bytes.
69  // Overhead: about 2 * Alignment bytes.
70  size_t alloc_size = Alignment * div_ceil(sizeof(char*) + meta_info_size, Alignment) + size;
71  char* buffer;
72  if (posix_memalign((void**)&buffer, Alignment, alloc_size) != 0)
73  throw std::bad_alloc();
74 #endif
75  if (buffer == nullptr)
76  throw std::bad_alloc();
77  #ifdef FOXXLL_ALIGNED_CALLOC
78  memset(buffer, 0, alloc_size);
79  #endif
80  char* reserve_buffer = buffer + sizeof(char*) + meta_info_size;
81  char* result = reserve_buffer + Alignment -
82  (reinterpret_cast<size_t>(reserve_buffer) % Alignment) - meta_info_size;
83  TLX_LOGC(debug_aligned_alloc)
84  << "foxxll::aligned_alloc<" << Alignment << ">() address "
85  << static_cast<void*>(result) << " lost " << (result - buffer) << " bytes";
86  //-tb: check that there is space for one char* before the "result" pointer
87  // delivered to the user. this char* is set below to the beginning of the
88  // allocated area.
89  assert(long(result - buffer) >= long(sizeof(char*)));
90 
91  // free unused memory behind the data area
92  // so access behind the requested size can be recognized
93  size_t realloc_size = static_cast<size_t>(result - buffer) + meta_info_size + size;
94  if (realloc_size < alloc_size && aligned_alloc_settings<int>::may_use_realloc) {
95  auto* realloced = static_cast<char*>(std::realloc(buffer, realloc_size));
96  if (buffer != realloced) {
97  // hmm, realloc does move the memory block around while shrinking,
98  // might run under valgrind, so disable realloc and retry
99  TLX_LOG1 << "foxxll::aligned_alloc: disabling realloc()";
100  std::free(realloced);
102  return aligned_alloc<Alignment>(size, meta_info_size);
103  }
104  assert(result + size <= buffer + realloc_size);
105  }
106 
107  *(reinterpret_cast<char**>(result) - 1) = buffer;
108  TLX_LOGC(debug_aligned_alloc)
109  << "foxxll::aligned_alloc<" << Alignment << ">(), allocated at "
110  << static_cast<void*>(buffer) << " returning " << static_cast<void*>(result);
111 
112  TLX_LOGC(debug_aligned_alloc)
113  << "foxxll::aligned_alloc<" << Alignment
114  << ">(size = " << size << ", meta info size = " << meta_info_size
115  << ") => buffer = " << static_cast<void*>(buffer) << ", ptr = " << static_cast<void*>(result);
116 
117  return result;
118 }
119 
120 template <size_t Alignment>
121 inline void
122 aligned_dealloc(void* ptr)
123 {
124  if (!ptr)
125  return;
126  char* buffer = *(static_cast<char**>(ptr) - 1);
127  TLX_LOGC(debug_aligned_alloc)
128  << "foxxll::aligned_dealloc<" << Alignment << ">(), "
129  << "ptr = " << ptr << ", buffer = " << static_cast<void*>(buffer);
130  std::free(buffer);
131 }
132 
133 } // namespace foxxll
134 
135 #endif // !FOXXLL_COMMON_ALIGNED_ALLOC_HEADER
136 
137 /**************************************************************************/
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
FOXXLL library namespace
void * aligned_alloc(size_t size, size_t meta_info_size=0)
#define TLX_LOGC(cond)
Explicitly specify the condition for logging.
Definition: core.hpp:137
#define TLX_LOG1
Definition: core.hpp:145
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