Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
official-stockfish
GitHub Repository: official-stockfish/Stockfish
Path: blob/master/src/memory.cpp
629 views
1
/*
2
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3
Copyright (C) 2004-2026 The Stockfish developers (see AUTHORS file)
4
5
Stockfish is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9
10
Stockfish is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include "memory.h"
20
21
#include <cstdlib>
22
23
#if __has_include("features.h")
24
#include <features.h>
25
#endif
26
27
#if defined(__linux__) && !defined(__ANDROID__)
28
#include <sys/mman.h>
29
#endif
30
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
38
#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
51
#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
58
#endif
59
60
61
namespace Stockfish {
62
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().
66
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
81
}
82
83
void std_aligned_free(void* ptr) {
84
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
94
}
95
96
// aligned_large_pages_alloc() will return suitably aligned memory,
97
// if possible using large pages.
98
99
#if defined(_WIN32)
100
101
static void* aligned_large_pages_alloc_windows([[maybe_unused]] size_t allocSize) {
102
103
return windows_try_with_large_page_priviliges(
104
[&](size_t largePageSize) {
105
// 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,
108
PAGE_READWRITE);
109
},
110
[]() { return (void*) nullptr; });
111
}
112
113
void* aligned_large_pages_alloc(size_t allocSize) {
114
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);
121
122
return mem;
123
}
124
125
#else
126
127
void* aligned_large_pages_alloc(size_t allocSize) {
128
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
141
return mem;
142
}
143
144
#endif
145
146
bool has_large_pages() {
147
148
#if defined(_WIN32)
149
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
{
154
return false;
155
}
156
else
157
{
158
aligned_large_pages_free(mem);
159
return true;
160
}
161
162
#elif defined(__linux__)
163
164
#if defined(MADV_HUGEPAGE)
165
return true;
166
#else
167
return false;
168
#endif
169
170
#else
171
172
return false;
173
174
#endif
175
}
176
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
200
201