|
18 | 18 |
|
19 | 19 | #include <folly/hash/Hash.h> |
20 | 20 | #include <folly/logging/xlog.h> |
| 21 | +#include <folly/ScopeGuard.h> |
21 | 22 | #include <sys/mman.h> |
22 | 23 | #include <sys/shm.h> |
| 24 | +#include <numa.h> |
| 25 | +#include <numaif.h> |
23 | 26 |
|
24 | 27 | #include "cachelib/common/Utils.h" |
25 | 28 |
|
@@ -184,6 +187,50 @@ void shmCtlImpl(int shmid, int cmd, shmid_ds* buf) { |
184 | 187 | } |
185 | 188 | } |
186 | 189 |
|
| 190 | +void mbindImpl(void *addr, unsigned long len, int mode, |
| 191 | + const std::vector<size_t>& memBindNumaNodes, |
| 192 | + unsigned int flags) { |
| 193 | + struct bitmask *nodesMask = numa_allocate_nodemask(); |
| 194 | + auto guard = folly::makeGuard([&] { numa_bitmask_free(nodesMask); }); |
| 195 | + |
| 196 | + for(auto node : memBindNumaNodes) { |
| 197 | + numa_bitmask_setbit(nodesMask, node); |
| 198 | + } |
| 199 | + |
| 200 | + long ret = mbind(addr, len, mode, nodesMask->maskp, nodesMask->size, flags); |
| 201 | + if(ret == 0) return; |
| 202 | + |
| 203 | + switch (errno) { |
| 204 | + case EFAULT: |
| 205 | + util::throwSystemError(errno); |
| 206 | + break; |
| 207 | + case EINVAL: |
| 208 | + util::throwSystemError(errno, "Invalid parameters when bind segment to NUMA node(s)"); |
| 209 | + break; |
| 210 | + case EIO: |
| 211 | + if(flags & MPOL_MF_STRICT) { |
| 212 | + util::throwSystemError(errno, "Segment already allocated on another NUMA node that does not follow the policy."); |
| 213 | + } |
| 214 | + if(flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL )) { |
| 215 | + util::throwSystemError(errno, "Segment already allocated but kernel was unable to move it to specified NUMA node(s)."); |
| 216 | + } |
| 217 | + util::throwSystemError(errno, "Invalid errno"); |
| 218 | + break; |
| 219 | + case ENOMEM: |
| 220 | + util::throwSystemError(errno, "Could not bind memory. Insufficient kernel memory was available"); |
| 221 | + break; |
| 222 | + case EPERM: |
| 223 | + if(flags & MPOL_MF_MOVE_ALL) { |
| 224 | + util::throwSystemError(errno, "Process does not have the CAP_SYS_NICE privilege to bind segment with MPOL_MF_MOVE_ALL flag"); |
| 225 | + } |
| 226 | + util::throwSystemError(errno, "Invalid errno"); |
| 227 | + break; |
| 228 | + default: |
| 229 | + XDCHECK(false); |
| 230 | + util::throwSystemError(errno, "Invalid errno"); |
| 231 | + } |
| 232 | +} |
| 233 | + |
187 | 234 | } // namespace detail |
188 | 235 |
|
189 | 236 | void ensureSizeforHugePage(size_t size) { |
@@ -270,11 +317,17 @@ void* SysVShmSegment::mapAddress(void* addr) const { |
270 | 317 |
|
271 | 318 | void* retAddr = detail::shmAttachImpl(shmid_, addr, shmFlags); |
272 | 319 | XDCHECK(retAddr == addr || addr == nullptr); |
| 320 | + memBind(retAddr); |
273 | 321 | return retAddr; |
274 | 322 | } |
275 | 323 |
|
276 | 324 | void SysVShmSegment::unMap(void* addr) const { detail::shmDtImpl(addr); } |
277 | 325 |
|
| 326 | +void SysVShmSegment::memBind(void* addr) const { |
| 327 | + if(opts_.memBindNumaNodes.empty()) return; |
| 328 | + detail::mbindImpl(addr, getSize(), MPOL_BIND, opts_.memBindNumaNodes, 0); |
| 329 | +} |
| 330 | + |
278 | 331 | void SysVShmSegment::markForRemoval() { |
279 | 332 | if (isMarkedForRemoval()) { |
280 | 333 | return; |
|
0 commit comments