cpufreq-info.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  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. if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
  141. cpupower_cpu_info.family >= 0x10) {
  142. ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
  143. pstates, &pstate_no);
  144. if (ret)
  145. return ret;
  146. printf(_(" Boost States: %d\n"), b_states);
  147. printf(_(" Total States: %d\n"), pstate_no);
  148. for (i = 0; i < pstate_no; i++) {
  149. if (i < b_states)
  150. printf(_(" Pstate-Pb%d: %luMHz (boost state)"
  151. "\n"), i, pstates[i]);
  152. else
  153. printf(_(" Pstate-P%d: %luMHz\n"),
  154. i - b_states, pstates[i]);
  155. }
  156. } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) {
  157. double bclk;
  158. unsigned long long intel_turbo_ratio = 0;
  159. unsigned int ratio;
  160. /* Any way to autodetect this ? */
  161. if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB)
  162. bclk = 100.00;
  163. else
  164. bclk = 133.33;
  165. intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu);
  166. dprint (" Ratio: 0x%llx - bclk: %f\n",
  167. intel_turbo_ratio, bclk);
  168. ratio = (intel_turbo_ratio >> 24) & 0xFF;
  169. if (ratio)
  170. printf(_(" %.0f MHz max turbo 4 active cores\n"),
  171. ratio * bclk);
  172. ratio = (intel_turbo_ratio >> 16) & 0xFF;
  173. if (ratio)
  174. printf(_(" %.0f MHz max turbo 3 active cores\n"),
  175. ratio * bclk);
  176. ratio = (intel_turbo_ratio >> 8) & 0xFF;
  177. if (ratio)
  178. printf(_(" %.0f MHz max turbo 2 active cores\n"),
  179. ratio * bclk);
  180. ratio = (intel_turbo_ratio >> 0) & 0xFF;
  181. if (ratio)
  182. printf(_(" %.0f MHz max turbo 1 active cores\n"),
  183. ratio * bclk);
  184. }
  185. return 0;
  186. }
  187. static void debug_output_one(unsigned int cpu)
  188. {
  189. char *driver;
  190. struct cpufreq_affected_cpus *cpus;
  191. struct cpufreq_available_frequencies *freqs;
  192. unsigned long min, max, freq_kernel, freq_hardware;
  193. unsigned long total_trans, latency;
  194. unsigned long long total_time;
  195. struct cpufreq_policy *policy;
  196. struct cpufreq_available_governors *governors;
  197. struct cpufreq_stats *stats;
  198. if (cpufreq_cpu_exists(cpu))
  199. return;
  200. freq_kernel = cpufreq_get_freq_kernel(cpu);
  201. freq_hardware = cpufreq_get_freq_hardware(cpu);
  202. driver = cpufreq_get_driver(cpu);
  203. if (!driver) {
  204. printf(_(" no or unknown cpufreq driver is active on this CPU\n"));
  205. } else {
  206. printf(_(" driver: %s\n"), driver);
  207. cpufreq_put_driver(driver);
  208. }
  209. cpus = cpufreq_get_related_cpus(cpu);
  210. if (cpus) {
  211. printf(_(" CPUs which run at the same hardware frequency: "));
  212. while (cpus->next) {
  213. printf("%d ", cpus->cpu);
  214. cpus = cpus->next;
  215. }
  216. printf("%d\n", cpus->cpu);
  217. cpufreq_put_related_cpus(cpus);
  218. }
  219. cpus = cpufreq_get_affected_cpus(cpu);
  220. if (cpus) {
  221. printf(_(" CPUs which need to have their frequency coordinated by software: "));
  222. while (cpus->next) {
  223. printf("%d ", cpus->cpu);
  224. cpus = cpus->next;
  225. }
  226. printf("%d\n", cpus->cpu);
  227. cpufreq_put_affected_cpus(cpus);
  228. }
  229. latency = cpufreq_get_transition_latency(cpu);
  230. if (latency) {
  231. printf(_(" maximum transition latency: "));
  232. print_duration(latency);
  233. printf(".\n");
  234. }
  235. if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) {
  236. printf(_(" hardware limits: "));
  237. print_speed(min);
  238. printf(" - ");
  239. print_speed(max);
  240. printf("\n");
  241. }
  242. freqs = cpufreq_get_available_frequencies(cpu);
  243. if (freqs) {
  244. printf(_(" available frequency steps: "));
  245. while (freqs->next) {
  246. print_speed(freqs->frequency);
  247. printf(", ");
  248. freqs = freqs->next;
  249. }
  250. print_speed(freqs->frequency);
  251. printf("\n");
  252. cpufreq_put_available_frequencies(freqs);
  253. }
  254. governors = cpufreq_get_available_governors(cpu);
  255. if (governors) {
  256. printf(_(" available cpufreq governors: "));
  257. while (governors->next) {
  258. printf("%s, ", governors->governor);
  259. governors = governors->next;
  260. }
  261. printf("%s\n", governors->governor);
  262. cpufreq_put_available_governors(governors);
  263. }
  264. policy = cpufreq_get_policy(cpu);
  265. if (policy) {
  266. printf(_(" current policy: frequency should be within "));
  267. print_speed(policy->min);
  268. printf(_(" and "));
  269. print_speed(policy->max);
  270. printf(".\n ");
  271. printf(_("The governor \"%s\" may"
  272. " decide which speed to use\n within this range.\n"),
  273. policy->governor);
  274. cpufreq_put_policy(policy);
  275. }
  276. if (freq_kernel || freq_hardware) {
  277. printf(_(" current CPU frequency is "));
  278. if (freq_hardware) {
  279. print_speed(freq_hardware);
  280. printf(_(" (asserted by call to hardware)"));
  281. } else
  282. print_speed(freq_kernel);
  283. printf(".\n");
  284. }
  285. stats = cpufreq_get_stats(cpu, &total_time);
  286. if (stats) {
  287. printf(_(" cpufreq stats: "));
  288. while (stats) {
  289. print_speed(stats->frequency);
  290. printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
  291. stats = stats->next;
  292. if (stats)
  293. printf(", ");
  294. }
  295. cpufreq_put_stats(stats);
  296. total_trans = cpufreq_get_transitions(cpu);
  297. if (total_trans)
  298. printf(" (%lu)\n", total_trans);
  299. else
  300. printf("\n");
  301. }
  302. get_boost_mode(cpu);
  303. }
  304. /* --freq / -f */
  305. static int get_freq_kernel(unsigned int cpu, unsigned int human)
  306. {
  307. unsigned long freq = cpufreq_get_freq_kernel(cpu);
  308. if (!freq)
  309. return -EINVAL;
  310. if (human) {
  311. print_speed(freq);
  312. printf("\n");
  313. } else
  314. printf("%lu\n", freq);
  315. return 0;
  316. }
  317. /* --hwfreq / -w */
  318. static int get_freq_hardware(unsigned int cpu, unsigned int human)
  319. {
  320. unsigned long freq = cpufreq_get_freq_hardware(cpu);
  321. if (!freq)
  322. return -EINVAL;
  323. if (human) {
  324. print_speed(freq);
  325. printf("\n");
  326. } else
  327. printf("%lu\n", freq);
  328. return 0;
  329. }
  330. /* --hwlimits / -l */
  331. static int get_hardware_limits(unsigned int cpu)
  332. {
  333. unsigned long min, max;
  334. if (cpufreq_get_hardware_limits(cpu, &min, &max))
  335. return -EINVAL;
  336. printf("%lu %lu\n", min, max);
  337. return 0;
  338. }
  339. /* --driver / -d */
  340. static int get_driver(unsigned int cpu)
  341. {
  342. char *driver = cpufreq_get_driver(cpu);
  343. if (!driver)
  344. return -EINVAL;
  345. printf("%s\n", driver);
  346. cpufreq_put_driver(driver);
  347. return 0;
  348. }
  349. /* --policy / -p */
  350. static int get_policy(unsigned int cpu)
  351. {
  352. struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
  353. if (!policy)
  354. return -EINVAL;
  355. printf("%lu %lu %s\n", policy->min, policy->max, policy->governor);
  356. cpufreq_put_policy(policy);
  357. return 0;
  358. }
  359. /* --governors / -g */
  360. static int get_available_governors(unsigned int cpu)
  361. {
  362. struct cpufreq_available_governors *governors =
  363. cpufreq_get_available_governors(cpu);
  364. if (!governors)
  365. return -EINVAL;
  366. while (governors->next) {
  367. printf("%s ", governors->governor);
  368. governors = governors->next;
  369. }
  370. printf("%s\n", governors->governor);
  371. cpufreq_put_available_governors(governors);
  372. return 0;
  373. }
  374. /* --affected-cpus / -a */
  375. static int get_affected_cpus(unsigned int cpu)
  376. {
  377. struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
  378. if (!cpus)
  379. return -EINVAL;
  380. while (cpus->next) {
  381. printf("%d ", cpus->cpu);
  382. cpus = cpus->next;
  383. }
  384. printf("%d\n", cpus->cpu);
  385. cpufreq_put_affected_cpus(cpus);
  386. return 0;
  387. }
  388. /* --related-cpus / -r */
  389. static int get_related_cpus(unsigned int cpu)
  390. {
  391. struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
  392. if (!cpus)
  393. return -EINVAL;
  394. while (cpus->next) {
  395. printf("%d ", cpus->cpu);
  396. cpus = cpus->next;
  397. }
  398. printf("%d\n", cpus->cpu);
  399. cpufreq_put_related_cpus(cpus);
  400. return 0;
  401. }
  402. /* --stats / -s */
  403. static int get_freq_stats(unsigned int cpu, unsigned int human)
  404. {
  405. unsigned long total_trans = cpufreq_get_transitions(cpu);
  406. unsigned long long total_time;
  407. struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
  408. while (stats) {
  409. if (human) {
  410. print_speed(stats->frequency);
  411. printf(":%.2f%%",
  412. (100.0 * stats->time_in_state) / total_time);
  413. } else
  414. printf("%lu:%llu",
  415. stats->frequency, stats->time_in_state);
  416. stats = stats->next;
  417. if (stats)
  418. printf(", ");
  419. }
  420. cpufreq_put_stats(stats);
  421. if (total_trans)
  422. printf(" (%lu)\n", total_trans);
  423. return 0;
  424. }
  425. /* --latency / -y */
  426. static int get_latency(unsigned int cpu, unsigned int human)
  427. {
  428. unsigned long latency = cpufreq_get_transition_latency(cpu);
  429. if (!latency)
  430. return -EINVAL;
  431. if (human) {
  432. print_duration(latency);
  433. printf("\n");
  434. } else
  435. printf("%lu\n", latency);
  436. return 0;
  437. }
  438. static struct option info_opts[] = {
  439. { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
  440. { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
  441. { .name = "freq", .has_arg = no_argument, .flag = NULL, .val = 'f'},
  442. { .name = "hwfreq", .has_arg = no_argument, .flag = NULL, .val = 'w'},
  443. { .name = "hwlimits", .has_arg = no_argument, .flag = NULL, .val = 'l'},
  444. { .name = "driver", .has_arg = no_argument, .flag = NULL, .val = 'd'},
  445. { .name = "policy", .has_arg = no_argument, .flag = NULL, .val = 'p'},
  446. { .name = "governors", .has_arg = no_argument, .flag = NULL, .val = 'g'},
  447. { .name = "related-cpus", .has_arg = no_argument, .flag = NULL, .val = 'r'},
  448. { .name = "affected-cpus",.has_arg = no_argument, .flag = NULL, .val = 'a'},
  449. { .name = "stats", .has_arg = no_argument, .flag = NULL, .val = 's'},
  450. { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
  451. { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
  452. { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
  453. { },
  454. };
  455. int cmd_freq_info(int argc, char **argv)
  456. {
  457. extern char *optarg;
  458. extern int optind, opterr, optopt;
  459. int ret = 0, cont = 1;
  460. unsigned int cpu = 0;
  461. unsigned int human = 0;
  462. int output_param = 0;
  463. do {
  464. ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL);
  465. switch (ret) {
  466. case '?':
  467. output_param = '?';
  468. cont = 0;
  469. break;
  470. case -1:
  471. cont = 0;
  472. break;
  473. case 'b':
  474. case 'o':
  475. case 'a':
  476. case 'r':
  477. case 'g':
  478. case 'p':
  479. case 'd':
  480. case 'l':
  481. case 'w':
  482. case 'f':
  483. case 'e':
  484. case 's':
  485. case 'y':
  486. if (output_param) {
  487. output_param = -1;
  488. cont = 0;
  489. break;
  490. }
  491. output_param = ret;
  492. break;
  493. case 'm':
  494. if (human) {
  495. output_param = -1;
  496. cont = 0;
  497. break;
  498. }
  499. human = 1;
  500. break;
  501. default:
  502. fprintf(stderr, "invalid or unknown argument\n");
  503. return EXIT_FAILURE;
  504. }
  505. } while (cont);
  506. switch (output_param) {
  507. case 'o':
  508. if (!bitmask_isallclear(cpus_chosen)) {
  509. printf(_("The argument passed to this tool can't be "
  510. "combined with passing a --cpu argument\n"));
  511. return -EINVAL;
  512. }
  513. break;
  514. case 0:
  515. output_param = 'e';
  516. }
  517. ret = 0;
  518. /* Default is: show output of CPU 0 only */
  519. if (bitmask_isallclear(cpus_chosen))
  520. bitmask_setbit(cpus_chosen, 0);
  521. switch (output_param) {
  522. case -1:
  523. printf(_("You can't specify more than one --cpu parameter and/or\n"
  524. "more than one output-specific argument\n"));
  525. return -EINVAL;
  526. case '?':
  527. printf(_("invalid or unknown argument\n"));
  528. return -EINVAL;
  529. case 'o':
  530. proc_cpufreq_output();
  531. return EXIT_SUCCESS;
  532. }
  533. for (cpu = bitmask_first(cpus_chosen);
  534. cpu <= bitmask_last(cpus_chosen); cpu++) {
  535. if (!bitmask_isbitset(cpus_chosen, cpu))
  536. continue;
  537. if (cpufreq_cpu_exists(cpu)) {
  538. printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu);
  539. continue;
  540. }
  541. printf(_("analyzing CPU %d:\n"), cpu);
  542. switch (output_param) {
  543. case 'b':
  544. get_boost_mode(cpu);
  545. break;
  546. case 'e':
  547. debug_output_one(cpu);
  548. break;
  549. case 'a':
  550. ret = get_affected_cpus(cpu);
  551. break;
  552. case 'r':
  553. ret = get_related_cpus(cpu);
  554. break;
  555. case 'g':
  556. ret = get_available_governors(cpu);
  557. break;
  558. case 'p':
  559. ret = get_policy(cpu);
  560. break;
  561. case 'd':
  562. ret = get_driver(cpu);
  563. break;
  564. case 'l':
  565. ret = get_hardware_limits(cpu);
  566. break;
  567. case 'w':
  568. ret = get_freq_hardware(cpu, human);
  569. break;
  570. case 'f':
  571. ret = get_freq_kernel(cpu, human);
  572. break;
  573. case 's':
  574. ret = get_freq_stats(cpu, human);
  575. break;
  576. case 'y':
  577. ret = get_latency(cpu, human);
  578. break;
  579. }
  580. if (ret)
  581. return ret;
  582. }
  583. return ret;
  584. }