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 <random>
17 #include <csignal>
18 #include <gtest/gtest.h>
19 #include "core/entity.h"
20 #include "core/version_ctx.h"
21 #include "ffrt_inner.h"
22 #include "c/ffrt_ipc.h"
23 #include "sched/task_state.h"
24 #include "dfx/log/ffrt_log_api.h"
25 #include "dfx/bbox/bbox.h"
26 #include "tm/cpu_task.h"
27 #include "tm/io_task.h"
28 #include "tm/queue_task.h"
29 #include "tm/scpu_task.h"
30 #include "tm/task_factory.h"
31 #include "../common.h"
32
33 using namespace std;
34 using namespace testing;
35 #ifdef HWTEST_TESTING_EXT_ENABLE
36 using namespace testing::ext;
37 #endif
38 using namespace ffrt;
39
40 class CoreTest : public testing::Test {
41 protected:
SetUpTestCase()42 static void SetUpTestCase()
43 {
44 }
45
TearDownTestCase()46 static void TearDownTestCase()
47 {
48 }
49
SetUp()50 void SetUp() override
51 {
52 }
53
TearDown()54 void TearDown() override
55 {
56 }
57 };
58
59 HWTEST_F(CoreTest, task_ctx_success_01, TestSize.Level1)
60 {
__anonb48cfec80102() 61 auto func1 = ([]() {std::cout << std::endl << " push a task " << std::endl;});
62 SCPUEUTask *task1 = new SCPUEUTask(nullptr, nullptr, 0, QoS(static_cast<int>(qos_user_interactive)));
__anonb48cfec80202() 63 auto func2 = ([]() {std::cout << std::endl << " push a task " << std::endl;});
64 SCPUEUTask *task2 = new SCPUEUTask(nullptr, task1, 0, QoS());
65 QoS qos = QoS(static_cast<int>(qos_inherit));
66 task2->SetQos(qos);
67 EXPECT_EQ(task2->qos_, static_cast<int>(qos_user_interactive));
68 delete task1;
69 delete task2;
70 }
71
72 /**
73 * @tc.name: ThreadWaitAndNotifyModeCheck
74 * @tc.desc: Test function of ThreadWaitMode and ThreadNotifyMode
75 * @tc.type: FUNC
76 */
77 HWTEST_F(CoreTest, ThreadWaitAndNotifyMode, TestSize.Level1)
78 {
79 SCPUEUTask* task = new SCPUEUTask(nullptr, nullptr, 0, QoS());
80
81 // when executing task is nullptr
82 EXPECT_EQ(ThreadWaitMode(nullptr), true);
83
84 // when executing task is root
85 EXPECT_EQ(ThreadWaitMode(task), true);
86
87 // when executing task in legacy mode
88 SCPUEUTask* parent = new SCPUEUTask(nullptr, nullptr, 0, QoS());
89 task->parent = parent;
90 task->legacyCountNum = 1;
91 EXPECT_EQ(ThreadWaitMode(task), true);
92
93 // when task is valid and not in legacy mode
94 task->legacyCountNum = 0;
95 EXPECT_EQ(ThreadWaitMode(task), false);
96
97 // when block thread is false
98 EXPECT_EQ(ThreadNotifyMode(task), false);
99
100 // when block thread is true
101 task->blockType = BlockType::BLOCK_THREAD;
102 EXPECT_EQ(ThreadNotifyMode(task), true);
103
104 delete parent;
105 delete task;
106 }
107
108 /**
109 * 测试用例名称:task_attr_set_timeout
110 * 测试用例描述:验证task_attr的设置timeout接口
111 * 预置条件:创建有效的task_attr
112 * 操作步骤:设置timeout值,通过get接口与设置值对比
113 * 预期结果:设置成功
114 */
115 HWTEST_F(CoreTest, task_attr_set_timeout, TestSize.Level1)
116 {
117 ffrt_task_attr_t* attr = (ffrt_task_attr_t *) malloc(sizeof(ffrt_task_attr_t));
118 ffrt_task_attr_init(attr);
119 ffrt_task_attr_set_timeout(attr, 1000);
120 uint64_t timeout = ffrt_task_attr_get_timeout(attr);
121 EXPECT_EQ(timeout, 1000);
122 free(attr);
123 }
124
125 /**
126 * 测试用例名称:task_attr_set_timeout_nullptr
127 * 测试用例描述:验证task_attr的设置timeout接口的异常场景
128 * 预置条件:针对nullptr进行设置
129 * 操作步骤:设置timeout值,通过get接口与设置值对比
130 * 预期结果:设置失败,返回值为0
131 */
132 HWTEST_F(CoreTest, task_attr_set_timeout_nullptr, TestSize.Level1)
133 {
134 ffrt_task_attr_t* attr = nullptr;
135 ffrt_task_attr_set_timeout(attr, 1000);
136 uint64_t timeout = ffrt_task_attr_get_timeout(attr);
137 EXPECT_EQ(timeout, 0);
138 }
139
140 /**
141 * 测试用例名称:task_attr_set_stack_size
142 * 测试用例描述:验证task_attr的设置stack_size接口
143 * 预置条件:创建有效的task_attr
144 * 操作步骤:设置stack_size值,通过get接口与设置值对比
145 * 预期结果:设置成功
146 */
147 HWTEST_F(CoreTest, task_attr_set_stack_size, TestSize.Level1)
148 {
149 ffrt_task_attr_t* attr = (ffrt_task_attr_t *) malloc(sizeof(ffrt_task_attr_t));
150 ffrt_task_attr_init(attr);
151 ffrt_task_attr_set_stack_size(attr, 1024 * 1024);
152 uint64_t stackSize = ffrt_task_attr_get_stack_size(attr);
153 EXPECT_EQ(stackSize, 1024 * 1024);
154 free(attr);
155 }
156
157 /**
158 * 测试用例名称:ffrt_task_handle_ref_nullptr
159 * 测试用例描述:验证task_handle的增加、消减引用计数接口的异常场景
160 * 预置条件:针对nullptr进行设置
161 * 操作步骤:对nullptr进行调用
162 * 预期结果:接口校验异常场景成功,用例正常执行结束
163 */
164 HWTEST_F(CoreTest, ffrt_task_handle_ref_nullptr, TestSize.Level1)
165 {
166 ffrt_task_handle_t handle = nullptr;
167 ffrt_task_handle_inc_ref(handle);
168 ffrt_task_handle_dec_ref(handle);
169 EXPECT_EQ(handle, nullptr);
170 }
171
172 /**
173 * 测试用例名称:ffrt_task_handle_ref
174 * 测试用例描述:验证task_handle的增加、消减引用计数接口
175 * 预置条件:创建有效的task_handle
176 * 操作步骤:对task_handle进行设置引用计数接口
177 * 预期结果:读取rc值
178 */
179 HWTEST_F(CoreTest, ffrt_task_handle_ref, TestSize.Level1)
180 {
181 // 验证notify_worker的功能
182 int result = 0;
183 ffrt_task_attr_t taskAttr;
184 (void)ffrt_task_attr_init(&taskAttr); // 初始化task属性,必须
185 ffrt_task_attr_set_delay(&taskAttr, 10000); // 延时10ms执行
__anonb48cfec80302() 186 std::function<void()>&& OnePlusFunc = [&result]() { result += 1; };
187 ffrt_task_handle_t handle = ffrt_submit_h_base(ffrt::create_function_wrapper(OnePlusFunc), {}, {}, &taskAttr);
188 EXPECT_GT(ffrt_task_handle_get_id(handle), 0);
189 auto task = static_cast<ffrt::CPUEUTask*>(handle);
190 EXPECT_EQ(task->rc.load(), 2); // task还未执行完成,所以task和handle各计数一次
191 ffrt_task_handle_inc_ref(handle);
192 EXPECT_EQ(task->rc.load(), 3);
193 ffrt_task_handle_dec_ref(handle);
194 EXPECT_EQ(task->rc.load(), 2);
195 ffrt::wait({handle});
196 EXPECT_EQ(result, 1);
197 ffrt_task_handle_destroy(handle);
198 }
199
200 /**
201 * 测试用例名称:WaitFailWhenReuseHandle
202 * 测试用例描述:构造2个submit_h的任务,验证task_handle转成dependence后,调用ffrt::wait的场景
203 * 预置条件:创建一个submit_h任务,确保执行完成,且将task_handle转成dependence后保存
204 * 操作步骤:创建另外一个task_handle任务,并且先执行ffrt::wait保存的dependence的数组
205 * 预期结果:任务正常执行结束
206 */
207 HWTEST_F(CoreTest, WaitFailWhenReuseHandle, TestSize.Level1)
208 {
209 int i = 0;
210 std::vector<ffrt::dependence> deps;
211 {
__anonb48cfec80402null212 auto h = ffrt::submit_h([&i] { printf("task0 done\n"); i++;});
213 printf("task0 handle: %p\n:", static_cast<void*>(h));
214 ffrt::dependence d(h);
215 ffrt::dependence dep = d;
216 deps.emplace_back(dep);
217 }
218 usleep(1000);
219 std::atomic_bool stop = false;
__anonb48cfec80502null220 auto h = ffrt::submit_h([&] {
221 printf("task1 start\n");
222 while (!stop);
223 i++;
224 printf("task1 done\n");
225 });
226 ffrt::wait(deps);
227 EXPECT_EQ(i, 1);
228 stop = true;
229 ffrt::wait();
230 EXPECT_EQ(i, 2);
231 }
232
233 /*
234 * 测试用例名称:ffrt_task_get_tid_test
235 * 测试用例描述:测试ffrt_task_get_tid接口
236 * 预置条件 :创建SCPUEUTask
237 * 操作步骤 :调用ffrt_task_get_tid方法,入参分别为SCPUEUTask、QueueTask对象和空指针
238 * 预期结果 :ffrt_task_get_tid功能正常,传入空指针时返回0
239 */
240 HWTEST_F(CoreTest, ffrt_task_get_tid_test, TestSize.Level1)
241 {
242 ffrt::CPUEUTask* task = new ffrt::SCPUEUTask(nullptr, nullptr, 0, ffrt::QoS(2));
243 ffrt::QueueTask* queueTask = new ffrt::QueueTask(nullptr);
244 pthread_t tid = ffrt_task_get_tid(task);
245 EXPECT_EQ(tid, 0);
246
247 tid = ffrt_task_get_tid(queueTask);
248 EXPECT_EQ(tid, 0);
249
250 tid = ffrt_task_get_tid(nullptr);
251 EXPECT_EQ(tid, 0);
252
253 delete task;
254 delete queueTask;
255 }
256
257 /*
258 * 测试用例名称:ffrt_get_cur_cached_task_id_test
259 * 测试用例描述:测试ffrt_get_cur_cached_task_id接口
260 * 预置条件 :设置ExecuteCtx::Cur->lastGid_为自定义值
261 * 操作步骤 :调用ffrt_get_cur_cached_task_id接口
262 * 预期结果 :ffrt_get_cur_cached_task_id返回值与自定义值相同
263 */
264 HWTEST_F(CoreTest, ffrt_get_cur_cached_task_id_test, TestSize.Level1)
265 {
266 auto ctx = ffrt::ExecuteCtx::Cur();
267 ctx->lastGid_ = 15;
268 EXPECT_EQ(ffrt_get_cur_cached_task_id(), 15);
269
__anonb48cfec80602null270 ffrt::submit([] {});
271 ffrt::wait();
272
273 EXPECT_NE(ffrt_get_cur_cached_task_id(), 0);
274 }
275
276 /*
277 * 测试用例名称:ffrt_get_cur_task_test
278 * 测试用例描述:测试ffrt_get_cur_task接口
279 * 预置条件 :提交ffrt任务
280 * 操作步骤 :在ffrt任务中调用ffrt_get_cur_task接口
281 * 预期结果 :返回的task地址不为空
282 */
283 HWTEST_F(CoreTest, ffrt_get_cur_task_test, TestSize.Level1)
284 {
285 void* taskPtr = nullptr;
__anonb48cfec80702null286 ffrt::submit([&] {
287 taskPtr = ffrt_get_cur_task();
288 });
289 ffrt::wait();
290
291 EXPECT_NE(taskPtr, nullptr);
292 }
293
294 /*
295 * 测试用例名称:ffrt_this_task_get_qos_test
296 * 测试用例描述:测试ffrt_this_task_get_qos接口
297 * 预置条件 :提交qos=3的ffrt任务
298 * 操作步骤 :在ffrt任务中调用ffrt_this_task_get_qos接口
299 * 预期结果 :ffrt_this_task_get_qos返回值=3
300 */
301 HWTEST_F(CoreTest, ffrt_this_task_get_qos_test, TestSize.Level1)
302 {
303 ffrt_qos_t qos = 0;
__anonb48cfec80802null304 ffrt::submit([&] {
305 qos = ffrt_this_task_get_qos();
306 }, ffrt::task_attr().qos(ffrt_qos_user_initiated));
307 ffrt::wait();
308 EXPECT_EQ(qos, ffrt::QoS(ffrt_qos_user_initiated)());
309 }
310
311 namespace ffrt {
312 template <typename T>
Instance()313 TaskFactory<T>& TaskFactory<T>::Instance()
314 {
315 static TaskFactory<T> fac;
316 return fac;
317 }
318 }
319
320 namespace TmTest {
321 class MyTask : public ffrt::TaskBase {
322 private:
FreeMem()323 void FreeMem() override { ffrt::TaskFactory<MyTask>::Free(this); }
Execute()324 void Execute() override {}
GetLabel() const325 std::string GetLabel() const override { return "my-task"; }
326 };
327
TestTaskFactory(bool isSimpleAllocator)328 void TestTaskFactory(bool isSimpleAllocator)
329 {
330 MyTask* task = ffrt::TaskFactory<MyTask>::Alloc();
331 uint32_t taskCount = ffrt::TaskFactory<MyTask>::GetUnfreedMem().size();
332 #ifdef FFRT_BBOX_ENABLE
333 EXPECT_FALSE(ffrt::TaskFactory<MyTask>::HasBeenFreed(task));
334 #else
335 EXPECT_TRUE(isSimpleAllocator || !ffrt::TaskFactory<MyTask>::HasBeenFreed(task));
336 #endif
337
338 std::vector<ffrt::TaskBase*> tasks;
339 new(task) MyTask();
340 tasks.push_back(task);
341 for (auto task : tasks) {
342 task->DecDeleteRef();
343 }
344
345 uint32_t newCount = ffrt::TaskFactory<MyTask>::GetUnfreedMem().size();
346 #ifdef FFRT_BBOX_ENABLE
347 EXPECT_GT(taskCount, newCount);
348 #else
349 if (!isSimpleAllocator) {
350 EXPECT_GT(taskCount, ffrt::TaskFactory<MyTask>::GetUnfreedMem().size());
351 }
352 #endif
353 EXPECT_TRUE(ffrt::TaskFactory<MyTask>::HasBeenFreed(task));
354 }
355
356 template <typename T>
357 class CustomTaskManager {
358 public:
Alloc()359 T* Alloc()
360 {
361 mutex.lock();
362 T* res = reinterpret_cast<T*>(malloc(sizeof(T)));
363 allocedTask.insert(res);
364 mutex.unlock();
365 return res;
366 }
367
Free(T * task)368 void Free(T* task)
369 {
370 mutex.lock();
371 allocedTask.erase(task);
372 free(task);
373 mutex.unlock();
374 }
375
LockMem()376 void LockMem()
377 {
378 mutex.lock();
379 }
380
UnlockMem()381 void UnlockMem()
382 {
383 mutex.unlock();
384 }
385
HasBeenFreed(T * task)386 bool HasBeenFreed(T* task)
387 {
388 return allocedTask.find(task) == allocedTask.end();
389 }
390
GetUnfreedMem()391 std::vector<void*> GetUnfreedMem()
392 {
393 std::vector<void*> res;
394 res.resize(allocedTask.size());
395 std::transform(allocedTask.begin(), allocedTask.end(), std::inserter(res, res.end()), [](T* ptr) {
396 return static_cast<void*>(ptr);
397 });
398 return res;
399 }
400
401 private:
402 std::mutex mutex;
403 std::set<T*> allocedTask;
404 };
405 } // namespace TmTest
406
407 /*
408 * 测试用例名称:ffrt_task_factory_test_001
409 * 测试用例描述:测试使用SimpleAllocator时,任务能够成功申请释放
410 * 预置条件 :注册使用SimpleAllocator的内存分配函数
411 * 操作步骤 :使用TaskFactory申请一个自定义Task的实例,初始化后调用各自的DecDeleteRef释放
412 * 预期结果 :能够正常申请和释放,释放前后GetUnFreedMem读取数组的值小于释放前
413 */
414 HWTEST_F(CoreTest, ffrt_task_factory_test_001, TestSize.Level1)
415 {
416 ffrt::TaskFactory<TmTest::MyTask>::RegistCb(
417 ffrt::SimpleAllocator<TmTest::MyTask>::AllocMem,
418 ffrt::SimpleAllocator<TmTest::MyTask>::FreeMem,
419 ffrt::SimpleAllocator<TmTest::MyTask>::FreeMem_,
420 ffrt::SimpleAllocator<TmTest::MyTask>::getUnfreedMem,
421 ffrt::SimpleAllocator<TmTest::MyTask>::HasBeenFreed,
422 ffrt::SimpleAllocator<TmTest::MyTask>::LockMem,
423 ffrt::SimpleAllocator<TmTest::MyTask>::UnlockMem);
424
425 TmTest::TestTaskFactory(true);
426 }
427
428 /*
429 * 测试用例名称:ffrt_task_factory_test_002
430 * 测试用例描述:测试使用自定义管理器时,任务能够成功申请释放
431 * 预置条件 :注册自定义Task内存分配函数
432 * 操作步骤 :使用TaskFactory申请一个自定义Task的实例,初始化后调用各自的DecDeleteRef释放
433 * 预期结果 :能够正常申请和释放,释放前后GetUnFreedMem读取数组的值小于释放前
434 */
435 HWTEST_F(CoreTest, ffrt_task_factory_test_002, TestSize.Level1)
436 {
437 TmTest::CustomTaskManager<TmTest::MyTask> custom_manager;
438 ffrt::TaskFactory<TmTest::MyTask>::RegistCb(
__anonb48cfec80a02() 439 [&] () -> TmTest::MyTask* { return custom_manager.Alloc(); },
__anonb48cfec80b02(TmTest::MyTask* task) 440 [&] (TmTest::MyTask* task) { custom_manager.Free(task); },
__anonb48cfec80c02(TmTest::MyTask* task) 441 [&] (TmTest::MyTask* task) { custom_manager.Free(task); },
__anonb48cfec80d02() 442 [&] () -> std::vector<void*> { return custom_manager.GetUnfreedMem(); },
__anonb48cfec80e02(TmTest::MyTask* task) 443 [&] (TmTest::MyTask* task) { return custom_manager.HasBeenFreed(task); },
__anonb48cfec80f02() 444 [&] () { custom_manager.LockMem(); },
__anonb48cfec81002() 445 [&] () { custom_manager.UnlockMem(); });
446
447 TmTest::TestTaskFactory(false);
448 }