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