• 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 <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 }