PackedSyncPtrTest.cpp 3.6 KB

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