Flow123d  DF_patch_fe_data_tables-586fb30
arena_resource.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file arena_resource.hh
15  */
16 
17 #ifndef ARENA_RESOURCE_HH_
18 #define ARENA_RESOURCE_HH_
19 
20 #include <memory_resource>
21 #include <vector>
22 #include <iostream>
23 #include <new>
24 #include <stdexcept> // !! Use Flow exception mechanism
25 
26 #include "system/asserts.hh"
27 
28 
29 // Final proposal of Arena
30 // TODO shared_ptr out of class, pass pointer to data, describe how to use
31 template <class Resource>
32 class PatchArenaResource : public std::pmr::memory_resource {
33 protected:
34  /// Returns different upstream resource in debug / release mode
35  static inline std::pmr::memory_resource* upstream_resource() {
36 #ifdef FLOW123D_DEBUG
37  return std::pmr::null_memory_resource();
38 #else
39  return std::pmr::get_default_resource();
40 #endif
41  }
42 
43 public:
44  /// Same as previous but doesn't construct buffer implicitly.
45  PatchArenaResource(void *buffer, size_t buffer_size, size_t simd_alignment, std::pmr::memory_resource* upstream = PatchArenaResource<Resource>::upstream_resource())
46  : upstream_( upstream ),
47  buffer_(buffer),
48  buffer_size_(buffer_size),
49  used_size_(0),
50  resource_(buffer_, buffer_size, upstream_),
51  simd_alignment_(simd_alignment),
52  full_data_(false)
53  {
54  ASSERT_PERMANENT_EQ( (buffer_size%simd_alignment), 0 );
55  }
56 
57 
58  ~PatchArenaResource() = default; // virtual, call destructor buffer_ = default_resource, (resource_)
59 
60  /// Compute and print free space and used space of arena buffer. Development method
61  inline void print_space() {
62  void *p = this->raw_allocate(1, simd_alignment_);
63  size_t used_size = (char *)p - (char *)buffer_;
64  size_t free_space = buffer_size_ - used_size;
65  std::cout << "Allocated space of arena is " << used_size << " B, free space is " << free_space << " B." << std::endl;
66  }
67 
68 
69  /// Getter for resource
70  Resource &resource() {
71  return resource_;
72  }
73 
74  /// Allocate and return data pointer of n_item array of type T (alignment to length 8 bytes)
75  template <class T>
76  T* allocate_8(size_t n_items) {
77  size_t bytes = sizeof(T) * n_items;
78  return (T*)this->raw_allocate(bytes, 8);
79  }
80 
81  /// Allocate and return data pointer of n_item array of type T (alignment to length given by simd_alignment constructor argument)
82  template <class T>
83  T* allocate_simd(size_t n_items) {
84  size_t bytes = sizeof(T) * n_items;
85  return (T*)this->raw_allocate(bytes, simd_alignment_);
86  }
87 
88  // Reset allocated data
89  void reset() {
90  resource_.release();
91  used_size_ = 0;
92  full_data_ = false;
93 #ifdef FLOW123D_DEBUG
94  char *c_buffer = (char *)buffer_;
95  for (size_t i=0; i<buffer_size_; ++i)
96  c_buffer[i] = 0;
97 #endif
98  }
99 
100 protected:
101  void* raw_allocate(size_t bytes, size_t alignment) {
102  ASSERT(!full_data_).error("Allocation of new data is not possible because child arena was created.");
103  ASSERT_EQ(buffer_size_%alignment, 0);
104 
105  void* p = resource_.allocate(bytes, alignment);
106  used_size_ += (bytes + alignment - 1) / alignment * alignment;
107  if (p == nullptr) { // test only in Debug when null_pointer_resource is in use
108  throw std::bad_alloc();
109  }
110  return p;
111  }
112 
113  /// Override do_allocate to handle allocation logic
114  void* do_allocate(size_t bytes, size_t alignment) override {
115  return raw_allocate(bytes, alignment);
116  }
117 
118  /// Override do_deallocate (no-op for monotonic buffer)
119  void do_deallocate(void* p, size_t bytes, size_t alignment) override {
120  upstream_->deallocate(p, bytes, alignment);
121  }
122 
123  /// Override do_is_equal for memory resource comparison
124  bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
125  return this == &other;
126  }
127 
128  std::pmr::memory_resource* upstream_; ///< Pointer to upstream
129  void* buffer_; ///< Pointer to buffer
130  size_t buffer_size_; ///< Size of buffer
131  size_t used_size_; ///< Temporary data member, will be removed
132  Resource resource_; ///< Resource of arena
133  size_t simd_alignment_; ///< Size of SIMD alignment
134  bool full_data_; ///< Flag signs full data (child arena is created)
135 };
136 
137 
138 template <class Resource>
139 class AssemblyArenaResource : public PatchArenaResource<Resource> {
140 public:
141  /// Constructor. Creates assembly arena
142  AssemblyArenaResource(size_t buffer_size, size_t simd_alignment, std::pmr::memory_resource* upstream = PatchArenaResource<Resource>::upstream_resource())
143  : PatchArenaResource<Resource>( std::pmr::get_default_resource()->allocate(buffer_size, simd_alignment), buffer_size, simd_alignment, upstream ) {}
144 
146  this->do_deallocate(this->buffer_, this->buffer_size_, this->simd_alignment_);
147  }
148 
149  /**
150  * Create and return child arena.
151  *
152  * Child arena is created in free space of actual arena.
153  * Actual arena is marked as full (flag full_data_) and cannot allocate new data.
154  */
156  void *p = this->raw_allocate(1, this->simd_alignment_);
157  size_t used_size = (char *)p - (char *)this->buffer_;
158  size_t free_space = this->buffer_size_ - used_size;
159  this->full_data_ = true;
160  return new PatchArenaResource<Resource>(p, free_space, this->simd_alignment_);
161  }
162 
163 
164 };
165 
166 
167 
170 
171 
172 #endif /* ARENA_RESOURCE_HH_ */
Definitions of ASSERTS.
#define ASSERT(expr)
Definition: asserts.hh:351
#define ASSERT_PERMANENT_EQ(a, b)
Definition of comparative assert macro (EQual)
Definition: asserts.hh:329
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:333
PatchArenaResource< Resource > * get_child_arena()
AssemblyArenaResource(size_t buffer_size, size_t simd_alignment, std::pmr::memory_resource *upstream=PatchArenaResource< Resource >::upstream_resource())
Constructor. Creates assembly arena.
virtual ~AssemblyArenaResource()
T * allocate_8(size_t n_items)
Allocate and return data pointer of n_item array of type T (alignment to length 8 bytes)
void print_space()
Compute and print free space and used space of arena buffer. Development method.
void * do_allocate(size_t bytes, size_t alignment) override
Override do_allocate to handle allocation logic.
std::pmr::memory_resource * upstream_
Pointer to upstream.
~PatchArenaResource()=default
size_t used_size_
Temporary data member, will be removed.
Resource & resource()
Getter for resource.
size_t buffer_size_
Size of buffer.
void do_deallocate(void *p, size_t bytes, size_t alignment) override
Override do_deallocate (no-op for monotonic buffer)
static std::pmr::memory_resource * upstream_resource()
Returns different upstream resource in debug / release mode.
PatchArenaResource(void *buffer, size_t buffer_size, size_t simd_alignment, std::pmr::memory_resource *upstream=PatchArenaResource< Resource >::upstream_resource())
Same as previous but doesn't construct buffer implicitly.
void * raw_allocate(size_t bytes, size_t alignment)
bool do_is_equal(const std::pmr::memory_resource &other) const noexcept override
Override do_is_equal for memory resource comparison.
void * buffer_
Pointer to buffer.
size_t simd_alignment_
Size of SIMD alignment.
T * allocate_simd(size_t n_items)
Allocate and return data pointer of n_item array of type T (alignment to length given by simd_alignme...
Resource resource_
Resource of arena.
bool full_data_
Flag signs full data (child arena is created)