/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
std::is_standard_layout<CachelinePadded<int>>::value,
"CachelinePadded<T> must be standard-layout if T is.");
-const int kCachelineSize = folly::detail::CacheLocality::kFalseSharingRange;
+static constexpr int kCachelineSize = folly::CacheLocality::kFalseSharingRange;
-template <int dataSize>
-struct SizedData {
+template <size_t dataSize, size_t alignment = alignof(void*)>
+struct alignas(alignment) SizedData {
SizedData() {
- for (unsigned i = 0; i < dataSize; ++i) {
- data[i] = i;
+ size_t i = 0;
+ for (auto& datum : data) {
+ datum = i++;
}
}
void doModifications() {
- for (unsigned i = 0; i < dataSize; ++i) {
- EXPECT_EQ(static_cast<unsigned char>(i), data[i]);
- ++data[i];
+ size_t i = 0;
+ for (auto& datum : data) {
+ EXPECT_EQ(static_cast<unsigned char>(i++), datum);
+ ++datum;
}
}
~SizedData() {
- for (unsigned i = 0; i < dataSize; ++i) {
- EXPECT_EQ(static_cast<unsigned char>(i + 1), data[i]);
+ size_t i = 1;
+ for (auto& datum : data) {
+ EXPECT_EQ(static_cast<unsigned char>(i++), datum);
}
}
unsigned char data[dataSize];
};
-using ExactlyCachelineSized = SizedData<kCachelineSize>;
-using DoubleCachelineSized = SizedData<2 * kCachelineSize>;
-using BelowCachelineSized = SizedData<kCachelineSize / 2>;
-using AboveCachelineSized = SizedData<kCachelineSize + kCachelineSize / 2>;
-
-TEST(CachelinePadded, Exact) {
- EXPECT_EQ(kCachelineSize, sizeof(CachelinePadded<ExactlyCachelineSized>));
- CachelinePadded<ExactlyCachelineSized> item;
- item.get()->doModifications();
- EXPECT_TRUE(
- reinterpret_cast<CachelinePadded<ExactlyCachelineSized>*>(item.get()) ==
- &item);
-}
-
-TEST(CachelinePadded, Double) {
- EXPECT_EQ(2 * kCachelineSize, sizeof(CachelinePadded<DoubleCachelineSized>));
- CachelinePadded<DoubleCachelineSized> item;
- item.get()->doModifications();
- EXPECT_TRUE(
- reinterpret_cast<CachelinePadded<DoubleCachelineSized>*>(item.get()) ==
- &item);
+template <typename T, size_t N = 1>
+using SizedDataMimic = SizedData<N * sizeof(T), alignof(T)>;
+
+template <typename T>
+struct CachelinePaddedTests : ::testing::Test {};
+
+using CachelinePaddedTypes = ::testing::Types<
+ SizedData<kCachelineSize>,
+ SizedData<2 * kCachelineSize>,
+ SizedData<kCachelineSize / 2>,
+ SizedData<kCachelineSize + kCachelineSize / 2>,
+ // Mimic single basic types:
+ SizedDataMimic<std::max_align_t>,
+ SizedDataMimic<void*>,
+ SizedDataMimic<long double>,
+ SizedDataMimic<double>,
+ SizedDataMimic<float>,
+ SizedDataMimic<long long>,
+ SizedDataMimic<long>,
+ SizedDataMimic<int>,
+ SizedDataMimic<short>,
+ SizedDataMimic<char>,
+ // Mimic small arrays of basic types:
+ SizedDataMimic<std::max_align_t, 3>,
+ SizedDataMimic<void*, 3>,
+ SizedDataMimic<long double, 3>,
+ SizedDataMimic<double, 3>,
+ SizedDataMimic<float, 3>,
+ SizedDataMimic<long long, 3>,
+ SizedDataMimic<long, 3>,
+ SizedDataMimic<int, 3>,
+ SizedDataMimic<short, 3>,
+ SizedDataMimic<char, 3>,
+ // Mimic large arrays of basic types:
+ SizedDataMimic<std::max_align_t, kCachelineSize + 3>,
+ SizedDataMimic<void*, kCachelineSize + 3>,
+ SizedDataMimic<long double, kCachelineSize + 3>,
+ SizedDataMimic<double, kCachelineSize + 3>,
+ SizedDataMimic<float, kCachelineSize + 3>,
+ SizedDataMimic<long long, kCachelineSize + 3>,
+ SizedDataMimic<long, kCachelineSize + 3>,
+ SizedDataMimic<int, kCachelineSize + 3>,
+ SizedDataMimic<short, kCachelineSize + 3>,
+ SizedDataMimic<char, kCachelineSize + 3>>;
+TYPED_TEST_CASE(CachelinePaddedTests, CachelinePaddedTypes);
+
+TYPED_TEST(CachelinePaddedTests, alignment) {
+ EXPECT_EQ(alignof(TypeParam), alignof(CachelinePadded<TypeParam>));
}
-TEST(CachelinePadded, Below) {
- EXPECT_EQ(kCachelineSize, sizeof(CachelinePadded<BelowCachelineSized>));
- CachelinePadded<BelowCachelineSized> item;
+TYPED_TEST(CachelinePaddedTests, integrity) {
+ CachelinePadded<TypeParam> item;
item.get()->doModifications();
- EXPECT_TRUE(
- reinterpret_cast<CachelinePadded<BelowCachelineSized>*>(item.get()) ==
- &item);
}
-TEST(CachelinePadded, Above) {
- EXPECT_EQ(2 * kCachelineSize, sizeof(CachelinePadded<AboveCachelineSized>));
- CachelinePadded<AboveCachelineSized> item;
- item.get()->doModifications();
- EXPECT_TRUE(
- reinterpret_cast<CachelinePadded<AboveCachelineSized>*>(item.get()) ==
- &item);
-}
-
-TEST(CachelinePadded, CanBeCastedBack) {
- CachelinePadded<int> padded;
- CachelinePadded<int>* ptr =
- reinterpret_cast<CachelinePadded<int>*>(padded.get());
- EXPECT_EQ(&padded, ptr);
+TYPED_TEST(CachelinePaddedTests, size) {
+ EXPECT_GT(
+ sizeof(TypeParam) + 2 * kCachelineSize,
+ sizeof(CachelinePadded<TypeParam>));
+ size_t const rawSize = sizeof(TypeParam);
+ size_t const rawAlign = alignof(TypeParam);
+ size_t const expectedPadding = kCachelineSize - (rawAlign % kCachelineSize);
+ size_t const expectedPaddedSize = rawSize + 2 * expectedPadding;
+ EXPECT_EQ(expectedPaddedSize, sizeof(CachelinePadded<TypeParam>));
}
TEST(CachelinePadded, PtrOperator) {