MySQL 8.0.40
Source Code Documentation
os0numa.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 2015, 2024, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is designed to work with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation. The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have either included with
15the program or referenced in the documentation.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20for more details.
21
22You should have received a copy of the GNU General Public License along with
23this program; if not, write to the Free Software Foundation, Inc.,
2451 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26*****************************************************************************/
27
28/** @file include/os0numa.h
29 NUMA API wrapper over various operating system specific APIs.
30
31 The os_numa*() functions in this file mimic the numa*() Linux API that is
32 documented in numa(3). They take the same arguments, have the same return
33 type and behave in the same way. There are two purposes behind this:
34 1. Have zero learning curve for developers already familiar with the Linux API.
35 2. Linux's numa*() functions are documented in more detail than ours
36 os_numa*(). Should any doubt arise about the behavior, the Linux docs should
37 be referred.
38
39 Created Jul 16, 2015 Vasil Dimov
40 *******************************************************/
41
42#ifndef os0numa_h
43#define os0numa_h
44
45#include "univ.i"
46
47#ifdef HAVE_LIBNUMA
48#include <numa.h>
49#endif /* HAVE_LIBNUMA */
50
51#ifdef HAVE_SCHED_GETCPU
52#include <utmpx.h>
53#endif /* HAVE_SCHED_GETCPU */
54
55#ifdef _WIN32
56
57/* https://msdn.microsoft.com/en-us/library/windows/desktop/dd405494(v=vs.85).aspx
58 */
59#define _WIN32_WINNT 0x0601
60#include <WinBase.h>
61
62#define HAVE_WINNUMA
63
64#endif
65
66/** Check if NUMA is available. This function must be called before any
67other os_numa_*() functions and it must return != -1, otherwise the behavior
68of the rest of the functions is undefined.
69@return != -1 if available. */
70inline int os_numa_available() {
71#if defined(HAVE_LIBNUMA)
72 return (numa_available());
73#elif defined(HAVE_WINNUMA)
74 /* See this page for a description of the NUMA Windows API:
75 "NUMA Support"
76 https://msdn.microsoft.com/en-us/library/windows/desktop/aa363804(v=vs.85).aspx
77 */
78 ULONG highest_node;
79
80 if (!GetNumaHighestNodeNumber(&highest_node)) {
81 return (-1);
82 }
83
84 if (highest_node > 0) {
85 return (1);
86 } else {
87 return (-1);
88 }
89#else
90 return (-1);
91#endif /* HAVE_LIBNUMA */
92}
93
94/** Get the number of CPUs in the system, including disabled ones.
95@return number of CPUs */
97#if defined(HAVE_LIBNUMA)
98 return (numa_num_configured_cpus());
99#elif defined(HAVE_WINNUMA)
100 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buf;
101 DWORD buf_bytes = 0;
102
103 if (GetLogicalProcessorInformationEx(RelationGroup, NULL, &buf_bytes)) {
104 /* GetLogicalProcessorInformationEx() unexpectedly succeeded. */
105 return (1);
106 }
107
108 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
109 /* GetLogicalProcessorInformationEx() failed with unexpected
110 error code. */
111 return (1);
112 }
113
114 /* Now 'buf_bytes' contains the necessary size of buf (in bytes!). */
115
116 buf = reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *>(
117 LocalAlloc(LMEM_FIXED, buf_bytes));
118
119 if (buf == NULL) {
120 return (1);
121 }
122
123 if (!GetLogicalProcessorInformationEx(RelationGroup, buf, &buf_bytes)) {
124 /* GetLogicalProcessorInformationEx() unexpectedly failed. */
125 LocalFree(buf);
126 return (1);
127 }
128
129 int n_cpus = 0;
130 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buf_orig = buf;
131
132 /* Maybe this loop will iterate just once, but this is not mentioned
133 explicitly anywhere in the GetLogicalProcessorInformationEx()
134 documentation (when the first argument is RelationGroup). If we are
135 sure that it will iterate just once, then this code could be
136 simplified. */
137 for (DWORD offset = 0; offset < buf_bytes;) {
138 for (WORD i = 0; i < buf->Group.ActiveGroupCount; i++) {
139 n_cpus += buf->Group.GroupInfo[i].ActiveProcessorCount;
140 }
141
142 offset += buf->Size;
143 buf = reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *>(
144 reinterpret_cast<char *>(buf) + buf->Size);
145 }
146
147 LocalFree(buf_orig);
148
149 return (n_cpus);
150#else
151 /* Consider
152 boost::thread::hardware_concurrency() or
153 std::thread::hardware_concurrency() (C++11) */
154 ut_error;
155 return (-1);
156#endif
157}
158
159/** Get the NUMA node of a given CPU.
160@param[in] cpu CPU whose NUMA node to return, must be obtained
161using os_getcpu().
162@return NUMA node id */
163inline int os_numa_node_of_cpu(int cpu) {
164#if defined(HAVE_LIBNUMA)
165 return (numa_node_of_cpu(cpu));
166#elif defined(HAVE_WINNUMA)
167 PROCESSOR_NUMBER p;
168 USHORT node;
169
170 p.Group = cpu >> 6;
171 p.Number = cpu & 63;
172
173 if (GetNumaProcessorNodeEx(&p, &node)) {
174 return (static_cast<int>(node));
175 } else {
176 return (0);
177 }
178#else
179 ut_error;
180 return (-1);
181#endif
182}
183
184/** Allocate a memory on a given NUMA node.
185@param[in] size number of bytes to allocate
186@param[in] node NUMA node on which to allocate the memory
187@return pointer to allocated memory or NULL if allocation failed */
188inline void *os_numa_alloc_onnode(size_t size, int node) {
189#if defined(HAVE_LIBNUMA)
190 return (numa_alloc_onnode(size, node));
191#elif defined(HAVE_WINNUMA)
192 return (VirtualAllocExNuma(GetCurrentProcess(), NULL, size,
193 MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, node));
194#else
195 ut_error;
196 return (NULL);
197#endif
198}
199
200/** Free a memory allocated by os_numa_alloc_onnode().
201@param[in] ptr pointer to memory to free
202@param[in] size size of the memory */
203inline void os_numa_free(void *ptr, size_t size [[maybe_unused]]) {
204#if defined(HAVE_LIBNUMA)
205 numa_free(ptr, size);
206#elif defined(HAVE_WINNUMA)
207 VirtualFreeEx(GetCurrentProcess(), ptr, 0, MEM_DECOMMIT | MEM_RELEASE);
208#else
209 ut_error;
210#endif
211}
212
213#if defined(HAVE_SCHED_GETCPU) || defined(HAVE_WINNUMA)
214
215#define HAVE_OS_GETCPU
216
217/** Get the number of the CPU that executes the current thread now.
218@return CPU number */
219inline int os_getcpu() {
220#if defined(HAVE_SCHED_GETCPU)
221 return (sched_getcpu());
222#elif defined(HAVE_WINNUMA)
223 PROCESSOR_NUMBER p;
224
225 GetCurrentProcessorNumberEx(&p);
226
227 return (static_cast<int>(p.Group << 6 | p.Number));
228#endif
229}
230#endif /* HAVE_SCHED_GETCPU || HAVE_WINNUMA */
231
232#endif /* os0numa_h */
const char * p
Definition: ctype-mb.cc:1237
Definition: buf0block_hint.cc:30
int os_numa_num_configured_cpus()
Get the number of CPUs in the system, including disabled ones.
Definition: os0numa.h:96
void os_numa_free(void *ptr, size_t size)
Free a memory allocated by os_numa_alloc_onnode().
Definition: os0numa.h:203
int os_numa_available()
Check if NUMA is available.
Definition: os0numa.h:70
void * os_numa_alloc_onnode(size_t size, int node)
Allocate a memory on a given NUMA node.
Definition: os0numa.h:188
int os_numa_node_of_cpu(int cpu)
Get the NUMA node of a given CPU.
Definition: os0numa.h:163
#define NULL
Definition: types.h:55
Version control for database, common definitions, and include files.
#define ut_error
Abort execution.
Definition: ut0dbg.h:65