MySQL 8.0.33
Source Code Documentation
aligned_atomic.h
Go to the documentation of this file.
1/* Copyright (c) 2008, 2023, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23#ifndef MEMORY_ALIGNED_ATOMIC_H
24#define MEMORY_ALIGNED_ATOMIC_H
25
26#include <assert.h>
27#include <atomic>
28#include <cmath>
29#include <cstddef>
30#include <cstdio>
31
32#if defined(__APPLE__)
33#include <sys/sysctl.h>
34#elif defined(_WIN32)
35#include <stdlib.h>
36#include <windows.h>
37#elif defined(__linux__)
38#include <unistd.h>
39#endif
40
41#include "my_aligned_malloc.h"
42
43namespace memory {
44/**
45 Calculates and returns the size of the CPU cache line.
46
47 @return the cache line size
48 */
49#if defined(__APPLE__)
50static inline size_t _cache_line_size() {
51 size_t line_size{0};
52 size_t sizeof_line_size = sizeof(line_size);
53 sysctlbyname("hw.cachelinesize", &line_size, &sizeof_line_size, 0, 0);
54 return line_size;
55}
56
57#elif defined(_WIN32)
58static inline size_t _cache_line_size() {
59 size_t line_size{0};
60 DWORD buffer_size = 0;
61 DWORD i = 0;
62 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer = 0;
63
64 GetLogicalProcessorInformation(0, &buffer_size);
65 buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)malloc(buffer_size);
66 GetLogicalProcessorInformation(&buffer[0], &buffer_size);
67
68 for (i = 0; i != buffer_size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
69 ++i) {
70 if (buffer[i].Relationship == RelationCache && buffer[i].Cache.Level == 1) {
71 line_size = buffer[i].Cache.LineSize;
72 break;
73 }
74 }
75
76 free(buffer);
77 return line_size;
78}
79
80#elif defined(__linux__)
81static inline size_t _cache_line_size() {
82 long size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
83 if (size == -1) return 64;
84#if defined(__s390x__)
85 // returns 0 on s390x RHEL 7.x
86 if (size == 0) {
87 FILE *p = fopen(
88 "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r");
89 if (p) {
90 fscanf(p, "%ld", &size);
91 fclose(p);
92 }
93 }
94#endif
95 return static_cast<size_t>(size);
96}
97
98#else
99static inline size_t _cache_line_size() { return 64; }
100#endif
101static inline size_t cache_line_size() {
102 static const size_t size{memory::_cache_line_size()};
103 return size;
104}
105
106/**
107 Retrieves the amount of bytes, multiple of the current cacheline size, needed
108 to store an element of type `T`. This is a non-caching non-thread safe helper
109 function and `memory::minimum_cacheline_for` should be used instead.
110
111 @return the amount of bytes, multiple of the current cacheline size, needed to
112 store an element of type `T`.
113 */
114template <typename T>
115static inline size_t _cacheline_for() {
116 size_t csize = memory::cache_line_size();
117 size_t size{static_cast<size_t>(std::ceil(static_cast<double>(sizeof(T)) /
118 static_cast<double>(csize))) *
119 csize};
120 return size;
121}
122
123/**
124 Retrieves the amount of bytes, multiple of the current cacheline size, needed
125 to store an element of type `T`. This function caches the computed value in a
126 static storage variable and does it in a thread-safe manner.
127
128 @return the amount of bytes, multiple of the current cacheline size, needed to
129 store an element of type `T`.
130 */
131template <typename T>
132static inline size_t minimum_cacheline_for() {
133 static const size_t size{memory::_cacheline_for<T>()};
134 return size;
135}
136
137/**
138 @class memory::Aligned_atomic
139
140 Templated class that encapsulates an `std::atomic` within a byte buffer that
141 is padded to the processor cache-line size.
142
143 This class purpose is to help prevent false sharing between atomically
144 accessed variables that are contiguous in memory. This is the normal case for
145 arrays or class members declared next to each other.
146
147 If the intended usage is none of the above, `std::atomic` class should be used
148 since the below implementation allocates more memory than needed for storing
149 the intended value (in order to implement the padding to the cache-line).
150 */
151template <typename T>
153 public:
154 /*
155 Default class constructor, will allocate a byte buffer with enough space to
156 store an instance of `std::atomic<T>` and paded to a multiple of the
157 processor cache-line size.
158
159 Will invoke `std::atomic<T>` inplace constructor using the allocated byte
160 array.
161 */
163 /*
164 Constructor that will assign the parameter value to the newly allocated
165 `std::atomic<T>`.
166
167 @param value The value to store in the underlying `std::atomic<T>` object.
168 */
170 /*
171 Deleted copy constructor, no copies allowed.
172 */
173 Aligned_atomic(Aligned_atomic<T> const &rhs) = delete;
174 /*
175 Move semantics constructor.
176
177 @param rhs The object to collect the underlying `std::atomic<T>` and byte
178 buffer from.
179 */
181 /*
182 Destructor that will invoke `std::atomi<T>` inplace destructor and release
183 the allocated byte buffer.
184 */
186
187 /*
188 Deleted copy operator.
189 */
191 /*
192 Move semantics operator.
193
194 @param rhs The object to collect the underlying `std::atomic<T>` and byte
195 buffer from.
196
197 @return This object reference, instantiated with the collected values.
198 */
200 /*
201 Assignment operator for parameter of templated type.
202
203 @param rhs The templated type value to be stored in the underlying
204 `std::atomic`.
205
206 @return This object reference, instantiated with the collected value.
207 */
209 /**
210 Casting operator for directly accessing the value of the underlying
211 `std::atomic<T>`.
212
213 @return The value of type `T` stored in the underlying `std::atomic`..
214 */
215 operator T() const;
216 /**
217 Equality operator to determine if the underlying storage memory is
218 initialized.
219
220 @param rhs nullptr value
221
222 @return true if the underlying storage memory is not initialized,
223 false otherwise.
224 */
225 bool operator==(std::nullptr_t rhs) const;
226 /**
227 Inequality operator to determine if the underlying storage memory is
228 initialized.
229
230 @param rhs nullptr value
231
232 @return true if the underlying storage memory is initialized, false
233 otherwise.
234 */
235 bool operator!=(std::nullptr_t rhs) const;
236 /**
237 Equality operator for determining if the value stored in the underlying
238 `std::atomic` equals the passed parameter.
239
240 @param rhs The value to compare with.
241
242 @return true if the parameter value equals the value stored in the
243 underlying `std::atomic`, false otherwise.
244 */
245 bool operator==(T rhs) const;
246 /**
247 Inequality operator for determining if the value stored in the underlying
248 `std::atomic` differs from the passed parameter.
249
250 @param rhs The value to compare with.
251
252 @return true if the parameter value differs from the value stored in the
253 underlying `std::atomic`, false otherwise.
254 */
255 bool operator!=(T rhs) const;
256 /*
257 Pointer operator that allows the access to the underlying `std::atomic<T>`
258 object.
259
260 @return The pointer to the underlying `std::atomic<T>` object.
261 */
262 std::atomic<T> *operator->();
263 /*
264 Pointer operator that allows the access to the underlying `std::atomic<T>`
265 object.
266
267 @return The const pointer to the underlying `std::atomic<T>` object.
268 */
269 const std::atomic<T> *operator->() const;
270 /*
271 Dereference operator that allows the access to the underlying
272 `std::atomic<T>` object.
273
274 @return The reference to the underlying `std::atomic<T>` object.
275 */
276 std::atomic<T> &operator*();
277 /*
278 Dereference operator that allows the access to the underlying
279 `std::atomic<T>` object.
280
281 @return The const reference to the underlying `std::atomic<T>` object.
282 */
283 const std::atomic<T> &operator*() const;
284 /*
285 The size of `std::atomic<T>`, as returned by `sizeof std::atomic<T>`.
286
287 @return The in-memory size of an `std::atomic<T>` instance.
288 */
289 size_t size() const;
290 /*
291 The size of the allocated byte buffer.
292
293 @return The in-memory size of the allocated byte buffer.
294 */
295 size_t allocated_size() const;
296
297 private:
298 /** The size of the byte buffer. */
299 size_t m_storage_size{0};
300 /** The byte buffer to use as underlying storage. */
301 void *m_storage{nullptr};
302 /** The pointer to the underlying `std::atomic<T>` object. */
303 std::atomic<T> *m_underlying{nullptr};
304};
305} // namespace memory
306
307template <typename T>
309 : m_storage_size{memory::minimum_cacheline_for<std::atomic<T>>()} {
311 m_underlying = new (this->m_storage) std::atomic<T>();
312}
313
314template <typename T>
316 : memory::Aligned_atomic<T>() {
317 this->m_underlying->store(value);
318}
319
320template <typename T>
322 if (this->m_underlying != nullptr) {
323 this->m_underlying->~atomic();
324 }
325 my_aligned_free(this->m_storage);
326 this->m_storage = rhs.m_storage;
327 this->m_storage_size = rhs.m_storage_size;
328 this->m_underlying = rhs.m_underlying;
329 rhs.m_storage = nullptr;
330 rhs.m_storage_size = 0;
331 rhs.m_underlying = nullptr;
332}
333
334template <typename T>
336 if (this->m_underlying != nullptr) {
337 this->m_underlying->~atomic();
338 }
339 my_aligned_free(this->m_storage);
340 this->m_storage = nullptr;
341 this->m_storage_size = 0;
342 this->m_underlying = nullptr;
343}
344
345template <typename T>
347 Aligned_atomic<T> &&rhs) {
348 if (this->m_underlying != nullptr) {
349 this->m_underlying->~atomic();
350 }
351 my_aligned_free(this->m_storage);
352 this->m_storage = rhs.m_storage;
353 this->m_storage_size = rhs.m_storage_size;
354 this->m_underlying = rhs.m_underlying;
355 rhs.m_storage = nullptr;
356 rhs.m_storage_size = 0;
357 rhs.m_underlying = nullptr;
358 return (*this);
359}
360
361template <typename T>
363 assert(this->m_underlying != nullptr);
364 this->m_underlying->store(rhs, std::memory_order_seq_cst);
365 return (*this);
366}
367
368template <typename T>
370 assert(this->m_underlying != nullptr);
371 return this->m_underlying->load(std::memory_order_relaxed);
372}
373
374template <typename T>
375bool memory::Aligned_atomic<T>::operator==(std::nullptr_t) const {
376 return this->m_underlying == nullptr;
377}
378
379template <typename T>
380bool memory::Aligned_atomic<T>::operator!=(std::nullptr_t) const {
381 return this->m_underlying != nullptr;
382}
383
384template <typename T>
386 if (this->m_underlying == nullptr) return false;
387 return this->m_underlying->load(std::memory_order_relaxed) == rhs;
388}
389
390template <typename T>
392 return !((*this) == rhs);
393}
394
395template <typename T>
397 assert(this->m_underlying != nullptr);
398 return this->m_underlying;
399}
400
401template <typename T>
402const std::atomic<T> *memory::Aligned_atomic<T>::operator->() const {
403 assert(this->m_underlying != nullptr);
404 return this->m_underlying;
405}
406
407template <typename T>
409 assert(this->m_underlying != nullptr);
410 return *this->m_underlying;
411}
412
413template <typename T>
414const std::atomic<T> &memory::Aligned_atomic<T>::operator*() const {
415 assert(this->m_underlying != nullptr);
416 return *this->m_underlying;
417}
418
419template <typename T>
421 return sizeof(std::atomic<T>);
422}
423
424template <typename T>
426 return this->m_storage_size;
427}
428
429#endif // MEMORY_ALIGNED_ATOMIC_H
Templated class that encapsulates an std::atomic within a byte buffer that is padded to the processor...
Definition: aligned_atomic.h:152
Aligned_atomic< T > & operator=(Aligned_atomic< T > const &rhs)=delete
Aligned_atomic(Aligned_atomic< T > &&rhs)
Definition: aligned_atomic.h:321
size_t allocated_size() const
Definition: aligned_atomic.h:425
const std::atomic< T > * operator->() const
Definition: aligned_atomic.h:402
Aligned_atomic< T > & operator=(Aligned_atomic< T > &&rhs)
Definition: aligned_atomic.h:346
virtual ~Aligned_atomic()
Definition: aligned_atomic.h:335
bool operator!=(std::nullptr_t rhs) const
Inequality operator to determine if the underlying storage memory is initialized.
Definition: aligned_atomic.h:380
bool operator==(T rhs) const
Equality operator for determining if the value stored in the underlying std::atomic equals the passed...
Definition: aligned_atomic.h:385
std::atomic< T > * operator->()
Definition: aligned_atomic.h:396
Aligned_atomic(Aligned_atomic< T > const &rhs)=delete
Aligned_atomic< T > & operator=(T rhs)
Definition: aligned_atomic.h:362
size_t size() const
Definition: aligned_atomic.h:420
Aligned_atomic()
Definition: aligned_atomic.h:308
std::atomic< T > & operator*()
Definition: aligned_atomic.h:408
size_t m_storage_size
The size of the byte buffer.
Definition: aligned_atomic.h:299
void * m_storage
The byte buffer to use as underlying storage.
Definition: aligned_atomic.h:301
bool operator==(std::nullptr_t rhs) const
Equality operator to determine if the underlying storage memory is initialized.
Definition: aligned_atomic.h:375
const std::atomic< T > & operator*() const
Definition: aligned_atomic.h:414
Aligned_atomic(T value)
Definition: aligned_atomic.h:315
std::atomic< T > * m_underlying
The pointer to the underlying std::atomic<T> object.
Definition: aligned_atomic.h:303
bool operator!=(T rhs) const
Inequality operator for determining if the value stored in the underlying std::atomic differs from th...
Definition: aligned_atomic.h:391
const char * p
Definition: ctype-mb.cc:1236
#define malloc(A)
Definition: lexyy.cc:914
#define free(A)
Definition: lexyy.cc:915
void * my_aligned_malloc(size_t size, size_t alignment)
Function allocates size bytes and returns a pointer to the allocated memory.
Definition: my_aligned_malloc.cc:37
void my_aligned_free(void *ptr)
Free allocated memory using my_aligned_malloc function.
Definition: my_aligned_malloc.cc:62
const std::string FILE("FILE")
std::unordered_map< meta::Metadata, Data_extension, meta::Metadata::Hash > Cache
Definition: cache.h:37
Definition: aligned_atomic.h:43
static size_t cache_line_size()
Definition: aligned_atomic.h:101
static size_t _cache_line_size()
Calculates and returns the size of the CPU cache line.
Definition: aligned_atomic.h:99
static size_t minimum_cacheline_for()
Retrieves the amount of bytes, multiple of the current cacheline size, needed to store an element of ...
Definition: aligned_atomic.h:132
static size_t _cacheline_for()
Retrieves the amount of bytes, multiple of the current cacheline size, needed to store an element of ...
Definition: aligned_atomic.h:115
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:419
size_t buffer_size(const ConstBufferSequence &buffers) noexcept
Definition: buffer.h:314
Definition: varlen_sort.h:183