Open3D (C++ API)  0.12.0
MemoryAllocation.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - Open3D: www.open3d.org -
3 // ----------------------------------------------------------------------------
4 // The MIT License (MIT)
5 //
6 // Copyright (c) 2020 www.open3d.org
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 // IN THE SOFTWARE.
25 // ----------------------------------------------------------------------------
26 
27 #pragma once
28 
29 #include <iostream>
30 #include <memory>
31 #include <stdexcept>
32 #include <utility>
33 #include <vector>
34 
35 namespace open3d {
36 namespace ml {
37 namespace impl {
38 
41 public:
49  MemoryAllocation(void* ptr, size_t size, size_t alignment = 1)
50  : _ptr(ptr),
51  _size(size),
52  _alignment(alignment),
53  _max_size_ptr((char*)ptr) {
54  // align start and end of memory segment
55  void* aligned_ptr = std::align(_alignment, 1, ptr, size);
56  size_t size_after_align =
57  (((char*)ptr + size) - (char*)aligned_ptr) / _alignment;
58  size_after_align *= _alignment;
59  _free_segments.push_back(
60  std::pair<void*, size_t>(aligned_ptr, size_after_align));
61  }
62 
66  template <class T>
67  std::pair<T*, size_t> Alloc(size_t size) {
68  std::pair<void*, size_t> tmp = Alloc(size * sizeof(T));
69  return std::pair<T*, size_t>((T*)tmp.first, tmp.first ? size : 0);
70  }
71 
74  std::pair<void*, size_t> Alloc(size_t size) {
75  // round up to alignment
76  if (size % _alignment) size += _alignment - size % _alignment;
77 
78  for (size_t i = 0; i < _free_segments.size(); ++i) {
79  void* ptr = std::align(_alignment, size, _free_segments[i].first,
80  _free_segments[i].second);
81  if (ptr) {
82  char* end_ptr = (char*)ptr + size;
83  if (end_ptr > _max_size_ptr) _max_size_ptr = end_ptr;
84 
85  _free_segments[i].first = end_ptr;
86  _free_segments[i].second -= size;
87  return std::pair<void*, size_t>(ptr, size);
88  }
89  }
90  return std::pair<void*, size_t>(nullptr, 0);
91  }
92 
94  std::pair<void*, size_t> AllocLargestSegment() {
95  size_t size = 0;
96  for (const auto& s : _free_segments)
97  if (s.second > size) size = s.second;
98 
99  return Alloc(size);
100  }
101 
103  template <class T>
104  void Free(const std::pair<T*, size_t>& segment) {
105  size_t size = sizeof(T) * segment.second;
106  if (size % _alignment) size += _alignment - size % _alignment;
107 
108  Free(std::pair<void*, size_t>(segment.first, size));
109  }
110 
112  void Free(const std::pair<void*, size_t>& segment) {
113  if (DEBUG) {
114  if ((char*)segment.first < (char*)_ptr ||
115  (char*)segment.first + segment.second > (char*)_ptr + _size)
116  throw std::runtime_error("free(): segment is out of bounds");
117  }
118  {
119  size_t i;
120  for (i = 0; i < _free_segments.size(); ++i) {
121  if ((char*)segment.first < (char*)_free_segments[i].first)
122  break;
123  }
124  _free_segments.insert(_free_segments.begin() + i, segment);
125  }
126 
127  // merge adjacent segments
128  auto seg = _free_segments[0];
129  char* end_ptr = (char*)seg.first + seg.second;
130  size_t count = 0;
131  for (size_t i = 1; i < _free_segments.size(); ++i) {
132  const auto& seg_i = _free_segments[i];
133 
134  if (end_ptr == (char*)seg_i.first) {
135  // merge with adjacent following segment
136  seg.second += seg_i.second;
137  end_ptr = (char*)seg.first + seg.second;
138  } else {
139  _free_segments[count] = seg;
140  seg = _free_segments[i];
141  end_ptr = (char*)seg.first + seg.second;
142  ++count;
143  }
144  }
145  _free_segments[count] = seg;
146  ++count;
147  _free_segments.resize(count);
148 
149  if (DEBUG) {
150  // check if there are overlapping segments
151  for (size_t i = 1; i < _free_segments.size(); ++i) {
152  char* prev_end_ptr = (char*)_free_segments[i - 1].first +
153  _free_segments[i - 1].second;
154  if (prev_end_ptr > (char*)_free_segments[i].first) {
155  throw std::runtime_error(
156  "free(): Overlapping free segments found after "
157  "call to free");
158  }
159  }
160  }
161  }
162 
164  size_t MaxUsed() const { return _max_size_ptr - (char*)_ptr; }
165 
167  size_t Alignment() const { return _alignment; }
168 
170  const std::vector<std::pair<void*, size_t>>& FreeSegments() const {
171  return _free_segments;
172  }
173 
175  template <class T>
176  static void PrintSegment(const std::pair<T*, size_t>& s) {
177  std::cerr << "ptr " << (void*)s.first << "\t size " << s.second
178  << "\t end " << (void*)((char*)s.first + s.second) << "\n";
179  }
180 
182  void PrintFreeSegments() const {
183  for (const auto& s : _free_segments) PrintSegment(s);
184  }
185 
186 private:
187  enum internal_config { DEBUG = 0 };
188 
190  const void* _ptr;
191 
193  const size_t _size;
194 
196  const size_t _alignment;
197 
199  char* _max_size_ptr;
200 
203  std::vector<std::pair<void*, size_t>> _free_segments;
204 };
205 
206 } // namespace impl
207 } // namespace ml
208 } // namespace open3d
A class for managing memory segments within a memory allocation.
Definition: MemoryAllocation.h:40
static void PrintSegment(const std::pair< T *, size_t > &s)
Prints the segment. Meant for debugging.
Definition: MemoryAllocation.h:176
void Free(const std::pair< void *, size_t > &segment)
Frees a previously returned segment.
Definition: MemoryAllocation.h:112
std::pair< void *, size_t > AllocLargestSegment()
Returns the largest free segment.
Definition: MemoryAllocation.h:94
int size
Definition: FilePCD.cpp:59
std::pair< T *, size_t > Alloc(size_t size)
Definition: MemoryAllocation.h:67
const std::vector< std::pair< void *, size_t > > & FreeSegments() const
Returns the list of free segments.
Definition: MemoryAllocation.h:170
void Free(const std::pair< T *, size_t > &segment)
Frees a previously returned segment.
Definition: MemoryAllocation.h:104
size_t MaxUsed() const
Returns the peak memory usage in bytes.
Definition: MemoryAllocation.h:164
int count
Definition: FilePCD.cpp:61
void PrintFreeSegments() const
Prints all free segments. Meant for debugging.
Definition: MemoryAllocation.h:182
Definition: PinholeCameraIntrinsic.cpp:35
std::pair< void *, size_t > Alloc(size_t size)
Definition: MemoryAllocation.h:74
MemoryAllocation(void *ptr, size_t size, size_t alignment=1)
Definition: MemoryAllocation.h:49
size_t Alignment() const
Returns the alignment in bytes.
Definition: MemoryAllocation.h:167