• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <benchmark/benchmark.h>
17 #include <thread>
18 #include <string>
19 #include "rwlock.h"
20 #include "../log.h"
21 #include "../assert.h"
22 using namespace std;
23 
24 namespace OHOS {
25 namespace {
26 
27 class BenchmarkRWLockTest : public benchmark::Fixture {
28 public:
BenchmarkRWLockTest()29     BenchmarkRWLockTest()
30     {
31         Iterations(iterations);
32         Repetitions(repetitions);
33         ReportAggregatesOnly();
34     }
35 
36     ~BenchmarkRWLockTest() override = default;
SetUp(const::benchmark::State & state)37     void SetUp(const ::benchmark::State& state) override
38     {
39     }
40 
TearDown(const::benchmark::State & state)41     void TearDown(const ::benchmark::State& state) override
42     {
43     }
44 
45 protected:
46     const int32_t repetitions = 3;
47     const int32_t iterations = 1000;
48 };
49 
50 const int SLEEP_DURATION_MS = 4;
51 
52 // This class is designed for test RWLock. "buf_" is protected by "rwLock_".
53 class TestRWLock {
54 public:
TestRWLock()55     TestRWLock():rwLock_(), buf_() {}
56 
TestRWLock(bool writeFirst)57     explicit TestRWLock(bool writeFirst):rwLock_(writeFirst), buf_() {}
58 
WriteStr(const string & str)59     void WriteStr(const string& str)
60     {
61         BENCHMARK_LOGD("RWLockTest void WriteStr is called.");
62         rwLock_.LockWrite();
63         for (auto it = str.begin(); it != str.end(); it++) {
64             buf_.push_back(*it);
65             this_thread::sleep_for(std::chrono::milliseconds(10)); // 10: Extend time of holding the lock
66         }
67         rwLock_.UnLockWrite();
68         return;
69     }
70 
ReadStr(string & str)71     void ReadStr(string& str)
72     {
73         BENCHMARK_LOGD("RWLockTest void ReadStr is called.");
74         rwLock_.LockRead();
75         for (auto it = buf_.begin(); it != buf_.end(); it++) {
76             str.push_back(*it);
77             this_thread::sleep_for(std::chrono::milliseconds(10)); // 10: Extend time of holding the lock
78         }
79         rwLock_.UnLockRead();
80         return;
81     }
82 private:
83     Utils::RWLock rwLock_;
84     string buf_;
85 };
86 
87 const string WRITE_IN_1("write1");
88 const string WRITE_IN_2("write2");
89 
90 /*
91  * @tc.name: testRWLock001
92  * @tc.desc: RWLock here is under write-first mode. If there are some writing operation waiting,
93  * reading will never happen. Reading operations are likely to run at the same time, when all writing operations
94  * have finished.
95  */
BENCHMARK_F(BenchmarkRWLockTest,testRWLock001)96 BENCHMARK_F(BenchmarkRWLockTest, testRWLock001)(benchmark::State& state)
97 {
98     BENCHMARK_LOGD("RWLockTest testRWLock001 start.");
99     while (state.KeepRunning()) {
100         TestRWLock test;
101 
102         thread first(bind(&TestRWLock::WriteStr, ref(test), ref(WRITE_IN_1)));
103         // Try our best to make `first` get the lock
104         this_thread::sleep_for(std::chrono::milliseconds(SLEEP_DURATION_MS));
105 
106         string readOut1("");
107         thread second(bind(&TestRWLock::ReadStr, ref(test), ref(readOut1)));
108         thread third(bind(&TestRWLock::WriteStr, ref(test), ref(WRITE_IN_2)));
109         string readOut2("");
110         thread fourth(bind(&TestRWLock::ReadStr, ref(test), ref(readOut2)));
111 
112 
113         first.join();
114         second.join();
115         third.join();
116         fourth.join();
117 
118         AssertEqual(readOut1, WRITE_IN_1 + WRITE_IN_2,
119             "readOut1 did not equal WRITE_IN_1 + WRITE_IN_2 as expected.", state);
120         AssertEqual(readOut2, WRITE_IN_1 + WRITE_IN_2,
121             "readOut2 did not equal WRITE_IN_1 + WRITE_IN_2 as expected.", state);
122     }
123     BENCHMARK_LOGD("RWLockTest testRWLock001 end.");
124 }
125 
126 /*
127  * @tc.name: testRWLock002
128  * @tc.desc: RWLock here is not under write-first mode. So if there are writing and reading operations in queue
129  * with a writing mission running, they will compete when the writing mission completing, but reading operations are
130  * likely to run at the same time.
131  */
BENCHMARK_F(BenchmarkRWLockTest,testRWLock002)132 BENCHMARK_F(BenchmarkRWLockTest, testRWLock002)(benchmark::State& state)
133 {
134     BENCHMARK_LOGD("RWLockTest testRWLock002 start.");
135     while (state.KeepRunning()) {
136         TestRWLock test(false);
137 
138         thread first(bind(&TestRWLock::WriteStr, ref(test), ref(WRITE_IN_1)));
139         this_thread::sleep_for(chrono::milliseconds(SLEEP_DURATION_MS));
140 
141         string readOut1("");
142         thread second(bind(&TestRWLock::ReadStr, ref(test), ref(readOut1)));
143         thread third(bind(&TestRWLock::WriteStr, ref(test), ref(WRITE_IN_2)));
144         string readOut2("");
145         thread fourth(bind(&TestRWLock::ReadStr, ref(test), ref(readOut2)));
146 
147         first.join();
148         second.join();
149         third.join();
150         fourth.join();
151 
152         AssertEqual(readOut1, readOut2, "readOut1 did not equal readOut2 as expected.", state);
153     }
154     BENCHMARK_LOGD("RWLockTest testRWLock002 end.");
155 }
156 
157 /*
158  * @tc.name: testRWLockDefaultConstructor001
159  * @tc.desc: This test case validates the default constructor of RWLock. By default, the RWLock is in write-first mode.
160  * In this mode, if there are pending write operations, read operations will not occur. This test case creates
161  * a default RWLock and attempts to perform read operations while write operations are pending.
162  * The expected behavior is that the read operations should not occur until the write operations are complete.
163  */
BENCHMARK_F(BenchmarkRWLockTest,testRWLockDefaultConstructor001)164 BENCHMARK_F(BenchmarkRWLockTest, testRWLockDefaultConstructor001)(benchmark::State& state)
165 {
166     BENCHMARK_LOGD("RWLockTest testRWLockDefaultConstructor001 start.");
167     while (state.KeepRunning()) {
168         TestRWLock test;
169 
170         thread first(bind(&TestRWLock::WriteStr, ref(test), ref(WRITE_IN_1)));
171         this_thread::sleep_for(std::chrono::milliseconds(SLEEP_DURATION_MS));
172 
173         string readOut1("");
174         thread second(bind(&TestRWLock::ReadStr, ref(test), ref(readOut1)));
175 
176         first.join();
177         second.join();
178 
179         AssertEqual(readOut1, WRITE_IN_1, "readOut1 did not equal WRITE_IN_1 as expected.", state);
180     }
181     BENCHMARK_LOGD("RWLockTest testRWLockDefaultConstructor001 end.");
182 }
183 
184 /*
185  * @tc.name: testUniqueWriteGuardScope001
186  * @tc.desc: This benchmark test is designed to test the functionality of the UniqueWriteGuard class.
187  * In this test, a write lock is acquired on an instance of the RWLock class using an instance of
188  * the UniqueWriteGuard class. The WriteStr method of the TestRWLock class is then called to write a string to
189  * the buffer of the TestRWLock instance. After the write operation, the write lock is automatically released
190  * because the UniqueWriteGuard instance goes out of scope. The ReadStr method of the TestRWLock class is then called
191  * to read the string from the buffer of the TestRWLock instance. If the read string does not match the written
192  * string, the test fails and an error message is logged. This test case is repeated multiple times to measure
193  * the performance of the write lock operation.
194  */
BENCHMARK_F(BenchmarkRWLockTest,testUniqueWriteGuardScope001)195 BENCHMARK_F(BenchmarkRWLockTest, testUniqueWriteGuardScope001)(benchmark::State& state)
196 {
197     BENCHMARK_LOGD("RWLockTest testUniqueWriteGuardScope001 start.");
198     while (state.KeepRunning()) {
199         OHOS::Utils::RWLock rwLock_;
200         TestRWLock test;
201         string readOut1("");
202         OHOS::Utils::UniqueWriteGuard<OHOS::Utils::RWLock> guard(rwLock_);
203         test.WriteStr(WRITE_IN_1);
204         test.ReadStr(readOut1);
205         AssertEqual(readOut1, WRITE_IN_1, "readOut1 did not equal WRITE_IN_1 as expected.", state);
206     }
207     BENCHMARK_LOGD("RWLockTest testUniqueWriteGuardScope001 end.");
208 }
209 
210 /*
211  * @tc.name: testUniqueReadGuardScope001
212  * @tc.desc: This benchmark test is designed to test the functionality of the UniqueReadGuard class.
213  * In this test, a read lock is acquired on an instance of the RWLock class using an instance of
214  * the UniqueReadGuard class. The ReadStr method of the TestRWLock class is then called to read the string from
215  * the buffer of the TestRWLock instance. After the read operation, the read lock is automatically released because
216  * the UniqueReadGuard instance goes out of scope. This test case is repeated multiple times to measure
217  * the performance of the read lock operation.
218  */
BENCHMARK_F(BenchmarkRWLockTest,testUniqueReadGuardScope001)219 BENCHMARK_F(BenchmarkRWLockTest, testUniqueReadGuardScope001)(benchmark::State& state)
220 {
221     BENCHMARK_LOGD("RWLockTest testUniqueReadGuardScope001 start.");
222     while (state.KeepRunning()) {
223         OHOS::Utils::RWLock rwLock_;
224         TestRWLock test;
225         string readOut1("");
226         test.WriteStr(WRITE_IN_1);  // Write a string to the buffer before acquiring the read lock.
227         OHOS::Utils::UniqueReadGuard<OHOS::Utils::RWLock> guard(rwLock_);
228         test.ReadStr(readOut1);
229         AssertEqual(readOut1, WRITE_IN_1, "readOut1 did not equal WRITE_IN_1 as expected.", state);
230     }
231     BENCHMARK_LOGD("RWLockTest testUniqueReadGuardScope001 end.");
232 }
233 }  // namespace
234 }  // namespace OHOS
235 // Run the benchmark
236 BENCHMARK_MAIN();
237