proxygen
PackedSyncPtrTest.cpp
Go to the documentation of this file.
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 #include <folly/PackedSyncPtr.h>
18 
19 #include <cinttypes>
20 #include <thread>
21 #include <unordered_map>
22 #include <utility>
23 
25 
27 
28 namespace {
29 
30 // Compile time check for packability. This requires that
31 // PackedSyncPtr is a POD struct on gcc.
33 struct ignore {
35  char c;
38 static_assert(sizeof(ignore) == 9, "PackedSyncPtr wasn't packable");
39 
40 } // namespace
41 
44  sp.init(new std::pair<int, int>[2]);
45  EXPECT_EQ(sizeof(sp), 8);
46  sp->first = 5;
47  EXPECT_EQ(sp[0].first, 5);
48  sp[1].second = 7;
49  EXPECT_EQ(sp[1].second, 7);
50  sp.lock();
51  EXPECT_EQ(sp[1].second, 7);
52  sp[0].first = 9;
53  EXPECT_EQ(sp->first, 9);
54  sp.unlock();
55  EXPECT_EQ((sp.get() + 1)->second, 7);
56 
57  sp.lock();
58  EXPECT_EQ(sp.extra(), 0);
59  sp.setExtra(0x13);
60  EXPECT_EQ(sp.extra(), 0x13);
61  EXPECT_EQ((sp.get() + 1)->second, 7);
62  delete[] sp.get();
63  auto newP = new std::pair<int, int>();
64  sp.set(newP);
65  EXPECT_EQ(sp.extra(), 0x13);
66  EXPECT_EQ(sp.get(), newP);
67  sp.unlock();
68  delete sp.get();
69 }
70 
71 // Here we use the PackedSyncPtr to lock the whole SyncVec (base, *base, and sz)
72 template <typename T>
73 struct SyncVec {
75  SyncVec() {
76  base.init();
77  }
79  free(base.get());
80  }
81  void push_back(const T& t) {
82  base.set((T*)realloc(base.get(), (base.extra() + 1) * sizeof(T)));
83  base[base.extra()] = t;
84  base.setExtra(base.extra() + 1);
85  }
86  void lock() {
87  base.lock();
88  }
89  void unlock() {
90  base.unlock();
91  }
92 
93  T* begin() const {
94  return base.get();
95  }
96  T* end() const {
97  return base.get() + base.extra();
98  }
99 };
101 typedef std::unordered_map<int64_t, VecT> Map;
102 const int mapCap = 1317;
103 const int nthrs = 297;
104 static Map map(mapCap);
105 
106 // Each app thread inserts it's ID into every vec in map
107 // map is read only, so doesn't need any additional locking
108 void appThread(intptr_t id) {
109  for (auto& kv : map) {
110  kv.second.lock();
111  kv.second.push_back(id);
112  kv.second.unlock();
113  }
114 }
115 
117  for (int64_t i = 0; i < mapCap / 2; ++i) {
118  map.insert(std::make_pair(i, VecT()));
119  }
120  std::vector<std::thread> thrs;
121  for (intptr_t i = 0; i < nthrs; i++) {
122  thrs.push_back(std::thread(appThread, i));
123  }
124  for (auto& t : thrs) {
125  t.join();
126  }
127 
128  for (auto& kv : map) {
129  // Make sure every thread successfully inserted it's ID into every vec
130  std::set<intptr_t> idsFound;
131  for (auto& elem : kv.second) {
132  EXPECT_TRUE(idsFound.insert(elem).second); // check for dups
133  }
134  EXPECT_EQ(idsFound.size(), nthrs); // check they are all there
135  }
136 }
137 
138 TEST(PackedSyncPtr, extraData) {
140  p.init();
141  int* unaligned = reinterpret_cast<int*>(0xf003);
142  p.lock();
143  p.set(unaligned);
144  uintptr_t* bytes = reinterpret_cast<uintptr_t*>(&p);
145  LOG(INFO) << "Bytes integer is: 0x" << std::hex << *bytes;
146  EXPECT_EQ(p.get(), unaligned);
147  p.unlock();
148 }
#define T(v)
Definition: http_parser.c:233
uint16_t extra() const
T * begin() const
T * end() const
void setExtra(uint16_t extra)
#define FOLLY_PACK_ATTR
Definition: Portability.h:144
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
PackedSyncPtr< T > base
void unlock() const
SyncVec< intptr_t > VecT
void push_back(const T &t)
std::unordered_map< int64_t, VecT > Map
void init(T *initialPtr=nullptr, uint16_t initialExtra=0)
Definition: PackedSyncPtr.h:77
const int nthrs
FOLLY_PACK_PUSH
static Map map(mapCap)
Definition: Traits.h:594
void appThread(intptr_t id)
void free()
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
TEST(PackedSyncPtr, Basic)
void lock() const
const int mapCap
char c
constexpr detail::First first
Definition: Base-inl.h:2553