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 #include <gtest/gtest.h>
16 #include <thread>
17 #include <cstring>
18 #include <cstdio>
19 #include <fstream>
20 #include <algorithm>
21 #include <sched.h>
22 #include <unistd.h>
23 #include <sys/syscall.h>
24 #include <sys/resource.h>
25 #include "c/thread.h"
26 #include "sync/perf_counter.h"
27 #include "sync/wait_queue.h"
28
29 #define private public
30 #include "eu/cpu_worker.h"
31 #undef private
32 #include "../common.h"
33
34 using namespace testing;
35 #ifdef HWTEST_TESTING_EXT_ENABLE
36 using namespace testing::ext;
37 #endif
38 using namespace ffrt;
39 #ifdef APP_USE_ARM
40 static const size_t WORKER_STACK_SIZE = 131072;
41 #else
42 static const size_t WORKER_STACK_SIZE = 10 * 1024 * 1024;
43 #endif
44
45 class CpuWorkerTest : public testing::Test {
46 protected:
SetUpTestCase()47 static void SetUpTestCase()
48 {
49 }
50
TearDownTestCase()51 static void TearDownTestCase()
52 {
53 }
54
SetUp()55 void SetUp() override
56 {
57 }
58
TearDown()59 void TearDown() override
60 {
61 }
62
MockStart(void * arg)63 static void* MockStart(void* arg)
64 {
65 int* inc = reinterpret_cast<int*>(arg);
66 (*inc) += 1;
67 return nullptr;
68 }
69 };
70
71 static int g_counter = 0;
SimpleThdFunc(void *)72 int SimpleThdFunc(void *)
73 {
74 g_counter++;
75 return 0;
76 }
77
TempFunc(void *)78 static void* TempFunc(void *)
79 {
80 ++g_counter;
81 return nullptr;
82 }
83
WorkerIdleAction(CPUWorker * thread)84 WorkerAction WorkerIdleAction(CPUWorker *thread)
85 {
86 return WorkerAction::RETRY;
87 }
88 /* a flag used to stall main thread till the worker is done. This prevents UAF */
89 std::atomic<bool> workerDone = false;
WorkerRetired(CPUWorker * thread)90 void WorkerRetired(CPUWorker* thread)
91 {
92 thread->SetExited();
93 thread->Detach();
94 /* worker is done, set flag to true */
95 workerDone = true;
96 }
WaitForWorker()97 void WaitForWorker()
98 {
99 /* Stall till worker is done to prevent UAF */
100 while (!workerDone) {
101 // spin till the worker is done
102 }
103 }
104
WorkerPrepare(CPUWorker * thread)105 void WorkerPrepare(CPUWorker* thread)
106 {
107 }
108
109 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
IsBlockAwareInit()110 bool IsBlockAwareInit()
111 {
112 return true;
113 }
114 #endif
115
116 HWTEST_F(CpuWorkerTest, WorkerStatusTest, TestSize.Level0)
117 {
118 CpuWorkerOps ops;
119 ops.WorkerIdleAction = WorkerIdleAction;
120 ops.WorkerRetired = WorkerRetired;
121 ops.WorkerPrepare = WorkerPrepare;
122 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
123 ops.IsBlockAwareInit = IsBlockAwareInit;
124 #endif
125 workerDone = false;
126 auto worker = std::make_unique<CPUWorker>(QoS(6), std::move(ops), 1024);
127 WorkerStatus status = worker->GetWorkerState();
128 EXPECT_EQ(WorkerStatus::EXECUTING, status);
129 worker->SetExited();
130 WaitForWorker();
131 }
132
133 HWTEST_F(CpuWorkerTest, SetWorkerStatusTest, TestSize.Level0)
134 {
135 CpuWorkerOps ops;
136 ops.WorkerIdleAction = WorkerIdleAction;
137 ops.WorkerRetired = WorkerRetired;
138 ops.WorkerPrepare = WorkerPrepare;
139 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
140 ops.IsBlockAwareInit = IsBlockAwareInit;
141 #endif
142 workerDone = false;
143 auto worker = std::make_unique<CPUWorker>(QoS(6), std::move(ops), 1024);
144 worker->SetWorkerState(WorkerStatus::SLEEPING);
145 EXPECT_EQ(WorkerStatus::SLEEPING, worker->state);
146 worker->SetExited();
147 WaitForWorker();
148 }
149
150 HWTEST_F(CpuWorkerTest, ExitedTest, TestSize.Level0)
151 {
152 CpuWorkerOps ops;
153 ops.WorkerIdleAction = WorkerIdleAction;
154 ops.WorkerRetired = WorkerRetired;
155 ops.WorkerPrepare = WorkerPrepare;
156 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
157 ops.IsBlockAwareInit = IsBlockAwareInit;
158 #endif
159 workerDone = false;
160 auto worker = std::make_unique<CPUWorker>(QoS(6), std::move(ops), 1024);
161 bool ret = worker->Exited();
162 EXPECT_FALSE(ret);
163 worker->SetExited();
164 WaitForWorker();
165 }
166
167 HWTEST_F(CpuWorkerTest, SetExitedTest, TestSize.Level0)
168 {
169 CpuWorkerOps ops;
170 ops.WorkerIdleAction = WorkerIdleAction;
171 ops.WorkerRetired = WorkerRetired;
172 ops.WorkerPrepare = WorkerPrepare;
173 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
174 ops.IsBlockAwareInit = IsBlockAwareInit;
175 #endif
176 workerDone = false;
177 auto worker = std::make_unique<CPUWorker>(QoS(6), std::move(ops), 1024);
178 worker->SetExited();
179 EXPECT_TRUE(worker->exited.load());
180 WaitForWorker();
181 }
182
183 HWTEST_F(CpuWorkerTest, GetQosTest, TestSize.Level0)
184 {
185 CpuWorkerOps ops;
186 ops.WorkerIdleAction = WorkerIdleAction;
187 ops.WorkerRetired = WorkerRetired;
188 ops.WorkerPrepare = WorkerPrepare;
189 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
190 ops.IsBlockAwareInit = IsBlockAwareInit;
191 #endif
192 workerDone = false;
193 auto qos = QoS(6);
194 auto worker = std::make_unique<CPUWorker>(qos, std::move(ops), 1024);
195 EXPECT_EQ(worker->GetQos(), qos);
196 worker->SetExited();
197 WaitForWorker();
198 }
199