1 // Copyright (c) 2015-2016 John Biddiscombe 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #ifndef HPX_PARCELSET_POLICIES_VERBS_MEMORY_REGION_HPP 7 #define HPX_PARCELSET_POLICIES_VERBS_MEMORY_REGION_HPP 8 9 #include <plugins/parcelport/parcelport_logging.hpp> 10 #include <plugins/parcelport/verbs/rdma/rdma_error.hpp> 11 #include <plugins/parcelport/verbs/rdma/verbs_protection_domain.hpp> 12 // 13 #include <infiniband/verbs.h> 14 #include <errno.h> 15 // 16 #include <memory> 17 18 namespace hpx { 19 namespace parcelset { 20 namespace policies { 21 namespace verbs 22 { 23 struct verbs_memory_region 24 { 25 // -------------------------------------------------------------------- verbs_memory_regionhpx::parcelset::policies::verbs::verbs_memory_region26 verbs_memory_region() : 27 region_(nullptr), address_(nullptr), flags_(0), size_(0), used_space_(0) {} 28 29 // -------------------------------------------------------------------- verbs_memory_regionhpx::parcelset::policies::verbs::verbs_memory_region30 verbs_memory_region(struct ibv_mr *region, char * address, 31 uint32_t flags, uint64_t size) : 32 region_(region), address_(address), flags_(flags), 33 size_(size), used_space_(0) {} 34 35 // -------------------------------------------------------------------- 36 // construct a memory region object by registering an existing address buffer verbs_memory_regionhpx::parcelset::policies::verbs::verbs_memory_region37 verbs_memory_region(verbs_protection_domain_ptr pd, 38 const void *buffer, const uint64_t length) 39 { 40 address_ = static_cast<char*>(const_cast<void*>(buffer)); 41 size_ = length; 42 used_space_ = length; 43 flags_ = BLOCK_USER; 44 45 region_ = ibv_reg_mr( 46 pd->getDomain(), 47 const_cast<void*>(buffer), used_space_, 48 IBV_ACCESS_LOCAL_WRITE | 49 IBV_ACCESS_REMOTE_WRITE | 50 IBV_ACCESS_REMOTE_READ); 51 52 if (region_ == nullptr) { 53 int err = errno; 54 rdma_error(errno, "error registering user mem ibv_reg_mr "); 55 LOG_ERROR_MSG( 56 "error registering user mem ibv_reg_mr " << hexpointer(buffer) << " " 57 << hexlength(length) << " error/message: " << err << "/" 58 << rdma_error::error_string(err)); 59 } 60 else { 61 LOG_DEBUG_MSG( 62 "OK registering memory =" 63 << hexpointer(buffer) << " : " << hexpointer(region_->addr) 64 << " length " << hexlength(get_length())); 65 } 66 67 } 68 69 // -------------------------------------------------------------------- 70 // allocate a block of size length and register it allocatehpx::parcelset::policies::verbs::verbs_memory_region71 int allocate(verbs_protection_domain_ptr pd, uint64_t length) 72 { 73 // Allocate storage for the memory region. 74 void *buffer = new char[length]; 75 if (buffer != nullptr) { 76 LOG_DEBUG_MSG("allocated storage for memory region with malloc OK " 77 << hexnumber(length)); 78 } 79 80 region_ = ibv_reg_mr( 81 pd->getDomain(), 82 buffer, length, 83 IBV_ACCESS_LOCAL_WRITE | 84 IBV_ACCESS_REMOTE_WRITE | 85 IBV_ACCESS_REMOTE_READ); 86 87 if (region_ == nullptr) { 88 LOG_ERROR_MSG("error registering ibv_reg_mr : " 89 << " " << errno << " " << rdma_error::error_string(errno)); 90 return -1; 91 } 92 else { 93 LOG_DEBUG_MSG("OK registering ibv_reg_mr"); 94 } 95 address_ = static_cast<char*>(region_->addr); 96 size_ = length; 97 98 LOG_DEBUG_MSG("allocated/registered memory region " << hexpointer(this) 99 << " with local key " << hexlength(get_local_key()) 100 << " at address " << hexpointer(get_address()) 101 << " with length " << hexlength(get_length())); 102 return 0; 103 } 104 105 // -------------------------------------------------------------------- 106 // destroy the region and memory according to flag settings ~verbs_memory_regionhpx::parcelset::policies::verbs::verbs_memory_region107 ~verbs_memory_region() 108 { 109 release(); 110 } 111 112 // -------------------------------------------------------------------- 113 // Deregister and free the memory region. 114 // returns 0 when successful, -1 otherwise releasehpx::parcelset::policies::verbs::verbs_memory_region115 int release(void) 116 { 117 LOG_TRACE_MSG("About to release memory region with local key " 118 << hexlength(get_local_key())); 119 if (region_ != nullptr) { 120 // get these before deleting/unregistering (for logging) 121 void *buffer = get_base_address(); 122 LOG_EXCLUSIVE( 123 uint32_t length = get_length(); 124 ); 125 // 126 if (!get_partial_region()) { 127 if (ibv_dereg_mr (region_)) { 128 LOG_ERROR_MSG("Error, ibv_dereg_mr() failed\n"); 129 return -1; 130 } 131 else { 132 LOG_DEBUG_MSG("deregistered memory region with local key " 133 << hexlength(get_local_key()) 134 << " at address " << hexpointer(buffer) 135 << " with length " << hexlength(length)); 136 } 137 } 138 if (!get_partial_region() && !get_user_region()) { 139 delete [](static_cast<char*>(buffer)); 140 } 141 region_ = nullptr; 142 } 143 return 0; 144 } 145 146 147 // -------------------------------------------------------------------- 148 // return the address of this memory region block. If this 149 // is a partial region, then the address will be offset from the 150 // base address get_addresshpx::parcelset::policies::verbs::verbs_memory_region151 inline char *get_address(void) const { 152 return address_; 153 } 154 155 // -------------------------------------------------------------------- 156 // Get the address of the base memory region. 157 // This is the address of the memory allocated from the system get_base_addresshpx::parcelset::policies::verbs::verbs_memory_region158 inline char *get_base_address(void) const { 159 return static_cast<char*>(region_->addr); 160 } 161 162 // -------------------------------------------------------------------- 163 // Get the allocated length of the internal memory region. get_lengthhpx::parcelset::policies::verbs::verbs_memory_region164 inline uint64_t get_length(void) const { 165 return (uint32_t) region_->length; 166 } 167 168 // -------------------------------------------------------------------- 169 // Get the size memory chunk usable by this memory region, 170 // this may be smaller than the value returned by get_length 171 // if the region is a sub region (partial region) within another block get_sizehpx::parcelset::policies::verbs::verbs_memory_region172 inline uint64_t get_size(void) const { 173 return size_; 174 } 175 176 // -------------------------------------------------------------------- 177 // Get the local key of the memory region. get_local_keyhpx::parcelset::policies::verbs::verbs_memory_region178 inline uint32_t get_local_key(void) const { 179 return region_->lkey; 180 } 181 182 // -------------------------------------------------------------------- 183 // Get the remote key of the memory region. get_remote_keyhpx::parcelset::policies::verbs::verbs_memory_region184 inline uint32_t get_remote_key(void) const { 185 return region_->rkey; 186 } 187 188 // -------------------------------------------------------------------- 189 // Set the size used by a message in the memory region. set_message_lengthhpx::parcelset::policies::verbs::verbs_memory_region190 inline void set_message_length(uint32_t length) { 191 used_space_ = length; 192 } 193 194 // -------------------------------------------------------------------- 195 // Get the size used by a message in the memory region. get_message_lengthhpx::parcelset::policies::verbs::verbs_memory_region196 inline uint32_t get_message_length(void) const { 197 return used_space_; 198 } 199 200 // -------------------------------------------------------------------- 201 // return the underlying infiniband region handle get_regionhpx::parcelset::policies::verbs::verbs_memory_region202 inline struct ibv_mr *get_region() { return region_; } 203 204 // -------------------------------------------------------------------- 205 // flags used for management of lifetime 206 enum { 207 BLOCK_USER = 1, 208 BLOCK_TEMP = 2, 209 BLOCK_PARTIAL = 4, 210 }; 211 212 // -------------------------------------------------------------------- 213 // A user allocated region use memory allocted by the user. 214 // on destruction, the memory is unregisterd, but not deleted set_user_regionhpx::parcelset::policies::verbs::verbs_memory_region215 inline void set_user_region() { 216 flags_ |= BLOCK_USER; 217 } get_user_regionhpx::parcelset::policies::verbs::verbs_memory_region218 inline bool get_user_region() const { 219 return (flags_ & BLOCK_USER) == BLOCK_USER; 220 } 221 222 // -------------------------------------------------------------------- 223 // A temp region is one that the memory pool is not managing 224 // so it is unregistered and deleted when returned to the pool and not reused set_temp_regionhpx::parcelset::policies::verbs::verbs_memory_region225 inline void set_temp_region() { 226 flags_ |= BLOCK_TEMP; 227 } get_temp_regionhpx::parcelset::policies::verbs::verbs_memory_region228 inline bool get_temp_region() const { 229 return (flags_ & BLOCK_TEMP) == BLOCK_TEMP; 230 } 231 232 // -------------------------------------------------------------------- 233 // a partial region is a subregion of a larger memory region 234 // on destruction, it is not unregister or deleted as the 'parent' region 235 // will delete many partial regions on destruction set_partial_regionhpx::parcelset::policies::verbs::verbs_memory_region236 inline void set_partial_region() { 237 flags_ |= BLOCK_PARTIAL; 238 } get_partial_regionhpx::parcelset::policies::verbs::verbs_memory_region239 inline bool get_partial_region() const { 240 return (flags_ & BLOCK_PARTIAL) == BLOCK_PARTIAL; 241 } 242 243 private: 244 // The internal Infiniband memory region handle 245 struct ibv_mr *region_; 246 247 // we may be a piece of a larger region, this gives the start address 248 // of this piece of the region. This is the address that should be used for data 249 // storage 250 char *address_; 251 252 // flags to control lifetime of blocks 253 uint32_t flags_; 254 255 // The size of the memory buffer, if this is a partial region 256 // it will be smaller than the value returned by region_->length 257 uint64_t size_; 258 259 // space used by a message in the memory region. 260 uint64_t used_space_; 261 }; 262 263 // Smart pointer for verbs_memory_region object. 264 typedef std::shared_ptr<verbs_memory_region> verbs_memory_region_ptr; 265 266 }}}} 267 268 #endif 269