Add bytesUsed() to folly::Arena
[folly.git] / folly / test / SmallLocksTest.cpp
1 /*
2  * Copyright 2012 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/SmallLocks.h"
18 #include <cassert>
19 #include <cstdio>
20 #include <string>
21 #include <vector>
22 #include <pthread.h>
23 #include <unistd.h>
24
25 #include <thread>
26
27 #include <gtest/gtest.h>
28
29 using std::string;
30 using folly::MicroSpinLock;
31 using folly::PicoSpinLock;
32 using folly::MSLGuard;
33
34 namespace {
35
36 struct LockedVal {
37   int ar[1024];
38   MicroSpinLock lock;
39
40   LockedVal() {
41     lock.init();
42     memset(ar, 0, sizeof ar);
43   }
44 };
45
46 // Compile time test for packed struct support (requires that both of
47 // these classes are POD).
48 struct ignore1 { MicroSpinLock msl; int16_t foo; } __attribute__((packed));
49 struct ignore2 { PicoSpinLock<uint32_t> psl; int16_t foo; }
50   __attribute__((packed));
51 static_assert(sizeof(ignore1) == 3, "Size check failed");
52 static_assert(sizeof(ignore2) == 6, "Size check failed");
53
54 LockedVal v;
55 void splock_test() {
56
57   const int max = 1000;
58   unsigned int seed = (uintptr_t)pthread_self();
59   for (int i = 0; i < max; i++) {
60     asm("pause");
61     MSLGuard g(v.lock);
62
63     int first = v.ar[0];
64     for (int i = 1; i < sizeof v.ar / sizeof i; ++i) {
65       EXPECT_EQ(first, v.ar[i]);
66     }
67
68     int byte = rand_r(&seed);
69     memset(v.ar, char(byte), sizeof v.ar);
70   }
71 }
72
73 template<class T> struct PslTest {
74   PicoSpinLock<T> lock;
75
76   PslTest() { lock.init(); }
77
78   void doTest() {
79     T ourVal = rand() % (T(1) << (sizeof(T) * 8 - 1));
80     for (int i = 0; i < 10000; ++i) {
81       std::lock_guard<PicoSpinLock<T>> guard(lock);
82       lock.setData(ourVal);
83       for (int n = 0; n < 10; ++n) {
84         asm volatile("pause");
85         EXPECT_EQ(lock.getData(), ourVal);
86       }
87     }
88   }
89 };
90
91 template<class T>
92 void doPslTest() {
93   PslTest<T> testObj;
94
95   const int nthrs = 17;
96   std::vector<std::thread> threads;
97   for (int i = 0; i < nthrs; ++i) {
98     threads.push_back(std::thread(&PslTest<T>::doTest, &testObj));
99   }
100   for (auto& t : threads) {
101     t.join();
102   }
103 }
104
105 }
106
107 TEST(SmallLocks, SpinLockCorrectness) {
108   EXPECT_EQ(sizeof(MicroSpinLock), 1);
109
110   int nthrs = sysconf(_SC_NPROCESSORS_ONLN) * 2;
111   std::vector<std::thread> threads;
112   for (int i = 0; i < nthrs; ++i) {
113     threads.push_back(std::thread(splock_test));
114   }
115   for (auto& t : threads) {
116     t.join();
117   }
118 }
119
120 TEST(SmallLocks, PicoSpinCorrectness) {
121   doPslTest<int16_t>();
122   doPslTest<uint16_t>();
123   doPslTest<int32_t>();
124   doPslTest<uint32_t>();
125   doPslTest<int64_t>();
126   doPslTest<uint64_t>();
127 }
128
129 TEST(SmallLocks, PicoSpinSigned) {
130   typedef PicoSpinLock<int16_t,0> Lock;
131   Lock val;
132   val.init(-4);
133   EXPECT_EQ(val.getData(), -4);
134
135   {
136     std::lock_guard<Lock> guard(val);
137     EXPECT_EQ(val.getData(), -4);
138     val.setData(-8);
139     EXPECT_EQ(val.getData(), -8);
140   }
141   EXPECT_EQ(val.getData(), -8);
142 }