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-
6135namespace 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
11367void * 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
12786void * 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