+ if (posix_memalign(&mem, alignment, size))
+ mem = nullptr;
+ madvise(mem, allocSize, MADV_HUGEPAGE);
+ return mem;
+}
+
+#elif defined(_WIN64)
+
+static void* aligned_ttmem_alloc_large_pages(size_t allocSize) {
+
+ HANDLE hProcessToken { };
+ LUID luid { };
+ void* mem = nullptr;
+
+ const size_t largePageSize = GetLargePageMinimum();
+ if (!largePageSize)
+ return nullptr;
+
+ // We need SeLockMemoryPrivilege, so try to enable it for the process
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken))
+ return nullptr;
+
+ if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid))
+ {
+ TOKEN_PRIVILEGES tp { };
+ TOKEN_PRIVILEGES prevTp { };
+ DWORD prevTpLen = 0;
+
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Luid = luid;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ // Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds,
+ // we still need to query GetLastError() to ensure that the privileges were actually obtained.
+ if (AdjustTokenPrivileges(
+ hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) &&
+ GetLastError() == ERROR_SUCCESS)
+ {
+ // Round up size to full pages and allocate
+ allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1);
+ mem = VirtualAlloc(
+ NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
+
+ // Privilege no longer needed, restore previous state
+ AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL);
+ }
+ }
+
+ CloseHandle(hProcessToken);
+
+ return mem;
+}
+
+void* aligned_ttmem_alloc(size_t allocSize, void*& mem) {
+
+ static bool firstCall = true;
+
+ // Try to allocate large pages
+ mem = aligned_ttmem_alloc_large_pages(allocSize);
+
+ // Suppress info strings on the first call. The first call occurs before 'uci'
+ // is received and in that case this output confuses some GUIs.
+ if (!firstCall)
+ {
+ if (mem)
+ sync_cout << "info string Hash table allocation: Windows large pages used." << sync_endl;
+ else
+ sync_cout << "info string Hash table allocation: Windows large pages not used." << sync_endl;
+ }
+ firstCall = false;
+
+ // Fall back to regular, page aligned, allocation if necessary
+ if (!mem)
+ mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+
+ return mem;