cpufreq-info.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /*
  2. * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
  3. *
  4. * Licensed under the terms of the GNU GPL License version 2.
  5. */
  6. #include <unistd.h>
  7. #include <stdio.h>
  8. #include <errno.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <getopt.h>
  12. #include "cpufreq.h"
  13. #include "helpers/helpers.h"
  14. #include "helpers/bitmask.h"
  15. #define LINE_LEN 10
  16. static unsigned int count_cpus(void)
  17. {
  18. FILE *fp;
  19. char value[LINE_LEN];
  20. unsigned int ret = 0;
  21. unsigned int cpunr = 0;
  22. fp = fopen("/proc/stat", "r");
  23. if (!fp) {
  24. printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
  25. return 1;
  26. }
  27. while (!feof(fp)) {
  28. if (!fgets(value, LINE_LEN, fp))
  29. continue;
  30. value[LINE_LEN - 1] = '\0';
  31. if (strlen(value) < (LINE_LEN - 2))
  32. continue;
  33. if (strstr(value, "cpu "))
  34. continue;
  35. if (sscanf(value, "cpu%d ", &cpunr) != 1)
  36. continue;
  37. if (cpunr > ret)
  38. ret = cpunr;
  39. }
  40. fclose(fp);
  41. /* cpu count starts from 0, on error return 1 (UP) */
  42. return ret + 1;
  43. }
  44. static void proc_cpufreq_output(void)
  45. {
  46. unsigned int cpu, nr_cpus;
  47. struct cpufreq_policy *policy;
  48. unsigned int min_pctg = 0;
  49. unsigned int max_pctg = 0;
  50. unsigned long min, max;
  51. printf(_(" minimum CPU frequency - maximum CPU frequency - governor\n"));
  52. nr_cpus = count_cpus();
  53. for (cpu = 0; cpu < nr_cpus; cpu++) {
  54. policy = cpufreq_get_policy(cpu);
  55. if (!policy)
  56. continue;
  57. if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
  58. max = 0;
  59. } else {
  60. min_pctg = (policy->min * 100) / max;
  61. max_pctg = (policy->max * 100) / max;
  62. }
  63. printf("CPU%3d %9lu kHz (%3d %%) - %9lu kHz (%3d %%) - %s\n",
  64. cpu , policy->min, max ? min_pctg : 0, policy->max,
  65. max ? max_pctg : 0, policy->governor);
  66. cpufreq_put_policy(policy);
  67. }
  68. }
  69. static void print_speed(unsigned long speed)
  70. {
  71. unsigned long tmp;
  72. if (speed > 1000000) {
  73. tmp = speed % 10000;
  74. if (tmp >= 5000)
  75. speed += 10000;
  76. printf("%u.%02u GHz", ((unsigned int) speed/1000000),
  77. ((unsigned int) (speed%1000000)/10000));
  78. } else if (speed > 100000) {
  79. tmp = speed % 1000;
  80. if (tmp >= 500)
  81. speed += 1000;
  82. printf("%u MHz", ((unsigned int) speed / 1000));
  83. } else if (speed > 1000) {
  84. tmp = speed % 100;
  85. if (tmp >= 50)
  86. speed += 100;
  87. printf("%u.%01u MHz", ((unsigned int) speed/1000),
  88. ((unsigned int) (speed%1000)/100));
  89. } else
  90. printf("%lu kHz", speed);
  91. return;
  92. }
  93. static void print_duration(unsigned long duration)
  94. {
  95. unsigned long tmp;
  96. if (duration > 1000000) {
  97. tmp = duration % 10000;
  98. if (tmp >= 5000)
  99. duration += 10000;
  100. printf("%u.%02u ms", ((unsigned int) duration/1000000),
  101. ((unsigned int) (duration%1000000)/10000));
  102. } else if (duration > 100000) {
  103. tmp = duration % 1000;
  104. if (tmp >= 500)
  105. duration += 1000;
  106. printf("%u us", ((unsigned int) duration / 1000));
  107. } else if (duration > 1000) {
  108. tmp = duration % 100;
  109. if (tmp >= 50)
  110. duration += 100;
  111. printf("%u.%01u us", ((unsigned int) duration/1000),
  112. ((unsigned int) (duration%1000)/100));
  113. } else
  114. printf("%lu ns", duration);
  115. return;
  116. }
  117. /* --boost / -b */
  118. static int get_boost_mode(unsigned int cpu)
  119. {
  120. int support, active, b_states = 0, ret, pstate_no, i;
  121. /* ToDo: Make this more global */
  122. unsigned long pstates[MAX_HW_PSTATES] = {0,};
  123. if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
  124. cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
  125. return 0;
  126. ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
  127. if (ret) {
  128. printf(_("Error while evaluating Boost Capabilities"
  129. " on CPU %d -- are you root?\n"), cpu);
  130. return ret;
  131. }
  132. /* P state changes via MSR are identified via cpuid 80000007
  133. on Intel and AMD, but we assume boost capable machines can do that
  134. if (cpuid_eax(0x80000000) >= 0x80000007
  135. && (cpuid_edx(0x80000007) & (1 << 7)))
  136. */
  137. printf(_(" boost state support:\n"));
  138. printf(_(" Supported: %s\n"), support ? _("yes") : _("no"));
  139. printf(_(" Active: %s\n"), active ? _("yes") : _("no"));
  140. /* ToDo: Only works for AMD for now... */
  141. if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
  142. cpupower_cpu_info.family >= 0x10) {
  143. ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
  144. pstates, &pstate_no);
  145. if (ret)
  146. return ret;
  147. } else
  148. return 0;
  149. printf(_(" Boost States: %d\n"), b_states);
  150. printf(_(" Total States: %d\n"), pstate_no);
  151. for (i = 0; i < pstate_no; i++) {
  152. if (i < b_states)
  153. printf(_(" Pstate-Pb%d: %luMHz (boost state)\n"),
  154. i, pstates[i]);
  155. else
  156. printf(_(" Pstate-P%d: %luMHz\n"),
  157. i - b_states, pstates[i]);
  158. }
  159. return 0;
  160. }
  161. static void debug_output_one(unsigned int cpu)
  162. {
  163. char *driver;
  164. struct cpufreq_affected_cpus *cpus;
  165. struct cpufreq_available_frequencies *freqs;
  166. unsigned long min, max, freq_kernel, freq_hardware;
  167. unsigned long total_trans, latency;
  168. unsigned long long total_time;
  169. struct cpufreq_policy *policy;
  170. struct cpufreq_available_governors *governors;
  171. struct cpufreq_stats *stats;
  172. if (cpufreq_cpu_exists(cpu))
  173. return;
  174. freq_kernel = cpufreq_get_freq_kernel(cpu);
  175. freq_hardware = cpufreq_get_freq_hardware(cpu);
  176. driver = cpufreq_get_driver(cpu);
  177. if (!driver) {
  178. printf(_(" no or unknown cpufreq driver is active on this CPU\n"));
  179. } else {
  180. printf(_(" driver: %s\n"), driver);
  181. cpufreq_put_driver(driver);
  182. }
  183. cpus = cpufreq_get_related_cpus(cpu);
  184. if (cpus) {
  185. printf(_(" CPUs which run at the same hardware frequency: "));
  186. while (cpus->next) {
  187. printf("%d ", cpus->cpu);
  188. cpus = cpus->next;
  189. }
  190. printf("%d\n", cpus->cpu);
  191. cpufreq_put_related_cpus(cpus);
  192. }
  193. cpus = cpufreq_get_affected_cpus(cpu);
  194. if (cpus) {
  195. printf(_(" CPUs which need to have their frequency coordinated by software: "));
  196. while (cpus->next) {
  197. printf("%d ", cpus->cpu);
  198. cpus = cpus->next;
  199. }
  200. printf("%d\n", cpus->cpu);
  201. cpufreq_put_affected_cpus(cpus);
  202. }
  203. latency = cpufreq_get_transition_latency(cpu);
  204. if (latency) {
  205. printf(_(" maximum transition latency: "));
  206. print_duration(latency);
  207. printf(".\n");
  208. }
  209. if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) {
  210. printf(_(" hardware limits: "));
  211. print_speed(min);
  212. printf(" - ");
  213. print_speed(max);
  214. printf("\n");
  215. }
  216. freqs = cpufreq_get_available_frequencies(cpu);
  217. if (freqs) {
  218. printf(_(" available frequency steps: "));
  219. while (freqs->next) {
  220. print_speed(freqs->frequency);
  221. printf(", ");
  222. freqs = freqs->next;
  223. }
  224. print_speed(freqs->frequency);
  225. printf("\n");
  226. cpufreq_put_available_frequencies(freqs);
  227. }
  228. governors = cpufreq_get_available_governors(cpu);
  229. if (governors) {
  230. printf(_(" available cpufreq governors: "));
  231. while (governors->next) {
  232. printf("%s, ", governors->governor);
  233. governors = governors->next;
  234. }
  235. printf("%s\n", governors->governor);
  236. cpufreq_put_available_governors(governors);
  237. }
  238. policy = cpufreq_get_policy(cpu);
  239. if (policy) {
  240. printf(_(" current policy: frequency should be within "));
  241. print_speed(policy->min);
  242. printf(_(" and "));
  243. print_speed(policy->max);
  244. printf(".\n ");
  245. printf(_("The governor \"%s\" may"
  246. " decide which speed to use\n within this range.\n"),
  247. policy->governor);
  248. cpufreq_put_policy(policy);
  249. }
  250. if (freq_kernel || freq_hardware) {
  251. printf(_(" current CPU frequency is "));
  252. if (freq_hardware) {
  253. print_speed(freq_hardware);
  254. printf(_(" (asserted by call to hardware)"));
  255. } else
  256. print_speed(freq_kernel);
  257. printf(".\n");
  258. }
  259. stats = cpufreq_get_stats(cpu, &total_time);
  260. if (stats) {
  261. printf(_(" cpufreq stats: "));
  262. while (stats) {
  263. print_speed(stats->frequency);
  264. printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
  265. stats = stats->next;
  266. if (stats)
  267. printf(", ");
  268. }
  269. cpufreq_put_stats(stats);
  270. total_trans = cpufreq_get_transitions(cpu);
  271. if (total_trans)
  272. printf(" (%lu)\n", total_trans);
  273. else
  274. printf("\n");
  275. }
  276. get_boost_mode(cpu);
  277. }
  278. /* --freq / -f */
  279. static int get_freq_kernel(unsigned int cpu, unsigned int human)
  280. {
  281. unsigned long freq = cpufreq_get_freq_kernel(cpu);
  282. if (!freq)
  283. return -EINVAL;
  284. if (human) {
  285. print_speed(freq);
  286. printf("\n");
  287. } else
  288. printf("%lu\n", freq);
  289. return 0;
  290. }
  291. /* --hwfreq / -w */
  292. static int get_freq_hardware(unsigned int cpu, unsigned int human)
  293. {
  294. unsigned long freq = cpufreq_get_freq_hardware(cpu);
  295. if (!freq)
  296. return -EINVAL;
  297. if (human) {
  298. print_speed(freq);
  299. printf("\n");
  300. } else
  301. printf("%lu\n", freq);
  302. return 0;
  303. }
  304. /* --hwlimits / -l */
  305. static int get_hardware_limits(unsigned int cpu)
  306. {
  307. unsigned long min, max;
  308. if (cpufreq_get_hardware_limits(cpu, &min, &max))
  309. return -EINVAL;
  310. printf("%lu %lu\n", min, max);
  311. return 0;
  312. }
  313. /* --driver / -d */
  314. static int get_driver(unsigned int cpu)
  315. {
  316. char *driver = cpufreq_get_driver(cpu);
  317. if (!driver)
  318. return -EINVAL;
  319. printf("%s\n", driver);
  320. cpufreq_put_driver(driver);
  321. return 0;
  322. }
  323. /* --policy / -p */
  324. static int get_policy(unsigned int cpu)
  325. {
  326. struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
  327. if (!policy)
  328. return -EINVAL;
  329. printf("%lu %lu %s\n", policy->min, policy->max, policy->governor);
  330. cpufreq_put_policy(policy);
  331. return 0;
  332. }
  333. /* --governors / -g */
  334. static int get_available_governors(unsigned int cpu)
  335. {
  336. struct cpufreq_available_governors *governors =
  337. cpufreq_get_available_governors(cpu);
  338. if (!governors)
  339. return -EINVAL;
  340. while (governors->next) {
  341. printf("%s ", governors->governor);
  342. governors = governors->next;
  343. }
  344. printf("%s\n", governors->governor);
  345. cpufreq_put_available_governors(governors);
  346. return 0;
  347. }
  348. /* --affected-cpus / -a */
  349. static int get_affected_cpus(unsigned int cpu)
  350. {
  351. struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
  352. if (!cpus)
  353. return -EINVAL;
  354. while (cpus->next) {
  355. printf("%d ", cpus->cpu);
  356. cpus = cpus->next;
  357. }
  358. printf("%d\n", cpus->cpu);
  359. cpufreq_put_affected_cpus(cpus);
  360. return 0;
  361. }
  362. /* --related-cpus / -r */
  363. static int get_related_cpus(unsigned int cpu)
  364. {
  365. struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
  366. if (!cpus)
  367. return -EINVAL;
  368. while (cpus->next) {
  369. printf("%d ", cpus->cpu);
  370. cpus = cpus->next;
  371. }
  372. printf("%d\n", cpus->cpu);
  373. cpufreq_put_related_cpus(cpus);
  374. return 0;
  375. }
  376. /* --stats / -s */
  377. static int get_freq_stats(unsigned int cpu, unsigned int human)
  378. {
  379. unsigned long total_trans = cpufreq_get_transitions(cpu);
  380. unsigned long long total_time;
  381. struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
  382. while (stats) {
  383. if (human) {
  384. print_speed(stats->frequency);
  385. printf(":%.2f%%",
  386. (100.0 * stats->time_in_state) / total_time);
  387. } else
  388. printf("%lu:%llu",
  389. stats->frequency, stats->time_in_state);
  390. stats = stats->next;
  391. if (stats)
  392. printf(", ");
  393. }
  394. cpufreq_put_stats(stats);
  395. if (total_trans)
  396. printf(" (%lu)\n", total_trans);
  397. return 0;
  398. }
  399. /* --latency / -y */
  400. static int get_latency(unsigned int cpu, unsigned int human)
  401. {
  402. unsigned long latency = cpufreq_get_transition_latency(cpu);
  403. if (!latency)
  404. return -EINVAL;
  405. if (human) {
  406. print_duration(latency);
  407. printf("\n");
  408. } else
  409. printf("%lu\n", latency);
  410. return 0;
  411. }
  412. void freq_info_help(void)
  413. {
  414. printf(_("Usage: cpupower freqinfo [options]\n"));
  415. printf(_("Options:\n"));
  416. printf(_(" -e, --debug Prints out debug information [default]\n"));
  417. printf(_(" -f, --freq Get frequency the CPU currently runs at, according\n"
  418. " to the cpufreq core *\n"));
  419. printf(_(" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n"
  420. " it from hardware (only available to root) *\n"));
  421. printf(_(" -l, --hwlimits Determine the minimum and maximum CPU frequency allowed *\n"));
  422. printf(_(" -d, --driver Determines the used cpufreq kernel driver *\n"));
  423. printf(_(" -p, --policy Gets the currently used cpufreq policy *\n"));
  424. printf(_(" -g, --governors Determines available cpufreq governors *\n"));
  425. printf(_(" -r, --related-cpus Determines which CPUs run at the same hardware frequency *\n"));
  426. printf(_(" -a, --affected-cpus Determines which CPUs need to have their frequency\n"
  427. " coordinated by software *\n"));
  428. printf(_(" -s, --stats Shows cpufreq statistics if available\n"));
  429. printf(_(" -y, --latency Determines the maximum latency on CPU frequency changes *\n"));
  430. printf(_(" -b, --boost Checks for turbo or boost modes *\n"));
  431. printf(_(" -o, --proc Prints out information like provided by the /proc/cpufreq\n"
  432. " interface in 2.4. and early 2.6. kernels\n"));
  433. printf(_(" -m, --human human-readable output for the -f, -w, -s and -y parameters\n"));
  434. printf(_(" -h, --help Prints out this screen\n"));
  435. printf("\n");
  436. printf(_("If no argument is given, full output about\n"
  437. "cpufreq is printed which is useful e.g. for reporting bugs.\n\n"));
  438. printf(_("By default info of CPU 0 is shown which can be overridden\n"
  439. "with the cpupower --cpu main command option.\n"));
  440. }
  441. static struct option info_opts[] = {
  442. { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
  443. { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
  444. { .name = "freq", .has_arg = no_argument, .flag = NULL, .val = 'f'},
  445. { .name = "hwfreq", .has_arg = no_argument, .flag = NULL, .val = 'w'},
  446. { .name = "hwlimits", .has_arg = no_argument, .flag = NULL, .val = 'l'},
  447. { .name = "driver", .has_arg = no_argument, .flag = NULL, .val = 'd'},
  448. { .name = "policy", .has_arg = no_argument, .flag = NULL, .val = 'p'},
  449. { .name = "governors", .has_arg = no_argument, .flag = NULL, .val = 'g'},
  450. { .name = "related-cpus", .has_arg = no_argument, .flag = NULL, .val = 'r'},
  451. { .name = "affected-cpus",.has_arg = no_argument, .flag = NULL, .val = 'a'},
  452. { .name = "stats", .has_arg = no_argument, .flag = NULL, .val = 's'},
  453. { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
  454. { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
  455. { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
  456. { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
  457. { },
  458. };
  459. int cmd_freq_info(int argc, char **argv)
  460. {
  461. extern char *optarg;
  462. extern int optind, opterr, optopt;
  463. int ret = 0, cont = 1;
  464. unsigned int cpu = 0;
  465. unsigned int human = 0;
  466. int output_param = 0;
  467. do {
  468. ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL);
  469. switch (ret) {
  470. case '?':
  471. output_param = '?';
  472. cont = 0;
  473. break;
  474. case 'h':
  475. output_param = 'h';
  476. cont = 0;
  477. break;
  478. case -1:
  479. cont = 0;
  480. break;
  481. case 'b':
  482. case 'o':
  483. case 'a':
  484. case 'r':
  485. case 'g':
  486. case 'p':
  487. case 'd':
  488. case 'l':
  489. case 'w':
  490. case 'f':
  491. case 'e':
  492. case 's':
  493. case 'y':
  494. if (output_param) {
  495. output_param = -1;
  496. cont = 0;
  497. break;
  498. }
  499. output_param = ret;
  500. break;
  501. case 'm':
  502. if (human) {
  503. output_param = -1;
  504. cont = 0;
  505. break;
  506. }
  507. human = 1;
  508. break;
  509. default:
  510. fprintf(stderr, "invalid or unknown argument\n");
  511. return EXIT_FAILURE;
  512. }
  513. } while (cont);
  514. switch (output_param) {
  515. case 'o':
  516. if (!bitmask_isallclear(cpus_chosen)) {
  517. printf(_("The argument passed to this tool can't be "
  518. "combined with passing a --cpu argument\n"));
  519. return -EINVAL;
  520. }
  521. break;
  522. case 0:
  523. output_param = 'e';
  524. }
  525. ret = 0;
  526. /* Default is: show output of CPU 0 only */
  527. if (bitmask_isallclear(cpus_chosen))
  528. bitmask_setbit(cpus_chosen, 0);
  529. switch (output_param) {
  530. case -1:
  531. printf(_("You can't specify more than one --cpu parameter and/or\n"
  532. "more than one output-specific argument\n"));
  533. return -EINVAL;
  534. case '?':
  535. printf(_("invalid or unknown argument\n"));
  536. freq_info_help();
  537. return -EINVAL;
  538. case 'h':
  539. freq_info_help();
  540. return EXIT_SUCCESS;
  541. case 'o':
  542. proc_cpufreq_output();
  543. return EXIT_SUCCESS;
  544. }
  545. for (cpu = bitmask_first(cpus_chosen);
  546. cpu <= bitmask_last(cpus_chosen); cpu++) {
  547. if (!bitmask_isbitset(cpus_chosen, cpu))
  548. continue;
  549. if (cpufreq_cpu_exists(cpu)) {
  550. printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu);
  551. continue;
  552. }
  553. printf(_("analyzing CPU %d:\n"), cpu);
  554. switch (output_param) {
  555. case 'b':
  556. get_boost_mode(cpu);
  557. break;
  558. case 'e':
  559. debug_output_one(cpu);
  560. break;
  561. case 'a':
  562. ret = get_affected_cpus(cpu);
  563. break;
  564. case 'r':
  565. ret = get_related_cpus(cpu);
  566. break;
  567. case 'g':
  568. ret = get_available_governors(cpu);
  569. break;
  570. case 'p':
  571. ret = get_policy(cpu);
  572. break;
  573. case 'd':
  574. ret = get_driver(cpu);
  575. break;
  576. case 'l':
  577. ret = get_hardware_limits(cpu);
  578. break;
  579. case 'w':
  580. ret = get_freq_hardware(cpu, human);
  581. break;
  582. case 'f':
  583. ret = get_freq_kernel(cpu, human);
  584. break;
  585. case 's':
  586. ret = get_freq_stats(cpu, human);
  587. break;
  588. case 'y':
  589. ret = get_latency(cpu, human);
  590. break;
  591. }
  592. if (ret)
  593. return ret;
  594. }
  595. return ret;
  596. }