• 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 <gtest/gtest.h>
17 
18 #define private public
19 #define protected public
20 
21 #include "ffrt_inner.h"
22 #include "ffrt.h"
23 #include "tm/scpu_task.h"
24 #include "eu/sexecute_unit.h"
25 #include "sched/stask_scheduler.h"
26 #include "../common.h"
27 
28 using namespace std;
29 using namespace testing;
30 #ifdef HWTEST_TESTING_EXT_ENABLE
31 using namespace testing::ext;
32 #endif
33 using namespace ffrt;
34 
35 class ExecuteUnitTest : public testing::Test {
36 protected:
SetUpTestCase()37     static void SetUpTestCase()
38     {
39     }
40 
TearDownTestCase()41     static void TearDownTestCase()
42     {
43     }
44 
SetUp()45     void SetUp() override
46     {
47     }
48 
TearDown()49     void TearDown() override
50     {
51     }
52 };
53 
54 /*
55 * 测试用例名称:ffrt_worker_escape
56 * 测试用例描述:ffrt_worker_escape接口测试
57 * 预置条件    :无
58 * 操作步骤    :调用enable和disable接口
59 * 预期结果    :正常参数enable成功,非法参数或者重复调用enable失败
60 */
61 HWTEST_F(ExecuteUnitTest, ffrt_worker_escape, TestSize.Level0)
62 {
63     EXPECT_EQ(ffrt::enable_worker_escape(0, 0, 0, 0, 0), 1);
64     EXPECT_EQ(ffrt::enable_worker_escape(10, 0, 0, 0, 0), 1);
65     EXPECT_EQ(ffrt::enable_worker_escape(10, 100, 0, 0, 0), 1);
66     EXPECT_EQ(ffrt::enable_worker_escape(10, 100, 1000, 10, 0), 1);
67     EXPECT_EQ(ffrt::enable_worker_escape(), 0);
68     EXPECT_EQ(ffrt::enable_worker_escape(), 1);
69     ffrt::disable_worker_escape();
70 }
71 
72 /*
73 * 测试用例名称:notify_workers
74 * 测试用例描述:notify_workers接口测试
75 * 预置条件    :无
76 * 操作步骤    :1.提交5个任务,执行完等待worker休眠
77                2.调用notify_workers接口,传入number为6
78 * 预期结果    :接口调用成功
79 */
80 HWTEST_F(ExecuteUnitTest, notify_workers, TestSize.Level0)
81 {
82     constexpr int count = 5;
83     std::atomic_int number = 0;
84     for (int i = 0; i < count; i++) {
__anon372b85b30102() 85         ffrt::submit([&]() {
86             number++;
87         });
88     }
89     sleep(1);
90     ffrt::notify_workers(2, 6);
91     EXPECT_EQ(count, number);
92 }
93 
94 /*
95 * 测试用例名称:ffrt_escape_submit_execute
96 * 测试用例描述:调用EU的逃生函数
97 * 预置条件    :创建SExecuteUnit
98 * 操作步骤    :调用ExecuteEscape、SubmitEscape、ReportEscapeEvent,包括异常分支
99 * 预期结果    :成功执行ExecuteEscape、SubmitEscape、ReportEscapeEvent方法
100 */
101 HWTEST_F(ExecuteUnitTest, ffrt_escape_submit_execute, TestSize.Level0)
102 {
103     auto manager = std::make_unique<ffrt::SExecuteUnit>();
104     EXPECT_EQ(manager->SetEscapeEnable(10, 100, 1000, 0, 30), 0);
105     manager->ExecuteEscape(qos_default);
106     manager->SubmitEscape(qos_default, 1);
107     manager->SubmitEscape(qos_default, 1);
108     manager->ReportEscapeEvent(qos_default, 1);
109 }
110 
111 /*
112 * 测试用例名称:ffrt_inc_worker_abnormal
113 * 测试用例描述:调用EU的IncWorker函数
114 * 预置条件    :创建SExecuteUnit
115 * 操作步骤    :1.调用方法IncWorker,传入异常参数
116                2.设置tearDown为true,调用IncWorker
117 * 预期结果    :返回false
118 */
119 HWTEST_F(ExecuteUnitTest, ffrt_inc_worker_abnormal, TestSize.Level0)
120 {
121     auto manager = std::make_unique<ffrt::SExecuteUnit>();
122     EXPECT_EQ(manager->IncWorker(QoS(-1)), false);
123     manager->tearDown = true;
124     EXPECT_EQ(manager->IncWorker(QoS(qos_default)), false);
125 }
126 
127 /**
128  * @tc.name: BindWG
129  * @tc.desc: Test whether the BindWG interface are normal.
130  * @tc.type: FUNC
131  */
132 HWTEST_F(ExecuteUnitTest, BindWG, TestSize.Level0)
133 {
134     auto qos1 = std::make_unique<QoS>();
135     FFRTFacade::GetEUInstance().BindWG(*qos1);
136     EXPECT_EQ(*qos1, qos_default);
137 }
138 
139 /**
140  * @tc.name: UnbindTG
141  * @tc.desc: Test whether the UnbindTG interface are normal.
142  * @tc.type: FUNC
143  */
144 HWTEST_F(ExecuteUnitTest, UnbindTG, TestSize.Level0)
145 {
146     auto qos1 = std::make_unique<QoS>();
147     FFRTFacade::GetEUInstance().UnbindTG(*qos1);
148     EXPECT_EQ(*qos1, qos_default);
149 }
150 
151 /**
152  * @tc.name: BindTG
153  * @tc.desc: Test whether the BindTG interface are normal.
154  * @tc.type: FUNC
155  */
156 HWTEST_F(ExecuteUnitTest, BindTG, TestSize.Level0)
157 {
158     auto qos1 = std::make_unique<QoS>();
159     ThreadGroup* it = FFRTFacade::GetEUInstance().BindTG(*qos1);
160     EXPECT_EQ(*qos1, qos_default);
161 }
162 
163 HWTEST_F(ExecuteUnitTest, WorkerShare, TestSize.Level0)
164 {
165     std::atomic<bool> done = false;
166     CpuWorkerOps ops{
__anon372b85b30202() 167         [](CPUWorker* thread) { return WorkerAction::RETIRE; },
__anon372b85b30302() 168         [&done](CPUWorker* thread) {
169             // prevent thread leak and UAF
170             // by sync. via done and detaching the thread
171             thread->SetExited();
172             thread->Detach();
173             done = true;
174         },
__anon372b85b30402() 175         [](CPUWorker* thread) {},
176 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
__anon372b85b30502() 177         []() { return false; },
178 #endif
179     };
180 
181     const auto qos = QoS(5);
182     auto manager = std::make_unique<SExecuteUnit>();
183     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(qos);
184     workerCtrl.workerShareConfig.push_back({qos, true});
185     auto worker = std::make_unique<CPUWorker>(qos, std::move(ops), 0);
186 
__anon372b85b30602(int qos, CPUWorker* worker) 187     std::function<bool(int, CPUWorker*)> trueFunc = [](int qos, CPUWorker* worker) { return true; };
__anon372b85b30702(int qos, CPUWorker* worker) 188     std::function<bool(int, CPUWorker*)> falseFunc = [](int qos, CPUWorker* worker) { return false; };
189 
190 #ifndef FFRT_GITEE
191     EXPECT_EQ(manager->WorkerShare(worker.get(), trueFunc), true);
192     EXPECT_EQ(manager->WorkerShare(worker.get(), falseFunc), false);
193 #endif
194 
195     workerCtrl.workerShareConfig[0].second = false;
196     EXPECT_EQ(manager->WorkerShare(worker.get(), trueFunc), true);
197     EXPECT_EQ(manager->WorkerShare(worker.get(), falseFunc), false);
198     while (!done) {
199         // busy wait for the worker thread to be done.
200         // delay the destruction of main thread till the retirement of the worker.
201     }
202 }
203 
204 HWTEST_F(ExecuteUnitTest, HandleTaskNotifyConservative, TestSize.Level0)
205 {
206     SExecuteUnit* manager = new SExecuteUnit();
207     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
208     EXPECT_EQ(workerCtrl.executingNum, 0);
209 
210     SExecuteUnit::HandleTaskNotifyConservative(manager, 5, TaskNotifyType::TASK_ADDED);
211     SExecuteUnit::HandleTaskNotifyUltraConservative(manager, 5, TaskNotifyType::TASK_ADDED);
212     EXPECT_EQ(workerCtrl.executingNum, 0);
213 
214     workerCtrl.sleepingNum++;
215     workerCtrl.executingNum = workerCtrl.maxConcurrency;
216     manager->PokeImpl(5, 1, TaskNotifyType::TASK_ADDED);
217     EXPECT_EQ(workerCtrl.executingNum, workerCtrl.maxConcurrency);
218 
219     workerCtrl.sleepingNum = 0;
220     manager->PokeImpl(5, 1, TaskNotifyType::TASK_ADDED);
221     EXPECT_EQ(workerCtrl.executingNum, workerCtrl.maxConcurrency);
222 
223     workerCtrl.maxConcurrency = 20;
224     workerCtrl.executingNum = workerCtrl.hardLimit;
225     manager->PokeImpl(5, 1, TaskNotifyType::TASK_ADDED);
226     EXPECT_EQ(workerCtrl.executingNum, workerCtrl.hardLimit);
227 
228     if (manager->we_[0] != nullptr) {
229         delete manager->we_[0];
230         manager->we_[0] = nullptr;
231     }
232     delete manager;
233 }
234 
235 HWTEST_F(ExecuteUnitTest, SetWorkerStackSize, TestSize.Level0)
236 {
237     SExecuteUnit* manager = new SExecuteUnit();
238     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
239 
240     manager->SetWorkerStackSize(5, 4096);
241     EXPECT_EQ(workerCtrl.workerStackSize, 4096);
242 }
243 
244 HWTEST_F(ExecuteUnitTest, WorkerCreate, TestSize.Level0)
245 {
246     ffrt::SExecuteUnit* manager = new ffrt::SExecuteUnit();
247     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
248     EXPECT_EQ(workerCtrl.executingNum, 0);
249 
250     workerCtrl.WorkerCreate();
251 
252     EXPECT_EQ(workerCtrl.executingNum, 1);
253 }
254 
255 HWTEST_F(ExecuteUnitTest, RollBackCreate, TestSize.Level0)
256 {
257     ffrt::SExecuteUnit* manager = new ffrt::SExecuteUnit();
258     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
259     EXPECT_EQ(workerCtrl.executingNum, 0);
260 
261     workerCtrl.RollBackCreate();
262 
263     EXPECT_EQ(workerCtrl.executingNum, -1);
264 }
265 
266 /**
267  * @tc.name: IntoSleep
268  * @tc.desc: Test whether the IntoSleep interface are normal.
269  * @tc.type: FUNC
270  */
271 HWTEST_F(ExecuteUnitTest, IntoSleep, TestSize.Level0)
272 {
273     ffrt::SExecuteUnit* manager = new ffrt::SExecuteUnit();
274     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
275     EXPECT_EQ(workerCtrl.executingNum, 0);
276     EXPECT_EQ(workerCtrl.sleepingNum, 0);
277 
278     manager->IntoSleep(QoS(5));
279 
280     EXPECT_EQ(workerCtrl.executingNum, -1);
281     EXPECT_EQ(workerCtrl.sleepingNum, 1);
282 }
283 
284 /**
285  * @tc.name: OutOfSleep
286  * @tc.desc: Test whether the OutOfSleep interface are normal.
287  * @tc.type: FUNC
288  */
289 HWTEST_F(ExecuteUnitTest, OutOfSleep, TestSize.Level0)
290 {
291     ffrt::SExecuteUnit* manager = new ffrt::SExecuteUnit();
292     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
293     EXPECT_EQ(workerCtrl.executingNum, 0);
294     EXPECT_EQ(workerCtrl.sleepingNum, 0);
295 
296     workerCtrl.OutOfSleep(QoS(5));
297 
298     EXPECT_EQ(workerCtrl.executingNum, 1);
299     EXPECT_EQ(workerCtrl.sleepingNum, -1);
300 }
301 
302 /**
303  * @tc.name: WorkerDestroy
304  * @tc.desc: Test whether the WorkerDestroy interface are normal.
305  * @tc.type: FUNC
306  */
307 HWTEST_F(ExecuteUnitTest, WorkerDestroy, TestSize.Level0)
308 {
309     ffrt::SExecuteUnit* manager = new ffrt::SExecuteUnit();
310     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
311     EXPECT_EQ(workerCtrl.sleepingNum, 0);
312 
313     workerCtrl.WorkerDestroy();
314 
315     EXPECT_EQ(workerCtrl.sleepingNum, -1);
316 }
317 
318 /**
319  * @tc.name: IntoDeepSleep
320  * @tc.desc: Test whether the IntoDeepSleep interface are normal.
321  * @tc.type: FUNC
322  */
323 HWTEST_F(ExecuteUnitTest, IntoDeepSleep, TestSize.Level0)
324 {
325     ffrt::SExecuteUnit* manager = new ffrt::SExecuteUnit();
326     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
327     EXPECT_EQ(workerCtrl.deepSleepingWorkerNum, 0);
328 
329     workerCtrl.IntoDeepSleep();
330 
331     EXPECT_EQ(workerCtrl.deepSleepingWorkerNum, 1);
332 }
333 
334 HWTEST_F(ExecuteUnitTest, OutOfDeepSleep, TestSize.Level0)
335 {
336     ffrt::SExecuteUnit* manager = new ffrt::SExecuteUnit();
337     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
338     EXPECT_EQ(workerCtrl.sleepingNum, 0);
339     EXPECT_EQ(workerCtrl.deepSleepingWorkerNum, 0);
340     EXPECT_EQ(workerCtrl.executingNum, 0);
341 
342     workerCtrl.OutOfDeepSleep(QoS(5));
343 
344     EXPECT_EQ(workerCtrl.sleepingNum, -1);
345     EXPECT_EQ(workerCtrl.deepSleepingWorkerNum, -1);
346     EXPECT_EQ(workerCtrl.executingNum, 1);
347 }
348 
349 HWTEST_F(ExecuteUnitTest, TryDestroy, TestSize.Level0)
350 {
351     ffrt::SExecuteUnit* manager = new ffrt::SExecuteUnit();
352     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
353     EXPECT_EQ(workerCtrl.sleepingNum, 0);
354 
355     bool res = workerCtrl.TryDestroy();
356 
357     EXPECT_EQ(false, res);
358 }
359 
360 HWTEST_F(ExecuteUnitTest, RollbackDestroy, TestSize.Level0)
361 {
362     ffrt::SExecuteUnit* manager = new ffrt::SExecuteUnit();
363     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(5);
364     EXPECT_EQ(workerCtrl.executingNum, 0);
365 
366     workerCtrl.RollbackDestroy();
367 
368     EXPECT_EQ(workerCtrl.executingNum, 1);
369 }
370 
371 HWTEST_F(ExecuteUnitTest, SetCgroupAttr, TestSize.Level0)
372 {
373     ffrt_os_sched_attr attr2 = {100, 19, 0, 10, 0, "0-6"};
374     EXPECT_EQ(ffrt::set_cgroup_attr(static_cast<int>(ffrt::qos_user_interactive), &attr2), 0);
375     ffrt::restore_qos_config();
376 }
377 
378 /*
379 * 测试用例名称:ffrt_disable_worker_monitor
380 * 测试用例描述:调用EU的DisableWorkerMonitor函数
381 * 预置条件    :创建SExecuteUnit
382 * 操作步骤    :1.调用方法DisableWorkerMonitor,传入异常参数
383 * 预期结果    :monitor相关参数被设置为false
384 */
385 HWTEST_F(ExecuteUnitTest, ffrt_disable_worker_monitor, TestSize.Level1)
386 {
387     std::atomic<bool> done = false;
388     CpuWorkerOps ops {
__anon372b85b30802() 389         [](CPUWorker* thread) { return WorkerAction::RETIRE; },
__anon372b85b30902() 390         [&done](CPUWorker* thread) {
391             // prevent thread leak and UAF
392             // by sync. via done and detaching the thread
393             thread->SetExited();
394             thread->Detach();
395             done = true;
396         },
__anon372b85b30a02() 397         [](CPUWorker* thread) {},
398 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
__anon372b85b30b02() 399         []() { return false; },
400 #endif
401     };
402 
403     const auto qos = QoS(5);
404     auto manager = std::make_unique<SExecuteUnit>();
405     CPUWorkerGroup& workerCtrl = manager->GetWorkerGroup(qos);
406     CPUWorker* worker = new CPUWorker(qos, std::move(ops), 0);
407     workerCtrl.threads[worker] = std::unique_ptr<CPUWorker>(worker);
408     EXPECT_TRUE(worker->monitor_);
409 
410     manager->DisableWorkerMonitor(qos, worker->Id());
411     EXPECT_FALSE(worker->monitor_);
412 
413     while (!done) {
414         // busy wait for the worker thread to be done.
415         // delay the destruction of main thread till the retirement of the worker.
416     }
417 }