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