cpufreq-info.c 14 KB

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