| 1494 | } |
| 1495 | |
| 1496 | Status MemoryAdviseWillNeed(const std::vector<MemoryRegion>& regions) { |
| 1497 | #ifndef __EMSCRIPTEN__ |
| 1498 | const auto page_size = static_cast<size_t>(GetPageSize()); |
| 1499 | DCHECK_GT(page_size, 0); |
| 1500 | const size_t page_mask = ~(page_size - 1); |
| 1501 | DCHECK_EQ(page_mask & page_size, page_size); |
| 1502 | |
| 1503 | auto align_region = [=](const MemoryRegion& region) -> MemoryRegion { |
| 1504 | const auto addr = reinterpret_cast<uintptr_t>(region.addr); |
| 1505 | const auto aligned_addr = addr & page_mask; |
| 1506 | DCHECK_LT(addr - aligned_addr, page_size); |
| 1507 | return {reinterpret_cast<void*>(aligned_addr), |
| 1508 | region.size + static_cast<size_t>(addr - aligned_addr)}; |
| 1509 | }; |
| 1510 | |
| 1511 | # ifdef _WIN32 |
| 1512 | // PrefetchVirtualMemory() is available on Windows 8 or later |
| 1513 | struct PrefetchEntry { // Like WIN32_MEMORY_RANGE_ENTRY |
| 1514 | void* VirtualAddress; |
| 1515 | size_t NumberOfBytes; |
| 1516 | |
| 1517 | PrefetchEntry(const MemoryRegion& region) // NOLINT runtime/explicit |
| 1518 | : VirtualAddress(region.addr), NumberOfBytes(region.size) {} |
| 1519 | }; |
| 1520 | using PrefetchVirtualMemoryFunc = BOOL (*)(HANDLE, ULONG_PTR, PrefetchEntry*, ULONG); |
| 1521 | static const auto prefetch_virtual_memory = reinterpret_cast<PrefetchVirtualMemoryFunc>( |
| 1522 | GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "PrefetchVirtualMemory")); |
| 1523 | if (prefetch_virtual_memory != nullptr) { |
| 1524 | std::vector<PrefetchEntry> entries; |
| 1525 | entries.reserve(regions.size()); |
| 1526 | for (const auto& region : regions) { |
| 1527 | if (region.size != 0) { |
| 1528 | entries.emplace_back(align_region(region)); |
| 1529 | } |
| 1530 | } |
| 1531 | if (!entries.empty() && |
| 1532 | !prefetch_virtual_memory(GetCurrentProcess(), |
| 1533 | static_cast<ULONG_PTR>(entries.size()), entries.data(), |
| 1534 | 0)) { |
| 1535 | return IOErrorFromWinError(GetLastError(), "PrefetchVirtualMemory failed"); |
| 1536 | } |
| 1537 | } |
| 1538 | return Status::OK(); |
| 1539 | # elif defined(POSIX_MADV_WILLNEED) |
| 1540 | for (const auto& region : regions) { |
| 1541 | if (region.size != 0) { |
| 1542 | const auto aligned = align_region(region); |
| 1543 | int err = posix_madvise(aligned.addr, aligned.size, POSIX_MADV_WILLNEED); |
| 1544 | // EBADF can be returned on Linux in the following cases: |
| 1545 | // - the kernel version is older than 3.9 |
| 1546 | // - the kernel was compiled with CONFIG_SWAP disabled (ARROW-9577) |
| 1547 | if (err != 0 && err != EBADF) { |
| 1548 | return IOErrorFromErrno(err, "posix_madvise failed"); |
| 1549 | } |
| 1550 | } |
| 1551 | } |
| 1552 | return Status::OK(); |
| 1553 | # else |