1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Unit test for mod_perf_controller.c
8 */
9
10 #include "scp_unity.h"
11 #include "unity.h"
12
13 #include <Mockmod_perf_controller_extra.h>
14 #include <config_mod_perf_controller.h>
15 #include <internal/perf_controller.h>
16
17 #include <mod_perf_controller.h>
18
19 #include <fwk_module_idx.h>
20
21 #include <stdlib.h>
22
23 #include UNIT_TEST_SRC
24
25 static struct mod_perf_controller_cluster_ctx
26 test_cluster_ctx_table[TEST_CLUSTER_COUNT];
27 static struct mod_perf_controller_core_ctx
28 test_core_ctx_table[TEST_CLUSTER_COUNT][MAX_CORE_PER_CLUSTER];
29
30 static struct mod_perf_controller_drv_api perf_driver_api = {
31 .set_performance_level = driver_set_performance_level,
32 };
33
34 static struct mod_perf_controller_power_model_api power_model_api = {
35 .power_to_performance = power_to_performance,
36 };
37
setUp(void)38 void setUp(void)
39 {
40 unsigned int cluster_idx;
41 struct mod_perf_controller_cluster_ctx *cluster_ctx;
42
43 perf_controller_ctx.cluster_ctx_table = test_cluster_ctx_table;
44 perf_controller_ctx.cluster_count = TEST_CLUSTER_COUNT;
45
46 for (cluster_idx = 0U; cluster_idx < TEST_CLUSTER_COUNT; cluster_idx++) {
47 cluster_ctx = &perf_controller_ctx.cluster_ctx_table[cluster_idx];
48 cluster_ctx->core_ctx_table = test_core_ctx_table[cluster_idx];
49 cluster_ctx->perf_driver_api = &perf_driver_api;
50 cluster_ctx->power_model_api = &power_model_api;
51 cluster_ctx->config = (struct mod_perf_controller_cluster_config *)
52 cluster_config[cluster_idx]
53 .data;
54 cluster_ctx->core_count = cluster_config[cluster_idx].sub_element_count;
55 }
56
57 internal_api.get_cores_min_power_limit = get_cores_min_power_limit_stub;
58 internal_api.cluster_apply_performance_granted =
59 cluster_apply_performance_granted_stub;
60 }
61
tearDown(void)62 void tearDown(void)
63 {
64 Mockmod_perf_controller_extra_Verify();
65 Mockmod_perf_controller_extra_Destroy();
66 }
67
68 /*!
69 * \brief Helper function to compare two values.
70 *
71 * \details returns -1 when a < b,
72 * returns 1 when a >b,
73 * return 0 when a = b.
74 */
helper_comp(const void * a,const void * b)75 int helper_comp(const void *a, const void *b)
76 {
77 return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
78 }
79
test_set_performance_level_within_limits(void)80 void test_set_performance_level_within_limits(void)
81 {
82 int status;
83 unsigned int cluster_idx;
84 fwk_id_t cluster_id;
85 struct mod_perf_controller_cluster_ctx *cluster_ctx;
86 uintptr_t cookie;
87 uint32_t performance_level;
88
89 for (cluster_idx = 0U; cluster_idx < TEST_CLUSTER_COUNT; cluster_idx++) {
90 cluster_id =
91 FWK_ID_ELEMENT(FWK_MODULE_IDX_PERF_CONTROLLER, cluster_idx);
92 cluster_ctx = &perf_controller_ctx.cluster_ctx_table[cluster_idx];
93
94 performance_level = 10U;
95 cluster_ctx->performance_limit = performance_level;
96
97 cookie = 15U;
98 driver_set_performance_level_ExpectAndReturn(
99 cluster_ctx->config->performance_driver_id,
100 cookie,
101 performance_level,
102 FWK_SUCCESS);
103
104 status = mod_perf_controller_set_performance_level(
105 cluster_id, cookie, performance_level);
106
107 TEST_ASSERT_EQUAL(
108 cluster_ctx->performance_request_details.level, performance_level);
109 TEST_ASSERT_EQUAL(cluster_ctx->performance_request_details.cookie, 0U);
110 TEST_ASSERT_EQUAL(status, FWK_SUCCESS);
111 }
112 }
113
test_set_performance_level_out_of_limits(void)114 void test_set_performance_level_out_of_limits(void)
115 {
116 int status;
117 unsigned int cluster_idx;
118 fwk_id_t cluster_id;
119 struct mod_perf_controller_cluster_ctx *cluster_ctx;
120 uintptr_t cookie;
121 uint32_t performance_level;
122
123 for (cluster_idx = 0U; cluster_idx < TEST_CLUSTER_COUNT; cluster_idx++) {
124 cluster_id =
125 FWK_ID_ELEMENT(FWK_MODULE_IDX_PERF_CONTROLLER, cluster_idx);
126 cluster_ctx = &perf_controller_ctx.cluster_ctx_table[cluster_idx];
127
128 cluster_ctx->performance_limit = 10U;
129 performance_level = cluster_ctx->performance_limit + 1U;
130
131 cookie = 1U;
132 status = mod_perf_controller_set_performance_level(
133 cluster_id, cookie, performance_level);
134
135 TEST_ASSERT_EQUAL(
136 cluster_ctx->performance_request_details.level, performance_level);
137 TEST_ASSERT_EQUAL(
138 cluster_ctx->performance_request_details.cookie, cookie);
139 TEST_ASSERT_EQUAL(status, FWK_PENDING);
140 }
141 }
142
test_set_limit_success(void)143 void test_set_limit_success(void)
144 {
145 int status;
146 fwk_id_t core_id;
147 struct mod_perf_controller_core_ctx *core_ctx;
148 struct mod_perf_controller_cluster_ctx *cluster_ctx;
149 unsigned int cluster_idx = TEST_CLUSTER_COUNT - 1U;
150 unsigned int core_idx = MAX_CORE_PER_CLUSTER - 1U;
151 uint32_t power_limit;
152
153 for (cluster_idx = 0U; cluster_idx < TEST_CLUSTER_COUNT - 1U;
154 cluster_idx++) {
155 cluster_ctx = &perf_controller_ctx.cluster_ctx_table[cluster_idx];
156 for (core_idx = 0U; core_idx < cluster_ctx->core_count; core_idx++) {
157 core_id = FWK_ID_SUB_ELEMENT(
158 FWK_MODULE_IDX_PERF_CONTROLLER, cluster_idx, core_idx);
159 core_ctx = &perf_controller_ctx.cluster_ctx_table[cluster_idx]
160 .core_ctx_table[core_idx];
161
162 power_limit = 20U;
163 status = mod_perf_controller_set_limit(core_id, power_limit);
164
165 TEST_ASSERT_EQUAL(core_ctx->power_limit, power_limit);
166 TEST_ASSERT_EQUAL(status, FWK_SUCCESS);
167 }
168 }
169 }
170
test_get_cores_min_power_limit(void)171 void test_get_cores_min_power_limit(void)
172 {
173 uint32_t min_power_limit;
174 unsigned int core_idx;
175 unsigned int cluster_idx;
176 struct mod_perf_controller_cluster_ctx *cluster_ctx;
177 uint32_t core_power_limit_test_values[MAX_CORE_PER_CLUSTER] = {
178 100U, 300U, 200U, 10U
179 };
180
181 for (cluster_idx = 0U; cluster_idx < TEST_CLUSTER_COUNT - 1U;
182 cluster_idx++) {
183 cluster_ctx = &perf_controller_ctx.cluster_ctx_table[cluster_idx];
184
185 for (core_idx = 0u; core_idx < cluster_ctx->core_count; core_idx++) {
186 cluster_ctx->core_ctx_table[core_idx].power_limit =
187 core_power_limit_test_values[core_idx];
188 }
189
190 min_power_limit = get_cores_min_power_limit(cluster_ctx);
191
192 /*
193 Using sorting to determine the minimum. qsort is used as it is a
194 standard function that would make the test easier. The heavy lifting
195 still needs to be done on the implementation side.
196 */
197
198 qsort(
199 core_power_limit_test_values,
200 cluster_ctx->core_count,
201 sizeof(core_power_limit_test_values[0]),
202 helper_comp);
203
204 TEST_ASSERT_EQUAL(core_power_limit_test_values[0], min_power_limit);
205 }
206 }
207
test_controller_apply_performance_granted_within_limits(void)208 void test_controller_apply_performance_granted_within_limits(void)
209 {
210 int status;
211 unsigned int cluster_idx;
212 struct mod_perf_controller_cluster_ctx *cluster_ctx;
213 uint32_t min_power_limit;
214 uint32_t performance_limit;
215 uint32_t *requested_performance;
216 uintptr_t *cookie;
217
218 for (cluster_idx = 0U; cluster_idx < TEST_CLUSTER_COUNT - 1U;
219 cluster_idx++) {
220 cluster_ctx = &perf_controller_ctx.cluster_ctx_table[cluster_idx];
221 requested_performance = &cluster_ctx->performance_request_details.level;
222 cookie = &cluster_ctx->performance_request_details.cookie;
223
224 min_power_limit = 500U;
225 performance_limit = 700U;
226
227 get_cores_min_power_limit_stub_ExpectAndReturn(
228 cluster_ctx, min_power_limit);
229
230 power_to_performance_ExpectAndReturn(
231 cluster_ctx->config->power_model_id,
232 min_power_limit,
233 NULL,
234 FWK_SUCCESS);
235
236 power_to_performance_IgnoreArg_performance_level();
237
238 power_to_performance_ReturnThruPtr_performance_level(
239 &performance_limit);
240
241 *requested_performance = performance_limit;
242 *cookie = 2U;
243
244 driver_set_performance_level_ExpectAndReturn(
245 cluster_ctx->config->performance_driver_id,
246 *cookie,
247 *requested_performance,
248 FWK_SUCCESS);
249
250 status = cluster_apply_performance_granted(cluster_ctx);
251
252 TEST_ASSERT_EQUAL(status, FWK_SUCCESS);
253 }
254 }
255
test_controller_apply_performance_granted_out_of_limits(void)256 void test_controller_apply_performance_granted_out_of_limits(void)
257 {
258 int status;
259 unsigned int cluster_idx;
260 struct mod_perf_controller_cluster_ctx *cluster_ctx;
261 uint32_t min_power_limit;
262 uint32_t performance_limit;
263 uint32_t *requested_performance;
264 uintptr_t *cookie;
265
266 for (cluster_idx = 0U; cluster_idx < TEST_CLUSTER_COUNT - 1U;
267 cluster_idx++) {
268 cluster_ctx = &perf_controller_ctx.cluster_ctx_table[cluster_idx];
269 requested_performance = &cluster_ctx->performance_request_details.level;
270 cookie = &cluster_ctx->performance_request_details.cookie;
271
272 min_power_limit = 800U;
273 performance_limit = 991U;
274
275 get_cores_min_power_limit_stub_ExpectAndReturn(
276 cluster_ctx, min_power_limit);
277
278 power_to_performance_ExpectAndReturn(
279 cluster_ctx->config->power_model_id,
280 min_power_limit,
281 NULL,
282 FWK_SUCCESS);
283
284 power_to_performance_IgnoreArg_performance_level();
285
286 power_to_performance_ReturnThruPtr_performance_level(
287 &performance_limit);
288
289 *requested_performance = performance_limit + 1U;
290 *cookie = 3U;
291
292 driver_set_performance_level_ExpectAndReturn(
293 cluster_ctx->config->performance_driver_id,
294 0U, /* No cookie */
295 performance_limit,
296 FWK_SUCCESS);
297
298 status = cluster_apply_performance_granted(cluster_ctx);
299
300 TEST_ASSERT_EQUAL(status, FWK_SUCCESS);
301 }
302 }
303
test_controller_apply_performance_granted_success(void)304 void test_controller_apply_performance_granted_success(void)
305 {
306 int status;
307 unsigned int cluster_idx;
308 struct mod_perf_controller_cluster_ctx *cluster_ctx;
309
310 for (cluster_idx = 0U; cluster_idx < TEST_CLUSTER_COUNT; cluster_idx++) {
311 cluster_ctx = &perf_controller_ctx.cluster_ctx_table[cluster_idx];
312 cluster_apply_performance_granted_stub_ExpectAndReturn(
313 cluster_ctx, FWK_SUCCESS);
314 }
315
316 status = mod_perf_controller_apply_performance_granted();
317
318 TEST_ASSERT_EQUAL(status, FWK_SUCCESS);
319 }
320
perf_controller_test_main(void)321 int perf_controller_test_main(void)
322 {
323 UNITY_BEGIN();
324
325 RUN_TEST(test_set_performance_level_within_limits);
326 RUN_TEST(test_set_performance_level_out_of_limits);
327 RUN_TEST(test_set_limit_success);
328 RUN_TEST(test_get_cores_min_power_limit);
329 RUN_TEST(test_controller_apply_performance_granted_within_limits);
330 RUN_TEST(test_controller_apply_performance_granted_out_of_limits);
331 RUN_TEST(test_controller_apply_performance_granted_success);
332
333 return UNITY_END();
334 }
335
336 #if !defined(TEST_ON_TARGET)
main(void)337 int main(void)
338 {
339 return perf_controller_test_main();
340 }
341 #endif
342