1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
3 */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <unistd.h>
8 #include <limits.h>
9 #include <string.h>
10 #include <inttypes.h>
11 #include <rte_cycles.h>
12
13 #include "test.h"
14
15 #ifndef RTE_LIB_POWER
16
17 static int
test_power_cpufreq(void)18 test_power_cpufreq(void)
19 {
20 printf("Power management library not supported, skipping test\n");
21 return TEST_SKIPPED;
22 }
23
24 static int
test_power_caps(void)25 test_power_caps(void)
26 {
27 printf("Power management library not supported, skipping test\n");
28 return TEST_SKIPPED;
29 }
30
31 #else
32 #include <rte_power.h>
33
34 #define TEST_POWER_LCORE_ID 2U
35 #define TEST_POWER_LCORE_INVALID ((unsigned)RTE_MAX_LCORE)
36 #define TEST_POWER_FREQS_NUM_MAX ((unsigned)RTE_MAX_LCORE_FREQS)
37
38 /* macros used for rounding frequency to nearest 100000 */
39 #define TEST_FREQ_ROUNDING_DELTA 50000
40 #define TEST_ROUND_FREQ_TO_N_100000 100000
41
42 #define TEST_POWER_SYSFILE_CPUINFO_FREQ \
43 "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_cur_freq"
44 #define TEST_POWER_SYSFILE_SCALING_FREQ \
45 "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq"
46
47 static uint32_t total_freq_num;
48 static uint32_t freqs[TEST_POWER_FREQS_NUM_MAX];
49
50 static int
check_cur_freq(unsigned int lcore_id,uint32_t idx,bool turbo)51 check_cur_freq(unsigned int lcore_id, uint32_t idx, bool turbo)
52 {
53 #define TEST_POWER_CONVERT_TO_DECIMAL 10
54 #define MAX_LOOP 100
55 FILE *f;
56 char fullpath[PATH_MAX];
57 char buf[BUFSIZ];
58 enum power_management_env env;
59 uint32_t cur_freq;
60 uint32_t freq_conv;
61 int ret = -1;
62 int i;
63
64 if (snprintf(fullpath, sizeof(fullpath),
65 TEST_POWER_SYSFILE_CPUINFO_FREQ, lcore_id) < 0) {
66 return 0;
67 }
68 f = fopen(fullpath, "r");
69 if (f == NULL) {
70 if (snprintf(fullpath, sizeof(fullpath),
71 TEST_POWER_SYSFILE_SCALING_FREQ, lcore_id) < 0) {
72 return 0;
73 }
74 f = fopen(fullpath, "r");
75 if (f == NULL) {
76 return 0;
77 }
78 }
79 for (i = 0; i < MAX_LOOP; i++) {
80 fflush(f);
81 if (fgets(buf, sizeof(buf), f) == NULL)
82 goto fail_all;
83
84 cur_freq = strtoul(buf, NULL, TEST_POWER_CONVERT_TO_DECIMAL);
85 freq_conv = cur_freq;
86
87 env = rte_power_get_env();
88 if (env == PM_ENV_CPPC_CPUFREQ || env == PM_ENV_PSTATE_CPUFREQ) {
89 /* convert the frequency to nearest 100000 value
90 * Ex: if cur_freq=1396789 then freq_conv=1400000
91 * Ex: if cur_freq=800030 then freq_conv=800000
92 */
93 freq_conv = (cur_freq + TEST_FREQ_ROUNDING_DELTA)
94 / TEST_ROUND_FREQ_TO_N_100000;
95 freq_conv = freq_conv * TEST_ROUND_FREQ_TO_N_100000;
96 }
97
98 if (turbo)
99 ret = (freqs[idx] <= freq_conv ? 0 : -1);
100 else
101 ret = (freqs[idx] == freq_conv ? 0 : -1);
102
103 if (ret == 0)
104 break;
105
106 if (fseek(f, 0, SEEK_SET) < 0) {
107 printf("Fail to set file position indicator to 0\n");
108 goto fail_all;
109 }
110
111 /* wait for the value to be updated */
112 rte_delay_ms(10);
113 }
114
115 fail_all:
116 fclose(f);
117
118 return ret;
119 }
120
121 /* Check rte_power_freqs() */
122 static int
check_power_freqs(void)123 check_power_freqs(void)
124 {
125 uint32_t ret;
126
127 total_freq_num = 0;
128 memset(freqs, 0, sizeof(freqs));
129
130 /* test with an invalid lcore id */
131 ret = rte_power_freqs(TEST_POWER_LCORE_INVALID, freqs,
132 TEST_POWER_FREQS_NUM_MAX);
133 if (ret > 0) {
134 printf("Unexpectedly get available freqs successfully on "
135 "lcore %u\n", TEST_POWER_LCORE_INVALID);
136 return -1;
137 }
138
139 /* test with NULL buffer to save available freqs */
140 ret = rte_power_freqs(TEST_POWER_LCORE_ID, NULL,
141 TEST_POWER_FREQS_NUM_MAX);
142 if (ret > 0) {
143 printf("Unexpectedly get available freqs successfully with "
144 "NULL buffer on lcore %u\n", TEST_POWER_LCORE_ID);
145 return -1;
146 }
147
148 /* test of getting zero number of freqs */
149 ret = rte_power_freqs(TEST_POWER_LCORE_ID, freqs, 0);
150 if (ret > 0) {
151 printf("Unexpectedly get available freqs successfully with "
152 "zero buffer size on lcore %u\n", TEST_POWER_LCORE_ID);
153 return -1;
154 }
155
156 /* test with all valid input parameters */
157 ret = rte_power_freqs(TEST_POWER_LCORE_ID, freqs,
158 TEST_POWER_FREQS_NUM_MAX);
159 if (ret == 0 || ret > TEST_POWER_FREQS_NUM_MAX) {
160 printf("Fail to get available freqs on lcore %u\n",
161 TEST_POWER_LCORE_ID);
162 return -1;
163 }
164
165 /* Save the total number of available freqs */
166 total_freq_num = ret;
167
168 return 0;
169 }
170
171 /* Check rte_power_get_freq() */
172 static int
check_power_get_freq(void)173 check_power_get_freq(void)
174 {
175 int ret;
176 uint32_t count;
177
178 /* test with an invalid lcore id */
179 count = rte_power_get_freq(TEST_POWER_LCORE_INVALID);
180 if (count < TEST_POWER_FREQS_NUM_MAX) {
181 printf("Unexpectedly get freq index successfully on "
182 "lcore %u\n", TEST_POWER_LCORE_INVALID);
183 return -1;
184 }
185
186 count = rte_power_get_freq(TEST_POWER_LCORE_ID);
187 if (count >= TEST_POWER_FREQS_NUM_MAX) {
188 printf("Fail to get the freq index on lcore %u\n",
189 TEST_POWER_LCORE_ID);
190 return -1;
191 }
192
193 /* Check the current frequency */
194 ret = check_cur_freq(TEST_POWER_LCORE_ID, count, false);
195 if (ret < 0)
196 return -1;
197
198 return 0;
199 }
200
201 /* Check rte_power_set_freq() */
202 static int
check_power_set_freq(void)203 check_power_set_freq(void)
204 {
205 int ret;
206
207 /* test with an invalid lcore id */
208 ret = rte_power_set_freq(TEST_POWER_LCORE_INVALID, 0);
209 if (ret >= 0) {
210 printf("Unexpectedly set freq index successfully on "
211 "lcore %u\n", TEST_POWER_LCORE_INVALID);
212 return -1;
213 }
214
215 /* test with an invalid freq index */
216 ret = rte_power_set_freq(TEST_POWER_LCORE_ID,
217 TEST_POWER_FREQS_NUM_MAX);
218 if (ret >= 0) {
219 printf("Unexpectedly set an invalid freq index (%u)"
220 "successfully on lcore %u\n", TEST_POWER_FREQS_NUM_MAX,
221 TEST_POWER_LCORE_ID);
222 return -1;
223 }
224
225 /**
226 * test with an invalid freq index which is right one bigger than
227 * total number of freqs
228 */
229 ret = rte_power_set_freq(TEST_POWER_LCORE_ID, total_freq_num);
230 if (ret >= 0) {
231 printf("Unexpectedly set an invalid freq index (%u)"
232 "successfully on lcore %u\n", total_freq_num,
233 TEST_POWER_LCORE_ID);
234 return -1;
235 }
236 ret = rte_power_set_freq(TEST_POWER_LCORE_ID, total_freq_num - 1);
237 if (ret < 0) {
238 printf("Fail to set freq index on lcore %u\n",
239 TEST_POWER_LCORE_ID);
240 return -1;
241 }
242
243 /* Check the current frequency */
244 ret = check_cur_freq(TEST_POWER_LCORE_ID, total_freq_num - 1, false);
245 if (ret < 0)
246 return -1;
247
248 return 0;
249 }
250
251 /* Check rte_power_freq_down() */
252 static int
check_power_freq_down(void)253 check_power_freq_down(void)
254 {
255 int ret;
256
257 rte_power_freq_enable_turbo(TEST_POWER_LCORE_ID);
258
259 /* test with an invalid lcore id */
260 ret = rte_power_freq_down(TEST_POWER_LCORE_INVALID);
261 if (ret >= 0) {
262 printf("Unexpectedly scale down successfully the freq on "
263 "lcore %u\n", TEST_POWER_LCORE_INVALID);
264 return -1;
265 }
266
267 /* Scale down to min and then scale down one step */
268 ret = rte_power_freq_min(TEST_POWER_LCORE_ID);
269 if (ret < 0) {
270 printf("Fail to scale down the freq to min on lcore %u\n",
271 TEST_POWER_LCORE_ID);
272 return -1;
273 }
274 ret = rte_power_freq_down(TEST_POWER_LCORE_ID);
275 if (ret < 0) {
276 printf("Fail to scale down the freq on lcore %u\n",
277 TEST_POWER_LCORE_ID);
278 return -1;
279 }
280
281 /* Check the current frequency */
282 ret = check_cur_freq(TEST_POWER_LCORE_ID, total_freq_num - 1, false);
283 if (ret < 0)
284 return -1;
285
286 /* Scale up to max and then scale down one step */
287 ret = rte_power_freq_max(TEST_POWER_LCORE_ID);
288 if (ret < 0) {
289 printf("Fail to scale up the freq to max on lcore %u\n",
290 TEST_POWER_LCORE_ID);
291 return -1;
292 }
293 ret = rte_power_freq_down(TEST_POWER_LCORE_ID);
294 if (ret < 0) {
295 printf("Fail to scale down the freq on lcore %u\n",
296 TEST_POWER_LCORE_ID);
297 return -1;
298 }
299
300 /* Check the current frequency */
301 ret = check_cur_freq(TEST_POWER_LCORE_ID, 1, false);
302 if (ret < 0)
303 return -1;
304
305 return 0;
306 }
307
308 /* Check rte_power_freq_up() */
309 static int
check_power_freq_up(void)310 check_power_freq_up(void)
311 {
312 int ret;
313
314 /* test with an invalid lcore id */
315 ret = rte_power_freq_up(TEST_POWER_LCORE_INVALID);
316 if (ret >= 0) {
317 printf("Unexpectedly scale up successfully the freq on %u\n",
318 TEST_POWER_LCORE_INVALID);
319 return -1;
320 }
321
322 /* Scale down to min and then scale up one step */
323 ret = rte_power_freq_min(TEST_POWER_LCORE_ID);
324 if (ret < 0) {
325 printf("Fail to scale down the freq to min on lcore %u\n",
326 TEST_POWER_LCORE_ID);
327 return -1;
328 }
329 ret = rte_power_freq_up(TEST_POWER_LCORE_ID);
330 if (ret < 0) {
331 printf("Fail to scale up the freq on lcore %u\n",
332 TEST_POWER_LCORE_ID);
333 return -1;
334 }
335
336 /* Check the current frequency */
337 ret = check_cur_freq(TEST_POWER_LCORE_ID, total_freq_num - 2, false);
338 if (ret < 0)
339 return -1;
340
341 /* Scale up to max and then scale up one step */
342 ret = rte_power_freq_max(TEST_POWER_LCORE_ID);
343 if (ret < 0) {
344 printf("Fail to scale up the freq to max on lcore %u\n",
345 TEST_POWER_LCORE_ID);
346 return -1;
347 }
348 ret = rte_power_freq_up(TEST_POWER_LCORE_ID);
349 if (ret < 0) {
350 printf("Fail to scale up the freq on lcore %u\n",
351 TEST_POWER_LCORE_ID);
352 return -1;
353 }
354
355 /* Check the current frequency */
356 ret = check_cur_freq(TEST_POWER_LCORE_ID, 0, true);
357 if (ret < 0)
358 return -1;
359
360 return 0;
361 }
362
363 /* Check rte_power_freq_max() */
364 static int
check_power_freq_max(void)365 check_power_freq_max(void)
366 {
367 int ret;
368
369 /* test with an invalid lcore id */
370 ret = rte_power_freq_max(TEST_POWER_LCORE_INVALID);
371 if (ret >= 0) {
372 printf("Unexpectedly scale up successfully the freq to max on "
373 "lcore %u\n", TEST_POWER_LCORE_INVALID);
374 return -1;
375 }
376 ret = rte_power_freq_max(TEST_POWER_LCORE_ID);
377 if (ret < 0) {
378 printf("Fail to scale up the freq to max on lcore %u\n",
379 TEST_POWER_LCORE_ID);
380 return -1;
381 }
382
383 /* Check the current frequency */
384 ret = check_cur_freq(TEST_POWER_LCORE_ID, 0, true);
385 if (ret < 0)
386 return -1;
387
388 return 0;
389 }
390
391 /* Check rte_power_freq_min() */
392 static int
check_power_freq_min(void)393 check_power_freq_min(void)
394 {
395 int ret;
396
397 /* test with an invalid lcore id */
398 ret = rte_power_freq_min(TEST_POWER_LCORE_INVALID);
399 if (ret >= 0) {
400 printf("Unexpectedly scale down successfully the freq to min "
401 "on lcore %u\n", TEST_POWER_LCORE_INVALID);
402 return -1;
403 }
404 ret = rte_power_freq_min(TEST_POWER_LCORE_ID);
405 if (ret < 0) {
406 printf("Fail to scale down the freq to min on lcore %u\n",
407 TEST_POWER_LCORE_ID);
408 return -1;
409 }
410
411 /* Check the current frequency */
412 ret = check_cur_freq(TEST_POWER_LCORE_ID, total_freq_num - 1, false);
413 if (ret < 0)
414 return -1;
415
416 return 0;
417 }
418
419 /* Check rte_power_turbo() */
420 static int
check_power_turbo(void)421 check_power_turbo(void)
422 {
423 int ret;
424
425 if (rte_power_turbo_status(TEST_POWER_LCORE_ID) == 0) {
426 printf("Turbo not available on lcore %u, skipping test\n",
427 TEST_POWER_LCORE_ID);
428 return 0;
429 }
430
431 /* test with an invalid lcore id */
432 ret = rte_power_freq_enable_turbo(TEST_POWER_LCORE_INVALID);
433 if (ret >= 0) {
434 printf("Unexpectedly enable turbo successfully on lcore %u\n",
435 TEST_POWER_LCORE_INVALID);
436 return -1;
437 }
438 ret = rte_power_freq_enable_turbo(TEST_POWER_LCORE_ID);
439 if (ret < 0) {
440 printf("Fail to enable turbo on lcore %u\n",
441 TEST_POWER_LCORE_ID);
442 return -1;
443 }
444 ret = rte_power_freq_max(TEST_POWER_LCORE_ID);
445 if (ret < 0) {
446 printf("Fail to scale up the freq to max on lcore %u\n",
447 TEST_POWER_LCORE_ID);
448 return -1;
449 }
450
451 /* Check the current frequency */
452 ret = check_cur_freq(TEST_POWER_LCORE_ID, 0, true);
453 if (ret < 0)
454 return -1;
455
456 /* test with an invalid lcore id */
457 ret = rte_power_freq_disable_turbo(TEST_POWER_LCORE_INVALID);
458 if (ret >= 0) {
459 printf("Unexpectedly disable turbo successfully on lcore %u\n",
460 TEST_POWER_LCORE_INVALID);
461 return -1;
462 }
463 ret = rte_power_freq_disable_turbo(TEST_POWER_LCORE_ID);
464 if (ret < 0) {
465 printf("Fail to disable turbo on lcore %u\n",
466 TEST_POWER_LCORE_ID);
467 return -1;
468 }
469 ret = rte_power_freq_max(TEST_POWER_LCORE_ID);
470 if (ret < 0) {
471 printf("Fail to scale up the freq to max on lcore %u\n",
472 TEST_POWER_LCORE_ID);
473 return -1;
474 }
475
476 /* Check the current frequency */
477 ret = check_cur_freq(TEST_POWER_LCORE_ID, 1, false);
478 if (ret < 0)
479 return -1;
480
481 return 0;
482 }
483
484 static int
test_power_cpufreq(void)485 test_power_cpufreq(void)
486 {
487 int ret = -1;
488 enum power_management_env env;
489
490 /* Test initialisation of a valid lcore */
491 ret = rte_power_init(TEST_POWER_LCORE_ID);
492 if (ret < 0) {
493 printf("Cannot initialise power management for lcore %u, this "
494 "may occur if environment is not configured "
495 "correctly(APCI cpufreq) or operating in another valid "
496 "Power management environment\n",
497 TEST_POWER_LCORE_ID);
498 rte_power_unset_env();
499 return TEST_SKIPPED;
500 }
501
502 /* Test environment configuration */
503 env = rte_power_get_env();
504 if ((env != PM_ENV_ACPI_CPUFREQ) && (env != PM_ENV_PSTATE_CPUFREQ) &&
505 (env != PM_ENV_CPPC_CPUFREQ)) {
506 printf("Unexpectedly got an environment other than ACPI/PSTATE\n");
507 goto fail_all;
508 }
509
510 /* verify that function pointers are not NULL */
511 if (rte_power_freqs == NULL) {
512 printf("rte_power_freqs should not be NULL, environment has not been "
513 "initialised\n");
514 goto fail_all;
515 }
516 if (rte_power_get_freq == NULL) {
517 printf("rte_power_get_freq should not be NULL, environment has not "
518 "been initialised\n");
519 goto fail_all;
520 }
521 if (rte_power_set_freq == NULL) {
522 printf("rte_power_set_freq should not be NULL, environment has not "
523 "been initialised\n");
524 goto fail_all;
525 }
526 if (rte_power_freq_up == NULL) {
527 printf("rte_power_freq_up should not be NULL, environment has not "
528 "been initialised\n");
529 goto fail_all;
530 }
531 if (rte_power_freq_down == NULL) {
532 printf("rte_power_freq_down should not be NULL, environment has not "
533 "been initialised\n");
534 goto fail_all;
535 }
536 if (rte_power_freq_max == NULL) {
537 printf("rte_power_freq_max should not be NULL, environment has not "
538 "been initialised\n");
539 goto fail_all;
540 }
541 if (rte_power_freq_min == NULL) {
542 printf("rte_power_freq_min should not be NULL, environment has not "
543 "been initialised\n");
544 goto fail_all;
545 }
546 if (rte_power_turbo_status == NULL) {
547 printf("rte_power_turbo_status should not be NULL, environment has not "
548 "been initialised\n");
549 goto fail_all;
550 }
551 if (rte_power_freq_enable_turbo == NULL) {
552 printf("rte_power_freq_enable_turbo should not be NULL, environment has not "
553 "been initialised\n");
554 goto fail_all;
555 }
556 if (rte_power_freq_disable_turbo == NULL) {
557 printf("rte_power_freq_disable_turbo should not be NULL, environment has not "
558 "been initialised\n");
559 goto fail_all;
560 }
561
562 ret = rte_power_exit(TEST_POWER_LCORE_ID);
563 if (ret < 0) {
564 printf("Cannot exit power management for lcore %u\n",
565 TEST_POWER_LCORE_ID);
566 rte_power_unset_env();
567 return -1;
568 }
569
570 /* test of init power management for an invalid lcore */
571 ret = rte_power_init(TEST_POWER_LCORE_INVALID);
572 if (ret == 0) {
573 printf("Unexpectedly initialise power management successfully "
574 "for lcore %u\n", TEST_POWER_LCORE_INVALID);
575 rte_power_unset_env();
576 return -1;
577 }
578
579 /* Test initialisation of a valid lcore */
580 ret = rte_power_init(TEST_POWER_LCORE_ID);
581 if (ret < 0) {
582 printf("Cannot initialise power management for lcore %u, this "
583 "may occur if environment is not configured "
584 "correctly(APCI cpufreq) or operating in another valid "
585 "Power management environment\n", TEST_POWER_LCORE_ID);
586 rte_power_unset_env();
587 return TEST_SKIPPED;
588 }
589
590 /**
591 * test of initialising power management for the lcore which has
592 * been initialised
593 */
594 ret = rte_power_init(TEST_POWER_LCORE_ID);
595 if (ret == 0) {
596 printf("Unexpectedly init successfully power twice on "
597 "lcore %u\n", TEST_POWER_LCORE_ID);
598 goto fail_all;
599 }
600
601 ret = check_power_freqs();
602 if (ret < 0)
603 goto fail_all;
604
605 if (total_freq_num < 2) {
606 rte_power_exit(TEST_POWER_LCORE_ID);
607 printf("Frequency can not be changed due to CPU itself\n");
608 rte_power_unset_env();
609 return 0;
610 }
611
612 ret = check_power_get_freq();
613 if (ret < 0)
614 goto fail_all;
615
616 ret = check_power_set_freq();
617 if (ret < 0)
618 goto fail_all;
619
620 ret = check_power_freq_down();
621 if (ret < 0)
622 goto fail_all;
623
624 ret = check_power_freq_up();
625 if (ret < 0)
626 goto fail_all;
627
628 ret = check_power_freq_max();
629 if (ret < 0)
630 goto fail_all;
631
632 ret = check_power_freq_min();
633 if (ret < 0)
634 goto fail_all;
635
636 ret = check_power_turbo();
637 if (ret < 0)
638 goto fail_all;
639
640 ret = rte_power_exit(TEST_POWER_LCORE_ID);
641 if (ret < 0) {
642 printf("Cannot exit power management for lcore %u\n",
643 TEST_POWER_LCORE_ID);
644 rte_power_unset_env();
645 return -1;
646 }
647
648 /**
649 * test of exiting power management for the lcore which has been exited
650 */
651 ret = rte_power_exit(TEST_POWER_LCORE_ID);
652 if (ret == 0) {
653 printf("Unexpectedly exit successfully power management twice "
654 "on lcore %u\n", TEST_POWER_LCORE_ID);
655 rte_power_unset_env();
656 return -1;
657 }
658
659 /* test of exit power management for an invalid lcore */
660 ret = rte_power_exit(TEST_POWER_LCORE_INVALID);
661 if (ret == 0) {
662 printf("Unexpectedly exit power management successfully for "
663 "lcore %u\n", TEST_POWER_LCORE_INVALID);
664 rte_power_unset_env();
665 return -1;
666 }
667 rte_power_unset_env();
668 return 0;
669
670 fail_all:
671 rte_power_exit(TEST_POWER_LCORE_ID);
672 rte_power_unset_env();
673 return -1;
674 }
675
676 static int
test_power_caps(void)677 test_power_caps(void)
678 {
679 struct rte_power_core_capabilities caps;
680 int ret;
681
682 ret = rte_power_init(TEST_POWER_LCORE_ID);
683 if (ret < 0) {
684 printf("Cannot initialise power management for lcore %u, this "
685 "may occur if environment is not configured "
686 "correctly(APCI cpufreq) or operating in another valid "
687 "Power management environment\n", TEST_POWER_LCORE_ID);
688 rte_power_unset_env();
689 return -1;
690 }
691
692 ret = rte_power_get_capabilities(TEST_POWER_LCORE_ID, &caps);
693 if (ret) {
694 printf("POWER: Error getting capabilities\n");
695 return -1;
696 }
697
698 printf("POWER: Capabilities %"PRIx64"\n", caps.capabilities);
699
700 rte_power_unset_env();
701 return 0;
702 }
703
704 #endif
705
706 REGISTER_TEST_COMMAND(power_cpufreq_autotest, test_power_cpufreq);
707 REGISTER_TEST_COMMAND(power_caps_autotest, test_power_caps);
708