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