• 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 "safe_queue.h"
18 #include <array>
19 #include <future>
20 #include <iostream>
21 #include <thread>
22 #include <chrono>
23 #include "../log.h"
24 #include "../assert.h"
25 using namespace std;
26 
27 namespace OHOS {
28 namespace {
29 
30 const unsigned int QUEUE_SLOTS = 10;
31 const unsigned int THREAD_NUM = QUEUE_SLOTS + 1;
32 const int TIME_INCREMENT = 2;
33 const int SLEEP_FOR_TWO_SECONDS = 2;
34 const int SLEEP_FOR_THREE_SECONDS = 3;
35 const int SLEEP_FOR_FOUR_SECONDS = 4;
36 
37 class BenchmarkSafeQueue : public benchmark::Fixture {
38 public:
BenchmarkSafeQueue()39     BenchmarkSafeQueue()
40     {
41         Iterations(iterations);
42         Repetitions(repetitions);
43         ReportAggregatesOnly();
44     }
45 
46     ~BenchmarkSafeQueue() override = default;
SetUp(const::benchmark::State & state)47     void SetUp(const ::benchmark::State& state) override
48     {
49     }
50 
TearDown(const::benchmark::State & state)51     void TearDown(const ::benchmark::State& state) override
52     {
53     }
54 
55 protected:
56     const int32_t repetitions = 3;
57     const int32_t iterations = 50;
58 };
59 
60 class DemoThreadData {
61 public:
DemoThreadData()62     DemoThreadData()
63     {
64         putStatus = false;
65         getStatus = false;
66         eraseStatus = false;
67         emptyStatus = false;
68     }
69     static SafeQueue<int> shareQueue;
70     bool putStatus;
71     bool getStatus;
72     bool eraseStatus;
73     bool emptyStatus;
74 
Put(int i)75     void Put(int i)
76     {
77         shareQueue.Push(i);
78         putStatus = true;
79     }
80 
Get(int & i)81     void Get(int &i)
82     {
83         shareQueue.Pop(i);
84         getStatus = true;
85     }
86 
Erase(int & i)87     void Erase(int &i)
88     {
89         shareQueue.Erase(i);
90         eraseStatus = true;
91     }
92 
Empty()93     void Empty()
94     {
95         shareQueue.Empty();
96         emptyStatus = true;
97     }
98 };
99 
100 SafeQueue<int> DemoThreadData::shareQueue;
101 
PutHandleThreadDataTime(DemoThreadData & q,int i,std::chrono::system_clock::time_point absTime)102 void PutHandleThreadDataTime(DemoThreadData &q, int i, std::chrono::system_clock::time_point absTime)
103 {
104     BENCHMARK_LOGD("SafeQueue PutHandleThreadDataTime is called i:%{public}d .", i);
105     std::this_thread::sleep_until(absTime);
106 
107     q.Put(i);
108 }
109 
GetHandleThreadDataTime(DemoThreadData & q,int i,std::chrono::system_clock::time_point absTime)110 void GetHandleThreadDataTime(DemoThreadData &q, int i, std::chrono::system_clock::time_point absTime)
111 {
112     BENCHMARK_LOGD("SafeQueue GetHandleThreadDataTime is called i:%{public}d.", i);
113     std::this_thread::sleep_until(absTime);
114     int t = 0;
115     q.Get(t);
116 }
117 
EraseHandleThreadDataTime(DemoThreadData & q,int i,std::chrono::system_clock::time_point absTime)118 void EraseHandleThreadDataTime(DemoThreadData &q, int i, std::chrono::system_clock::time_point absTime)
119 {
120     BENCHMARK_LOGD("SafeQueue EraseHandleThreadDataTime is called i:%{public}d.", i);
121     std::this_thread::sleep_until(absTime);
122 
123     q.Erase(i);
124 }
125 
EmptyHandleThreadDataTime(DemoThreadData & q,std::chrono::system_clock::time_point absTime)126 void EmptyHandleThreadDataTime(DemoThreadData &q, std::chrono::system_clock::time_point absTime)
127 {
128     BENCHMARK_LOGD("SafeQueue EmptyHandleThreadDataTime is called.");
129     std::this_thread::sleep_until(absTime);
130 
131     q.Empty();
132 }
133 
134 class TestThreading {
135 public:
TestThreading()136     TestThreading()
137     {
138         demoDatas.fill(DemoThreadData());
139     }
140 
AllThreadPut(std::time_t & timeT)141     void AllThreadPut(std::time_t &timeT)
142     {
143         using std::chrono::system_clock;
144         for (unsigned int i = 0; i < THREAD_NUM; i++) {
145             threads[i] = std::thread(PutHandleThreadDataTime,
146                 std::ref(demoDatas[i]), i, system_clock::from_time_t(timeT));
147         }
148     }
AllThreadGet(std::time_t & timeT)149     void AllThreadGet(std::time_t &timeT)
150     {
151         using std::chrono::system_clock;
152         for (unsigned int i = 0; i < THREAD_NUM; i++) {
153             threads[i] = std::thread(GetHandleThreadDataTime,
154                 std::ref(demoDatas[i]), i, system_clock::from_time_t(timeT));
155         }
156     }
157 
AllThreadErase(std::time_t & timeT)158     void AllThreadErase(std::time_t &timeT)
159     {
160         using std::chrono::system_clock;
161         for (unsigned int i = 0; i < THREAD_NUM; i++) {
162             threads[i] = std::thread(EraseHandleThreadDataTime,
163                 std::ref(demoDatas[i]), i, system_clock::from_time_t(timeT));
164         }
165     }
166 
AllThreadEmpty(std::time_t & timeT)167     void AllThreadEmpty(std::time_t &timeT)
168     {
169         using std::chrono::system_clock;
170         for (unsigned int i = 0; i < THREAD_NUM; i++) {
171             threads[i] = std::thread(EmptyHandleThreadDataTime,
172                 std::ref(demoDatas[i]), system_clock::from_time_t(timeT));
173         }
174     }
175 
GetThreadDatePushedStatus(unsigned int & pushedIn,unsigned int & unpushedIn)176     void GetThreadDatePushedStatus(unsigned int &pushedIn, unsigned int &unpushedIn)
177     {
178         pushedIn = 0;
179         unpushedIn = 0;
180         for (auto &t : demoDatas) {
181             if (t.putStatus) {
182                 pushedIn++;
183             } else {
184                 unpushedIn++;
185             }
186         }
187         BENCHMARK_LOGD("SafeQueue GetThreadDatePushedStatus pIn:%{public}d upIn:%{public}d.", pushedIn, unpushedIn);
188     }
189 
GetThreadDateGetedStatus(unsigned int & getedOut,unsigned int & ungetedOut)190     void GetThreadDateGetedStatus(unsigned int &getedOut, unsigned int &ungetedOut)
191     {
192         BENCHMARK_LOGD("SafeQueue void GetThreadDateGetedStatus is called.");
193         getedOut = 0;
194         ungetedOut = 0;
195         for (auto &t : demoDatas) {
196             if (t.getStatus) {
197                 getedOut++;
198             } else {
199                 ungetedOut++;
200             }
201         }
202         BENCHMARK_LOGD("SafeQueue GetThreadDateGetedStatus gOut:%{public}d uOut:%{public}d.", getedOut, ungetedOut);
203     }
204 
GetThreadDateEraseStatus(unsigned int & erase,unsigned int & unErase)205     void GetThreadDateEraseStatus(unsigned int &erase, unsigned int &unErase)
206     {
207         erase = 0;
208         unErase = 0;
209         for (auto &t : demoDatas) {
210             if (t.eraseStatus) {
211                 erase++;
212             } else {
213                 unErase++;
214             }
215         }
216         BENCHMARK_LOGD("SafeQueue GetThreadDateEraseStatus erase:%{public}d unErase:%{public}d.", erase, unErase);
217     }
218 
GetThreadDateEmptyStatus(unsigned int & empty,unsigned int & unEmpty)219     void GetThreadDateEmptyStatus(unsigned int &empty, unsigned int &unEmpty)
220     {
221         empty = 0;
222         unEmpty = 0;
223         for (auto &t : demoDatas) {
224             if (t.emptyStatus) {
225                 empty++;
226             } else {
227                 unEmpty++;
228             }
229         }
230         BENCHMARK_LOGD("SafeQueue GetThreadDateEmptyStatus empty:%{public}d unEmpty:%{public}d.", empty, unEmpty);
231     }
232 
ResetStatus()233     void ResetStatus()
234     {
235         BENCHMARK_LOGD("SafeQueue void ResetStatus is called.");
236         for (auto &t : threads) {
237             t.join();
238         }
239 
240         DemoThreadData::shareQueue.Clear();
241     }
242 
243     std::thread threads[THREAD_NUM];
244     std::array<DemoThreadData, THREAD_NUM> demoDatas;
245 };
246 
247 /*
248 * Feature: SafeBlockQueue
249 * Function:put
250 * SubFunction: NA
251 * FunctionPoints:
252 * EnvConditions: NA
253 * CaseDescription: Multiple threads put, one thread gets, all threads finish running normally
254 */
BENCHMARK_F(BenchmarkSafeQueue,testMutilthreadPutAndOneThreadGetOnemptyQueue)255 BENCHMARK_F(BenchmarkSafeQueue, testMutilthreadPutAndOneThreadGetOnemptyQueue)(benchmark::State& state)
256 {
257     BENCHMARK_LOGD("SafeQueue testMutilthreadPutAndOneThreadGetOnemptyQueue start.");
258     while (state.KeepRunning()) {
259         TestThreading testThread;
260         using std::chrono::system_clock;
261         std::time_t timeT = system_clock::to_time_t(system_clock::now());
262         timeT += TIME_INCREMENT;
263         testThread.AllThreadPut(timeT);
264 
265         // 1. queue is full and some threads is blocked
266         std::this_thread::sleep_for(std::chrono::seconds(SLEEP_FOR_THREE_SECONDS));
267         AssertTrue((DemoThreadData::shareQueue.Size() > 0),
268             "DemoThreadData::shareQueue.Size() > 0 did not equal true as expected.", state);
269 
270         unsigned int pushedIn = 0;
271         unsigned int unpushedIn = 0;
272 
273         testThread.GetThreadDatePushedStatus(pushedIn, unpushedIn);
274         AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state);
275 
276         //2.  get one out  and wait some put in
277         for (unsigned int i = 0; i < THREAD_NUM; i++) {
278             int t = 0;
279             testThread.demoDatas[0].Get(t);
280         }
281 
282         std::this_thread::sleep_for(std::chrono::seconds(SLEEP_FOR_TWO_SECONDS));
283         // queue is full and some threads is blocked and is not joined
284         AssertTrue((DemoThreadData::shareQueue.Size() == 0),
285             "DemoThreadData::shareQueue.Size() == 0 did not equal true as expected.", state);
286 
287         // here means all thread end ok or if some operation blocked and the testcase blocked
288         testThread.ResetStatus();
289     }
290     BENCHMARK_LOGD("SafeQueue testMutilthreadPutAndOneThreadGetOnemptyQueue end.");
291 }
292 
293 /*
294 * Feature: SafeBlockQueue
295 * Function:put
296 * SubFunction: NA
297 * FunctionPoints:
298 * EnvConditions: NA
299 * CaseDescription: Multi-threaded put() and Multi-threaded get() on the empty queue.
300 * When all threads are waiting to reach a certain
301 * time-point, everyone run concurrently to see the status of the queue and the state of the thread.
302 */
BENCHMARK_F(BenchmarkSafeQueue,testMutilthreadPutAndGetConcurrently)303 BENCHMARK_F(BenchmarkSafeQueue, testMutilthreadPutAndGetConcurrently)(benchmark::State& state)
304 {
305     BENCHMARK_LOGD("SafeQueue testMutilthreadPutAndGetConcurrently start.");
306     while (state.KeepRunning()) {
307         using std::chrono::system_clock;
308         std::time_t timeT = system_clock::to_time_t(system_clock::now());
309         timeT += TIME_INCREMENT;
310 
311         TestThreading putInTestThread;
312         putInTestThread.AllThreadPut(timeT);
313 
314         TestThreading getOutTestThread;
315         getOutTestThread.AllThreadGet(timeT);
316 
317         // 1. queue is full and some threads is blocked
318         std::this_thread::sleep_for(std::chrono::seconds(SLEEP_FOR_FOUR_SECONDS));
319 
320         unsigned int pushedIn = 0;
321         unsigned int unpushedIn = 0;
322         unsigned int getedOut = 0;
323         unsigned int ungetedOut = 0;
324         putInTestThread.GetThreadDatePushedStatus(pushedIn, unpushedIn);
325         getOutTestThread.GetThreadDateGetedStatus(getedOut, ungetedOut);
326         AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state);
327         AssertEqual(getedOut, THREAD_NUM, "getedOut did not equal THREAD_NUM as expected.", state);
328 
329         putInTestThread.ResetStatus();
330         getOutTestThread.ResetStatus();
331     }
332     BENCHMARK_LOGD("SafeQueue testMutilthreadPutAndGetConcurrently end.");
333 }
334 
335 /*
336 * Feature: SafeBlockQueue
337 * Function:put
338 * SubFunction: NA
339 * FunctionPoints:
340 * EnvConditions: NA
341 * CaseDescription: Multi-threaded put() and Multi-threaded get() on the not empty queue.
342 * When all threads are waiting to reach a certain
343 * time-point, everyone run concurrently to see the status of the queue and the state of the thread.
344 */
BENCHMARK_F(BenchmarkSafeQueue,testMutilthreadConcurrentGetAndPopInNotEmptyQueue)345 BENCHMARK_F(BenchmarkSafeQueue, testMutilthreadConcurrentGetAndPopInNotEmptyQueue)(benchmark::State& state)
346 {
347     BENCHMARK_LOGD("SafeQueue testMutilthreadConcurrentGetAndPopInNotEmptyQueue start.");
348     while (state.KeepRunning()) {
349         //1. prepare
350         using std::chrono::system_clock;
351         std::time_t timeT = system_clock::to_time_t(system_clock::now());
352         timeT += TIME_INCREMENT;
353 
354         AssertTrue((DemoThreadData::shareQueue.Size() == 0),
355             "DemoThreadData::shareQueue.Size() == 0 did not equal true as expected.", state);
356 
357         int t = 1;
358         for (unsigned int i = 0; i < THREAD_NUM; i++) {
359             DemoThreadData::shareQueue.Push(t);
360         }
361 
362         AssertTrue((DemoThreadData::shareQueue.Size() == THREAD_NUM),
363             "DemoThreadData::shareQueue.Size() == THREAD_NUM did not equal true as expected.", state);
364 
365         //2. start thread put in not full queue
366         TestThreading putInTestThread;
367         putInTestThread.AllThreadPut(timeT);
368 
369         TestThreading getOutTestThread;
370         getOutTestThread.AllThreadGet(timeT);
371 
372         std::this_thread::sleep_for(std::chrono::seconds(SLEEP_FOR_THREE_SECONDS));
373         AssertTrue((DemoThreadData::shareQueue.Size() == THREAD_NUM),
374             "DemoThreadData::shareQueue.Size() == THREAD_NUM did not equal true as expected.", state);
375 
376         unsigned int getedOut = 0;
377         unsigned int ungetedOut = 0;
378         unsigned int pushedIn = 0;
379         unsigned int unpushedIn = 0;
380         getOutTestThread.GetThreadDateGetedStatus(getedOut, ungetedOut);
381         putInTestThread.GetThreadDatePushedStatus(pushedIn, unpushedIn);
382         AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state);
383         AssertEqual(getedOut, THREAD_NUM, "getedOut did not equal THREAD_NUM as expected.", state);
384 
385         // 3. reset status
386         putInTestThread.ResetStatus();
387         getOutTestThread.ResetStatus();
388     }
389     BENCHMARK_LOGD("SafeQueue testMutilthreadConcurrentGetAndPopInNotEmptyQueue end.");
390 }
391 
392 /*
393 * Feature: SafeBlockQueue
394 * Function:erase empty
395 * SubFunction: NA
396 * FunctionPoints:
397 * EnvConditions: NA
398 * CaseDescription: Multi-threaded erase() and Multi-threaded empty() on the empty queue.
399 * When all threads are waiting to reach a certain
400 * time-point, everyone run concurrently to see the status of the queue and the state of the thread.
401 */
BENCHMARK_F(BenchmarkSafeQueue,testMutilthreadEraseAndEmptyConcurrently)402 BENCHMARK_F(BenchmarkSafeQueue, testMutilthreadEraseAndEmptyConcurrently)(benchmark::State& state)
403 {
404     BENCHMARK_LOGD("SafeQueue testMutilthreadEraseAndEmptyConcurrently start.");
405     while (state.KeepRunning()) {
406         using std::chrono::system_clock;
407         std::time_t timeT = system_clock::to_time_t(system_clock::now());
408         timeT += TIME_INCREMENT;
409 
410         TestThreading putThread;
411         putThread.AllThreadPut(timeT);
412 
413         TestThreading eraseThread;
414         eraseThread.AllThreadErase(timeT);
415 
416         TestThreading emptyThread;
417         emptyThread.AllThreadEmpty(timeT);
418         std::this_thread::sleep_for(std::chrono::seconds(SLEEP_FOR_FOUR_SECONDS));
419 
420         unsigned int pushedIn = 0;
421         unsigned int unpushedIn = 0;
422         unsigned int erase = 0;
423         unsigned int unerase = 0;
424         unsigned int empty = 0;
425         unsigned int unempty = 0;
426         putThread.GetThreadDatePushedStatus(pushedIn, unpushedIn);
427         eraseThread.GetThreadDateEraseStatus(erase, unerase);
428         emptyThread.GetThreadDateEmptyStatus(empty, unempty);
429         AssertEqual(pushedIn, THREAD_NUM, "pushedIn did not equal THREAD_NUM as expected.", state);
430         AssertEqual(erase, THREAD_NUM, "erase did not equal THREAD_NUM as expected.", state);
431         AssertEqual(empty, THREAD_NUM, "empty did not equal THREAD_NUM as expected.", state);
432 
433         putThread.ResetStatus();
434         eraseThread.ResetStatus();
435         emptyThread.ResetStatus();
436     }
437     BENCHMARK_LOGD("SafeQueue testMutilthreadEraseAndEmptyConcurrently end.");
438 }
439 }  // namespace
440 }  // namespace OHOS
441 // Run the benchmark
442 BENCHMARK_MAIN();