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 }