2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/CachelinePadded.h>
19 #include <type_traits>
21 #include <folly/lang/Align.h>
22 #include <folly/portability/GTest.h>
24 using folly::CachelinePadded;
27 std::is_standard_layout<CachelinePadded<int>>::value,
28 "CachelinePadded<T> must be standard-layout if T is.");
30 static constexpr int kCachelineSize = folly::CacheLocality::kFalseSharingRange;
32 template <size_t dataSize, size_t alignment = alignof(void*)>
33 struct alignas(alignment) SizedData {
36 for (auto& datum : data) {
41 void doModifications() {
43 for (auto& datum : data) {
44 EXPECT_EQ(static_cast<unsigned char>(i++), datum);
51 for (auto& datum : data) {
52 EXPECT_EQ(static_cast<unsigned char>(i++), datum);
56 unsigned char data[dataSize];
59 template <typename T, size_t N = 1>
60 using SizedDataMimic = SizedData<N * sizeof(T), alignof(T)>;
63 struct CachelinePaddedTests : ::testing::Test {};
65 using CachelinePaddedTypes = ::testing::Types<
66 SizedData<kCachelineSize>,
67 SizedData<2 * kCachelineSize>,
68 SizedData<kCachelineSize / 2>,
69 SizedData<kCachelineSize + kCachelineSize / 2>,
70 // Mimic single basic types:
71 SizedDataMimic<folly::max_align_t>,
72 SizedDataMimic<void*>,
73 SizedDataMimic<long double>,
74 SizedDataMimic<double>,
75 SizedDataMimic<float>,
76 SizedDataMimic<long long>,
79 SizedDataMimic<short>,
81 // Mimic small arrays of basic types:
82 SizedDataMimic<folly::max_align_t, 3>,
83 SizedDataMimic<void*, 3>,
84 SizedDataMimic<long double, 3>,
85 SizedDataMimic<double, 3>,
86 SizedDataMimic<float, 3>,
87 SizedDataMimic<long long, 3>,
88 SizedDataMimic<long, 3>,
89 SizedDataMimic<int, 3>,
90 SizedDataMimic<short, 3>,
91 SizedDataMimic<char, 3>,
92 // Mimic large arrays of basic types:
93 SizedDataMimic<folly::max_align_t, kCachelineSize + 3>,
94 SizedDataMimic<void*, kCachelineSize + 3>,
95 SizedDataMimic<long double, kCachelineSize + 3>,
96 SizedDataMimic<double, kCachelineSize + 3>,
97 SizedDataMimic<float, kCachelineSize + 3>,
98 SizedDataMimic<long long, kCachelineSize + 3>,
99 SizedDataMimic<long, kCachelineSize + 3>,
100 SizedDataMimic<int, kCachelineSize + 3>,
101 SizedDataMimic<short, kCachelineSize + 3>,
102 SizedDataMimic<char, kCachelineSize + 3>>;
103 TYPED_TEST_CASE(CachelinePaddedTests, CachelinePaddedTypes);
105 TYPED_TEST(CachelinePaddedTests, alignment) {
106 EXPECT_EQ(alignof(TypeParam), alignof(CachelinePadded<TypeParam>));
109 TYPED_TEST(CachelinePaddedTests, integrity) {
110 CachelinePadded<TypeParam> item;
111 item.get()->doModifications();
114 TYPED_TEST(CachelinePaddedTests, size) {
116 sizeof(TypeParam) + 2 * kCachelineSize,
117 sizeof(CachelinePadded<TypeParam>));
118 size_t const rawSize = sizeof(TypeParam);
119 size_t const rawAlign = alignof(TypeParam);
120 size_t const expectedPadding = kCachelineSize - (rawAlign % kCachelineSize);
121 size_t const expectedPaddedSize = rawSize + 2 * expectedPadding;
122 EXPECT_EQ(expectedPaddedSize, sizeof(CachelinePadded<TypeParam>));
125 TEST(CachelinePadded, PtrOperator) {
126 CachelinePadded<int> padded;
127 EXPECT_TRUE(padded.get() == padded.operator->());
128 EXPECT_TRUE(&*padded == padded.get());
129 const CachelinePadded<int> constPadded;
130 EXPECT_TRUE(constPadded.get() == constPadded.operator->());
131 EXPECT_TRUE(constPadded.get() == &*constPadded.get());
134 TEST(CachelinePadded, PropagatesConstness) {
135 struct OverloadedOnConst {
136 void assign(int* dst) {
139 void assign(int* dst) const {
144 CachelinePadded<OverloadedOnConst> padded;
150 const CachelinePadded<OverloadedOnConst> constPadded;
151 constPadded->assign(&i);
152 EXPECT_EQ(271828, i);
155 TEST(CachelinePadded, ConstructsAndDestructs) {
156 enum LifetimeStatus {
161 struct WriteOnLifetimeOp {
162 explicit WriteOnLifetimeOp(LifetimeStatus* dst) : dst_(dst) {
165 ~WriteOnLifetimeOp() {
168 LifetimeStatus* dst_;
170 LifetimeStatus status = kNone;
171 CachelinePadded<WriteOnLifetimeOp>* ptr =
172 new CachelinePadded<WriteOnLifetimeOp>(&status);
173 EXPECT_EQ(kConstructed, status);
175 EXPECT_EQ(kDestroyed, status);
178 TEST(CachelinePadded, ConstructsAndDestructsArrays) {
179 static thread_local int numConstructions;
180 static thread_local int numDestructions;
181 numConstructions = 0;
183 struct LifetimeCountingClass {
184 LifetimeCountingClass() {
187 ~LifetimeCountingClass() {
191 const static int kNumItems = 123;
192 CachelinePadded<LifetimeCountingClass>* ptr =
193 new CachelinePadded<LifetimeCountingClass>[kNumItems];
194 EXPECT_EQ(kNumItems, numConstructions);
196 EXPECT_EQ(kNumItems, numDestructions);
199 TEST(CachelinePadded, ForwardsCorrectly) {
200 struct RvalueOverloadedConstructor {
201 RvalueOverloadedConstructor(int* dst, int& /* ignored */) {
204 RvalueOverloadedConstructor(int* dst, int&& /* ignored */) {
208 int shouldBeZero = 12345;
209 int shouldBeOne = 67890;
212 CachelinePadded<RvalueOverloadedConstructor> padded1(
213 &shouldBeZero, ignored);
214 CachelinePadded<RvalueOverloadedConstructor> padded2(
215 &shouldBeOne, static_cast<int&&>(ignored));
217 EXPECT_EQ(0, shouldBeZero);
218 EXPECT_EQ(1, shouldBeOne);