Flow123d  DF_patch_fe_data_tables-dc76198
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  DECLARE_EXCEPTION( ExcArenaAllocation,
45  << "Allocation of ArenaResource failed. Please check if correct type of upstream is used.");
46 
47  /// Same as previous but doesn't construct buffer implicitly.
48  PatchArenaResource(void *buffer, size_t buffer_size, size_t simd_alignment, std::pmr::memory_resource* upstream = PatchArenaResource<Resource>::upstream_resource())
49  : upstream_( upstream ),
50  buffer_(buffer),
51  buffer_size_(buffer_size),
52  resource_(buffer_, buffer_size, upstream_),
53  simd_alignment_(simd_alignment),
54  full_data_(false)
55  {
56  ASSERT_PERMANENT_EQ( (buffer_size%simd_alignment), 0 );
57  }
58 
59 
60  ~PatchArenaResource() = default; // virtual, call destructor buffer_ = default_resource, (resource_)
61 
62  /// Compute and print free space and used space of arena buffer. Development method
63  inline void print_space() {
64  void *p = this->raw_allocate(1, simd_alignment_);
65  size_t used_size = (char *)p - (char *)buffer_;
66  size_t free_space = buffer_size_ - used_size;
67  std::cout << "Allocated space of arena is " << used_size << " B, free space is " << free_space << " B." << std::endl;
68  }
69 
70 
71  /// Getter for resource
72  Resource &resource() {
73  return resource_;
74  }
75 
76  /// Allocate and return data pointer of n_item array of type T (alignment to length 8 bytes)
77  template <class T>
78  T* allocate_8(size_t n_items) {
79  size_t bytes = sizeof(T) * n_items;
80  return (T*)this->raw_allocate(bytes, 8);
81  }
82 
83  /// Allocate and return data pointer of n_item array of type T (alignment to length given by simd_alignment constructor argument)
84  template <class T>
85  T* allocate_simd(size_t n_items) {
86  size_t bytes = sizeof(T) * n_items;
87  return (T*)this->raw_allocate(bytes, simd_alignment_);
88  }
89 
90  // Reset allocated data
91  void reset() {
92  resource_.release();
93  full_data_ = false;
94 #ifdef FLOW123D_DEBUG
95  char *c_buffer = (char *)buffer_;
96  for (size_t i=0; i<buffer_size_; ++i)
97  c_buffer[i] = 0;
98 #endif
99  }
100 
101 protected:
102  void* raw_allocate(size_t bytes, size_t alignment) {
103  ASSERT(!full_data_).error("Allocation of new data is not possible because child arena was created.");
104  ASSERT_EQ(buffer_size_%alignment, 0);
105 
106  try {
107  void* p = resource_.allocate(bytes, alignment);
108  return p;
109  } catch ( std::bad_alloc& ) {
110  THROW( ExcArenaAllocation() );
111  }
112  return nullptr;
113  }
114 
115  /// Override do_allocate to handle allocation logic
116  void* do_allocate(size_t bytes, size_t alignment) override {
117  return raw_allocate(bytes, alignment);
118  }
119 
120  /// Override do_deallocate (no-op for monotonic buffer)
121  void do_deallocate(void* p, size_t bytes, size_t alignment) override {
122  upstream_->deallocate(p, bytes, alignment);
123  }
124 
125  /// Override do_is_equal for memory resource comparison
126  bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
127  return this == &other;
128  }
129 
130  std::pmr::memory_resource* upstream_; ///< Pointer to upstream
131  void* buffer_; ///< Pointer to buffer
132  size_t buffer_size_; ///< Size of buffer
133  Resource resource_; ///< Resource of arena
134  size_t simd_alignment_; ///< Size of SIMD alignment
135  bool full_data_; ///< Flag signs full data (child arena is created)
136 };
137 
138 
139 template <class Resource>
140 class AssemblyArenaResource : public PatchArenaResource<Resource> {
141 public:
142  /// Constructor. Creates assembly arena
143  AssemblyArenaResource(size_t buffer_size, size_t simd_alignment, std::pmr::memory_resource* upstream = PatchArenaResource<Resource>::upstream_resource())
144  : PatchArenaResource<Resource>( std::pmr::get_default_resource()->allocate(buffer_size, simd_alignment), buffer_size, simd_alignment, upstream ) {}
145 
147  this->do_deallocate(this->buffer_, this->buffer_size_, this->simd_alignment_);
148  }
149 
150  /**
151  * Create and return child arena.
152  *
153  * Child arena is created in free space of actual arena.
154  * Actual arena is marked as full (flag full_data_) and cannot allocate new data.
155  */
157  void *p = this->raw_allocate(1, this->simd_alignment_);
158  size_t used_size = (char *)p - (char *)this->buffer_;
159  size_t free_space = this->buffer_size_ - used_size;
160  this->full_data_ = true;
161  return new PatchArenaResource<Resource>(p, free_space, this->simd_alignment_);
162  }
163 
164 
165 };
166 
167 
168 
171 
172 
173 #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
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.
DECLARE_EXCEPTION(ExcArenaAllocation,<< "Allocation of ArenaResource failed. Please check if correct type of upstream is used.")
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)
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53