Skip to content

Commit 91a9349

Browse files
authored
cleanup aligned allocation
1 parent 133731f commit 91a9349

1 file changed

Lines changed: 60 additions & 125 deletions

File tree

src/memory.cpp

Lines changed: 60 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -19,181 +19,116 @@
1919
#include "memory.h"
2020

2121
#include <cstdlib>
22-
23-
#if __has_include("features.h")
24-
#include <features.h>
25-
#endif
22+
#include <new>
2623

2724
#if defined(__linux__) && !defined(__ANDROID__)
2825
#include <sys/mman.h>
2926
#endif
3027

31-
#if defined(__APPLE__) || defined(__ANDROID__) || defined(__OpenBSD__) \
32-
|| (defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) && !defined(_WIN32)) \
33-
|| defined(__e2k__)
34-
#define POSIXALIGNEDALLOC
35-
#include <stdlib.h>
36-
#endif
37-
3828
#ifdef _WIN32
39-
#if _WIN32_WINNT < 0x0601
40-
#undef _WIN32_WINNT
41-
#define _WIN32_WINNT 0x0601 // Force to include needed API prototypes
42-
#endif
43-
44-
#ifndef NOMINMAX
45-
#define NOMINMAX
46-
#endif
47-
48-
#include <ios> // std::hex, std::dec
49-
#include <iostream> // std::cerr
50-
#include <ostream> // std::endl
29+
#include <ios>
30+
#include <iostream>
31+
#include <ostream>
5132
#include <windows.h>
52-
53-
// The needed Windows API for processor groups could be missed from old Windows
54-
// versions, so instead of calling them directly (forcing the linker to resolve
55-
// the calls at compile time), try to load them at runtime. To do this we need
56-
// first to define the corresponding function pointers.
57-
5833
#endif
5934

60-
6135
namespace Stockfish {
6236

63-
// Wrappers for systems where the c++17 implementation does not guarantee the
64-
// availability of aligned_alloc(). Memory allocated with std_aligned_alloc()
65-
// must be freed with std_aligned_free().
37+
namespace {
6638

67-
void* std_aligned_alloc(size_t alignment, size_t size) {
68-
#if defined(_ISOC11_SOURCE)
69-
return aligned_alloc(alignment, size);
70-
#elif defined(POSIXALIGNEDALLOC)
71-
void* mem = nullptr;
72-
posix_memalign(&mem, alignment, size);
73-
return mem;
74-
#elif defined(_WIN32) && !defined(_M_ARM) && !defined(_M_ARM64)
75-
return _mm_malloc(size, alignment);
76-
#elif defined(_WIN32)
77-
return _aligned_malloc(size, alignment);
78-
#else
79-
return std::aligned_alloc(alignment, size);
80-
#endif
39+
constexpr size_t round_up(size_t value, size_t alignment) {
40+
return ((value + alignment - 1) / alignment) * alignment;
8141
}
8242

83-
void std_aligned_free(void* ptr) {
43+
} // namespace
8444

85-
#if defined(POSIXALIGNEDALLOC)
86-
free(ptr);
87-
#elif defined(_WIN32) && !defined(_M_ARM) && !defined(_M_ARM64)
88-
_mm_free(ptr);
89-
#elif defined(_WIN32)
90-
_aligned_free(ptr);
91-
#else
92-
free(ptr);
93-
#endif
45+
void* std_aligned_alloc(size_t alignment, size_t size) {
46+
return ::operator new(size, std::align_val_t(alignment), std::nothrow);
9447
}
9548

96-
// aligned_large_pages_alloc() will return suitably aligned memory,
97-
// if possible using large pages.
49+
void std_aligned_free(void* ptr, size_t alignment) noexcept {
50+
::operator delete(ptr, std::align_val_t(alignment));
51+
}
9852

9953
#if defined(_WIN32)
10054

101-
static void* aligned_large_pages_alloc_windows([[maybe_unused]] size_t allocSize) {
102-
55+
static void* aligned_large_pages_alloc_windows(size_t allocSize) {
10356
return windows_try_with_large_page_priviliges(
10457
[&](size_t largePageSize) {
10558
// Round up size to full pages and allocate
106-
allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1);
107-
return VirtualAlloc(nullptr, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES,
59+
allocSize = round_up(allocSize, largePageSize);
60+
return VirtualAlloc(nullptr, allocSize,
61+
MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES,
10862
PAGE_READWRITE);
10963
},
110-
[]() { return (void*) nullptr; });
64+
[] { return static_cast<void*>(nullptr); });
11165
}
11266

11367
void* aligned_large_pages_alloc(size_t allocSize) {
68+
if (void* mem = aligned_large_pages_alloc_windows(allocSize))
69+
return mem;
11470

115-
// Try to allocate large pages
116-
void* mem = aligned_large_pages_alloc_windows(allocSize);
117-
118-
// Fall back to regular, page-aligned, allocation if necessary
119-
if (!mem)
120-
mem = VirtualAlloc(nullptr, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
71+
return VirtualAlloc(nullptr, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
72+
}
12173

122-
return mem;
74+
void aligned_large_pages_free(void* mem) {
75+
if (mem && !VirtualFree(mem, 0, MEM_RELEASE))
76+
{
77+
DWORD err = GetLastError();
78+
std::cerr << "Failed to free large page memory. Error code: 0x"
79+
<< std::hex << err << std::dec << std::endl;
80+
std::exit(EXIT_FAILURE);
81+
}
12382
}
12483

12584
#else
12685

12786
void* aligned_large_pages_alloc(size_t allocSize) {
87+
#if defined(__linux__)
88+
constexpr size_t Alignment = 2 * 1024 * 1024;
89+
#else
90+
constexpr size_t Alignment = 4096;
91+
#endif
92+
93+
const size_t size = round_up(allocSize, Alignment);
94+
void* mem = std_aligned_alloc(Alignment, size);
95+
96+
#if defined(MADV_HUGEPAGE)
97+
if (mem)
98+
madvise(mem, size, MADV_HUGEPAGE);
99+
#endif
128100

129-
#if defined(__linux__)
130-
constexpr size_t alignment = 2 * 1024 * 1024; // 2MB page size assumed
131-
#else
132-
constexpr size_t alignment = 4096; // small page size assumed
133-
#endif
134-
135-
// Round up to multiples of alignment
136-
size_t size = ((allocSize + alignment - 1) / alignment) * alignment;
137-
void* mem = std_aligned_alloc(alignment, size);
138-
#if defined(MADV_HUGEPAGE)
139-
madvise(mem, size, MADV_HUGEPAGE);
140-
#endif
141101
return mem;
142102
}
143103

104+
void aligned_large_pages_free(void* mem) {
105+
#if defined(__linux__)
106+
constexpr size_t Alignment = 2 * 1024 * 1024;
107+
#else
108+
constexpr size_t Alignment = 4096;
144109
#endif
145110

146-
bool has_large_pages() {
111+
std_aligned_free(mem, Alignment);
112+
}
113+
114+
#endif
147115

116+
bool has_large_pages() {
148117
#if defined(_WIN32)
118+
constexpr size_t PageSize = 2 * 1024 * 1024;
149119

150-
constexpr size_t page_size = 2 * 1024 * 1024; // 2MB page size assumed
151-
void* mem = aligned_large_pages_alloc_windows(page_size);
152-
if (mem == nullptr)
153-
{
120+
void* mem = aligned_large_pages_alloc_windows(PageSize);
121+
if (!mem)
154122
return false;
155-
}
156-
else
157-
{
158-
aligned_large_pages_free(mem);
159-
return true;
160-
}
161123

162-
#elif defined(__linux__)
163-
164-
#if defined(MADV_HUGEPAGE)
124+
aligned_large_pages_free(mem);
165125
return true;
166-
#else
167-
return false;
168-
#endif
169126

127+
#elif defined(__linux__) && defined(MADV_HUGEPAGE)
128+
return true;
170129
#else
171-
172130
return false;
173-
174131
#endif
175132
}
176133

177-
178-
// aligned_large_pages_free() will free the previously memory allocated
179-
// by aligned_large_pages_alloc(). The effect is a nop if mem == nullptr.
180-
181-
#if defined(_WIN32)
182-
183-
void aligned_large_pages_free(void* mem) {
184-
185-
if (mem && !VirtualFree(mem, 0, MEM_RELEASE))
186-
{
187-
DWORD err = GetLastError();
188-
std::cerr << "Failed to free large page memory. Error code: 0x" << std::hex << err
189-
<< std::dec << std::endl;
190-
exit(EXIT_FAILURE);
191-
}
192-
}
193-
194-
#else
195-
196-
void aligned_large_pages_free(void* mem) { std_aligned_free(mem); }
197-
198-
#endif
199-
} // namespace Stockfish
134+
} // namespace Stockfish

0 commit comments

Comments
 (0)