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 <vector>
17 #include <mutex>
18 #include <thread>
19 #include <condition_variable>
20 #include <atomic>
21 
22 #include <gtest/gtest.h>
23 
24 #include "eu/rtg_ioctl.h"
25 #include "dfx/log/ffrt_log_api.h"
26 #include "../common.h"
27 
28 using namespace testing;
29 #ifdef HWTEST_TESTING_EXT_ENABLE
30 using namespace testing::ext;
31 #endif
32 using namespace ffrt;
33 
34 class RTGTest : public testing::Test {
35 protected:
SetUpTestCase()36     static void SetUpTestCase()
37     {
38     }
39 
TearDownTestCase()40     static void TearDownTestCase()
41     {
42     }
43 
SetUp()44     virtual void SetUp()
45     {
46     }
47 
TearDown()48     virtual void TearDown()
49     {
50     }
51 };
52 
53 HWTEST_F(RTGTest, rtg_init_test, TestSize.Level1)
54 {
55     bool enabled = RTGCtrl::Instance().Enabled();
56     FFRT_LOGE("RTGCtrl Init %s", enabled ? "Success" : "Failed");
57 }
58 
59 HWTEST_F(RTGTest, rtg_get_group_test, TestSize.Level1)
60 {
61     int tgid = RTGCtrl::Instance().GetThreadGroup();
62     if (tgid < 0) {
63         FFRT_LOGE("Failed to Get RTG id %d", tgid);
64     }
65 
66     bool ret = RTGCtrl::Instance().PutThreadGroup(tgid);
67     if (!ret) {
68         FFRT_LOGE("Failed to Put RTG id %d", tgid);
69     }
70 }
71 
72 HWTEST_F(RTGTest, rtg_set_window_size_test, TestSize.Level1)
73 {
74     constexpr int WINDOW_SIZE = 10000;
75 
76     int tgid = RTGCtrl::Instance().GetThreadGroup();
77     if (tgid < 0) {
78         FFRT_LOGE("Failed to Get RTG id %d", tgid);
79     }
80 
81     bool ret = RTGCtrl::Instance().SetGroupWindowSize(tgid, WINDOW_SIZE);
82     if (!ret) {
83         FFRT_LOGE("Failed to Set Window Size %d", WINDOW_SIZE);
84     }
85 
86     ret = RTGCtrl::Instance().PutThreadGroup(tgid);
87     if (!ret) {
88         FFRT_LOGE("Failed to Put RTG id %d", tgid);
89     }
90 }
91 
92 HWTEST_F(RTGTest, rtg_set_invalid_interval_test, TestSize.Level1)
93 {
94     constexpr int INVALID_INTERVAL = 10;
95 
96     int tgid = RTGCtrl::Instance().GetThreadGroup();
97     if (tgid < 0) {
98         FFRT_LOGE("Failed to Get RTG id %d", tgid);
99     }
100 
101     bool ret = RTGCtrl::Instance().SetInvalidInterval(tgid, INVALID_INTERVAL);
102     if (!ret) {
103         FFRT_LOGE("Failed to Set Invalid Interval %d", INVALID_INTERVAL);
104     }
105 
106     ret = RTGCtrl::Instance().PutThreadGroup(tgid);
107     if (!ret) {
108         FFRT_LOGE("Failed to Put RTG id %d", tgid);
109     }
110 }
111 
112 HWTEST_F(RTGTest, rtg_set_preferred_cluster_test, TestSize.Level1)
113 {
114     constexpr int CLUSTER_ID = 0;
115 
116     int tgid = RTGCtrl::Instance().GetThreadGroup();
117     if (tgid < 0) {
118         FFRT_LOGE("Failed to Get RTG id %d", tgid);
119     }
120 
121     bool ret = RTGCtrl::Instance().SetPreferredCluster(tgid, CLUSTER_ID);
122     if (!ret) {
123         FFRT_LOGE("Failed to Set Preferred Cluster %d", CLUSTER_ID);
124     }
125 
126     ret = RTGCtrl::Instance().PutThreadGroup(tgid);
127     if (!ret) {
128         FFRT_LOGE("Failed to Put RTG id %d", tgid);
129     }
130 }
131 
132 HWTEST_F(RTGTest, rtg_begin_end_test, TestSize.Level1)
133 {
134     int tgid = RTGCtrl::Instance().GetThreadGroup();
135     if (tgid < 0) {
136         FFRT_LOGE("Failed to Get RTG id %d", tgid);
137     }
138 
139     bool ret = RTGCtrl::Instance().Begin(tgid);
140     if (!ret) {
141         FFRT_LOGE("Failed to Begin");
142     }
143 
144     ret = RTGCtrl::Instance().End(tgid);
145     if (!ret) {
146         FFRT_LOGE("Failed to End");
147     }
148 
149     ret = RTGCtrl::Instance().PutThreadGroup(tgid);
150     if (!ret) {
151         FFRT_LOGE("Failed to Put RTG id %d", tgid);
152     }
153 }
154 
155 HWTEST_F(RTGTest, rtg_add_tread_test, TestSize.Level1)
156 {
157     constexpr int THREAD_NUM = 8;
158     bool ret;
159     int tgid = RTGCtrl::Instance().GetThreadGroup();
160     if (tgid < 0) {
161         FFRT_LOGE("Failed to Get RTG id %d", tgid);
162     }
163 
164     std::vector<std::thread> threads;
165 
166     std::mutex tidMutex;
167     std::vector<pid_t> tids;
168 
169     std::mutex condMutex;
170     std::condition_variable cond;
171 
__anone3ead2840102() 172     auto f = [&]() {
173         pid_t tid = RTGCtrl::GetTID();
174 
175         {
176             std::unique_lock lock(tidMutex);
177             tids.emplace_back(tid);
178         }
179 
180         std::unique_lock lock(condMutex);
181         cond.wait(lock);
182     };
183 
184     for (int i = 0; i < THREAD_NUM; ++i) {
185         threads.emplace_back(std::thread(f));
186     }
187 
188     while (true) {
189         std::unique_lock lock(tidMutex);
190         if (tids.size() >= THREAD_NUM) {
191             break;
192         }
193     }
194 
195     for (auto tid : tids) {
196         ret = RTGCtrl::Instance().JoinThread(tgid, tid);
197         if (!ret) {
198             FFRT_LOGE("Failed To Join Thread %d", tid);
199         }
200     }
201 
202     ret = RTGCtrl::Instance().UpdatePerfFreq(tgid, 960000);
203     for (auto tid : tids) {
204         auto [t_load, t_runtime] = RTGCtrl::Instance().UpdateAndGetLoad(tgid, tid);
205         FFRT_LOGE("Get Load %lu runtime %lu", t_load, t_runtime);
206         ret = RTGCtrl::Instance().RemoveThread(tgid, tid);
207         if (!ret) {
208             FFRT_LOGE("Failed To Leave Thread %d", tid);
209         }
210     }
211 
212     cond.notify_all();
213     for (auto& thread : threads) {
214         thread.join();
215     }
216 
217     ret = RTGCtrl::Instance().PutThreadGroup(tgid);
218     if (!ret) {
219         FFRT_LOGE("Failed to Put RTG id %d", tgid);
220     }
221 }
222 
223 HWTEST_F(RTGTest, rtg_update_util_test, TestSize.Level1)
224 {
225     constexpr int THREAD_NUM = 8;
226 
227     int tgid = RTGCtrl::Instance().GetThreadGroup();
228     if (tgid < 0) {
229         FFRT_LOGE("Failed to Get RTG id %d", tgid);
230     }
231 
232     std::vector<std::thread> threads;
233 
234     std::mutex tidMutex;
235     std::vector<pid_t> tids;
236 
237     std::mutex condMutex;
238     std::condition_variable cond;
239 
__anone3ead2840202() 240     auto f = [&]() {
241         pid_t tid = RTGCtrl::GetTID();
242 
243         {
244             std::unique_lock lock(tidMutex);
245             tids.emplace_back(tid);
246         }
247 
248         std::unique_lock lock(condMutex);
249         cond.wait(lock);
250     };
251 
252     for (int i = 0; i < THREAD_NUM; ++i) {
253         threads.emplace_back(std::thread(f));
254     }
255 
256     while (true) {
257         std::unique_lock lock(tidMutex);
258         if (tids.size() >= THREAD_NUM) {
259             break;
260         }
261     }
262 
263     for (auto tid : tids) {
264         bool ret = RTGCtrl::Instance().JoinThread(tgid, tid);
265         if (!ret) {
266             FFRT_LOGE("Failed To Join Thread %d", tid);
267         }
268     }
269 
270     bool ret = RTGCtrl::Instance().Begin(tgid);
271     if (!ret) {
272         FFRT_LOGE("Failed to Begin");
273     }
274 
275     for (int util = 8; util <= 1024; util <<= 1) {
276         auto [load, runtime] = RTGCtrl::Instance().UpdateAndGetLoad(tgid);
277         FFRT_LOGE("Get Load %lu runtime %lu", load, runtime);
278 
279         ret = RTGCtrl::Instance().UpdatePerfUtil(tgid, util);
280         if (!ret) {
281             FFRT_LOGE("Failed To Update Util %d", util);
282         }
283     }
284 
285     for (auto tid : tids) {
286         ret = RTGCtrl::Instance().RemoveThread(tgid, tid);
287         if (!ret) {
288             FFRT_LOGE("Failed To Leave Thread %d", tid);
289         }
290     }
291 
292     ret = RTGCtrl::Instance().End(tgid);
293     if (!ret) {
294         FFRT_LOGE("Failed to End");
295     }
296 
297     cond.notify_all();
298     for (auto& thread : threads) {
299         thread.join();
300     }
301 
302     ret = RTGCtrl::Instance().PutThreadGroup(tgid);
303     if (!ret) {
304         FFRT_LOGE("Failed to Put RTG id %d", tgid);
305     }
306 }
307