1 | /* |
2 | * Copyright 2011-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <cstddef> |
20 | |
21 | #include <folly/Portability.h> |
22 | |
23 | namespace folly { |
24 | |
25 | namespace detail { |
26 | |
27 | // Implemented this way because of a bug in Clang for ARMv7, which gives the |
28 | // wrong result for `alignof` a `union` with a field of each scalar type. |
29 | constexpr size_t max_align_(std::size_t a) { |
30 | return a; |
31 | } |
32 | template <typename... Es> |
33 | constexpr std::size_t max_align_(std::size_t a, std::size_t e, Es... es) { |
34 | return !(a < e) ? a : max_align_(e, es...); |
35 | } |
36 | template <typename... Ts> |
37 | struct max_align_t_ { |
38 | static constexpr std::size_t value = max_align_(0u, alignof(Ts)...); |
39 | }; |
40 | using max_align_v_ = max_align_t_< |
41 | long double, |
42 | double, |
43 | float, |
44 | long long int, |
45 | long int, |
46 | int, |
47 | short int, |
48 | bool, |
49 | char, |
50 | char16_t, |
51 | char32_t, |
52 | wchar_t, |
53 | void*, |
54 | std::max_align_t>; |
55 | |
56 | } // namespace detail |
57 | |
58 | // max_align_v is the alignment of max_align_t. |
59 | // |
60 | // max_align_t is a type which is aligned at least as strictly as the |
61 | // most-aligned basic type (see the specification of std::max_align_t). This |
62 | // implementation exists because 32-bit iOS platforms have a broken |
63 | // std::max_align_t (see below). |
64 | // |
65 | // You should refer to this as `::folly::max_align_t` in portable code, even if |
66 | // you have `using namespace folly;` because C11 defines a global namespace |
67 | // `max_align_t` type. |
68 | // |
69 | // To be certain, we consider every non-void fundamental type specified by the |
70 | // standard. On most platforms `long double` would be enough, but iOS 32-bit |
71 | // has an 8-byte aligned `double` and `long long int` and a 4-byte aligned |
72 | // `long double`. |
73 | // |
74 | // So far we've covered locals and other non-allocated storage, but we also need |
75 | // confidence that allocated storage from `malloc`, `new`, etc will also be |
76 | // suitable for objects with this alignment requirement. |
77 | // |
78 | // Apple document that their implementation of malloc will issue 16-byte |
79 | // granularity chunks for small allocations (large allocations are page-size |
80 | // granularity and page-aligned). We think that allocated storage will be |
81 | // suitable for these objects based on the following assumptions: |
82 | // |
83 | // 1. 16-byte granularity also means 16-byte aligned. |
84 | // 2. `new` and other allocators follow the `malloc` rules. |
85 | // |
86 | // We also have some anecdotal evidence: we don't see lots of misaligned-storage |
87 | // crashes on 32-bit iOS apps that use `double`. |
88 | // |
89 | // Apple's allocation reference: http://bit.ly/malloc-small |
90 | constexpr std::size_t max_align_v = detail::max_align_v_::value; |
91 | struct alignas(max_align_v) max_align_t {}; |
92 | |
93 | // Memory locations within the same cache line are subject to destructive |
94 | // interference, also known as false sharing, which is when concurrent |
95 | // accesses to these different memory locations from different cores, where at |
96 | // least one of the concurrent accesses is or involves a store operation, |
97 | // induce contention and harm performance. |
98 | // |
99 | // Microbenchmarks indicate that pairs of cache lines also see destructive |
100 | // interference under heavy use of atomic operations, as observed for atomic |
101 | // increment on Sandy Bridge. |
102 | // |
103 | // We assume a cache line size of 64, so we use a cache line pair size of 128 |
104 | // to avoid destructive interference. |
105 | // |
106 | // mimic: std::hardware_destructive_interference_size, C++17 |
107 | constexpr std::size_t hardware_destructive_interference_size = |
108 | kIsArchArm ? 64 : 128; |
109 | static_assert(hardware_destructive_interference_size >= max_align_v, "math?" ); |
110 | |
111 | // Memory locations within the same cache line are subject to constructive |
112 | // interference, also known as true sharing, which is when accesses to some |
113 | // memory locations induce all memory locations within the same cache line to |
114 | // be cached, benefiting subsequent accesses to different memory locations |
115 | // within the same cache line and heping performance. |
116 | // |
117 | // mimic: std::hardware_constructive_interference_size, C++17 |
118 | constexpr std::size_t hardware_constructive_interference_size = 64; |
119 | static_assert(hardware_constructive_interference_size >= max_align_v, "math?" ); |
120 | |
121 | } // namespace folly |
122 | |